Skip to content
This repository was archived by the owner on Mar 25, 2026. It is now read-only.

Commit 3f87389

Browse files
authored
Changes for new Streaming, Wait Until and File Import Improvements (#299)
1 parent ee7b973 commit 3f87389

3 files changed

Lines changed: 930 additions & 4 deletions

File tree

‎content/Guides/agent-streaming.mdx‎

Lines changed: 140 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ description: How to use streaming in your agents
3535

3636
## How Streaming Works in Agentuity
3737

38-
1. **Outbound:** `resp.stream(source)` – where `source` can be:
38+
Agentuity provides multiple approaches for streaming data:
39+
40+
1. **High-level Streaming:** `resp.stream(source)` – where `source` can be:
3941
- An async iterator (e.g. OpenAI SDK stream)
4042
- A ReadableStream
4143
- Another agent's stream
42-
2. **Inbound:** `await request.data.stream()` – consume the client's incoming stream.
43-
3. Under the hood Agentuity handles the details of the streaming input and output for you.
44+
2. **Low-level Stream Control:** `context.stream.create(name, props)` – create and manage server-side streams directly
45+
3. **Inbound:** `await request.data.stream()` – consume the client's incoming stream.
46+
47+
Under the hood Agentuity handles the details of the streaming input and output for you.
4448

4549
### OpenAI Streaming Example
4650

@@ -182,6 +186,139 @@ export default async function Agent(
182186

183187
Chain as many agents as you like; each one can inspect, transform, or just relay the chunks.
184188

189+
## Low-Level Stream Control
190+
191+
For advanced use cases, you can use `context.stream.create()` to create and manage streams directly. This gives you fine-grained control over stream creation, data flow, and background processing.
192+
193+
### Creating Streams with `context.stream.create`
194+
195+
The `context.stream.create()` method creates a named, writable stream that returns immediately, allowing for non-blocking operation and background data processing.
196+
197+
```ts
198+
import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
199+
import { openai } from '@ai-sdk/openai';
200+
import { streamText } from 'ai';
201+
202+
export default async function Agent(
203+
req: AgentRequest,
204+
resp: AgentResponse,
205+
ctx: AgentContext,
206+
) {
207+
const { prompt } = await req.data.json();
208+
209+
// Create a stream immediately - this returns right away
210+
const stream = ctx.stream.create('llm-response', {
211+
contentType: 'text/plain',
212+
metadata: {
213+
requestId: req.id,
214+
type: 'llm-generation',
215+
model: 'gpt-4o',
216+
userId: req.headers.get('user-id')
217+
}
218+
});
219+
220+
// Use waitUntil to handle streaming in the background
221+
ctx.waitUntil(async () => {
222+
const { textStream } = streamText({
223+
model: openai('gpt-4o'),
224+
prompt
225+
});
226+
227+
// Pipe the LLM stream to our created stream
228+
await textStream.pipeTo(stream);
229+
});
230+
231+
// Return stream information immediately
232+
return resp.json({
233+
streamId: stream.id,
234+
streamUrl: stream.url,
235+
status: 'streaming'
236+
});
237+
}
238+
```
239+
240+
### Manual Stream Writing
241+
242+
You can also write to streams manually for complete control over the data flow:
243+
244+
```ts
245+
export default async function Agent(
246+
req: AgentRequest,
247+
resp: AgentResponse,
248+
ctx: AgentContext,
249+
) {
250+
const stream = ctx.stream.create('progress-updates', {
251+
contentType: 'application/json',
252+
metadata: { type: 'progress-tracking' }
253+
});
254+
255+
ctx.waitUntil(async () => {
256+
try {
257+
// Send progress updates
258+
const steps = ['Initializing', 'Processing', 'Analyzing', 'Finalizing'];
259+
260+
for (let i = 0; i < steps.length; i++) {
261+
await stream.write(JSON.stringify({
262+
step: i + 1,
263+
total: steps.length,
264+
message: steps[i],
265+
progress: ((i + 1) / steps.length) * 100,
266+
timestamp: new Date().toISOString()
267+
}) + '\n');
268+
269+
// Simulate work
270+
await new Promise(resolve => setTimeout(resolve, 1000));
271+
}
272+
} finally {
273+
await stream.close();
274+
}
275+
});
276+
277+
return resp.json({
278+
streamId: stream.id,
279+
streamUrl: stream.url
280+
});
281+
}
282+
```
283+
284+
### Stream as Direct Response
285+
286+
You can return a stream directly from your agent handler, which will automatically redirect clients to the stream URL:
287+
288+
```ts
289+
export default async function Agent(
290+
req: AgentRequest,
291+
resp: AgentResponse,
292+
ctx: AgentContext,
293+
) {
294+
const { prompt } = await req.data.json();
295+
296+
const stream = ctx.stream.create('direct-stream', {
297+
contentType: 'text/plain'
298+
});
299+
300+
ctx.waitUntil(async () => {
301+
const { textStream } = streamText({
302+
model: openai('gpt-4o'),
303+
prompt
304+
});
305+
await textStream.pipeTo(stream);
306+
});
307+
308+
// Return the stream directly - client gets redirected to stream URL
309+
return stream;
310+
}
311+
```
312+
313+
### Benefits of Low-Level Stream Control
314+
315+
- **Non-blocking**: Stream creation returns immediately, allowing instant responses
316+
- **Background Processing**: Use `ctx.waitUntil()` to handle data streaming without blocking
317+
- **Rich Metadata**: Associate custom metadata with streams for tracking and debugging
318+
- **Direct Access**: Clients can access streams via direct URLs
319+
- **Flexible Content Types**: Support any content type (text, JSON, binary, etc.)
320+
- **Manual Control**: Write data chunks manually for complex streaming scenarios
321+
185322
---
186323

187324
## Further Reading

0 commit comments

Comments
 (0)