Skip to main content

Streaming

The TypeScript SDK uses fetch + ReadableStream for SSE streaming, enabling POST requests with custom headers β€” something EventSource cannot do.

Basic Streaming​

import { FaosClient } from '@faos/sdk';

const client = new FaosClient({ apiKey: 'faos_sk_...' });

for await (const chunk of client.agents.stream(
'credit-risk-analyst',
{ query: 'Analyze Q1 2024' },
)) {
switch (chunk.type) {
case 'text':
process.stdout.write(chunk.data);
break;
case 'tool_call':
console.log(`Tool: ${chunk.data.name}`, chunk.data.input);
break;
case 'metadata':
console.log('Metadata:', chunk.data);
break;
case 'error':
console.error(`Error: ${chunk.data.code} - ${chunk.data.message}`);
break;
case 'done':
console.log('\nDone:', chunk.data);
break;
}
}
<PlaygroundButton code={"import { FaosClient } from '@faos/sdk';\n\nconst client = new FaosClient({ apiKey: 'faos_sk_...' });\n\nfor await (const chunk of client.agents.stream(\n 'credit-risk-analyst',\n { query: 'Analyze Q1 2024' },\n)) {\n switch (chunk.type) {\n case 'text':\n process.stdout.write(chunk.data);\n break;\n case 'tool_call':\n console.log(`Tool: ${chunk.data.name}`, chunk.data.input);\n break;\n case 'metadata':\n console.log('Metadata:', chunk.data);\n break;\n case 'error':\n console.error(`Error: ${chunk.data.code} - ${chunk.data.message}`);\n break;\n case 'done':\n console.log('\\nDone:', chunk.data);\n break;\n }\n}"} lang="typescript" />

Text-Only Convenience​

Use streamText for a simpler API that yields only text strings:

for await (const text of client.agents.streamText(
'credit-risk-analyst',
{ query: 'Analyze Q1 2024' },
)) {
process.stdout.write(text);
}
<PlaygroundButton code={"for await (const text of client.agents.streamText(\n 'credit-risk-analyst',\n { query: 'Analyze Q1 2024' },\n)) {\n process.stdout.write(text);\n}"} lang="typescript" />

StreamChunk Types​

The StreamChunk is a discriminated union:

type StreamChunk =
| { type: 'text'; data: string; index: number }
| { type: 'tool_call'; data: { name: string; input: Record<string, unknown> }; index: number }
| { type: 'metadata'; data: Record<string, unknown>; index: number }
| { type: 'error'; data: { code: string; message: string }; index: number }
| { type: 'done'; data: { usage: TokenUsage; durationMs: number }; index: number };

TypeScript narrows the data type based on chunk.type.

Reconnection​

Pass lastEventId to resume a stream after disconnection (ADR-FE-2):

for await (const chunk of client.agents.stream(
'analyst',
{ query: '...' },
{ lastEventId: 'evt-42' },
)) {
// Resumes from where the previous stream left off
}

Building a Chat UI​

async function streamToUI(agentId: string, query: string) {
const client = new FaosClient({ apiKey: 'faos_sk_...' });
let fullText = '';

for await (const chunk of client.agents.stream(agentId, { query })) {
if (chunk.type === 'text') {
fullText += chunk.data;
// Update UI incrementally
updateChatBubble(fullText);
}
}
return fullText;
}
<PlaygroundButton code={"async function streamToUI(agentId: string, query: string) {\n const client = new FaosClient({ apiKey: 'faos_sk_...' });\n let fullText = '';\n\n for await (const chunk of client.agents.stream(agentId, { query })) {\n if (chunk.type === 'text') {\n fullText += chunk.data;\n // Update UI incrementally\n updateChatBubble(fullText);\n }\n }\n return fullText;\n}"} lang="typescript" />

Browser Usage​

The SDK works in browsers with native fetch β€” no polyfills needed:

// Works in any modern browser
const client = new FaosClient({ apiKey: 'faos_sk_...' });
for await (const text of client.agents.streamText('analyst', { query })) {
document.getElementById('output')!.textContent += text;
}