feat(ai): inline source citations in the AI chat

Retrieval tools now register a PHI-free sourceId per record/list and stream a
data-source part with the real clinician-facing title; the system prompt asks
the model to cite facts inline as [[src:id]]. The chat renders those markers as
numbered inline citation chips (PreviewCard hover) via a Streamdown link
override, with a Sources footer fallback when the model omits markers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-19 20:41:48 +03:00
parent 2f36875d37
commit 0fa2802723
6 changed files with 216 additions and 11 deletions
+11
View File
@@ -43,6 +43,16 @@ export type StepData = {
status: "active" | "complete";
};
// A citable source the agent retrieved (one per display-tool call). The model
// references it inline via a [[src:id]] marker; the client renders that marker
// as an inline citation chip and a sources footer. `title` is the real,
// clinician-facing label; `id` is PHI-free (s1, s2, …).
export type SourceData = {
id: string;
title: string;
kind: string;
};
// Read-only list cards (display actions).
export type AppointmentListData = { appointments: Appointment[] };
export type TaskListData = { tasks: Task[] };
@@ -85,6 +95,7 @@ export type TemetroDataParts = {
importPreview: ImportPreviewData;
veilNotice: VeilNoticeData;
step: StepData;
source: SourceData;
appointmentList: AppointmentListData;
taskList: TaskListData;
prescriptionList: PrescriptionListData;
@@ -947,6 +947,19 @@
"thinking": "Thinking…",
"steps": "Steps",
"reasoning": "Reasoning",
"sources": {
"title": "Sources",
"kind": {
"patient": "Patient record",
"lab": "Lab results",
"appointments": "Schedule",
"tasks": "Tasks",
"prescriptions": "Prescriptions",
"clinic": "Clinic",
"analytics": "Analytics",
"inventory": "Inventory"
}
},
"graphCard": {
"label": "Record graph"
},