Open app
Moonborn — Developers

Streaming patterns

Server-Sent Events from the generation pipeline and the chat endpoint — event shapes, reconnect, abort.

Two endpoints stream:

  • POST /v1/personas?stream=true — the six-step generation pipeline.
  • POST /v1/chat/sessions/{id}/messages?stream=true — chat replies.

Both speak Server-Sent Events. Same envelope, different event types.

Generation events

event: step.started      data: { step: "soul_draft" }
event: step.completed    data: { step: "soul_draft", durationMs, model }
event: pipeline.completed data: { personaId, durationMs }

The six steps emit step.started + step.completed in order; the terminal pipeline.completed carries the final persona ID.

Chat events

event: token       data: { delta: "Walk..." }
event: token       data: { delta: " me through" }
event: completed   data: { messageId, driftScore, driftThreshold }

Tokens stream in order; completed arrives once, with the drift envelope.

Read loop (TypeScript)

const res = await fetch(url, { method: 'POST', headers, body });
const reader = res.body!.getReader();
const decoder = new TextDecoder();
let buf = '';
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  buf += decoder.decode(value, { stream: true });
  let idx;
  while ((idx = buf.indexOf('\n\n')) !== -1) {
    const frame = buf.slice(0, idx);
    buf = buf.slice(idx + 2);
    const lines = frame.split('\n');
    const event = lines.find((l) => l.startsWith('event:'))?.slice(6).trim();
    const data = lines.find((l) => l.startsWith('data:'))?.slice(5).trim();
    if (event === 'token') process.stdout.write(JSON.parse(data!).delta);
  }
}

The SDK does this for you — see client.chat.streamMessage() and client.personas.createStream().

Abort

Pass an AbortController.signal to fetch. Moonborn stops billing the moment the client disconnects.

Reconnect

SSE has no built-in resume. If your client drops mid-stream, the generation/reply is already running server-side — re-fetch it via GET /v1/personas/{id} (for generation) or GET /v1/chat/sessions/{id}/messages (for chat). Don't retry the stream itself.

Tier

Every tier.