Build 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.
Install with Tessl CLI
npx tessl i github:jezweb/claude-skills --skill openai-responses75
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
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.
fa91c34
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.