Handle safety and escalation
Build explicit, forward-compatible behavior for safety and workflow events.
Doctronic returns assistant text and typed control events on the same Server-Sent Events stream. Your integration should render text and make workflow decisions through separate code paths.
The documented safety interface is the published event stream, including guardian, conversation.end,
conversation.offtopic, skill_code.cta, ai_consultation.complete, and error.
Handle guardian events explicitly
A guardian event contains a stable guardianId and a message for the integration's approved
safety behavior.
event: guardian
data: {"type":"guardian","guardianId":"emergency_breathing","message":"Please call emergency services now."}
If it arrives:
- Stop any routine local flow that conflicts with your approved safety behavior.
- Apply the presentation or escalation behavior defined for your integration.
- Record the event type,
guardianId, chat ID, and timestamp in your operational telemetry. - Avoid placing the Bearer token or unrestricted patient content in logs.
- Follow the escalation behavior agreed with your Doctronic business or implementation contact.
The API does not define a guardian acknowledgement endpoint. Do not invent an acknowledgement by replaying the chat turn or sending another message automatically.
Branch on event type
function handleClinicalEvent(event: ClinicalEvent) {
switch (event.type) {
case 'message.start':
return messages.begin(event.messageId);
case 'message.content':
return messages.append(event.messageId, event.content);
case 'message.stop':
return messages.finish(event.messageId);
case 'guardian':
return safety.enter(event.guardianId, event.message);
case 'skill_code.cta':
return actions.present(event);
case 'conversation.end':
return conversation.finish(event.reason);
case 'ai_consultation.complete':
return artifacts.capture(event.artifacts);
case 'error':
return streamErrors.handle(event);
default:
return;
}
}ClinicalEvent in this example is an integration-owned type. Generate or maintain it from the
published event examples, and keep an unknown-event branch so additive changes do not break the
stream.
Distinguish the end states
| Signal | Meaning | What not to assume |
|---|---|---|
message.stop | One assistant message has finished. | The consultation is complete. |
conversation.end | The assistant ended the conversation and supplied a reason. | That any artifact is ready. |
ai_consultation.complete | Stable artifact IDs are available. | That every artifact is ready; retrieval can return 202 while generation continues. |
| HTTP stream closes | Transport for the turn ended. | A clinical or workflow outcome occurred. |
Use these signals independently. For example, capture artifact IDs only from
ai_consultation.complete, then retrieve each artifact through its resource endpoint.
Handle recoverable errors
An error event can arrive after the HTTP response has already started. Parse it separately from
HTTP failures. If the event includes retryAfterSeconds, wait at least that long before retrying.
Do not automatically replay a chat turn after a network interruption. The stream operation does
not accept an idempotency key, so first reconcile the transcript with
GET /chats/{chatId}/messages/ or ask the user to retry through an explicit interface.
Define a local fallback
Before production, agree on behavior for:
- An unknown guardian ID.
- An unknown CTA widget or skill code.
- A stream that ends before
message.stop. - A recoverable
errorwithoutretryAfterSeconds. - A prolonged loss of connectivity.
- A user who returns to a conversation after
conversation.end.
These are integration decisions. The public API does not prescribe the user interface or an external escalation destination.