mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
chore(coach): publish the trail route, list it among the mixed reads, and ship its strings in every locale
This commit is contained in:
1 parent
2f5877cf97
commit
8e7fd0b873
12 files changed
+248
-61
No files matched your search
@@ -9429,6 +9429,47 @@ paths:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"422": *a4
|
||||
"429": *a5
|
||||
/api/insights/chat/{id}/messages/{messageId}/trail:
|
||||
get:
|
||||
tags:
|
||||
- Insights
|
||||
summary: Read the trail text of one Coach message
|
||||
description: "v1.41 — the model-written text of one assistant message's trail: the screened reasoning titles and
|
||||
summaries by trail entry, the fact texts the turn recalled, and a pending fact proposal. The trail's structure
|
||||
(phases, statuses, counts) is plaintext on the message's `metricSource.activity`; this route serves only the
|
||||
text, decrypted for the account that owns the conversation. Fetch lazily when the person opens the trail. A
|
||||
mixed read: while the Coach's text may not be shown for the record, the answer is 200 with `trail: null` and the
|
||||
`ai` state beside it. A foreign or unknown conversation or message id maps to 404 (never 403). Auth via cookie
|
||||
or a full-access Bearer token."
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: Conversation id.
|
||||
- name: messageId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: Assistant message id within the conversation.
|
||||
responses:
|
||||
"200":
|
||||
description: The trail text, or null while it may not be served.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CoachMessageTrailResponse"
|
||||
"401": *a1
|
||||
"404":
|
||||
description: Conversation or message not found, or not owned by the caller.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"422": *a4
|
||||
"429": *a5
|
||||
/api/insights/chat/{id}:
|
||||
get:
|
||||
tags:
|
||||
@@ -54159,6 +54200,88 @@ components:
|
||||
- withheld
|
||||
additionalProperties: false
|
||||
description: "One stored table, or the reason it is not served. Absence is explicit: a withheld table names why."
|
||||
CoachMessageTrailResponse:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
trail:
|
||||
anyOf:
|
||||
- $ref: "#/components/schemas/CoachTrail"
|
||||
- type: "null"
|
||||
ai:
|
||||
description: The `coach` capability. While unavailable `trail` is null.
|
||||
$ref: "#/components/schemas/AiCapabilityState"
|
||||
required:
|
||||
- trail
|
||||
- ai
|
||||
additionalProperties: false
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
CoachTrail:
|
||||
type: object
|
||||
properties:
|
||||
entries:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
pattern: ^a[1-9]\d?$
|
||||
title:
|
||||
type: string
|
||||
maxLength: 80
|
||||
text:
|
||||
type: string
|
||||
maxLength: 400
|
||||
required:
|
||||
- id
|
||||
additionalProperties: false
|
||||
recalled:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
maxLength: 160
|
||||
proposal:
|
||||
type: object
|
||||
properties:
|
||||
proposalId:
|
||||
type: string
|
||||
pattern: ^[A-Za-z0-9_-]{1,64}$
|
||||
category:
|
||||
type: string
|
||||
enum:
|
||||
- preference
|
||||
- goal
|
||||
- context
|
||||
- condition
|
||||
- constraint
|
||||
- medication
|
||||
fact:
|
||||
type: string
|
||||
maxLength: 160
|
||||
required:
|
||||
- proposalId
|
||||
- category
|
||||
- fact
|
||||
additionalProperties: false
|
||||
required:
|
||||
- entries
|
||||
additionalProperties: false
|
||||
description: v1.41 — the model-written text of a turn's trail and the fact texts it touched. Encrypted at rest and
|
||||
served only to the account that owns the conversation.
|
||||
CoachConversationDetailResponse:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"en": {
|
||||
"coach": {
|
||||
"clarify": {
|
||||
"comparison": {
|
||||
"baseline90d": "Compare with my usual 90 days"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Since the illness of {date}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"insights": {
|
||||
"coach": {
|
||||
"memory": {
|
||||
"declined": "Okay, I won't."
|
||||
},
|
||||
"plan": {
|
||||
"declined": "Okay, not now."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"de": {
|
||||
"coach": {
|
||||
"clarify": {
|
||||
"comparison": {
|
||||
"baseline90d": "Mit meinen üblichen 90 Tagen vergleichen"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Seit der Erkrankung vom {date}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"insights": {
|
||||
"coach": {
|
||||
"memory": {
|
||||
"declined": "Alles klar, dann nicht."
|
||||
},
|
||||
"plan": {
|
||||
"declined": "Alles klar, dann nicht jetzt."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Rückgängig",
|
||||
"accept": "Ja, merken",
|
||||
"decline": "Nein",
|
||||
"confirmed": "Gemerkt."
|
||||
"confirmed": "Gemerkt.",
|
||||
"declined": "Alles klar, dann nicht."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Plan übernehmen",
|
||||
"decline": "Nicht jetzt",
|
||||
"confirmed": "Ist notiert. Ich schaue in {days} Tagen mit dir drauf."
|
||||
"confirmed": "Ist notiert. Ich schaue in {days} Tagen mit dir drauf.",
|
||||
"declined": "Alles klar, dann nicht jetzt."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Angenommen: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "Letzte 90 Tage",
|
||||
"lastYear": "Letzte 12 Monate",
|
||||
"allTime": "Gesamter Zeitraum"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Mit meinen üblichen 90 Tagen vergleichen"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Seit der Erkrankung vom {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Undo",
|
||||
"accept": "Yes, remember it",
|
||||
"decline": "No",
|
||||
"confirmed": "Got it, I'll remember."
|
||||
"confirmed": "Got it, I'll remember.",
|
||||
"declined": "Okay, I won't."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Take on this plan",
|
||||
"decline": "Not now",
|
||||
"confirmed": "Noted. I'll check in with you in {days} days."
|
||||
"confirmed": "Noted. I'll check in with you in {days} days.",
|
||||
"declined": "Okay, not now."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Assumed: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "Last 90 days",
|
||||
"lastYear": "Last 12 months",
|
||||
"allTime": "All time"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Compare with my usual 90 days"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Since the illness of {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Deshacer",
|
||||
"accept": "Sí, recuérdalo",
|
||||
"decline": "No",
|
||||
"confirmed": "Entendido, lo recordaré."
|
||||
"confirmed": "Entendido, lo recordaré.",
|
||||
"declined": "De acuerdo, no lo haré."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Adoptar este plan",
|
||||
"decline": "Ahora no",
|
||||
"confirmed": "Anotado. Lo revisaremos juntos dentro de {days} días."
|
||||
"confirmed": "Anotado. Lo revisaremos juntos dentro de {days} días.",
|
||||
"declined": "De acuerdo, ahora no."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Supuesto: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "Últimos 90 días",
|
||||
"lastYear": "Últimos 12 meses",
|
||||
"allTime": "Todo el periodo"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Comparar con mis 90 días habituales"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Desde la enfermedad del {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Annuler",
|
||||
"accept": "Oui, retiens-le",
|
||||
"decline": "Non",
|
||||
"confirmed": "C'est noté, je m'en souviendrai."
|
||||
"confirmed": "C'est noté, je m'en souviendrai.",
|
||||
"declined": "D'accord, je ne le ferai pas."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Adopter ce plan",
|
||||
"decline": "Pas maintenant",
|
||||
"confirmed": "C'est noté. On fait le point ensemble dans {days} jours."
|
||||
"confirmed": "C'est noté. On fait le point ensemble dans {days} jours.",
|
||||
"declined": "D'accord, pas maintenant."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Hypothèse : {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "90 derniers jours",
|
||||
"lastYear": "12 derniers mois",
|
||||
"allTime": "Toute la période"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Comparer avec mes 90 jours habituels"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Depuis la maladie du {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Annulla",
|
||||
"accept": "Sì, ricordalo",
|
||||
"decline": "No",
|
||||
"confirmed": "Ricevuto, me lo ricorderò."
|
||||
"confirmed": "Ricevuto, me lo ricorderò.",
|
||||
"declined": "D'accordo, non lo faccio."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Adotta questo piano",
|
||||
"decline": "Non ora",
|
||||
"confirmed": "Annotato. Ne riparliamo insieme tra {days} giorni."
|
||||
"confirmed": "Annotato. Ne riparliamo insieme tra {days} giorni.",
|
||||
"declined": "D'accordo, non ora."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Ipotesi: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "Ultimi 90 giorni",
|
||||
"lastYear": "Ultimi 12 mesi",
|
||||
"allTime": "Intero periodo"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Confronta con i miei soliti 90 giorni"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Dalla malattia del {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "실행 취소",
|
||||
"accept": "네, 기억해 줘",
|
||||
"decline": "아니요",
|
||||
"confirmed": "알겠어요, 기억해 둘게요."
|
||||
"confirmed": "알겠어요, 기억해 둘게요.",
|
||||
"declined": "알겠어요, 저장하지 않을게요."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "이 계획 시작하기",
|
||||
"decline": "나중에",
|
||||
"confirmed": "기록했어요. {days}일 뒤에 함께 살펴볼게요."
|
||||
"confirmed": "기록했어요. {days}일 뒤에 함께 살펴볼게요.",
|
||||
"declined": "알겠어요, 지금은 하지 않을게요."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "가정: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "최근 90일",
|
||||
"lastYear": "최근 12개월",
|
||||
"allTime": "전체 기간"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "평소 90일과 비교하기"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "{date} 질환 이후부터"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
+10
-2
@@ -3185,12 +3185,14 @@
|
||||
"undo": "Cofnij",
|
||||
"accept": "Tak, zapamiętaj",
|
||||
"decline": "Nie",
|
||||
"confirmed": "Jasne, zapamiętam."
|
||||
"confirmed": "Jasne, zapamiętam.",
|
||||
"declined": "Dobrze, nie zapiszę tego."
|
||||
},
|
||||
"plan": {
|
||||
"accept": "Przyjmij ten plan",
|
||||
"decline": "Nie teraz",
|
||||
"confirmed": "Zanotowane. Wrócimy do tego razem za {days} dni."
|
||||
"confirmed": "Zanotowane. Wrócimy do tego razem za {days} dni.",
|
||||
"declined": "Dobrze, nie teraz."
|
||||
},
|
||||
"assumption": {
|
||||
"line": "Założenie: {value}",
|
||||
@@ -10033,6 +10035,12 @@
|
||||
"last90days": "Ostatnie 90 dni",
|
||||
"lastYear": "Ostatnie 12 miesięcy",
|
||||
"allTime": "Cały okres"
|
||||
},
|
||||
"comparison": {
|
||||
"baseline90d": "Porównaj z moimi zwykłymi 90 dniami"
|
||||
},
|
||||
"anchor": {
|
||||
"illness": "Od choroby z {date}"
|
||||
}
|
||||
},
|
||||
"reuse": {
|
||||
|
||||
@@ -102,6 +102,11 @@ export const AI_ROUTES: Readonly<Record<string, AiRouteEntry>> = {
|
||||
capabilities: ["coach"],
|
||||
why: "POST streams a Coach reply from a model. The history GET in the same file asks nothing.",
|
||||
},
|
||||
"src/app/api/insights/chat/[id]/messages/[messageId]/trail/route.ts": {
|
||||
kind: "mixed",
|
||||
capabilities: ["coach"],
|
||||
why: "The trail's reasoning text is model-written and served only while the Coach's text may be shown; otherwise 200 with trail null and the ai state.",
|
||||
},
|
||||
"src/app/api/insights/generate/route.ts": {
|
||||
kind: "action",
|
||||
capabilities: ["briefing"],
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
import {
|
||||
PLAN_REVIEW_DAYS,
|
||||
REMEMBER_FACT_MAX_CHARS,
|
||||
} from "@/lib/ai/coach/memory/contract";
|
||||
} from "@/lib/ai/coach/memory/shared";
|
||||
import {
|
||||
SUGGESTED_ACTION_TYPES,
|
||||
type CheckupIntervalId,
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
coachProvenanceSchema,
|
||||
coachResultEntrySchema,
|
||||
coachStreamEventSchema,
|
||||
coachTrailSchema,
|
||||
} from "@/lib/ai/coach/stream-events";
|
||||
import {
|
||||
coachAttachmentCreateSchema,
|
||||
@@ -870,6 +871,54 @@ export const coachPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/insights/chat/{id}/messages/{messageId}/trail": {
|
||||
get: {
|
||||
tags: ["Insights"],
|
||||
summary: "Read the trail text of one Coach message",
|
||||
description:
|
||||
"v1.41 — the model-written text of one assistant message's trail: the screened reasoning titles and summaries by trail entry, the fact texts the turn recalled, and a pending fact proposal. The trail's structure (phases, statuses, counts) is plaintext on the message's `metricSource.activity`; this route serves only the text, decrypted for the account that owns the conversation. Fetch lazily when the person opens the trail. A mixed read: while the Coach's text may not be shown for the record, the answer is 200 with `trail: null` and the `ai` state beside it. A foreign or unknown conversation or message id maps to 404 (never 403). Auth via cookie or a full-access Bearer token.",
|
||||
parameters: [
|
||||
{
|
||||
name: "id",
|
||||
in: "path",
|
||||
required: true,
|
||||
schema: { type: "string" },
|
||||
description: "Conversation id.",
|
||||
},
|
||||
{
|
||||
name: "messageId",
|
||||
in: "path",
|
||||
required: true,
|
||||
schema: { type: "string" },
|
||||
description: "Assistant message id within the conversation.",
|
||||
},
|
||||
],
|
||||
responses: {
|
||||
"200": {
|
||||
description: "The trail text, or null while it may not be served.",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: dataEnvelope(
|
||||
z.object({
|
||||
trail: coachTrailSchema.nullable(),
|
||||
ai: aiCapabilityState.describe(
|
||||
"The `coach` capability. While unavailable `trail` is null.",
|
||||
),
|
||||
}),
|
||||
"CoachMessageTrailResponse",
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
"404": {
|
||||
description:
|
||||
"Conversation or message not found, or not owned by the caller.",
|
||||
content: { "application/json": { schema: errorEnvelope } },
|
||||
},
|
||||
...stdResponses,
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/insights/chat/{id}": {
|
||||
get: {
|
||||
tags: ["Insights"],
|
||||
|
||||
Reference in new issue
Block a user