Developers

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:

  1. Stop any routine local flow that conflicts with your approved safety behavior.
  2. Apply the presentation or escalation behavior defined for your integration.
  3. Record the event type, guardianId, chat ID, and timestamp in your operational telemetry.
  4. Avoid placing the Bearer token or unrestricted patient content in logs.
  5. 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

SignalMeaningWhat not to assume
message.stopOne assistant message has finished.The consultation is complete.
conversation.endThe assistant ended the conversation and supplied a reason.That any artifact is ready.
ai_consultation.completeStable artifact IDs are available.That every artifact is ready; retrieval can return 202 while generation continues.
HTTP stream closesTransport 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 error without retryAfterSeconds.
  • 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.

On this page