--- name: openai-responses description: | Build agentic AI applications with OpenAI's Responses API - the stateful successor to Chat Completions. Preserves reasoning across turns for 5% better multi-turn performance and 40-80% improved cache utilization. Use when: building AI agents with persistent reasoning, integrating MCP servers for external tools, using built-in Code Interpreter/File Search/Web Search, managing stateful conversations, implementing background processing for long tasks, or migrating from Chat Completions to gain polymorphic outputs and server-side tools. license: MIT --- # OpenAI Responses API **Status**: Production Ready **Last Updated**: 2025-10-25 **API Launch**: March 2025 **Dependencies**: openai@5.19.1+ (Node.js) or fetch API (Cloudflare Workers) --- ## What Is the Responses API? The Responses API (`/v1/responses`) is OpenAI's unified interface for building agentic applications, launched in March 2025. It fundamentally changes how you interact with OpenAI models by providing **stateful conversations** and a **structured loop for reasoning and acting**. ### Key Innovation: Preserved Reasoning State Unlike Chat Completions where reasoning is discarded between turns, Responses **keeps the notebook open**. The model's step-by-step thought processes survive into the next turn, improving performance by approximately **5% on TAUBench** and enabling better multi-turn interactions. ### Why Use Responses Over Chat Completions? | Feature | Chat Completions | Responses API | Benefit | |---------|-----------------|---------------|---------| | **State Management** | Manual (you track history) | Automatic (conversation IDs) | Simpler code, less error-prone | | **Reasoning** | Dropped between turns | Preserved across turns | Better multi-turn performance | | **Tools** | Client-side round trips | Server-side hosted | Lower latency, simpler code | | **Output Format** | Single message | Polymorphic (messages, reasoning, tool calls) | Richer debugging, better UX | | **Cache Utilization** | Baseline | 40-80% better | Lower costs, faster responses | | **MCP Support** | Manual integration | Built-in | Easy external tool connections | --- ## Quick Start (5 Minutes) ### 1. Get API Key ```bash # Sign up at https://platform.openai.com/ # Navigate to API Keys section # Create new key and save securely export OPENAI_API_KEY="sk-proj-..." ``` **Why this matters:** - API key required for all requests - Keep secure (never commit to git) - Use environment variables ### 2. Install SDK (Node.js) ```bash npm install openai ``` ```typescript import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); const response = await openai.responses.create({ model: 'gpt-5', input: 'What are the 5 Ds of dodgeball?', }); console.log(response.output_text); ``` **CRITICAL:** - Always use server-side (never expose API key in client code) - Model defaults to `gpt-5` (can use `gpt-5-mini`, `gpt-4o`, etc.) - `input` can be string or array of messages ### 3. Or Use Direct API (Cloudflare Workers) ```typescript // No SDK needed - use fetch() const response = await fetch('https://api.openai.com/v1/responses', { method: 'POST', headers: { 'Authorization': `Bearer ${env.OPENAI_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-5', input: 'Hello, world!', }), }); const data = await response.json(); console.log(data.output_text); ``` **Why fetch?** - No dependencies in edge environments - Full control over request/response - Works in Cloudflare Workers, Deno, Bun --- ## Responses vs Chat Completions: Complete Comparison ### When to Use Each **Use Responses API when:** - ✅ Building agentic applications (reasoning + actions) - ✅ Need preserved reasoning state across turns - ✅ Want built-in tools (Code Interpreter, File Search, Web Search) - ✅ Using MCP servers for external integrations - ✅ Implementing conversational AI with automatic state management - ✅ Background processing for long-running tasks - ✅ Need polymorphic outputs (messages, reasoning, tool calls) **Use Chat Completions when:** - ✅ Simple one-off text generation - ✅ Fully stateless interactions (no conversation continuity needed) - ✅ Legacy integrations (existing Chat Completions code) - ✅ Very simple use cases without tools ### Architecture Differences **Chat Completions Flow:** ``` User Input → Model → Single Message → Done (Reasoning discarded, state lost) ``` **Responses API Flow:** ``` User Input → Model (preserved reasoning) → Polymorphic Outputs ↓ (server-side tools) Tool Call → Tool Result → Model → Final Response (Reasoning preserved, state maintained) ``` ### Performance Benefits **Cache Utilization:** - Chat Completions: Baseline performance - Responses API: **40-80% better cache utilization** - Result: Lower latency + reduced costs **Reasoning Performance:** - Chat Completions: Reasoning dropped between turns - Responses API: Reasoning preserved across turns - Result: **5% better on TAUBench** (GPT-5 with Responses vs Chat Completions) --- ## Stateful Conversations ### Automatic State Management The Responses API can automatically manage conversation state using **conversation IDs**. #### Creating a Conversation ```typescript // Create conversation with initial message const conversation = await openai.conversations.create({ metadata: { user_id: 'user_123' }, items: [ { type: 'message', role: 'user', content: 'Hello!', }, ], }); console.log(conversation.id); // "conv_abc123..." ``` #### Using Conversation ID ```typescript // First turn const response1 = await openai.responses.create({ model: 'gpt-5', conversation: 'conv_abc123', input: 'What are the 5 Ds of dodgeball?', }); console.log(response1.output_text); // Second turn - model remembers previous context const response2 = await openai.responses.create({ model: 'gpt-5', conversation: 'conv_abc123', input: 'Tell me more about the first one', }); console.log(response2.output_text); // Model automatically knows "first one" refers to first D from previous turn ``` **Why this matters:** - No manual history tracking required - Reasoning state preserved between turns - Automatic context management - Lower risk of context errors ### Manual State Management (Alternative) If you need full control, you can manually manage history: ```typescript let history = [ { role: 'user', content: 'Tell me a joke' }, ]; const response = await openai.responses.create({ model: 'gpt-5', input: history, store: true, // Optional: store for retrieval later }); // Add response to history history = [ ...history, ...response.output.map(el => ({ role: el.role, content: el.content, })), ]; // Next turn history.push({ role: 'user', content: 'Tell me another' }); const secondResponse = await openai.responses.create({ model: 'gpt-5', input: history, }); ``` **When to use manual management:** - Need custom history pruning logic - Want to modify conversation history programmatically - Implementing custom caching strategies --- ## Built-in Tools (Server-Side) The Responses API includes **server-side hosted tools** that eliminate costly backend round trips. ### Available Tools | Tool | Purpose | Use Case | |------|---------|----------| | **Code Interpreter** | Execute Python code | Data analysis, calculations, charts | | **File Search** | RAG without vector stores | Search uploaded files for answers | | **Web Search** | Real-time web information | Current events, fact-checking | | **Image Generation** | DALL-E integration | Create images from descriptions | | **MCP** | Connect external tools | Stripe, databases, custom APIs | ### Code Interpreter Execute Python code server-side for data analysis, calculations, and visualizations. ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Calculate the mean, median, and mode of: 10, 20, 30, 40, 50', tools: [{ type: 'code_interpreter' }], }); console.log(response.output_text); // Model writes and executes Python code, returns results ``` **Advanced Example: Data Analysis** ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Analyze this sales data and create a bar chart showing monthly revenue: [data here]', tools: [{ type: 'code_interpreter' }], }); // Check output for code execution results response.output.forEach(item => { if (item.type === 'code_interpreter_call') { console.log('Code executed:', item.input); console.log('Result:', item.output); } }); ``` **Why this matters:** - No need to run Python locally - Sandboxed execution environment - Automatic chart generation - Can process uploaded files ### File Search (RAG Without Vector Stores) Search through uploaded files without building your own RAG pipeline. ```typescript // 1. Upload files first (one-time setup) const file = await openai.files.create({ file: fs.createReadStream('knowledge-base.pdf'), purpose: 'assistants', }); // 2. Use file search const response = await openai.responses.create({ model: 'gpt-5', input: 'What does the document say about pricing?', tools: [ { type: 'file_search', file_ids: [file.id], }, ], }); console.log(response.output_text); // Model searches file and provides answer with citations ``` **Supported File Types:** - PDFs, Word docs, text files - Markdown, HTML - Code files (Python, JavaScript, etc.) - Max: 512MB per file ### Web Search Get real-time information from the web. ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'What are the latest updates on GPT-5?', tools: [{ type: 'web_search' }], }); console.log(response.output_text); // Model searches web and provides current information with sources ``` **Why this matters:** - No cutoff date limitations - Automatic source citations - Real-time data access - No need for external search APIs ### Image Generation (DALL-E) Generate images directly in the Responses API. ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Create an image of a futuristic cityscape at sunset', tools: [{ type: 'image_generation' }], }); // Find image in output response.output.forEach(item => { if (item.type === 'image_generation_call') { console.log('Image URL:', item.output.url); } }); ``` **Models Available:** - DALL-E 3 (default) - Various sizes and quality options --- ## MCP Server Integration The Responses API has built-in support for **Model Context Protocol (MCP)** servers, allowing you to connect external tools. ### What Is MCP? MCP is an open protocol that standardizes how applications provide context to LLMs. It allows you to: - Connect to external APIs (Stripe, databases, CRMs) - Use hosted MCP servers - Build custom tool integrations ### Basic MCP Integration ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Roll 2d6 dice', tools: [ { type: 'mcp', server_label: 'dice', server_url: 'https://example.com/mcp', }, ], }); // Model discovers available tools on MCP server and uses them console.log(response.output_text); ``` ### MCP with Authentication (OAuth) ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Create a $20 payment link', tools: [ { type: 'mcp', server_label: 'stripe', server_url: 'https://mcp.stripe.com', authorization: process.env.STRIPE_OAUTH_TOKEN, }, ], }); console.log(response.output_text); // Model uses Stripe MCP server to create payment link ``` **CRITICAL:** - API does NOT store authorization tokens - Must provide token with each request - Use environment variables for security ### Polymorphic Output: MCP Tool Calls ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Roll 2d4+1', tools: [ { type: 'mcp', server_label: 'dice', server_url: 'https://dmcp.example.com', }, ], }); // Inspect tool calls response.output.forEach(item => { if (item.type === 'mcp_call') { console.log('Tool:', item.name); console.log('Arguments:', item.arguments); console.log('Output:', item.output); } if (item.type === 'mcp_list_tools') { console.log('Available tools:', item.tools); } }); ``` **Output Types:** - `mcp_list_tools` - Tools discovered on server - `mcp_call` - Tool invocation and result - `message` - Final response to user --- ## Reasoning Preservation ### How It Works The Responses API preserves the model's **internal reasoning state** across turns, unlike Chat Completions which discards it. **Visual Analogy:** - **Chat Completions**: Model has a scratchpad, writes reasoning, then **tears out the page** before responding - **Responses API**: Model keeps the scratchpad open, **previous reasoning visible** for next turn ### Performance Impact **TAUBench Results (GPT-5):** - Chat Completions: Baseline score - Responses API: **+5% better** (purely from preserved reasoning) **Why This Matters:** - Better multi-turn problem solving - More coherent long conversations - Improved step-by-step reasoning - Fewer context errors ### Reasoning Summaries (Free!) The Responses API provides **reasoning summaries** at no additional cost. ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Solve this complex math problem: [problem]', }); // Inspect reasoning response.output.forEach(item => { if (item.type === 'reasoning') { console.log('Model reasoning:', item.summary[0].text); } if (item.type === 'message') { console.log('Final answer:', item.content[0].text); } }); ``` **Use Cases:** - Debugging model decisions - Audit trails for compliance - Understanding model thought process - Building transparent AI systems --- ## Background Mode (Long-Running Tasks) For tasks that take longer than standard timeout limits, use **background mode**. ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Analyze this 500-page document and summarize key findings', background: true, tools: [{ type: 'file_search', file_ids: [fileId] }], }); // Returns immediately with status console.log(response.status); // "in_progress" console.log(response.id); // Use to check status later // Poll for completion const checkStatus = async (responseId) => { const result = await openai.responses.retrieve(responseId); if (result.status === 'completed') { console.log(result.output_text); } else if (result.status === 'failed') { console.error('Task failed:', result.error); } else { // Still running, check again later setTimeout(() => checkStatus(responseId), 5000); } }; checkStatus(response.id); ``` **When to Use:** - Large file processing - Complex calculations - Multi-step research tasks - Data analysis on large datasets **Timeout Limits:** - Standard mode: 60 seconds - Background mode: Up to 10 minutes --- ## Polymorphic Outputs The Responses API returns **multiple output types** instead of a single message. ### Output Types | Type | Description | Example | |------|-------------|---------| | `message` | Text response to user | Final answer, explanation | | `reasoning` | Model's internal thought process | Step-by-step reasoning summary | | `code_interpreter_call` | Code execution | Python code + results | | `mcp_call` | Tool invocation | Tool name, args, output | | `mcp_list_tools` | Available tools | Tool definitions from MCP server | | `file_search_call` | File search results | Matched chunks, citations | | `web_search_call` | Web search results | URLs, snippets | | `image_generation_call` | Image generation | Image URL | ### Processing Polymorphic Outputs ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: 'Search the web for the latest AI news and summarize', tools: [{ type: 'web_search' }], }); // Process different output types response.output.forEach(item => { switch (item.type) { case 'reasoning': console.log('Reasoning:', item.summary[0].text); break; case 'web_search_call': console.log('Searched:', item.query); console.log('Sources:', item.results); break; case 'message': console.log('Response:', item.content[0].text); break; } }); // Or use helper for text-only console.log(response.output_text); ``` **Why This Matters:** - Better debugging (see all steps) - Audit trails (track all tool calls) - Richer UX (show progress to users) - Compliance (log all actions) --- ## Migration from Chat Completions ### Breaking Changes | Feature | Chat Completions | Responses API | Migration | |---------|-----------------|---------------|-----------| | **Endpoint** | `/v1/chat/completions` | `/v1/responses` | Update URL | | **Parameter** | `messages` | `input` | Rename parameter | | **State** | Manual (`messages` array) | Automatic (`conversation` ID) | Use conversation IDs | | **Tools** | `tools` array with functions | Built-in types + MCP | Update tool definitions | | **Output** | `choices[0].message.content` | `output_text` or `output` array | Update response parsing | | **Streaming** | `data: {"choices":[...]}` | SSE with multiple item types | Update stream parser | ### Migration Example **Before (Chat Completions):** ```typescript const response = await openai.chat.completions.create({ model: 'gpt-5', messages: [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Hello!' }, ], }); console.log(response.choices[0].message.content); ``` **After (Responses):** ```typescript const response = await openai.responses.create({ model: 'gpt-5', input: [ { role: 'developer', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Hello!' }, ], }); console.log(response.output_text); ``` **Key Differences:** 1. `chat.completions.create` → `responses.create` 2. `messages` → `input` 3. `system` role → `developer` role 4. `choices[0].message.content` → `output_text` ### When to Migrate **Migrate now if:** - ✅ Building new applications - ✅ Need stateful conversations - ✅ Using agentic patterns (reasoning + tools) - ✅ Want better performance (preserved reasoning) **Stay on Chat Completions if:** - ✅ Simple one-off generations - ✅ Legacy integrations - ✅ No need for state management --- ## Error Handling ### Common Errors and Solutions #### 1. Session State Not Persisting **Error:** ``` Conversation state not maintained between turns ``` **Cause:** - Not using conversation IDs - Using different conversation IDs per turn **Solution:** ```typescript // Create conversation once const conv = await openai.conversations.create(); // Reuse conversation ID for all turns const response1 = await openai.responses.create({ model: 'gpt-5', conversation: conv.id, // ✅ Same ID input: 'First message', }); const response2 = await openai.responses.create({ model: 'gpt-5', conversation: conv.id, // ✅ Same ID input: 'Follow-up message', }); ``` #### 2. MCP Server Connection Failed **Error:** ```json { "error": { "type": "mcp_connection_error", "message": "Failed to connect to MCP server" } } ``` **Causes:** - Invalid server URL - Missing or expired authorization token - Server not responding **Solutions:** ```typescript // 1. Verify URL is correct const response = await openai.responses.create({ model: 'gpt-5', input: 'Test MCP', tools: [ { type: 'mcp', server_label: 'test', server_url: 'https://api.example.com/mcp', // ✅ Full URL authorization: process.env.AUTH_TOKEN, // ✅ Valid token }, ], }); // 2. Test server URL manually const testResponse = await fetch('https://api.example.com/mcp'); console.log(testResponse.status); // Should be 200 // 3. Check token expiration console.log('Token expires:', parseJWT(token).exp); ``` #### 3. Code Interpreter Timeout **Error:** ```json { "error": { "type": "code_interpreter_timeout", "message": "Code execution exceeded time limit" } } ``` **Cause:** - Code runs longer than 30 seconds **Solution:** ```typescript // Use background mode for long-running code const response = await openai.responses.create({ model: 'gpt-5', input: 'Process this large dataset', background: true, // ✅ Extended timeout tools: [{ type: 'code_interpreter' }], }); // Poll for results const result = await openai.responses.retrieve(response.id); ``` #### 4. Image Generation Rate Limit **Error:** ```json { "error": { "type": "rate_limit_error", "message": "DALL-E rate limit exceeded" } } ``` **Cause:** - Too many image generation requests **Solution:** ```typescript // Implement retry with exponential backoff const generateImage = async (prompt, retries = 3) => { try { return await openai.responses.create({ model: 'gpt-5', input: prompt, tools: [{ type: 'image_generation' }], }); } catch (error) { if (error.type === 'rate_limit_error' && retries > 0) { const delay = (4 - retries) * 1000; // 1s, 2s, 3s await new Promise(resolve => setTimeout(resolve, delay)); return generateImage(prompt, retries - 1); } throw error; } }; ``` #### 5. File Search Relevance Issues **Problem:** - File search returns irrelevant results **Solution:** ```typescript // Use more specific queries const response = await openai.responses.create({ model: 'gpt-5', input: 'Find sections about pricing in Q4 2024 specifically', // ✅ Specific // NOT: 'Find pricing' (too vague) tools: [{ type: 'file_search', file_ids: [fileId] }], }); // Or filter results manually response.output.forEach(item => { if (item.type === 'file_search_call') { const relevantChunks = item.results.filter( chunk => chunk.score > 0.7 // ✅ Only high-confidence matches ); } }); ``` #### 6. Cost Tracking Confusion **Problem:** - Billing different than expected **Explanation:** - Responses API bills for: input tokens + output tokens + tool usage + stored conversations - Chat Completions bills only: input tokens + output tokens **Solution:** ```typescript // Monitor usage const response = await openai.responses.create({ model: 'gpt-5', input: 'Hello', store: false, // ✅ Don't store if not needed }); console.log('Usage:', response.usage); // { // prompt_tokens: 10, // completion_tokens: 20, // tool_tokens: 5, // total_tokens: 35 // } ``` #### 7. Conversation Not Found **Error:** ```json { "error": { "type": "invalid_request_error", "message": "Conversation conv_xyz not found" } } ``` **Causes:** - Conversation ID typo - Conversation deleted - Conversation expired (90 days) **Solution:** ```typescript // Verify conversation exists before using const conversations = await openai.conversations.list(); const exists = conversations.data.some(c => c.id === 'conv_xyz'); if (!exists) { // Create new conversation const newConv = await openai.conversations.create(); // Use newConv.id } ``` #### 8. Tool Output Parsing Failed **Problem:** - Can't access tool outputs correctly **Solution:** ```typescript // Use helper methods const response = await openai.responses.create({ model: 'gpt-5', input: 'Search for AI news', tools: [{ type: 'web_search' }], }); // Helper: Get text-only output console.log(response.output_text); // Manual: Inspect all outputs response.output.forEach(item => { console.log('Type:', item.type); console.log('Content:', item); }); ``` --- ## Production Patterns ### Cost Optimization **1. Use Conversation IDs (Cache Benefits)** ```typescript // ✅ GOOD: Reuse conversation ID const conv = await openai.conversations.create(); const response1 = await openai.responses.create({ model: 'gpt-5', conversation: conv.id, input: 'Question 1', }); // 40-80% better cache utilization // ❌ BAD: New manual history each time const response2 = await openai.responses.create({ model: 'gpt-5', input: [...previousHistory, newMessage], }); // No cache benefits ``` **2. Disable Storage When Not Needed** ```typescript // For one-off requests const response = await openai.responses.create({ model: 'gpt-5', input: 'Quick question', store: false, // ✅ Don't store conversation }); ``` **3. Use Smaller Models When Possible** ```typescript // For simple tasks const response = await openai.responses.create({ model: 'gpt-5-mini', // ✅ 50% cheaper input: 'Summarize this paragraph', }); ``` ### Rate Limit Handling ```typescript const createResponseWithRetry = async (params, maxRetries = 3) => { for (let i = 0; i < maxRetries; i++) { try { return await openai.responses.create(params); } catch (error) { if (error.type === 'rate_limit_error' && i < maxRetries - 1) { const delay = Math.pow(2, i) * 1000; // Exponential backoff console.log(`Rate limited, retrying in ${delay}ms`); await new Promise(resolve => setTimeout(resolve, delay)); } else { throw error; } } } }; ``` ### Monitoring and Logging ```typescript const monitoredResponse = async (input) => { const startTime = Date.now(); try { const response = await openai.responses.create({ model: 'gpt-5', input, }); // Log success metrics console.log({ status: 'success', latency: Date.now() - startTime, tokens: response.usage.total_tokens, model: response.model, conversation: response.conversation_id, }); return response; } catch (error) { // Log error metrics console.error({ status: 'error', latency: Date.now() - startTime, error: error.message, type: error.type, }); throw error; } }; ``` --- ## Node.js vs Cloudflare Workers ### Node.js Implementation ```typescript import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); export async function handleRequest(input: string) { const response = await openai.responses.create({ model: 'gpt-5', input, tools: [{ type: 'web_search' }], }); return response.output_text; } ``` **Pros:** - Full SDK support - Type safety - Streaming helpers **Cons:** - Requires Node.js runtime - Larger bundle size ### Cloudflare Workers Implementation ```typescript export default { async fetch(request: Request, env: Env): Promise { const { input } = await request.json(); const response = await fetch('https://api.openai.com/v1/responses', { method: 'POST', headers: { 'Authorization': `Bearer ${env.OPENAI_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'gpt-5', input, tools: [{ type: 'web_search' }], }), }); const data = await response.json(); return new Response(data.output_text, { headers: { 'Content-Type': 'text/plain' }, }); }, }; ``` **Pros:** - No dependencies - Edge deployment - Faster cold starts **Cons:** - Manual request building - No type safety without custom types --- ## Always Do / Never Do ### ✅ Always Do 1. **Use conversation IDs for multi-turn interactions** ```typescript const conv = await openai.conversations.create(); // Reuse conv.id for all related turns ``` 2. **Handle all output types in polymorphic responses** ```typescript response.output.forEach(item => { if (item.type === 'reasoning') { /* log */ } if (item.type === 'message') { /* display */ } }); ``` 3. **Use background mode for long-running tasks** ```typescript const response = await openai.responses.create({ background: true, // ✅ For tasks >30s ... }); ``` 4. **Provide authorization tokens for MCP servers** ```typescript tools: [{ type: 'mcp', authorization: process.env.TOKEN, // ✅ Required }] ``` 5. **Monitor token usage for cost control** ```typescript console.log(response.usage.total_tokens); ``` ### ❌ Never Do 1. **Never expose API keys in client-side code** ```typescript // ❌ DANGER: API key in browser const response = await fetch('https://api.openai.com/v1/responses', { headers: { 'Authorization': 'Bearer sk-proj-...' } }); ``` 2. **Never assume single message output** ```typescript // ❌ BAD: Ignores reasoning, tool calls console.log(response.output[0].content); // ✅ GOOD: Use helper or check all types console.log(response.output_text); ``` 3. **Never reuse conversation IDs across users** ```typescript // ❌ DANGER: User A sees User B's conversation const sharedConv = 'conv_123'; ``` 4. **Never ignore error types** ```typescript // ❌ BAD: Generic error handling try { ... } catch (e) { console.log('error'); } // ✅ GOOD: Type-specific handling catch (e) { if (e.type === 'rate_limit_error') { /* retry */ } if (e.type === 'mcp_connection_error') { /* alert */ } } ``` 5. **Never poll faster than 1 second for background tasks** ```typescript // ❌ BAD: Too frequent setInterval(() => checkStatus(), 100); // ✅ GOOD: Reasonable interval setInterval(() => checkStatus(), 5000); ``` --- ## References ### Official Documentation - **Responses API Guide**: https://platform.openai.com/docs/guides/responses - **API Reference**: https://platform.openai.com/docs/api-reference/responses - **MCP Integration**: https://platform.openai.com/docs/guides/tools-connectors-mcp - **Blog Post (Why Responses API)**: https://developers.openai.com/blog/responses-api/ - **Starter App**: https://github.com/openai/openai-responses-starter-app ### Skill Resources - `templates/` - Working code examples - `references/responses-vs-chat-completions.md` - Feature comparison - `references/mcp-integration-guide.md` - MCP server setup - `references/built-in-tools-guide.md` - Tool usage patterns - `references/stateful-conversations.md` - Conversation management - `references/migration-guide.md` - Chat Completions → Responses - `references/top-errors.md` - Common errors and solutions --- ## Next Steps 1. ✅ Read `templates/basic-response.ts` - Simple example 2. ✅ Try `templates/stateful-conversation.ts` - Multi-turn chat 3. ✅ Explore `templates/mcp-integration.ts` - External tools 4. ✅ Review `references/top-errors.md` - Avoid common pitfalls 5. ✅ Check `references/migration-guide.md` - If migrating from Chat Completions **Happy building with the Responses API!** 🚀