Chat agent
The AI chat endpoint — a tool-using agent over patient data.
The chat endpoint runs a tool-using AI agent over the clinic's patient data. It requires
a signed-in user, an active clinic, and patient:read. It also honours the clinic's
AI policy: if the assistant is disabled for the caller, POST /api/chat
returns 403.
| Method | Path | Auth | Returns |
|---|---|---|---|
POST | /api/chat | patient:read | A streamed UI-message response (SSE) |
GET | /api/chat/threads | patient:read | Your saved conversations |
GET | /api/chat/threads/{id} | patient:read | One conversation + messages |
PUT | /api/chat/threads/{id} | patient:read | Save a conversation snapshot |
DELETE | /api/chat/threads/{id} | patient:read | Delete a conversation |
Request
{
"messages": [ /* AI SDK UI messages */ ],
"model": "claude-sonnet-4-6",
"effort": "medium",
"mode": "analysis"
}The model selects the provider too (e.g. a claude-* id routes to Anthropic, gpt-*
to OpenAI, gemini-* to Gemini, the ollama sentinel to your local model). The matching
provider key from your AI config is used. If no key is configured for the
chosen provider, the request fails with a clear message.
The optional mode (chat | analysis | graph) is the clinician's chosen situation
mode. It appends a short directive to the system prompt — analysis steers the assistant
toward interpreting patterns across a patient's history, graph toward describing how their
problems and visits connect (the UI also renders a record graph). chat (the default) adds
nothing.
File attachments. Messages may include AI-SDK file parts (uploaded files). The
server reads text-like files (CSV/JSON/TXT/…) into the prompt so the agent can parse them
(e.g. a medications list to stock, or a database export to import); images and PDFs are
passed through for vision-capable providers. In the UI these render as attachment chips,
not raw text.
What the agent can do
The agent can display and add data — but never edits, deletes, or alters the database structure. Every add is a dry-run proposal that streams an approval card; the record is written only after the clinician approves, through the existing RBAC-gated REST endpoint (so an under-privileged role is rejected at commit).
Display (read):
getPatient— look up a patient by file number and render record cards.getPatientLabs— pull labs + trend and render a lab chart with high/low flags.searchPatients— find patients by name, then look one up.listAppointments/listTasks/listPrescriptions— render the clinic's schedule, task queue, or prescriptions as list cards.getClinicInfo— the clinic's name / basic info.getAnalytics— clinic KPIs and earnings (billed/paid/outstanding, by month), rendered with an earnings chart.listInventory— stock levels and low-stock items.
Add (propose → approve, nothing written until approved):
proposeAppointment/proposeTask/proposePrescription— validate a new record and show an approval card. On Add, the client commits via/api/appointments,/api/tasks, or/api/prescriptions.proposeInventory— parse an uploaded stock/medications list (names, quantities, prices) into inventory items and show an approval card; on Add, commits via/api/inventory. Use this to stock inventory, vs.proposeInvoicewhich bills a patient.proposeInvoice— parse an uploaded purchase/medication list into invoice line items and show an approval card; on Add, commits via/api/invoices(creating/linking a patient when needed).previewImport— a dry run for migration (or a single add): validates records parsed from an uploaded export and shows an approval card. Nothing is written until the clinician approves and the client callsPOST /api/ai/import.
All tools run under the caller's role scoping (a doctor only sees their own panel;
reception sees demographics only) — identical to the patient routes.
Response
The endpoint streams an AI-SDK UI-message stream. Alongside the assistant's text it
emits custom data parts the clinician's UI renders as rich cards:
data-patientCard, data-labCard, data-importPreview, data-appointmentList,
data-taskList, data-prescriptionList, data-inventoryList, data-clinicCard,
data-analyticsCard, data-actionPreview (an add awaiting approval),
data-step (a live Chain-of-Thought step), data-source (a citable record the
model can reference), and a data-veilNotice flag.
Each retrieval tool also registers a PHI-free sourceId and emits a data-source part
({ id, title, kind }). The model cites facts inline with a [[src:id]] marker, which the
UI renders as a numbered inline citation chip; a sources footer attributes the records
when the model omits markers.
Conversations are persisted per user via the /api/chat/threads endpoints (the client
saves a snapshot after each exchange and lists/opens them in the sidebar history).
These data parts carry the real record data straight to the clinician. On external providers the model itself only ever receives Veil-redacted results.