Streaming
Agents and graphs emit a shared AiEvent stream. Pipe it to SSE, websockets, logs, or OpenTelemetry.
Agent SSE
sse.ts
typescript
reply.hijack();
reply.raw.writeHead(200, {
"content-type": "text/event-stream",
"cache-control": "no-cache",
connection: "keep-alive",
});
for await (const ev of bot.stream(message)) {
reply.raw.write(`data: ${JSON.stringify(ev)}\n\n`);
}
reply.raw.end();Event union
events.ts
typescript
type AiEvent =
| { type: "run_start"; runId: string; kind: "agent" | "graph"; name: string }
| { type: "text"; runId: string; text: string }
| { type: "tool_call"; runId: string; toolCall: AiToolCall }
| { type: "tool_result"; runId: string; toolCallId: string; name: string; content: string }
| { type: "node_start"; runId: string; nodeId: string; nodeType: string }
| { type: "node_end"; runId: string; nodeId: string; output?: string }
| { type: "interrupt"; runId: string; nodeId: string; prompt: string }
| { type: "handoff"; runId: string; from: string; to: string }
| { type: "error"; runId: string; error: string }
| {
type: "run_end";
runId: string;
status: "completed" | "failed" | "waitingInterrupt" | "handed_off" | "aborted";
result?: JsonValue;
};Helpers
helpers.ts
typescript
import { collectEvents, tapEvents, createOtelListener } from "@monorch/ai";
const events = await collectEvents(bot.stream("hi"));
for await (const ev of tapEvents(bot.stream("hi"), createOtelListener())) {
// same events, plus OTel side effects
}