Files
gh-jezweb-claude-skills-ski…/templates/shared/error-handling.ts
2025-11-30 08:25:09 +08:00

145 lines
4.3 KiB
TypeScript

/**
* 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();