Skip to content

Commit 5e9be0e

Browse files
Document enhanced stream method with transformer support (#255)
- Add comprehensive stream method documentation to JavaScript SDK API reference - Include Vercel AI SDK streamObject integration example as requested - Document function and generator transformer patterns for filtering/transforming stream data - Add examples showing auto-conversion to JSON for object streams - Update agent streaming guide with structured object streaming section - Maintain backward compatibility documentation - Include error handling patterns and best practices Addresses PR #155 changes in agentuity/sdk-js for enhanced streaming capabilities. Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]>
1 parent b5dba38 commit 5e9be0e

File tree

2 files changed

+255
-0
lines changed

2 files changed

+255
-0
lines changed

content/Guides/agent-streaming.mdx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,84 @@ async def run(request: AgentRequest, response: AgentResponse, context: AgentCont
7878
return response.stream(chat_completion, lambda chunk: chunk.choices[0].delta.content)
7979
`} />
8080

81+
### Structured Object Streaming with Vercel AI SDK
82+
83+
The stream method now supports transformer functions that can filter and transform stream items. This is particularly useful when working with structured data from AI SDKs like Vercel AI SDK's `streamObject`.
84+
85+
<CodeExample js={`import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
86+
import { openai } from '@ai-sdk/openai';
87+
import { streamObject } from 'ai';
88+
import { z } from 'zod';
89+
90+
export default async function Agent(
91+
req: AgentRequest,
92+
resp: AgentResponse,
93+
ctx: AgentContext,
94+
) {
95+
const { elementStream } = streamObject({
96+
model: openai('gpt-4o'),
97+
output: 'array',
98+
schema: z.object({
99+
name: z.string(),
100+
class: z
101+
.string()
102+
.describe('Character class, e.g. warrior, mage, or thief.'),
103+
description: z.string(),
104+
}),
105+
prompt: 'Generate 3 hero descriptions for a fantasy role playing game.',
106+
});
107+
108+
return resp.stream(elementStream);
109+
}`} />
110+
111+
The SDK automatically detects object streams and converts them to JSON newline format with the appropriate `application/json` content type.
112+
113+
### Stream Transformers
114+
115+
You can provide transformer functions to filter and transform stream data:
116+
117+
<CodeExample js={`import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
118+
119+
export default async function Agent(
120+
req: AgentRequest,
121+
resp: AgentResponse,
122+
ctx: AgentContext,
123+
) {
124+
// Get stream from another source
125+
const dataStream = getDataStream();
126+
127+
// Transform and filter items
128+
const transformer = (item: any) => {
129+
// Filter out items (return null/undefined to skip)
130+
if (!item.active) return null;
131+
132+
// Transform the item
133+
return {
134+
id: item.id,
135+
name: item.name.toUpperCase(),
136+
timestamp: Date.now()
137+
};
138+
};
139+
140+
return resp.stream(dataStream, undefined, {}, transformer);
141+
}`} />
142+
143+
You can also use generator functions for more complex transformations:
144+
145+
<CodeExample js={`// Generator transformer that can yield multiple items or filter
146+
function* transformer(item: any) {
147+
if (item.type === 'batch') {
148+
// Yield multiple items from a batch
149+
for (const subItem of item.items) {
150+
yield { ...subItem, processed: true };
151+
}
152+
} else if (item.valid) {
153+
// Yield single transformed item
154+
yield { ...item, enhanced: true };
155+
}
156+
// Return nothing to filter out invalid items
157+
}`} />
158+
81159
### Agent-to-Agent Streaming
82160

83161
In this example, we use the Agentuity SDK to stream the response from one agent to another.

content/SDKs/javascript/api-reference.mdx

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This section provides detailed documentation for the Agentuity JavaScript SDK AP
1414
- [Object Storage](#object-storage)
1515
- [Agent Communication](#agent-communication)
1616
- [Response Types](#response-types)
17+
- [Stream Method](#stream-method)
1718
- [Request Handling](#request-handling)
1819
- [Logging](#logging)
1920
- [Telemetry](#telemetry)
@@ -556,6 +557,182 @@ return response.handoff(
556557

557558
The Agentuity SDK provides various methods for creating different types of responses through the `response` object.
558559

560+
### Stream Method
561+
562+
The `stream` method allows you to stream responses back to the client, supporting both `ReadableStream` and `AsyncIterable` inputs with optional transformer functions for filtering and transforming stream data.
563+
564+
#### Method Signature
565+
566+
```typescript
567+
stream<T = unknown, U = T, M = unknown>(
568+
stream: ReadableStream<T> | AsyncIterable<T>,
569+
contentType?: string,
570+
metadata?: M,
571+
transformer?:
572+
| ((item: T) => U | null | undefined)
573+
| ((item: T) => Generator<U, void, unknown>)
574+
): Promise<AgentResponseData>
575+
```
576+
577+
#### Parameters
578+
579+
- `stream`: The stream to return - can be a `ReadableStream` or `AsyncIterable`
580+
- `contentType` (optional): The content type of the stream. If not provided, the SDK will auto-detect based on the stream content
581+
- `metadata` (optional): Metadata to return as headers
582+
- `transformer` (optional): Function or generator to transform/filter each stream item
583+
- **Function transformer**: `(item: T) => U | null | undefined` - returns single value or skips with null/undefined
584+
- **Generator transformer**: `(item: T) => Generator<U, void, unknown>` - yields transformed values
585+
586+
#### Auto-Conversion Features
587+
588+
The stream method automatically detects object streams and converts them to JSON newline format with the appropriate `application/json` content type. This makes it seamless to work with structured data from AI SDKs.
589+
590+
#### Basic Usage
591+
592+
```typescript
593+
import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
594+
595+
export default async function Agent(
596+
req: AgentRequest,
597+
resp: AgentResponse,
598+
ctx: AgentContext,
599+
) {
600+
// Stream from another source
601+
const dataStream = getDataStream();
602+
603+
return resp.stream(dataStream);
604+
}
605+
```
606+
607+
#### Vercel AI SDK Integration
608+
609+
The stream method works seamlessly with Vercel AI SDK's `streamObject` for structured streaming:
610+
611+
```typescript
612+
import type { AgentRequest, AgentResponse, AgentContext } from "@agentuity/sdk";
613+
import { openai } from '@ai-sdk/openai';
614+
import { streamObject } from 'ai';
615+
import { z } from 'zod';
616+
617+
export default async function Agent(
618+
req: AgentRequest,
619+
resp: AgentResponse,
620+
ctx: AgentContext,
621+
) {
622+
const { elementStream } = streamObject({
623+
model: openai('gpt-4o'),
624+
output: 'array',
625+
schema: z.object({
626+
name: z.string(),
627+
class: z
628+
.string()
629+
.describe('Character class, e.g. warrior, mage, or thief.'),
630+
description: z.string(),
631+
}),
632+
prompt: 'Generate 3 hero descriptions for a fantasy role playing game.',
633+
});
634+
635+
return resp.stream(elementStream);
636+
}
637+
```
638+
639+
#### Function Transformers
640+
641+
Use function transformers to filter and transform stream items:
642+
643+
```typescript
644+
export default async function Agent(
645+
req: AgentRequest,
646+
resp: AgentResponse,
647+
ctx: AgentContext,
648+
) {
649+
const dataStream = getUserStream();
650+
651+
// Transform and filter items
652+
const transformer = (user: any) => {
653+
// Filter out inactive users (return null to skip)
654+
if (!user.active) return null;
655+
656+
// Transform the user object
657+
return {
658+
id: user.id,
659+
name: user.name.toUpperCase(),
660+
timestamp: Date.now()
661+
};
662+
};
663+
664+
return resp.stream(dataStream, undefined, {}, transformer);
665+
}
666+
```
667+
668+
#### Generator Transformers
669+
670+
Use generator transformers for more complex transformations:
671+
672+
```typescript
673+
export default async function Agent(
674+
req: AgentRequest,
675+
resp: AgentResponse,
676+
ctx: AgentContext,
677+
) {
678+
const batchStream = getBatchStream();
679+
680+
// Generator that can yield multiple items or filter
681+
function* transformer(batch: any) {
682+
if (batch.type === 'user_batch') {
683+
// Yield multiple items from a batch
684+
for (const user of batch.users) {
685+
if (user.active) {
686+
yield { ...user, processed: true };
687+
}
688+
}
689+
} else if (batch.valid) {
690+
// Yield single transformed item
691+
yield { ...batch, enhanced: true };
692+
}
693+
// Return nothing to filter out invalid batches
694+
}
695+
696+
return resp.stream(batchStream, undefined, {}, transformer);
697+
}
698+
```
699+
700+
#### Error Handling
701+
702+
Transformer errors are propagated when the stream is consumed:
703+
704+
```typescript
705+
export default async function Agent(
706+
req: AgentRequest,
707+
resp: AgentResponse,
708+
ctx: AgentContext,
709+
) {
710+
const dataStream = getDataStream();
711+
712+
const transformer = (item: any) => {
713+
// Validate item before transformation
714+
if (!item || typeof item !== 'object') {
715+
throw new Error(`Invalid item: ${JSON.stringify(item)}`);
716+
}
717+
718+
return { ...item, validated: true };
719+
};
720+
721+
return resp.stream(dataStream, undefined, {}, transformer);
722+
}
723+
```
724+
725+
#### Backward Compatibility
726+
727+
The transformer parameter is optional, so all existing stream usage continues to work unchanged:
728+
729+
```typescript
730+
// This continues to work exactly as before
731+
return resp.stream(textStream);
732+
return resp.stream(dataStream, 'application/json');
733+
return resp.stream(binaryStream, 'application/octet-stream', { version: '1.0' });
734+
```
735+
559736
### JSON Responses
560737

561738
`json(data: Json, metadata?: Record<string, Json>): AgentResponseType`

0 commit comments

Comments
 (0)