Skip to main content

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"
}
]
}
FieldDescription
replyThe AI's answer text (rendered as Markdown)
session_idPassed in all follow-up messages to maintain context on the AI side
intentDetected topic
sourcesFHIR resources the AI referenced

Note: The ResourceChatDrawer component (used on health record pages for per-resource explanations) may call different endpoints. ChatAssistantPage exclusively uses /api/chat.


How it works​

  1. Patient types a question (or clicks a quick-answer card).
  2. If no ChatSession exists yet, one is created lazily (draft mode β€” no API call until the first message is sent).
  3. The user message is optimistically shown, then persisted as a ChatMessage resource.
  4. POST /api/chat is called with the message and the current Python-side session_id (if any).
  5. The AI response is shown and also persisted as a ChatMessage resource.
  6. The ChatSession title is set to the first 100 characters of the patient's first message.

Chat Sessions​

  • Sessions are stored as ChatSession FHIR 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 its ChatMessage resources), and switch between sessions.
  • A Medplum session ID β†’ Python session_id mapping 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:

CardPre-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​

ResourcePurpose
ChatSessionStores each conversation session (title, lastActive)
ChatMessageStores each message β€” role, content, intent, sources, sourceIds

Audit Logging​

Every chat message is logged via useAuditLog() for security and compliance.