Files
gh-jezweb-claude-skills-ski…/templates/text-agents/agent-streaming.ts
2025-11-30 08:25:09 +08:00

180 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Streaming Agent Responses
*
* Demonstrates:
* - Enabling streaming with stream: true
* - Handling different stream event types
* - Processing raw model chunks
* - Detecting agent handoffs in streams
* - Tool call events
*/
import { z } from 'zod';
import { Agent, run, tool } from '@openai/agents';
// Define a slow tool to see streaming behavior
const searchDocsTool = tool({
name: 'search_docs',
description: 'Search documentation for relevant information',
parameters: z.object({
query: z.string(),
}),
execute: async ({ query }) => {
// Simulate slow search
await new Promise(resolve => setTimeout(resolve, 1000));
return `Found 3 articles about "${query}":
1. Getting Started Guide
2. Advanced Patterns
3. Troubleshooting Common Issues`;
},
});
const docsAgent = new Agent({
name: 'Documentation Assistant',
instructions: 'You help users find information in documentation. Use the search_docs tool when needed.',
tools: [searchDocsTool],
});
// ========================================
// Example 1: Basic Streaming (Text Only)
// ========================================
async function streamBasicResponse() {
console.log('\n📡 Streaming Basic Response:\n');
const stream = await run(
docsAgent,
'Explain how to set up authentication',
{ stream: true }
);
// Pipe raw text stream to stdout
stream
.toTextStream({ compatibleWithNodeStreams: true })
.pipe(process.stdout);
// Wait for completion
await stream.completed;
console.log('\n\n✅ Stream completed');
console.log('Tokens used:', stream.result.usage.totalTokens);
}
// ========================================
// Example 2: Detailed Event Streaming
// ========================================
async function streamWithEvents() {
console.log('\n📡 Streaming with Event Handling:\n');
const stream = await run(
docsAgent,
'Search for information about multi-agent patterns',
{ stream: true }
);
for await (const event of stream) {
if (event.type === 'raw_model_stream_event') {
// Raw model response chunks
const chunk = event.data?.choices?.[0]?.delta?.content || '';
if (chunk) {
process.stdout.write(chunk);
}
} else if (event.type === 'agent_updated_stream_event') {
// Agent handoff occurred
console.log(`\n\n🔄 Agent changed to: ${event.agent.name}\n`);
} else if (event.type === 'run_item_stream_event') {
// Tool calls, outputs, or other run items
if (event.name === 'tool_call_started') {
const toolCall = event.item as any;
console.log(`\n\n🛠 Calling tool: ${toolCall.name}`);
console.log(` Arguments:`, JSON.stringify(toolCall.arguments, null, 2));
} else if (event.name === 'tool_call_completed') {
const toolResult = event.item as any;
console.log(`\n✅ Tool result received`);
} else if (event.name === 'agent_message') {
// Agent produced a message
// (already handled by raw_model_stream_event above)
}
}
}
await stream.completed;
console.log('\n\n✅ Stream completed');
console.log('Tokens used:', stream.result.usage.totalTokens);
}
// ========================================
// Example 3: Streaming with Multiple Agents
// ========================================
const specialistAgent = new Agent({
name: 'Advanced Specialist',
instructions: 'You provide advanced technical guidance.',
handoffDescription: 'Transfer for advanced technical questions',
});
const triageAgent = Agent.create({
name: 'Triage',
instructions: 'Route questions to specialists if they are advanced.',
handoffs: [specialistAgent],
});
async function streamMultiAgent() {
console.log('\n📡 Streaming Multi-Agent Response:\n');
let currentAgent = 'Triage';
const stream = await run(
triageAgent,
'I need advanced help with distributed systems architecture',
{ stream: true }
);
for await (const event of stream) {
if (event.type === 'agent_updated_stream_event') {
currentAgent = event.agent.name;
console.log(`\n${'='.repeat(50)}`);
console.log(`🔄 Handoff to: ${currentAgent}`);
console.log('='.repeat(50) + '\n');
} else if (event.type === 'raw_model_stream_event') {
const chunk = event.data?.choices?.[0]?.delta?.content || '';
if (chunk) {
process.stdout.write(chunk);
}
}
}
await stream.completed;
console.log('\n\n✅ Final agent:', stream.result.currentAgent?.name);
}
// ========================================
// Usage
// ========================================
async function main() {
try {
await streamBasicResponse();
console.log('\n' + '='.repeat(60) + '\n');
await streamWithEvents();
console.log('\n' + '='.repeat(60) + '\n');
await streamMultiAgent();
} catch (error) {
console.error('\n❌ Error:', error);
process.exit(1);
}
}
// Uncomment to run
// main();
export { streamBasicResponse, streamWithEvents, streamMultiAgent };