stratus

Streaming

Real-time streaming of model responses

Streaming displays partial responses as they arrive. Stratus supports it at every level - sessions, stream(), and the raw model interface.

Stream Events

All streaming APIs yield StreamEvent objects:

EventFieldsDescription
content_deltacontent: stringA chunk of text content
tool_call_starttoolCall: { id, name }A tool call has started
tool_call_deltatoolCallId, argumentsIncremental tool call arguments
tool_call_donetoolCallIdTool call arguments are complete
hosted_tool_calltoolType, statusA built-in tool is executing server-side
subagent_startagentName: stringA subagent started executing
subagent_deltaagentName, contentContent from a running subagent
subagent_endagentName, resultSubagent finished and returned a result
doneresponse: ModelResponseThe model finished a response

Streaming with Sessions

session-stream.ts
session.send("Tell me a story");
for await (const event of session.stream()) {
  switch (event.type) {
    case "content_delta":
      process.stdout.write(event.content);
      break;
    case "done":
      console.log("\n\nTokens:", event.response.usage?.totalTokens);
      break;
  }
}

Streaming with stream()

The lower-level stream() function returns both a stream and a result promise:

stream.ts
import { Agent, stream } from "@usestratus/sdk/core";

const agent = new Agent({ name: "writer", model });
const { stream: s, result } = stream(agent, "Write a haiku");

for await (const event of s) {
  if (event.type === "content_delta") {
    process.stdout.write(event.content);
  }
}

const finalResult = await result;
console.log(finalResult.output);
console.log(finalResult.usage);

Hosted Tool Events

When using built-in tools (web search, code interpreter, etc.), you'll receive hosted_tool_call events as the server-side tool executes:

hosted-tool-events.ts
for await (const event of session.stream()) {
  if (event.type === "hosted_tool_call") { 
    console.log(`${event.toolType}: ${event.status}`);
    // e.g. "web_search: searching", "code_interpreter: interpreting"
  }
}

The status field indicates the current state: "in_progress", "completed", "searching", "generating", or "interpreting".

Subagent Events

When a subagent runs during streaming, its output is relayed through the parent stream in real time:

subagent-events.ts
for await (const event of session.stream()) {
  switch (event.type) {
    case "subagent_start":
      console.log(`Delegating to ${event.agentName}...`);
      break;
    case "subagent_delta":
      process.stdout.write(event.content); // real-time child output
      break;
    case "subagent_end":
      console.log(`\n${event.agentName} returned: ${event.result}`);
      break;
  }
}

Multi-Turn Tool Calls

When the model makes tool calls during streaming, you'll see multiple rounds of events. Each round consists of tool call events followed by content events:

tool-events.ts
for await (const event of session.stream()) {
  switch (event.type) {
    case "tool_call_start":
      console.log(`Calling tool: ${event.toolCall.name}`);
      break;
    case "content_delta":
      process.stdout.write(event.content);
      break;
    case "done":
      // One 'done' per model call - you may see multiple if tools are used
      break;
  }
}

Abort Signal

Pass an AbortSignal to cancel a running stream or run(). When aborted, a RunAbortedError is thrown.

abort-run.ts
import { RunAbortedError } from "@usestratus/sdk/core";

const ac = new AbortController();
setTimeout(() => ac.abort(), 5000); // Cancel after 5 seconds

try {
  const result = await run(agent, "Write a novel", { signal: ac.signal }); 
} catch (error) {
  if (error instanceof RunAbortedError) {
    console.log("Run was cancelled");
  }
}
abort-stream.ts
const ac = new AbortController();
const { stream: s, result } = stream(agent, "Write a novel", {
  signal: ac.signal, 
});

try {
  for await (const event of s) {
    if (event.type === "content_delta") process.stdout.write(event.content);
  }
} catch (error) {
  if (error instanceof RunAbortedError) {
    console.log("Stream was cancelled");
  }
}

// The result promise also rejects with RunAbortedError
abort-session.ts
const ac = new AbortController();

session.send("Write a very long essay.");
try {
  for await (const event of session.stream({ signal: ac.signal })) { 
    if (event.type === "content_delta") process.stdout.write(event.content);
  }
} catch (error) {
  if (error instanceof RunAbortedError) {
    console.log("Session stream was cancelled");
  }
}

The signal is threaded through to model API calls and tool execute functions, so cancellation is immediate. Pre-aborted signals throw RunAbortedError without making any API calls.

Non-Streaming with run()

If you don't need streaming, run() returns the complete result directly:

import { Agent, run } from "@usestratus/sdk/core";

const agent = new Agent({ name: "assistant", model });
const result = await run(agent, "What is 2 + 2?");
console.log(result.output);

RunResult

Both run() and stream() produce a RunResult:

PropertyTypeDescription
outputstringRaw text output from the model
finalOutputTOutputParsed structured output (if outputType is set)
messagesChatMessage[]Full message history for this run
usageUsageInfoAccumulated token usage
lastAgentAgentThe agent that produced the final response
finishReasonstring?The model's finish reason ("stop", "tool_calls", etc.)
numTurnsnumberNumber of model calls made during the run
totalCostUsdnumberEstimated cost in USD (requires costEstimator)
inputGuardrailResultsGuardrailRunResult[]Results from input guardrails
outputGuardrailResultsGuardrailRunResult[]Results from output guardrails
Edit on GitHub

Last updated on

On this page