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:
| Event | Fields | Description |
|---|---|---|
content_delta | content: string | A chunk of text content |
tool_call_start | toolCall: { id, name } | A tool call has started |
tool_call_delta | toolCallId, arguments | Incremental tool call arguments |
tool_call_done | toolCallId | Tool call arguments are complete |
hosted_tool_call | toolType, status | A built-in tool is executing server-side |
subagent_start | agentName: string | A subagent started executing |
subagent_delta | agentName, content | Content from a running subagent |
subagent_end | agentName, result | Subagent finished and returned a result |
done | response: ModelResponse | The model finished a response |
Streaming with Sessions
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:
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:
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:
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:
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.
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");
}
}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 RunAbortedErrorconst 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:
| Property | Type | Description |
|---|---|---|
output | string | Raw text output from the model |
finalOutput | TOutput | Parsed structured output (if outputType is set) |
messages | ChatMessage[] | Full message history for this run |
usage | UsageInfo | Accumulated token usage |
lastAgent | Agent | The agent that produced the final response |
finishReason | string? | The model's finish reason ("stop", "tool_calls", etc.) |
numTurns | number | Number of model calls made during the run |
totalCostUsd | number | Estimated cost in USD (requires costEstimator) |
inputGuardrailResults | GuardrailRunResult[] | Results from input guardrails |
outputGuardrailResults | GuardrailRunResult[] | Results from output guardrails |
Last updated on