tessl install github:jezweb/claude-skills --skill openai-responsesBuild agentic AI with OpenAI Responses API - stateful conversations with preserved reasoning, built-in tools (Code Interpreter, File Search, Web Search), and MCP integration. Prevents 11 documented errors. Use when: building agents with persistent reasoning, using server-side tools, or migrating from Chat Completions/Assistants for better multi-turn performance.
Review Score
75%
Validation Score
11/16
Implementation Score
73%
Activation Score
N/A
Status: Production Ready Last Updated: 2026-01-21 API Launch: March 2025 Dependencies: openai@6.16.0 (Node.js) or fetch API (Cloudflare Workers)
OpenAI's unified interface for agentic applications, launched March 2025. Provides stateful conversations with preserved reasoning state across turns.
Key Innovation: Unlike Chat Completions (reasoning discarded between turns), Responses preserves the model's reasoning notebook, improving performance by 5% on TAUBench and enabling better multi-turn interactions.
vs Chat Completions:
| Feature | Chat Completions | Responses API |
|---|---|---|
| State | Manual history tracking | Automatic (conversation IDs) |
| Reasoning | Dropped between turns | Preserved across turns (+5% TAUBench) |
| Tools | Client-side round trips | Server-side hosted |
| Output | Single message | Polymorphic (8 types) |
| Cache | Baseline | 40-80% better utilization |
| MCP | Manual | Built-in |
npm install openai@6.16.0import 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);Key differences from Chat Completions:
/v1/responses (not /v1/chat/completions)input (not messages)developer (not system)response.output_text (not choices[0].message.content)Use Responses:
Use Chat Completions:
Automatic State Management using conversation IDs:
// Create conversation
const conv = await openai.conversations.create({
metadata: { user_id: 'user_123' },
});
// First turn
const response1 = await openai.responses.create({
model: 'gpt-5',
conversation: conv.id,
input: 'What are the 5 Ds of dodgeball?',
});
// Second turn - model remembers context + reasoning
const response2 = await openai.responses.create({
model: 'gpt-5',
conversation: conv.id,
input: 'Tell me more about the first one',
});Benefits: No manual history tracking, reasoning preserved, 40-80% better cache utilization
Conversation Limits: 90-day expiration
Server-side hosted tools eliminate backend round trips:
| Tool | Purpose | Notes |
|---|---|---|
code_interpreter | Execute Python code | Sandboxed, 30s timeout (use background: true for longer) |
file_search | RAG without vector stores | Max 512MB per file, supports PDF/Word/Markdown/HTML/code |
web_search | Real-time web information | Automatic source citations |
image_generation | DALL-E integration | DALL-E 3 default |
mcp | Connect external tools | OAuth supported, tokens NOT stored |
Usage:
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Calculate mean of: 10, 20, 30, 40, 50',
tools: [{ type: 'code_interpreter' }],
});TypeScript Limitation: The web_search tool's external_web_access option is missing from SDK types (as of v6.16.0).
Workaround:
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Search for recent news',
tools: [{
type: 'web_search',
external_web_access: true,
} as any], // ✅ Type assertion to suppress error
});Source: GitHub Issue #1716
Built-in support for Model Context Protocol (MCP) servers to connect external tools (Stripe, databases, custom APIs).
By default, explicit user approval is required before any data is shared with a remote MCP server (security feature).
Handling Approval:
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Get my Stripe balance',
tools: [{
type: 'mcp',
server_label: 'stripe',
server_url: 'https://mcp.stripe.com',
authorization: process.env.STRIPE_TOKEN,
}],
});
if (response.status === 'requires_approval') {
// Show user: "This action requires sharing data with Stripe. Approve?"
// After user approves, retry with approval token
}Alternative: Pre-approve MCP servers in OpenAI dashboard (users configure trusted servers via settings)
Source: Official MCP Guide
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',
authorization: process.env.TOKEN, // ⚠️ NOT stored, required each request
}],
});MCP Output Types:
mcp_list_tools - Tools discovered on servermcp_call - Tool invocation + resultmessage - Final responseKey Innovation: Model's internal reasoning state survives across turns (unlike Chat Completions which discards it).
Visual Analogy:
Performance: +5% on TAUBench (GPT-5) purely from preserved reasoning
Reasoning Summaries (free):
response.output.forEach(item => {
if (item.type === 'reasoning') console.log(item.summary[0].text);
if (item.type === 'message') console.log(item.content[0].text);
});What You Get: Reasoning summaries (not full internal traces) What OpenAI Keeps: Full chain-of-thought reasoning (proprietary, for security/privacy)
For GPT-5-Thinking models:
Source: Sean Goedecke Analysis
For long-running tasks, use background: true:
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Analyze 500-page document',
background: true,
tools: [{ type: 'file_search', file_ids: [fileId] }],
});
// Poll for completion (check every 5s)
const result = await openai.responses.retrieve(response.id);
if (result.status === 'completed') console.log(result.output_text);Timeout Limits:
Time-to-First-Token (TTFT) Latency: Background mode currently has higher TTFT compared to synchronous responses. OpenAI is working to reduce this gap.
Recommendation:
Source: OpenAI Background Mode Docs
Default Retention: 30 days when store: true (default)
Zero Data Retention (ZDR): Organizations with ZDR automatically enforce store: false
Background Mode: NOT ZDR compatible (stores data ~10 minutes for polling)
Timeline:
store: trueControl Storage:
// Disable storage (no retention)
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Hello!',
store: false, // ✅ No retention
});
// ZDR organizations: store always treated as false
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Hello!',
store: true, // ⚠️ Ignored by OpenAI for ZDR orgs, treated as false
});ZDR Compliance:
store: false for claritySource: OpenAI Data Controls
Returns 8 output types instead of single message:
| Type | Example |
|---|---|
message | Final answer, explanation |
reasoning | Step-by-step thought process (free!) |
code_interpreter_call | Python code + results |
mcp_call | Tool name, args, output |
mcp_list_tools | Tool definitions from MCP server |
file_search_call | Matched chunks, citations |
web_search_call | URLs, snippets |
image_generation_call | Image URL |
Processing:
response.output.forEach(item => {
if (item.type === 'reasoning') console.log(item.summary[0].text);
if (item.type === 'web_search_call') console.log(item.results);
if (item.type === 'message') console.log(item.content[0].text);
});
// Or use helper for text-only
console.log(response.output_text);Breaking Changes:
| Feature | Chat Completions | Responses API |
|---|---|---|
| Endpoint | /v1/chat/completions | /v1/responses |
| Parameter | messages | input |
| Role | system | developer |
| Output | choices[0].message.content | output_text |
| State | Manual array | Automatic (conversation ID) |
| Streaming | data: {"choices":[...]} | SSE with 8 item types |
Example:
// Before
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
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);CRITICAL: Assistants API Sunset Timeline
Migrate before August 26, 2026 to avoid breaking changes.
Source: Assistants API Sunset Announcement
Key Breaking Changes:
| Assistants API | Responses API |
|---|---|
| Assistants (created via API) | Prompts (created in dashboard) |
| Threads | Conversations (store items, not just messages) |
| Runs (server-side lifecycle) | Responses (stateless calls) |
| Run-Steps | Items (polymorphic outputs) |
Migration Example:
// Before (Assistants API - deprecated)
const assistant = await openai.beta.assistants.create({
model: 'gpt-4',
instructions: 'You are helpful.',
});
const thread = await openai.beta.threads.create();
const run = await openai.beta.threads.runs.create(thread.id, {
assistant_id: assistant.id,
});
// After (Responses API - current)
const conversation = await openai.conversations.create({
metadata: { purpose: 'customer_support' },
});
const response = await openai.responses.create({
model: 'gpt-5',
conversation: conversation.id,
input: [
{ role: 'developer', content: 'You are helpful.' },
{ role: 'user', content: 'Hello!' },
],
});Migration Guide: Official Assistants Migration Docs
This skill prevents 11 documented errors:
1. Session State Not Persisting
const conv = await openai.conversations.create()), reuse conv.id for all turns2. MCP Server Connection Failed (mcp_connection_error)
fetch(), check token expiration3. Code Interpreter Timeout (code_interpreter_timeout)
background: true for extended timeout (up to 10 min)4. Image Generation Rate Limit (rate_limit_error)
5. File Search Relevance Issues
chunk.score > 0.76. Cost Tracking Confusion
store: false if not needed, monitor response.usage.tool_tokens7. Conversation Not Found (invalid_request_error)
openai.conversations.list() before using8. Tool Output Parsing Failed
response.output_text helper or iterate response.output.forEach(item => ...) checking item.type9. Zod v4 Incompatibility with Structured Outputs
Invalid schema for response_format 'name': schema must be a JSON Schema of 'type: "object"', got 'type: "string"'.zod-to-json-schema library doesn't support Zod v4 (missing ZodFirstPartyTypeKind export)"zod": "^3.23.8") or use custom zodTextFormat with z.toJSONSchema({ target: "draft-7" })// Workaround: Pin to Zod v3 (recommended)
{
"dependencies": {
"openai": "^6.16.0",
"zod": "^3.23.8" // DO NOT upgrade to v4 yet
}
}10. Background Mode Web Search Missing Sources
web_search_call output items contain query but no sources/resultsbackground: true + web_search tool, OpenAI doesn't return sources in the responsebackground: false) when web search sources are needed// ✅ Sources available in sync mode
const response = await openai.responses.create({
model: 'gpt-5',
input: 'Latest AI news?',
background: false, // Required for sources
tools: [{ type: 'web_search' }],
});11. Streaming Mode Missing output_text Helper
finalResponse().output_text is undefined in streaming modestream.finalResponse() doesn't include output_text convenience field (only available in non-streaming responses)output_text.done event or manually extract from output items// Workaround: Listen for event
const stream = openai.responses.stream({ model: 'gpt-5', input: 'Hello!' });
let outputText = '';
for await (const event of stream) {
if (event.type === 'output_text.done') {
outputText = event.output_text; // ✅ Available in event
}
}✅ Always:
background: true for tasks >30sauthorization tokens (NOT stored, required each request)response.usage.total_tokens for cost control❌ Never:
response.output_text helper)rate_limit_error, mcp_connection_error specifically)Official Docs:
Skill Resources: templates/, references/responses-vs-chat-completions.md, references/mcp-integration-guide.md, references/built-in-tools-guide.md, references/migration-guide.md, references/top-errors.md
Last verified: 2026-01-21 | Skill version: 2.1.0 | Changes: Added 3 TIER 1 issues (Zod v4, background web search, streaming output_text), 2 TIER 2 findings (MCP approval, reasoning privacy), Data Retention & ZDR section, Assistants API sunset timeline, background mode TTFT note, web search TypeScript limitation. Updated SDK version to 6.16.0.