flowchart LR C([curl]) -- POST /chat --> H[node:http] --> S[StreamingAgent] S -. SSE events .-> C
What it shows
- Each agent event becomes one
data:line. - The server uses only
node:http; any framework works the same way.
Serve a streaming agent over HTTP with Server-Sent Events.
flowchart LR C([curl]) -- POST /chat --> H[node:http] --> S[StreamingAgent] S -. SSE events .-> C
data: line.node:http; any framework works the same way.import { createServer } from 'node:http';
import { StreamingAgent } from '@astack-tech/components';
import { ModelProvider } from '@astack-tech/integrations';
const apiKey = process.env['DEEPSEEK_API_KEY'];
if (!apiKey) {
throw new Error('Set DEEPSEEK_API_KEY to run this example.');
}
const agent = new StreamingAgent({ model: new ModelProvider.Deepseek({ apiKey }) });
const port = Number(process.env['PORT'] ?? 3000);
// POST /chat with a plain-text body. The reply is a stream of Server-Sent Events.
const server = createServer((request, response) => {
if (request.method !== 'POST' || request.url !== '/chat') {
response.writeHead(404).end();
return;
}
let body = '';
request.setEncoding('utf8');
request.on('data', (chunk: string) => {
body += chunk;
});
request.on('end', () => {
response.writeHead(200, {
'content-type': 'text/event-stream',
'cache-control': 'no-cache',
connection: 'keep-alive',
});
void (async () => {
try {
for await (const event of agent.runStream(body)) {
response.write(`data: ${JSON.stringify(event)}\n\n`);
}
} catch {
// runStream already sent an `error` event before it threw.
} finally {
response.end();
}
})();
});
});
server.listen(port, () => {
console.log(`curl -N -X POST localhost:${String(port)}/chat -d "Explain ports in one line"`);
});
pnpm install && pnpm build
export DEEPSEEK_API_KEY=sk-...
pnpm --filter @astack-examples/http-server start