Shirube

Documentation

Streaming and events

run() waits for the full answer. UIs need progress: tokens, tools, handoffs, errors.

What it is

run() waits for the full answer. UIs need progress: tokens (or the final chunk), tool start/stop, handoffs, errors.

Shirube exposes the same timeline as:

  • async iteratorfor await (const event of agent.runStream(...))
  • callbackagent.run(prompt, { onEvent })

Use streaming for chat bubbles, terminals, and live traces. The iterator completes when the run succeeds; it throws if the run fails (run.failed is still emitted first).

Event types

TypeWhen
run.startedLoop begins
model.calledA provider request finished
text.streamedAssistant text (data.delta)
tool.started / tool.completedFunction call lifecycle (data.name, denied if approval failed)
handoff.startedSpecialist takes over
guardrail.triggeredA rail redacted or blocked
memory.updatedLong-term memory write
graph.updatedConversation queued for graph workers
run.completed / run.failedTerminal
stream.ts
for await (const event of agent.runStream("Hello", { userId: "ada" })) {
  switch (event.type) {
    case "text.streamed":
      process.stdout.write(String(event.data?.delta ?? ""));
      break;
    case "tool.started":
      console.log("tool", event.data?.name);
      break;
    case "handoff.started":
      console.log("handoff", event.data?.from, "→", event.data?.to);
      break;
    case "run.completed":
      console.log("done");
      break;
  }
}

Each event has runId and timestamp. This is enough to drive a React log or an OpenTelemetry span per tool.