Chat Assistant
Route: /chat
File: memberportal/src/pages/ChatAssistantPage.tsx
The Chat Assistant lets patients ask plain-English questions about their health records. It is powered by a separate AI backend service at CHAT_API_BASE_URL (configured in config.ts).
AI API Endpointβ
ChatAssistantPage uses a single endpoint:
POST {CHAT_API_BASE_URL}/api/chat
Request body:
{
"message": "Give me a summary of my recent health activity",
"session_id": "optional-existing-session-id"
}
The request is authenticated with an Authorization: Bearer {accessToken} header β no patient_id in the body.
Response:
{
"reply": "Your hemoglobin A1c is within the normal range...",
"session_id": "session-uuid",
"intent": "lab",
"sources": [
{
"name": "HbA1c result - 2024-03-01",
"resource_type": "Observation",
"resource_id": "xyz456"
}
]
}
| Field | Description |
|---|---|
reply | The AI's answer text (rendered as Markdown) |
session_id | Passed in all follow-up messages to maintain context on the AI side |
intent | Detected topic |
sources | FHIR resources the AI referenced |
Note: The
ResourceChatDrawercomponent (used on health record pages for per-resource explanations) may call different endpoints.ChatAssistantPageexclusively uses/api/chat.
How it worksβ
- Patient types a question (or clicks a quick-answer card).
- If no
ChatSessionexists yet, one is created lazily (draft mode β no API call until the first message is sent). - The user message is optimistically shown, then persisted as a
ChatMessageresource. POST /api/chatis called with the message and the current Python-sidesession_id(if any).- The AI response is shown and also persisted as a
ChatMessageresource. - The
ChatSessiontitle is set to the first 100 characters of the patient's first message.
Chat Sessionsβ
- Sessions are stored as
ChatSessionFHIR resources. - On page load, the last 7 days of sessions are fetched (
_lastUpdated: gt{sevenDaysAgo}). Older sessions are loaded on demand via infinite scroll in the sidebar (IntersectionObserver on a sentinel element, page size 20). - Sessions are grouped in the sidebar by time: Today, Yesterday, This Week, Older.
- Patients can rename (sets
ChatSession.title), delete (removes the session and all itsChatMessageresources), and switch between sessions. - A Medplum session ID β Python
session_idmapping is kept in an in-memory ref (apiSessionMap) per browser tab.
Draft mode (lazy session creation)β
When the patient opens the chat or clicks New Chat, the app enters "draft mode" β no ChatSession is created yet. The session is created the first time the patient actually sends a message. This avoids creating empty sessions.
Context-Aware Chat (Explain feature)β
From any health record page, patients can click Ask ChartChat on a row to open the ResourceChatDrawer pre-loaded with that resource as context. URL params can also drive the initial context:
?explain=Observation/xyz456β opens chat pre-focused on that lab result?topic=labβ sets the welcome message and category context
The ResourceChatDrawer component handles per-resource chats across all record pages.
Quick-Answer Cardsβ
When no messages have been sent yet (welcome state), 8 clickable cards are shown. Clicking one immediately sends the associated pre-written message:
| Card | Pre-sent message |
|---|---|
| Explain my last visit | "Can you explain what happened during my last visit?" |
| What changed recently? | "What changed since my last visit? Any new conditions, medications, or lab results?" |
| Why am I taking this? | "Can you explain why I am taking my current medicationsβ¦" |
| Are my labs normal? | "Are my recent lab results normal? Please explain any flagged results." |
| What conditions do I have? | "What are my active medical conditions? Can you explain each one?" |
| Do I have any allergies? | "What allergies do I have on record? What reactions are associated with them?" |
| Summarize my health | "Can you give me an overall summary of my health based on my medical records?" |
| What procedures have I had? | "What medical procedures have I had? Can you explain what each one was for?" |
FHIR Resources Usedβ
| Resource | Purpose |
|---|---|
ChatSession | Stores each conversation session (title, lastActive) |
ChatMessage | Stores each message β role, content, intent, sources, sourceIds |
Audit Loggingβ
Every chat message is logged via useAuditLog() for security and compliance.