Initial commit
This commit is contained in:
144
templates/shared/error-handling.ts
Normal file
144
templates/shared/error-handling.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Comprehensive error handling patterns for OpenAI Agents SDK
|
||||
*
|
||||
* Covers all major error types:
|
||||
* - MaxTurnsExceededError: Agent hit maximum turns limit
|
||||
* - InputGuardrailTripwireTriggered: Input blocked by guardrail
|
||||
* - OutputGuardrailTripwireTriggered: Output blocked by guardrail
|
||||
* - ToolCallError: Tool execution failed
|
||||
* - ModelBehaviorError: Unexpected model behavior
|
||||
* - GuardrailExecutionError: Guardrail itself failed
|
||||
*/
|
||||
|
||||
import {
|
||||
Agent,
|
||||
run,
|
||||
MaxTurnsExceededError,
|
||||
InputGuardrailTripwireTriggered,
|
||||
OutputGuardrailTripwireTriggered,
|
||||
ModelBehaviorError,
|
||||
ToolCallError,
|
||||
GuardrailExecutionError,
|
||||
} from '@openai/agents';
|
||||
|
||||
/**
|
||||
* Run agent with comprehensive error handling and retry logic
|
||||
*/
|
||||
export async function runAgentWithErrorHandling(
|
||||
agent: Agent,
|
||||
input: string,
|
||||
options: {
|
||||
maxRetries?: number;
|
||||
maxTurns?: number;
|
||||
onError?: (error: Error, attempt: number) => void;
|
||||
} = {}
|
||||
) {
|
||||
const { maxRetries = 3, maxTurns = 10, onError } = options;
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
const result = await run(agent, input, { maxTurns });
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
// Notify error callback
|
||||
if (onError) {
|
||||
onError(error as Error, attempt);
|
||||
}
|
||||
|
||||
// Handle specific error types
|
||||
if (error instanceof MaxTurnsExceededError) {
|
||||
console.error('❌ Agent exceeded maximum turns');
|
||||
console.error(` Agent entered an infinite loop after ${maxTurns} turns`);
|
||||
throw error; // Don't retry - this is a logic issue
|
||||
|
||||
} else if (error instanceof InputGuardrailTripwireTriggered) {
|
||||
console.error('❌ Input blocked by guardrail');
|
||||
console.error(' Reason:', error.outputInfo);
|
||||
throw error; // Don't retry - input is invalid
|
||||
|
||||
} else if (error instanceof OutputGuardrailTripwireTriggered) {
|
||||
console.error('❌ Output blocked by guardrail');
|
||||
console.error(' Reason:', error.outputInfo);
|
||||
throw error; // Don't retry - output violates policy
|
||||
|
||||
} else if (error instanceof ToolCallError) {
|
||||
console.error(`⚠️ Tool call failed (attempt ${attempt}/${maxRetries})`);
|
||||
console.error(' Tool:', error.toolName);
|
||||
console.error(' Error:', error.message);
|
||||
|
||||
if (attempt === maxRetries) {
|
||||
throw error; // Give up after max retries
|
||||
}
|
||||
|
||||
// Exponential backoff
|
||||
const delay = 1000 * Math.pow(2, attempt - 1);
|
||||
console.log(` Retrying in ${delay}ms...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
|
||||
} else if (error instanceof ModelBehaviorError) {
|
||||
console.error('❌ Unexpected model behavior');
|
||||
console.error(' Details:', error.message);
|
||||
throw error; // Don't retry - model is behaving incorrectly
|
||||
|
||||
} else if (error instanceof GuardrailExecutionError) {
|
||||
console.error('❌ Guardrail execution failed');
|
||||
console.error(' Guardrail:', error.guardrailName);
|
||||
console.error(' Error:', error.message);
|
||||
|
||||
// Option to retry with fallback guardrail
|
||||
// See common-errors.md for fallback pattern
|
||||
throw error;
|
||||
|
||||
} else {
|
||||
// Unknown error - retry with exponential backoff
|
||||
console.error(`⚠️ Unknown error (attempt ${attempt}/${maxRetries})`);
|
||||
console.error(' Error:', error);
|
||||
|
||||
if (attempt === maxRetries) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const delay = 1000 * Math.pow(2, attempt - 1);
|
||||
console.log(` Retrying in ${delay}ms...`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Max retries exceeded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage
|
||||
*/
|
||||
export async function exampleUsage() {
|
||||
const agent = new Agent({
|
||||
name: 'Assistant',
|
||||
instructions: 'You are a helpful assistant.',
|
||||
});
|
||||
|
||||
try {
|
||||
const result = await runAgentWithErrorHandling(
|
||||
agent,
|
||||
'What is 2+2?',
|
||||
{
|
||||
maxRetries: 3,
|
||||
maxTurns: 10,
|
||||
onError: (error, attempt) => {
|
||||
console.log(`Error on attempt ${attempt}:`, error.message);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
console.log('✅ Success:', result.finalOutput);
|
||||
console.log('Tokens used:', result.usage.totalTokens);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Final error:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Uncomment to run example
|
||||
// exampleUsage();
|
||||
24
templates/shared/package.json
Normal file
24
templates/shared/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "openai-agents-templates",
|
||||
"version": "1.0.0",
|
||||
"description": "OpenAI Agents SDK templates for Claude Code skill",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openai/agents": "^0.2.1",
|
||||
"@openai/agents-realtime": "^0.2.1",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.2",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
}
|
||||
}
|
||||
127
templates/shared/tracing-setup.ts
Normal file
127
templates/shared/tracing-setup.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Tracing and debugging configuration for OpenAI Agents SDK
|
||||
*
|
||||
* Built-in tracing helps visualize agent execution:
|
||||
* - Agent transitions (handoffs)
|
||||
* - Tool calls
|
||||
* - LLM requests
|
||||
* - Guardrail executions
|
||||
* - Token usage
|
||||
*
|
||||
* Tracing is automatically enabled when you import from '@openai/agents'
|
||||
*/
|
||||
|
||||
import { Agent, run } from '@openai/agents';
|
||||
|
||||
/**
|
||||
* Enable detailed logging for debugging
|
||||
*/
|
||||
export function enableVerboseLogging() {
|
||||
// Set environment variable for debug mode
|
||||
process.env.DEBUG = '@openai/agents:*';
|
||||
}
|
||||
|
||||
/**
|
||||
* Run agent with detailed trace logging
|
||||
*/
|
||||
export async function runWithTracing(agent: Agent, input: string) {
|
||||
console.log('🔍 Starting traced agent execution...\n');
|
||||
|
||||
const result = await run(agent, input);
|
||||
|
||||
// Log execution summary
|
||||
console.log('\n📊 Execution Summary:');
|
||||
console.log('─────────────────────────────────────');
|
||||
console.log('Final Output:', result.finalOutput);
|
||||
console.log('Current Agent:', result.currentAgent?.name || 'N/A');
|
||||
console.log('Total Tokens:', result.usage.totalTokens);
|
||||
console.log('Input Tokens:', result.usage.inputTokens);
|
||||
console.log('Output Tokens:', result.usage.outputTokens);
|
||||
console.log('Conversation Turns:', result.history.length);
|
||||
console.log('─────────────────────────────────────\n');
|
||||
|
||||
// Log conversation history
|
||||
console.log('💬 Conversation History:');
|
||||
result.history.forEach((message, index) => {
|
||||
console.log(`\n[${index + 1}] ${message.role}:`);
|
||||
if (message.role === 'user' || message.role === 'assistant') {
|
||||
console.log(message.content);
|
||||
} else if (message.role === 'tool') {
|
||||
console.log(` Tool: ${message.name}`);
|
||||
console.log(` Result:`, message.result);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream agent execution with event logging
|
||||
*/
|
||||
export async function runWithStreamTracing(agent: Agent, input: string) {
|
||||
console.log('🔍 Starting streamed agent execution...\n');
|
||||
|
||||
const stream = await run(agent, input, { stream: true });
|
||||
|
||||
for await (const event of stream) {
|
||||
if (event.type === 'raw_model_stream_event') {
|
||||
// Raw model response chunk
|
||||
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🔄 Handoff to: ${event.agent.name}`);
|
||||
|
||||
} else if (event.type === 'run_item_stream_event') {
|
||||
// Tool call, output, or other run item
|
||||
if (event.name === 'tool_call') {
|
||||
console.log(`\n🛠️ Tool call: ${event.item.name}`);
|
||||
console.log(` Arguments:`, event.item.arguments);
|
||||
} else if (event.name === 'tool_result') {
|
||||
console.log(`✅ Tool result:`, event.item.result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
await stream.completed;
|
||||
const result = stream.result;
|
||||
|
||||
console.log('\n\n📊 Stream Summary:');
|
||||
console.log('─────────────────────────────────────');
|
||||
console.log('Total Tokens:', result.usage.totalTokens);
|
||||
console.log('─────────────────────────────────────\n');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Debug a complex multi-agent workflow
|
||||
*/
|
||||
export async function exampleTracedWorkflow() {
|
||||
// Enable verbose logging
|
||||
enableVerboseLogging();
|
||||
|
||||
const agent = new Agent({
|
||||
name: 'Debug Agent',
|
||||
instructions: 'You are a debugging assistant.',
|
||||
});
|
||||
|
||||
// Run with tracing
|
||||
await runWithTracing(
|
||||
agent,
|
||||
'Explain how to debug a TypeScript application'
|
||||
);
|
||||
|
||||
// Run with stream tracing
|
||||
await runWithStreamTracing(
|
||||
agent,
|
||||
'What are the best debugging tools for Node.js?'
|
||||
);
|
||||
}
|
||||
|
||||
// Uncomment to run example
|
||||
// exampleTracedWorkflow();
|
||||
Reference in New Issue
Block a user