SPB Git

Repository Public

deployment-checklist.md 60.1 KB 1,875 lines markdown

1# API deployment checklist23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45| Contents                                                                        | Expected impact                     |6| ------------------------------------------------------------------------------- | ----------------------------------- |7| [Use the Responses API](#use-the-responses-api)                                 | Quality, cost, latency, reliability |8| [Choose a GPT-5.6 model](#choose-a-gpt-56-model)                                | Quality, cost, latency              |9| [Set up `reasoning.effort`](#set-up-reasoningeffort)                            | Quality, cost, latency              |10| [Set up `text.verbosity`](#set-up-textverbosity)                                | Quality, cost, latency              |11| [Set up the assistant `phase` parameter](#set-up-the-assistant-phase-parameter) | Quality, cost                       |12| [Use `tool_search`](#use-toolsearch)                                            | Cost, latency                       |13| [Use Programmatic Tool Calling](#use-programmatic-tool-calling)                 | Quality, cost, latency              |14| [Use Multi-agent for parallel work](#use-multi-agent-for-parallel-work)         | Quality, cost, latency              |15| [Leverage built-in tools](#leverage-built-in-tools)                             | Quality                             |16| [Leverage compaction](#leverage-compaction)                                     | Cost                                |17| [Optimize prompt caching](#optimize-prompt-caching)                             | Latency, cost                       |18| [Use `reasoning.encrypted_content`](#use-reasoningencryptedcontent)             | Quality, latency                    |19| [Set image detail intentionally](#set-image-detail-intentionally)               | Quality, cost, latency              |20| [Send a safety identifier](#send-a-safety-identifier)                           | Safety, reliability                 |21| [Use `background=True`](#use-backgroundtrue)                                    | Resuming work                       |22| [Use WebSocket mode](#use-websocket-mode)                                       | Latency                             |2324## Use the Responses API2526**Always start** with the27[Responses API](https://developers.openai.com/api/docs/guides/migrate-to-responses). It is OpenAI's flagship28API and the best place to access the newest model behavior, built-in tools,29stateful workflows, and agent features.3031## Choose a GPT-5.6 model3233Choose a [GPT-5.6 model](https://developers.openai.com/api/docs/guides/latest-model?model=gpt-5.6) for the workload instead34of routing every request to the most capable tier. Use `gpt-5.6` or35`gpt-5.6-sol` for flagship capability, `gpt-5.6-terra` for strong performance36at a lower price, and `gpt-5.6-luna` for efficient, high-volume workloads.3738When migrating, preserve the current model's workload role and effective39reasoning effort for the first comparison. Run representative evals before40changing prompts or adding new capabilities. Compare task success, latency,41input, output, reasoning, and cache-write tokens, and cost per successful task.4243## Set up `reasoning.effort`4445Use `reasoning.effort` to decide how much thinking the model should do before it46answers.4748For GPT-5.6 models, the supported values are `none`, `low`, `medium`, `high`,49`xhigh`, and `max`. The default is `medium`. Lower effort is faster and uses50fewer reasoning tokens. Higher effort gives the model more time for planning,51debugging, synthesis, and multi-step tradeoffs.5253Use `low` when the job is mostly extraction, routing, classification, or a54routine rewrite. Use `medium` or `high` when the model needs to diagnose a55problem, compare options, write a plan, or reason through code. Use `xhigh` or56`max` only when representative evals show that the quality gain justifies the57extra latency and cost. When migrating from GPT-5.5 or GPT-5.4, start with the58current effort and compare the same setting with one level lower. GPT-5.6 can59often maintain or improve quality with fewer reasoning tokens, so the lower60setting may also reduce latency and cost.6162For the hardest quality-first workloads, also compare63[`reasoning.mode: "pro"`](https://developers.openai.com/api/docs/guides/reasoning#reasoning-mode) with64standard mode at the same effort. Reasoning mode and effort are independent.65Pro mode can improve reliability by applying more model work before returning a66single final answer, but it increases latency and token usage.6768Tune reasoning effort for the task6970```javascript71import OpenAI from "openai";7273const openai = new OpenAI();7475const prompt = [76  "Our CI job started failing after a dependency bump.",77  "",78  "Error:",79  "TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'",80  "",81  "Identify the likeliest root cause and the smallest safe fix.",82].join("\n");8384const response = await openai.responses.create({85  model: "gpt-6-astra",86  reasoning: { effort: "xhigh", mode: "pro" },87  input: prompt,88});8990console.log(response.output_text);91```9293```python94from openai import OpenAI9596client = OpenAI()9798prompt = """99Our CI job started failing after a dependency bump.100101Error:102TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'103104Identify the likeliest root cause and the smallest safe fix.105"""106107response = client.responses.create(108    model="gpt-6-astra",109    reasoning={"effort": "xhigh", "mode": "pro"},110    input=prompt,111)112113print(response.output_text)114```115116```go117package main118119import (120	"context"121	"fmt"122	"strings"123124	"github.com/openai/openai-go/v3"125	"github.com/openai/openai-go/v3/responses"126	"github.com/openai/openai-go/v3/shared"127)128129func main() {130	client := openai.NewClient()131	prompt := strings.Join([]string{132		"Our CI job started failing after a dependency bump.",133		"",134		"Error:",135		"TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'",136		"",137		"Identify the likeliest root cause and the smallest safe fix.",138	}, "\n")139	reasoning := shared.ReasoningParam{Effort: shared.ReasoningEffortXhigh}140	reasoning.SetExtraFields(map[string]any{"mode": "pro"})141	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{142		Model:     "gpt-6-astra",143		Reasoning: reasoning,144		Input:     responses.ResponseNewParamsInputUnion{OfString: openai.String(prompt)},145	})146	if err != nil {147		panic(err)148	}149	fmt.Println(response.OutputText())150}151```152153```java154import com.openai.client.OpenAIClient;155import com.openai.client.okhttp.OpenAIOkHttpClient;156import com.openai.core.JsonValue;157import com.openai.models.Reasoning;158import com.openai.models.ReasoningEffort;159import com.openai.models.responses.ResponseCreateParams;160161ResponseCreateParams params =162    ResponseCreateParams.builder()163        .model("gpt-6-astra")164        .input(165            "Our CI job started failing after a dependency bump. Error: TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'. Identify the likeliest root cause and the smallest safe fix.")166        .reasoning(167            Reasoning.builder()168                .effort(ReasoningEffort.XHIGH)169                .putAdditionalProperty("mode", JsonValue.from("pro"))170                .build())171        .build();172173client.responses().create(params).output().stream()174    .flatMap(item -> item.message().stream())175    .flatMap(message -> message.content().stream())176    .flatMap(content -> content.outputText().stream())177    .forEach(text -> System.out.println(text.text()));178```179180```ruby181require "openai"182183client = OpenAI::Client.new184prompt = <<~PROMPT185  Our CI job started failing after a dependency bump.186187  Error:188  TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'189190  Identify the likeliest root cause and the smallest safe fix.191PROMPT192193response = client.responses.create(194  model: "gpt-6-astra",195  reasoning: {196    effort: :xhigh,197    mode: :pro198  },199  input: prompt200)201202puts(response.output_text)203```204205206## Set up `text.verbosity`207208`text.verbosity` is the main lever for balancing brevity against completeness.209Use lower verbosity when the product needs a quick, compact answer, and higher210verbosity when the response needs richer explanation, clearer structure, or211complete context. Lower verbosity means fewer output tokens, so the model212generates less and returns output faster.213214For coding, `medium` and `high` tend to produce longer, more organized output215with clearer structure. `low` keeps the answer tighter and more minimal.216217GPT-5.6 tends to be more concise by default than GPT-5.5. When migrating, check218whether broad instructions like "Be concise" still help. In some cases, they may219make responses too brief. Keep them only when they still help, and prefer using220`text.verbosity` to control the default level of detail; then use the prompt to221specify required content, structure, and a more specific length, if applicable.222223Set lower verbosity for compact output224225```javascript226import OpenAI from "openai";227228const openai = new OpenAI();229230const incident = [231  "Summarize this incident for the next on-call engineer.",232  "- checkout latency spiked from 220 ms to 4.8 s",233  "- only us-east-1 was affected",234  "- rollback is complete",235  "- likely trigger: cache stampede after deploy",236].join("\n");237238const response = await openai.responses.create({239  model: "gpt-6-astra",240  text: { verbosity: "low" },241  input: incident,242});243244console.log(response.output_text);245```246247```python248from openai import OpenAI249250client = OpenAI()251252response = client.responses.create(253    model="gpt-6-astra",254    text={"verbosity": "low"},255    input="""256    Summarize this incident for the next on-call engineer.257    - checkout latency spiked from 220 ms to 4.8 s258    - only us-east-1 was affected259    - rollback is complete260    - likely trigger: cache stampede after deploy261    """,262)263264print(response.output_text)265```266267```go268package main269270import (271	"context"272	"fmt"273	"strings"274275	"github.com/openai/openai-go/v3"276	"github.com/openai/openai-go/v3/responses"277)278279func main() {280	client := openai.NewClient()281	incident := strings.Join([]string{282		"Summarize this incident for the next on-call engineer.",283		"- checkout latency spiked from 220 ms to 4.8 s",284		"- only us-east-1 was affected",285		"- rollback is complete",286		"- likely trigger: cache stampede after deploy",287	}, "\n")288	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{289		Model: "gpt-6-astra",290		Text:  responses.ResponseTextConfigParam{Verbosity: "low"},291		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(incident)},292	})293	if err != nil {294		panic(err)295	}296	fmt.Println(response.OutputText())297}298```299300```java301import com.openai.client.OpenAIClient;302import com.openai.client.okhttp.OpenAIOkHttpClient;303import com.openai.models.responses.ResponseCreateParams;304import com.openai.models.responses.ResponseTextConfig;305306ResponseCreateParams params =307    ResponseCreateParams.builder()308        .model("gpt-6-astra")309        .input(310            "Summarize this incident for the next on-call engineer: checkout latency spiked from 220 ms to 4.8 s, only us-east-1 was affected, rollback is complete, and the likely trigger was a cache stampede.")311        .text(ResponseTextConfig.builder().verbosity(ResponseTextConfig.Verbosity.LOW).build())312        .build();313314client.responses().create(params).output().stream()315    .flatMap(item -> item.message().stream())316    .flatMap(message -> message.content().stream())317    .flatMap(content -> content.outputText().stream())318    .forEach(text -> System.out.println(text.text()));319```320321```ruby322require "openai"323324client = OpenAI::Client.new325incident = <<~INCIDENT326  Summarize this incident for the next on-call engineer.327  - checkout latency spiked from 220 ms to 4.8 s328  - only us-east-1 was affected329  - rollback is complete330  - likely trigger: cache stampede after deploy331INCIDENT332333response = client.responses.create(334  model: "gpt-6-astra",335  text: { verbosity: :low },336  input: incident337)338339puts(response.output_text)340```341342343## Set up the assistant `phase` parameter344345`phase` is a label on assistant messages in the conversation history. It346indicates to the model whether a prior assistant message was an intermediate347working commentary or the final answer. Use `phase: "commentary"` for progress348updates, pre-tool-call notes, and other in-between messages. Use349`phase: "final_answer"` for the completed response.350351The assistant might say something like:352353Assistant commentary message354355```json356{357  "role": "assistant",358  "phase": "commentary",359  "content": "I'm checking the logs and comparing them to the last successful deploy."360}361```362363364That is not the answer. It is a progress note. Later, the assistant might say:365366Assistant final answer message367368```json369{370  "role": "assistant",371  "phase": "final_answer",372  "content": "The deploy failed because the migration referenced a column that does not exist in production."373}374```375376377This is useful in long-running or tool-heavy workflows where the assistant may378produce visible progress updates before it finishes. When you send that history379back on follow-up requests for `gpt-5.3-codex` and later models,380**preserve and resend `phase`** on assistant messages so the model can distinguish381progress updates from the final result. This helps reduce early stopping, making382the agent more likely to continue until it reaches the final answer.383384## Use `tool_search`385386Instead of loading the full tool catalog into every request, use387[tool search](https://developers.openai.com/api/docs/guides/tools-tool-search): add388`{"type": "tool_search"}` and mark expensive tool definitions with389`defer_loading: true`. The model can then load the subset it needs at runtime.390At request start, the model only sees the search tool name and description. If391the model decides it needs a deferred tool, it runs tool search, and only then392are the deferred tool definitions loaded into context. Only then will the model393call them. This saves tokens and preserves cache performance.394395Tool search has two modes:396397- **Hosted tool search** is the simpler option. Use it when you already know398  which tools could be available for the request.399- **Client-executed tool search** is for cases where your app has to decide what400  tools are available, like based on the user's tenant, project, permissions, or401  internal registry.402403**Start with hosted tool search** unless your app really needs to control404discovery itself.405406Group your tools by user intent. Use namespaces or MCP servers when you can. It407is easier for the model to choose between a few clear groups than a long flat408list of functions. We recommend keeping each namespace under about 10 functions409for optimal token efficiency and model performance.410411Keep namespace descriptions short and discriminative. Put the detailed412instructions inside the deferred tool definitions. Avoid making one giant413namespace for everything.414415Use hosted tool search with deferred tools416417```javascript418import OpenAI from "openai";419420const openai = new OpenAI();421422const billingNamespace = {423  type: "namespace",424  name: "billing",425  description: "Billing tools for invoices, payments, taxes, and credits.",426  tools: [427    {428      type: "function",429      name: "lookup_invoice",430      description:431        "Look up invoice state, taxes, credits, and payment attempts.",432      parameters: {433        type: "object",434        properties: {435          invoice_id: { type: "string" },436        },437        required: ["invoice_id"],438        additionalProperties: false,439      },440      strict: true,441      defer_loading: true,442    },443  ],444};445446const crmNamespace = {447  type: "namespace",448  name: "crm",449  description:450    "CRM tools for account ownership, plans, health, and payment history.",451  tools: [452    {453      type: "function",454      name: "get_account",455      description: "Fetch account owner, plan, health, and payment history.",456      parameters: {457        type: "object",458        properties: {459          account_id: { type: "string" },460        },461        required: ["account_id"],462        additionalProperties: false,463      },464      strict: true,465      defer_loading: true,466    },467  ],468};469470const response = await openai.responses.create({471  model: "gpt-6-astra",472  input:473    "Find the right billing tool and explain why invoice INV-1043 still " +474    "shows overdue after a payment yesterday.",475  tools: [billingNamespace, crmNamespace, { type: "tool_search" }],476});477478console.log(response.output);479```480481```python482from openai import OpenAI483484client = OpenAI()485486billing_namespace = {487    "type": "namespace",488    "name": "billing",489    "description": "Billing tools for invoices, payments, taxes, and credits.",490    "tools": [491        {492            "type": "function",493            "name": "lookup_invoice",494            "description": "Look up invoice state, taxes, credits, and payment attempts.",495            "parameters": {496                "type": "object",497                "properties": {498                    "invoice_id": {"type": "string"},499                },500                "required": ["invoice_id"],501                "additionalProperties": False,502            },503            "strict": True,504            "defer_loading": True,505        }506    ],507}508509crm_namespace = {510    "type": "namespace",511    "name": "crm",512    "description": "CRM tools for account ownership, plans, health, and payment history.",513    "tools": [514        {515            "type": "function",516            "name": "get_account",517            "description": "Fetch account owner, plan, health, and payment history.",518            "parameters": {519                "type": "object",520                "properties": {521                    "account_id": {"type": "string"},522                },523                "required": ["account_id"],524                "additionalProperties": False,525            },526            "strict": True,527            "defer_loading": True,528        }529    ],530}531532response = client.responses.create(533    model="gpt-6-astra",534    input=(535        "Find the right billing tool and explain why invoice INV-1043 still "536        "shows overdue after a payment yesterday."537    ),538    tools=[billing_namespace, crm_namespace, {"type": "tool_search"}],539)540541print(response.output)542```543544```go545package main546547import (548	"context"549	"fmt"550551	"github.com/openai/openai-go/v3"552	"github.com/openai/openai-go/v3/responses"553)554555func main() {556	client := openai.NewClient()557	billing := namespaceTool(558		"billing",559		"Billing tools for invoices, payments, taxes, and credits.",560		"lookup_invoice",561		"Look up invoice state, taxes, credits, and payment attempts.",562		"invoice_id",563	)564	crm := namespaceTool(565		"crm",566		"CRM tools for account ownership, plans, health, and payment history.",567		"get_account",568		"Fetch account owner, plan, health, and payment history.",569		"account_id",570	)571	toolSearch := responses.ToolUnionParam{OfToolSearch: &responses.ToolSearchToolParam{}}572	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{573		Model: "gpt-6-astra",574		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(575			"Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.",576		)},577		Tools: []responses.ToolUnionParam{billing, crm, toolSearch},578	})579	if err != nil {580		panic(err)581	}582	fmt.Println(response.Output)583}584585func namespaceTool(namespace, namespaceDescription, name, description, argument string) responses.ToolUnionParam {586	parameters := map[string]any{587		"type": "object",588		"properties": map[string]any{589			argument: map[string]any{"type": "string"},590		},591		"required":             []string{argument},592		"additionalProperties": false,593	}594	function := responses.NamespaceToolToolFunctionParam{595		Name: name, Description: openai.String(description), Parameters: parameters, Strict: openai.Bool(true), DeferLoading: openai.Bool(true),596	}597	return responses.ToolParamOfNamespace(598		namespaceDescription,599		namespace,600		[]responses.NamespaceToolToolUnionParam{{OfFunction: &function}},601	)602}603```604605```java606import com.openai.client.OpenAIClient;607import com.openai.client.okhttp.OpenAIOkHttpClient;608import com.openai.core.JsonValue;609import com.openai.models.responses.NamespaceTool;610import com.openai.models.responses.ResponseCreateParams;611import com.openai.models.responses.ToolSearchTool;612import java.util.List;613import java.util.Map;614615ResponseCreateParams params =616    ResponseCreateParams.builder()617        .model("gpt-6-astra")618        .input(619            "Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.")620        .addTool(621            namespace(622                "billing",623                "Billing tools for invoices, payments, taxes, and credits.",624                "lookup_invoice",625                "Look up invoice state, taxes, credits, and payment attempts.",626                "invoice_id"))627        .addTool(628            namespace(629                "crm",630                "CRM tools for account ownership, plans, health, and payment history.",631                "get_account",632                "Fetch account owner, plan, health, and payment history.",633                "account_id"))634        .addTool(ToolSearchTool.builder().execution(ToolSearchTool.Execution.SERVER).build())635        .build();636637client.responses().create(params).output().forEach(System.out::println);638639private static NamespaceTool namespace(640    String name,641    String description,642    String function,643    String functionDescription,644    String argument) {645  return NamespaceTool.builder()646      .name(name)647      .description(description)648      .addTool(649          NamespaceTool.Tool.Function.builder()650              .name(function)651              .description(functionDescription)652              .deferLoading(true)653              .strict(true)654              .parameters(655                  JsonValue.from(656                      Map.of(657                          "type",658                          "object",659                          "properties",660                          Map.of(argument, Map.of("type", "string")),661                          "required",662                          List.of(argument),663                          "additionalProperties",664                          false)))665              .build())666      .build();667}668```669670```ruby671require "openai"672673def namespace_tool(name, description, function_name, function_description, argument)674  {675    type: :namespace,676    name: name,677    description: description,678    tools: [679      {680        type: :function,681        name: function_name,682        description: function_description,683        defer_loading: true,684        strict: true,685        parameters: {686          type: "object",687          properties: { argument => { type: "string" } },688          required: [argument],689          additionalProperties: false690        }691      }692    ]693  }694end695696client = OpenAI::Client.new697billing = namespace_tool(698  "billing",699  "Billing tools for invoices, payments, taxes, and credits.",700  "lookup_invoice",701  "Look up invoice state, taxes, credits, and payment attempts.",702  "invoice_id"703)704crm = namespace_tool(705  "crm",706  "CRM tools for account ownership, plans, health, and payment history.",707  "get_account",708  "Fetch account owner, plan, health, and payment history.",709  "account_id"710)711712response = client.responses.create(713  model: "gpt-6-astra",714  input: "Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.",715  tools: [billing, crm, { type: :tool_search }]716)717718puts(response.output)719```720721722## Use Programmatic Tool Calling723724[Programmatic Tool Calling](https://developers.openai.com/api/docs/guides/tools-programmatic-tool-calling)725lets GPT-5.6 write JavaScript that calls eligible tools and reduces their726intermediate results inside a hosted runtime. Use it for bounded stages where727code can filter, join, rank, remove duplicates, combine, or check large tool728results before returning a smaller structured result to the model.729730Add the `programmatic_tool_calling` tool and opt in each eligible tool. Use731`allowed_callers: ["programmatic"]` for program-only tools, or use732`allowed_callers: ["direct", "programmatic"]` when the model may also call the733tool directly. Keep calls direct when each result may change the model's next734decision, an action requires approval, or the final answer must preserve735citations or native artifacts. Document tool return fields and error behavior so736the model can write a correct program without first inspecting a result.737738Your tool loop must handle `program` and `program_output` items, as well as739program-issued `function_call` items and their `function_call_output` items.740Preserve each `call_id`, and copy the function call's `caller` into its output so741the service can resume the correct program.742743Test both the `program_output` and the final assistant message. A correct program744result can still become an incomplete final answer. Compare task success,745required evidence, total tokens, latency, and cost against the same workflow746using direct tool calls.747748## Use Multi-agent for parallel work749750[Multi-agent](https://developers.openai.com/api/docs/guides/responses-multi-agent) is a GPT-5.6 feature that751lets a root agent delegate independent workstreams to subagents and synthesize752their results. Use it when you can split research, analysis, or implementation753into concrete, bounded tasks that use separate context and run in parallel.754755Set `multi_agent.enabled` to `true` in the request. For HTTP, use the beta756Responses SDK with `client.beta.responses` and pass `responses_multi_agent=v1`757in `betas`. For raw HTTP or WebSocket connections, send758`OpenAI-Beta: responses_multi_agent=v1`. Item schemas can change while759Multi-agent is in beta.760761Prefer one agent for short tasks, ordered chains where each step depends on the762last, or work that writes to the same mutable resource. Subagents can increase763token usage, so start with the default `max_concurrent_subagents` value of `3`764and measure end-to-end quality, latency, and cost. For tool-heavy or long-running765Multi-agent workflows, WebSocket mode can reduce continuation overhead.766767Before enabling Multi-agent, account for its current limitations:768`/responses/compact`, `reasoning.summary`, and `max_tool_calls` are not769supported. The server automatically compacts the root context and every770subagent context.771772## Leverage built-in tools773774[Built-in tools](https://developers.openai.com/api/docs/guides/tools) are native capabilities of the API.775Instead of building every tool yourself, you can give the model access to tools776that already work inside the Responses API. The model can then decide when to777use them.778779OpenAI keeps adding more native tools, so start with built-in tools when they780fit your workflow. Build custom tools when native options do not cover the task.781Current built-in tools and related tool options include:782783- **Web search**: Search the web for up-to-date information784- **File search**: Search uploaded files or vector stores785- **Code interpreter**: Run Python for analysis, math, charts, and file786  processing787- **Shell**: Run shell commands in a hosted container or your own runtime788- **Computer use**: Operate a UI through screenshots, clicks, typing, and789  scrolling790- **Image generation**: Generate or edit images791- **MCP/connectors**: Connect the model to external services and tools792- **Skills**: Attach reusable instruction bundles and workflow files793- **Apply patch**: Make structured code edits794795Model quality is another reason to prefer them. Built-in tools are796in-distribution for our post-training, meaning that the models are trained and797evaluated around these tool shapes, behaviors, and outputs. With built-in tools,798OpenAI models support better tool selection, cleaner execution, and fewer799failures than with new tools.800801## Leverage compaction802803[Compaction](https://developers.openai.com/api/docs/guides/compaction) is a context engineering tool: it804decides what information the model carries forward across many turns. In805long-running agents, the problem is not just, "Will I hit the context limit?" It806is that old messages, tool logs, retries, and stale details crowd out the state807the model needs.808809Compaction gives you a controlled way to reduce context size while preserving810state needed for subsequent turns. After a meaningful milestone, like finishing811a debugging phase or narrowing a root cause, you can compact the prior window812and continue from the compacted output. This keeps the model sharp because the813next turn is built around the important state, not every intermediate reasoning,814failed command, and obsolete branch of reasoning.815816You can use compaction in two ways:817818- **Let the server handle it**: if you use `previous_response_id`, turn on819  `context_management` with a `compact_threshold`. The server will automatically820  compact the conversation when it gets too large. You keep sending only the821  newest user message.822- **Do it yourself**: if you manage the full input array yourself, call823  `client.responses.compact()`. It gives back a smaller context window. Use that824  returned output directly in the next `responses.create()` call.825826**Do not edit the compacted output.** It is not a human summary, but the machine827state that helps the model continue. Pass it forward as-is, then add the next828user message.829830Continue from compacted response state831832```javascript833import OpenAI from "openai";834import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";835836const openai = new OpenAI();837838// Full window collected from a long debugging session:839// user messages, assistant outputs, tool calls, and tool outputs.840const longWindow = sessionItems;841842const compacted = await openai.responses.compact({843  model: "gpt-6-astra",844  input: longWindow,845});846847const nextResponse = await openai.responses.create({848  model: "gpt-6-astra",849  store: false,850  input: [851    // Preserve replayable compacted items.852    ...toResponseInputItems(compacted.output),853    {854      type: "message",855      role: "user",856      content:857        "We found the bad cache invalidation path. Write the fix plan " +858        "and the verification checklist.",859    },860  ],861});862863console.log(nextResponse.output_text);864```865866```python867from openai import OpenAI868869client = OpenAI()870871# Full window collected from a long debugging session:872# user messages, assistant outputs, tool calls, and tool outputs.873long_window = session_items874875compacted = client.responses.compact(876    model="gpt-6-astra",877    input=long_window,878)879880next_response = client.responses.create(881    model="gpt-6-astra",882    store=False,883    input=[884        *compacted.output,  # Use compact output as-is.885        {886            "type": "message",887            "role": "user",888            "content": (889                "We found the bad cache invalidation path. Write the fix plan "890                "and the verification checklist."891            ),892        },893    ],894)895896print(next_response.output_text)897```898899```go900package main901902import (903	"context"904	"encoding/json"905	"fmt"906907	"github.com/openai/openai-go/v3"908	"github.com/openai/openai-go/v3/responses"909)910911func main() {912	client := openai.NewClient()913	longWindow := []responses.ResponseInputItemUnionParam{914		responses.ResponseInputItemParamOfMessage("Find the cache invalidation bug in this debugging session.", responses.EasyInputMessageRoleUser),915	}916	compacted, err := client.Responses.Compact(context.Background(), responses.ResponseCompactParams{917		Model: "gpt-6-astra",918		Input: responses.ResponseCompactParamsInputUnion{OfResponseInputItemArray: longWindow},919	})920	if err != nil {921		panic(err)922	}923	input := append(outputAsInput(compacted.Output),924		responses.ResponseInputItemParamOfMessage(925			"We found the bad cache invalidation path. Write the fix plan and the verification checklist.",926			responses.EasyInputMessageRoleUser,927		),928	)929	nextResponse, err := client.Responses.New(context.Background(), responses.ResponseNewParams{930		Model: "gpt-6-astra",931		Store: openai.Bool(false),932		Input: responses.ResponseNewParamsInputUnion{OfInputItemList: input},933	})934	if err != nil {935		panic(err)936	}937	fmt.Println(nextResponse.OutputText())938}939940func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {941	input := make([]responses.ResponseInputItemUnionParam, 0, len(output))942	for _, item := range output {943		var converted responses.ResponseInputItemUnion944		if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {945			panic(err)946		}947		input = append(input, converted.ToParam())948	}949	return input950}951```952953```java954import com.openai.client.OpenAIClient;955import com.openai.client.okhttp.OpenAIOkHttpClient;956import com.openai.models.responses.EasyInputMessage;957import com.openai.models.responses.ResponseCompactParams;958import com.openai.models.responses.ResponseCompactionItemParam;959import com.openai.models.responses.ResponseCreateParams;960import com.openai.models.responses.ResponseInputItem;961import java.util.ArrayList;962963var compacted =964    client965        .responses()966        .compact(967            ResponseCompactParams.builder()968                .model("gpt-6-astra")969                .input("Find the cache invalidation bug in this debugging session.")970                .build());971var input = new ArrayList<ResponseInputItem>();972for (var item : compacted.output()) {973  item.message().map(ResponseInputItem::ofResponseOutputMessage).ifPresent(input::add);974  item.reasoning().map(ResponseInputItem::ofReasoning).ifPresent(input::add);975  item.compaction()976      .map(977          value ->978              ResponseInputItem.ofCompaction(979                  ResponseCompactionItemParam.builder()980                      .id(value.id())981                      .encryptedContent(value.encryptedContent())982                      .build()))983      .ifPresent(input::add);984}985input.add(986    ResponseInputItem.ofEasyInputMessage(987        EasyInputMessage.builder()988            .role(EasyInputMessage.Role.USER)989            .content(990                "We found the bad cache invalidation path. Write the fix plan and the verification checklist.")991            .build()));992993client994    .responses()995    .create(996        ResponseCreateParams.builder()997            .model("gpt-6-astra")998            .inputOfResponse(input)999            .store(false)1000            .build())1001    .output()1002    .stream()1003    .flatMap(item -> item.message().stream())1004    .flatMap(message -> message.content().stream())1005    .flatMap(content -> content.outputText().stream())1006    .forEach(text -> System.out.println(text.text()));1007```10081009```ruby1010require "openai"10111012client = OpenAI::Client.new1013long_window = [1014  {1015    role: :user,1016    content: "Find the cache invalidation bug in this debugging session."1017  }1018]10191020compacted = client.responses.compact(1021  model: "gpt-6-astra",1022  input: long_window1023)1024input = compacted.output.dup1025input << {1026  role: :user,1027  content: "We found the bad cache invalidation path. Write the fix plan and the verification checklist."1028}10291030response = client.responses.create(1031  model: "gpt-6-astra",1032  store: false,1033  input: input1034)10351036puts(response.output_text)1037```103810391040<a id="use-promptcachekey"></a>10411042<a id="separate-prompts-with-promptcachekey"></a>10431044## Optimize prompt caching10451046[Prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching) automatically reduces latency1047and cost when requests reuse the same long prefix. Put stable instructions,1048examples, and reference material first, followed by dynamic user-specific1049content. Keep tool definitions and ordering stable, and append new conversation1050turns without rewriting earlier context.10511052GPT-5.6 introduced explicit prompt caching. Implicit caching remains the1053default, but GPT-5.6 models and later model families also support explicit1054cache breakpoints and request-wide cache policy. If a changing suffix comes1055after a stable prefix, add an explicit `prompt_cache_breakpoint` at the reusable boundary. Set1056`prompt_cache_options.mode` to `explicit` only when the request should use only1057the breakpoints you provide and no implicit breakpoint. Earlier models continue1058to use automatic prompt caching only.10591060On GPT-5.6 models and later model families, cache writes cost 1.25× the1061uncached input token rate. Log `cached_tokens` and `cache_write_tokens`, then1062compare write volume with later cache reads to measure net cost and tune1063breakpoint placement.10641065Use a stable `prompt_cache_key` for requests that share a reusable prefix to1066help route related requests to the same cache and optimize cache hit rates on1067models before GPT-5.6. For busy groups, follow the [guidance for distributing1068traffic across more keys](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-keys).10691070On GPT-5.6 and later, `prompt_cache_key` is optional: you can achieve optimal1071cache hit rates without it. You can use it to maintain separate cache accounting1072for customers, users, or workspaces. This can make cached token usage and billing1073easier to explain for each group. Assign a distinct key to each customer and1074keep it stable across that customer's related requests. Separate keys also help1075prevent cache-hit probing across customers. See [Separate cache accounting with1076keys](https://developers.openai.com/api/docs/guides/prompt-caching#separate-prompts-with-cache-keys).10771078Maintain separate cache accounting for a customer10791080```javascript1081import OpenAI from "openai";10821083const openai = new OpenAI();10841085const instructions = [1086  "You are the support agent for Acme.",1087  "Follow the Acme support policy and escalation rubric.",1088  "Use the same tone, safety rules, and tool plan for each ticket.",1089].join("\n");10901091const response = await openai.responses.create({1092  model: "gpt-6-astra",1093  prompt_cache_key: "tenant-acme-support-agent",1094  instructions,1095  input: "Summarize the current escalation for the on-call lead.",1096});10971098console.log(response.output_text);1099```11001101```python1102from openai import OpenAI11031104client = OpenAI()11051106instructions = """1107You are the support agent for Acme.1108Follow the Acme support policy and escalation rubric.1109Use the same tone, safety rules, and tool plan for each ticket.1110"""11111112response = client.responses.create(1113    model="gpt-6-astra",1114    prompt_cache_key="tenant-acme-support-agent",1115    instructions=instructions,1116    input="Summarize the current escalation for the on-call lead.",1117)11181119print(response.output_text)1120```11211122```go1123package main11241125import (1126	"context"1127	"fmt"1128	"strings"11291130	"github.com/openai/openai-go/v3"1131	"github.com/openai/openai-go/v3/responses"1132)11331134func main() {1135	client := openai.NewClient()1136	instructions := strings.Join([]string{1137		"You are the support agent for Acme.",1138		"Follow the Acme support policy and escalation rubric.",1139		"Use the same tone, safety rules, and tool plan for each ticket.",1140	}, "\n")1141	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1142		Model:          "gpt-6-astra",1143		PromptCacheKey: openai.String("tenant-acme-support-agent"),1144		Instructions:   openai.String(instructions),1145		Input:          responses.ResponseNewParamsInputUnion{OfString: openai.String("Summarize the current escalation for the on-call lead.")},1146	})1147	if err != nil {1148		panic(err)1149	}1150	fmt.Println(response.OutputText())1151}1152```11531154```java1155import com.openai.client.OpenAIClient;1156import com.openai.client.okhttp.OpenAIOkHttpClient;1157import com.openai.models.responses.ResponseCreateParams;11581159ResponseCreateParams params =1160    ResponseCreateParams.builder()1161        .model("gpt-6-astra")1162        .instructions(1163            "You are the support agent for Acme.\n"1164                + "Follow the Acme support policy and escalation rubric.\n"1165                + "Use the same tone, safety rules, and tool plan for each ticket.")1166        .input("Summarize the current escalation for the on-call lead.")1167        .promptCacheKey("tenant-acme-support-agent")1168        .build();11691170client.responses().create(params).output().stream()1171    .flatMap(item -> item.message().stream())1172    .flatMap(message -> message.content().stream())1173    .flatMap(content -> content.outputText().stream())1174    .forEach(text -> System.out.println(text.text()));1175```11761177```csharp1178using OpenAI.Responses;1179#pragma warning disable OPENAI00111801181string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;1182ResponsesClient client = new(key);11831184CreateResponseOptions options = new()1185{1186    Model = "gpt-6-astra",1187    PromptCacheKey = "tenant-acme-support-agent",1188    Instructions = "Follow the Acme support policy and escalation rubric.",1189};1190options.InputItems.Add(1191    ResponseItem.CreateUserMessageItem("Summarize the current escalation for the on-call lead.")1192);11931194ResponseResult response = await client.CreateResponseAsync(options);1195Console.WriteLine(response.GetOutputText());1196```11971198```ruby1199require "openai"12001201client = OpenAI::Client.new1202instructions = <<~INSTRUCTIONS1203  You are the support agent for Acme.1204  Follow the Acme support policy and escalation rubric.1205  Use the same tone, safety rules, and tool plan for each ticket.1206INSTRUCTIONS12071208response = client.responses.create(1209  model: "gpt-6-astra",1210  prompt_cache_key: "tenant-acme-support-agent",1211  instructions: instructions,1212  input: "Summarize the current escalation for the on-call lead."1213)12141215puts(response.output_text)1216```121712181219## Use `reasoning.encrypted_content`12201221GPT-5.6 can [preserve reasoning across1222calls](https://developers.openai.com/api/docs/guides/reasoning#preserve-reasoning-across-calls). Use1223`reasoning.context: "all_turns"` when the task's goals, assumptions, and1224priorities remain stable. Use `current_turn` when earlier reasoning is no longer1225relevant and might anchor the model to an outdated approach. If you omit1226`reasoning.context` or set it to `auto`, inspect the response's1227`reasoning.context` field to confirm the effective mode.12281229[Persisted reasoning](https://developers.openai.com/api/docs/guides/reasoning#keeping-reasoning-items-in-context)1230works only when earlier reasoning items are available. Use `previous_response_id`1231for stored responses. If your [Zero Data Retention1232(ZDR)](https://developers.openai.com/api/docs/guides/your-data#zero-data-retention) requirements do not allow1233storing response data, encrypted reasoning content enables a stateless1234handoff.12351236Reasoning items in the response output include encrypted reasoning content by1237default. You can access the encrypted reasoning content from each reasoning1238item's `encrypted_content` property. Your app does not need to understand that1239value. It just keeps each reasoning item exactly as returned and sends it back1240during the next turn, so the model can use it to continue the workflow.12411242Pass encrypted reasoning between stateless turns12431244```javascript1245import OpenAI from "openai";1246import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";12471248const openai = new OpenAI();12491250const history = [1251  {1252    role: "user",1253    content: "Investigate why invoice INV-1043 has mismatched tax totals.",1254  },1255];12561257const first = await openai.responses.create({1258  model: "gpt-6-astra",1259  store: false,1260  reasoning: { effort: "medium", context: "current_turn" },1261  input: history,1262});12631264history.push(...toResponseInputItems(first.output));1265history.push({1266  role: "user",1267  content: "Now write the customer-facing explanation in plain English.",1268});12691270const second = await openai.responses.create({1271  model: "gpt-6-astra",1272  store: false,1273  reasoning: { effort: "medium", context: "all_turns" },1274  input: history,1275});12761277console.log(second.output_text);1278```12791280```python1281from openai import OpenAI12821283client = OpenAI()12841285history = [1286    {1287        "role": "user",1288        "content": "Investigate why invoice INV-1043 has mismatched tax totals.",1289    }1290]12911292first = client.responses.create(1293    model="gpt-6-astra",1294    store=False,1295    reasoning={"effort": "medium", "context": "current_turn"},1296    input=history,1297)12981299history.extend(item.model_dump(exclude={"status"}) for item in first.output)1300history.append(1301    {1302        "role": "user",1303        "content": "Now write the customer-facing explanation in plain English.",1304    }1305)13061307second = client.responses.create(1308    model="gpt-6-astra",1309    store=False,1310    reasoning={"effort": "medium", "context": "all_turns"},1311    input=history,1312)13131314print(second.output_text)1315```13161317```go1318package main13191320import (1321	"context"1322	"encoding/json"1323	"fmt"13241325	"github.com/openai/openai-go/v3"1326	"github.com/openai/openai-go/v3/responses"1327	"github.com/openai/openai-go/v3/shared"1328)13291330func main() {1331	client := openai.NewClient()1332	history := []responses.ResponseInputItemUnionParam{1333		responses.ResponseInputItemParamOfMessage("Investigate why invoice INV-1043 has mismatched tax totals.", responses.EasyInputMessageRoleUser),1334	}1335	first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1336		Model:     "gpt-6-astra",1337		Store:     openai.Bool(false),1338		Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortMedium, Context: shared.ReasoningContextCurrentTurn},1339		Include:   []responses.ResponseIncludable{responses.ResponseIncludableReasoningEncryptedContent},1340		Input:     responses.ResponseNewParamsInputUnion{OfInputItemList: history},1341	})1342	if err != nil {1343		panic(err)1344	}1345	history = append(history, outputAsInput(first.Output)...)1346	history = append(history, responses.ResponseInputItemParamOfMessage(1347		"Now write the customer-facing explanation in plain English.",1348		responses.EasyInputMessageRoleUser,1349	))1350	second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1351		Model:     "gpt-6-astra",1352		Store:     openai.Bool(false),1353		Reasoning: shared.ReasoningParam{Effort: shared.ReasoningEffortMedium, Context: shared.ReasoningContextAllTurns},1354		Input:     responses.ResponseNewParamsInputUnion{OfInputItemList: history},1355	})1356	if err != nil {1357		panic(err)1358	}1359	fmt.Println(second.OutputText())1360}13611362func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {1363	input := make([]responses.ResponseInputItemUnionParam, 0, len(output))1364	for _, item := range output {1365		var converted responses.ResponseInputItemUnion1366		if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {1367			panic(err)1368		}1369		input = append(input, converted.ToParam())1370	}1371	return input1372}1373```13741375```java1376import com.openai.client.OpenAIClient;1377import com.openai.client.okhttp.OpenAIOkHttpClient;1378import com.openai.core.JsonValue;1379import com.openai.models.Reasoning;1380import com.openai.models.responses.EasyInputMessage;1381import com.openai.models.responses.ResponseCreateParams;1382import com.openai.models.responses.ResponseIncludable;1383import com.openai.models.responses.ResponseInputItem;1384import java.util.ArrayList;13851386var history = new ArrayList<ResponseInputItem>();1387history.add(1388    ResponseInputItem.ofEasyInputMessage(1389        EasyInputMessage.builder()1390            .role(EasyInputMessage.Role.USER)1391            .content("Investigate why invoice INV-1043 has mismatched tax totals.")1392            .build()));13931394var first =1395    client1396        .responses()1397        .create(1398            ResponseCreateParams.builder()1399                .model("gpt-6-astra")1400                .inputOfResponse(history)1401                .store(false)1402                .reasoning(1403                    Reasoning.builder()1404                        .effort(com.openai.models.ReasoningEffort.MEDIUM)1405                        .putAdditionalProperty("context", JsonValue.from("current_turn"))1406                        .build())1407                .addInclude(ResponseIncludable.of("reasoning.encrypted_content"))1408                .build());1409first.output().stream()1410    .map(item -> JsonValue.from(item).convert(ResponseInputItem.class))1411    .forEach(history::add);1412history.add(1413    ResponseInputItem.ofEasyInputMessage(1414        EasyInputMessage.builder()1415            .role(EasyInputMessage.Role.USER)1416            .content("Now write the customer-facing explanation in plain English.")1417            .build()));14181419client1420    .responses()1421    .create(1422        ResponseCreateParams.builder()1423            .model("gpt-6-astra")1424            .inputOfResponse(history)1425            .store(false)1426            .reasoning(1427                Reasoning.builder()1428                    .effort(com.openai.models.ReasoningEffort.MEDIUM)1429                    .putAdditionalProperty("context", JsonValue.from("all_turns"))1430                    .build())1431            .build())1432    .output()1433    .stream()1434    .flatMap(item -> item.message().stream())1435    .flatMap(message -> message.content().stream())1436    .flatMap(content -> content.outputText().stream())1437    .forEach(text -> System.out.println(text.text()));1438```14391440```ruby1441require "openai"14421443client = OpenAI::Client.new1444history = [1445  {1446    role: :user,1447    content: "Investigate why invoice INV-1043 has mismatched tax totals."1448  }1449]14501451first = client.responses.create(1452  model: "gpt-6-astra",1453  store: false,1454  reasoning: {1455    effort: :medium,1456    context: :current_turn1457  },1458  include: ["reasoning.encrypted_content"],1459  input: history1460)1461history.concat(first.output)1462history << {1463  role: :user,1464  content: "Now write the customer-facing explanation in plain English."1465}14661467second = client.responses.create(1468  model: "gpt-6-astra",1469  store: false,1470  reasoning: {1471    effort: :medium,1472    context: :all_turns1473  },1474  input: history1475)14761477puts(second.output_text)1478```147914801481## Set image detail intentionally14821483On GPT-5.6 models, omitted image `detail` and `detail: "auto"` use the same1484sizing behavior as `original`. The service preserves the input dimensions,1485except that images larger than 65,535 pixels on either side are scaled down to1486fit that limit. The API rejects images that still exceed the1487[30,000-patch limit](https://developers.openai.com/api/docs/guides/images-vision#image-input-requirements),1488rather than resizing them to fit it. Large images can use more input tokens and1489add latency as a result.14901491Choose [`detail`](https://developers.openai.com/api/docs/guides/images-vision#choose-an-image-detail-level)1492for the task. Resize the image, use `low` when fine visual detail is not1493important, or use `high` for standard high-fidelity image understanding. Keep1494`original` for large, dense, coordinate-sensitive, OCR, localization, or1495visual-inspection tasks where the extra detail improves quality. Measure1496worst-case image tokens and latency before deployment.14971498## Send a safety identifier14991500If your application serves individual end users, send a stable,1501privacy-preserving1502[`safety_identifier`](https://developers.openai.com/api/docs/guides/safety-best-practices#implement-safety-identifiers)1503with each request. It helps OpenAI detect misuse and gives your team a stable way1504to trace policy violations. It also reduces the chance that one user's misuse1505disrupts access for your broader organization.15061507Hash the user's username or email address instead of sending identifying1508information. For logged-out experiences, use a stable session ID.15091510## Use `background=True`15111512Use [`background=True`](https://developers.openai.com/api/docs/guides/background) for requests that may take1513a long time. Instead of keeping the client connection open, the API starts a job1514and returns an ID. Your app can poll that job until it finishes, fails, or is1515canceled. Use it for large analyses, long tool runs, or work that needs status1516and retry behavior.15171518Run and poll a background response15191520```javascript1521// Replace the illustrative IDs and URLs below with your own resource values.1522import OpenAI from "openai";15231524const openai = new OpenAI();1525const logBundleFileId = "file_123";15261527let job = await openai.responses.create({1528  model: "gpt-6-astra",1529  background: true,1530  store: false,1531  input: "Analyze this large log bundle and cluster the primary failure modes.",1532  tools: [1533    {1534      type: "code_interpreter",1535      container: {1536        type: "auto",1537        file_ids: [logBundleFileId],1538      },1539    },1540  ],1541});15421543while (["queued", "in_progress"].includes(job.status)) {1544  await new Promise((resolve) => setTimeout(resolve, 2000));1545  job = await openai.responses.retrieve(job.id);1546}15471548console.log(job.output_text);1549```15501551```python1552# Replace the illustrative IDs and URLs below with your own resource values.1553from openai import OpenAI1554import time15551556client = OpenAI()1557log_bundle_file_id = "file_123"15581559job = client.responses.create(1560    model="gpt-6-astra",1561    background=True,1562    store=False,1563    input="Analyze this large log bundle and cluster the primary failure modes.",1564    tools=[1565        {1566            "type": "code_interpreter",1567            "container": {1568                "type": "auto",1569                "file_ids": [log_bundle_file_id],1570            },1571        }1572    ],1573)15741575while job.status in {"queued", "in_progress"}:1576    time.sleep(2)1577    job = client.responses.retrieve(job.id)15781579print(job.output_text)1580```15811582```go1583package main15841585import (1586	"context"1587	"fmt"1588	"time"15891590	"github.com/openai/openai-go/v3"1591	"github.com/openai/openai-go/v3/responses"1592)15931594func main() {1595	client := openai.NewClient()1596	tool := responses.ToolParamOfCodeInterpreter(responses.ToolCodeInterpreterContainerCodeInterpreterContainerAutoParam{1597		FileIDs: []string{"file_abc123"},1598	})1599	job, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1600		Model:      "gpt-6-astra",1601		Background: openai.Bool(true),1602		Store:      openai.Bool(false),1603		Input:      responses.ResponseNewParamsInputUnion{OfString: openai.String("Analyze this large log bundle and cluster the primary failure modes.")},1604		Tools:      []responses.ToolUnionParam{tool},1605	})1606	if err != nil {1607		panic(err)1608	}1609	for job.Status == responses.ResponseStatusQueued || job.Status == responses.ResponseStatusInProgress {1610		time.Sleep(2 * time.Second)1611		job, err = client.Responses.Get(context.Background(), job.ID, responses.ResponseGetParams{})1612		if err != nil {1613			panic(err)1614		}1615	}1616	fmt.Println(job.OutputText())1617}1618```16191620```java1621import com.openai.client.OpenAIClient;1622import com.openai.client.okhttp.OpenAIOkHttpClient;1623import com.openai.models.responses.ResponseCreateParams;1624import com.openai.models.responses.ResponseStatus;1625import com.openai.models.responses.Tool;16261627String fileId = "file_abc123";16281629ResponseCreateParams params =1630    ResponseCreateParams.builder()1631        .model("gpt-6-astra")1632        .input("Analyze this large log bundle and cluster the primary failure modes.")1633        .background(true)1634        .store(false)1635        .addCodeInterpreterTool(1636            Tool.CodeInterpreter.Container.CodeInterpreterToolAuto.builder()1637                .addFileId(fileId)1638                .build())1639        .build();16401641var response = client.responses().create(params);1642while (response.status().filter(ResponseStatus.QUEUED::equals).isPresent()1643    || response.status().filter(ResponseStatus.IN_PROGRESS::equals).isPresent()) {1644  Thread.sleep(1000);1645  response = client.responses().retrieve(response.id());1646}1647if (response.status().filter(ResponseStatus.COMPLETED::equals).isEmpty()) {1648  throw new IllegalStateException(1649      "Research ended with status: " + response.status().orElseThrow());1650}16511652response.output().stream()1653    .flatMap(item -> item.message().stream())1654    .flatMap(message -> message.content().stream())1655    .flatMap(content -> content.outputText().stream())1656    .forEach(text -> System.out.println(text.text()));1657```16581659```ruby1660require "openai"16611662client = OpenAI::Client.new16631664job = client.responses.create(1665  model: "gpt-6-astra",1666  background: true,1667  store: false,1668  input: "Analyze this large log bundle and cluster the primary failure modes.",1669  tools: [1670    {1671      type: :code_interpreter,1672      container: {1673        type: :auto,1674        file_ids: ["file_abc123"]1675      }1676    }1677  ]1678)16791680while [:queued, :in_progress].include?(job.status)1681  sleep(2)1682  job = client.responses.retrieve(job.id)1683end16841685puts(job.output_text)1686```168716881689You can combine it with `stream=True` for progress events, but the first event1690may take longer than a normal request.16911692From the UI perspective, background mode indicates, "This is running; here is1693the status; the result will appear here when it's ready."16941695## Use WebSocket mode16961697[WebSocket mode](https://developers.openai.com/api/docs/guides/websocket-mode) is built for long-running,1698tool-call-heavy workflows where you keep a persistent connection open and1699continue by sending only new input items plus `previous_response_id`. For1700runs with 20 or more tool calls, this approach is roughly 40% faster1701end-to-end.17021703**How this works**: The first message will look like a normal Responses request:1704model, instructions, tools, and user input. The server streams events back. If1705the model asks for a tool, your app runs the tool. Then, instead of sending a new1706HTTP request, you send another `response.create` event on the same socket with1707the prior `previous_response_id` and the new item. That is where the latency win1708comes from. In plain HTTP, every follow-up is a fresh request. In WebSocket mode,1709the connection stays open and the most recent response state stays warm in1710memory on that connection. When the next turn continues from that response, the1711backend has to do less setup work.17121713If your workflow is one request, one answer, then **keep HTTP**. If your1714workflow behaves like a long-running agent, try WebSocket mode.17151716A single WebSocket connection handles one in-flight response at a time, so1717parallel work needs multiple connections. Connections currently top out at 601718minutes. Continuation uses the same `previous_response_id` semantics as HTTP1719mode, with a connection-local cache for the most recent response.17201721Note: WebSocket mode works with ZDR because your data is not stored to disk,1722only stored in memory.17231724The Python sample uses `pip install "openai[realtime]>=3.8.0"`.1725The JavaScript sample uses `npm install openai@^7.10.0 ws`.1726The Ruby sample uses `gem install openai async-websocket`.17271728Start a Responses API WebSocket session17291730```javascript1731import OpenAI from "openai";1732import { ResponsesWS } from "openai/resources/responses/ws";17331734const openai = new OpenAI();17351736const ws = new ResponsesWS(openai);17371738ws.on("event", (event) => {1739  console.log(event.type);1740  if (1741    event.type === "response.completed" ||1742    event.type === "response.failed" ||1743    event.type === "response.incomplete"1744  ) {1745    ws.close();1746  }1747});1748ws.on("error", (error) => {1749  console.error(error);1750  ws.close();1751});17521753ws.send({1754  type: "response.create",1755  model: "gpt-6-astra",1756  store: false,1757  input: [1758    {1759      type: "message",1760      role: "user",1761      content: [1762        {1763          type: "input_text",1764          text:1765            "Find the flaky test in this run, call the tools you need, " +1766            "and keep going until you can explain the root cause.",1767        },1768      ],1769    },1770  ],1771  tools: [testLogTool, codeSearchTool],1772});1773```17741775```python1776from openai import OpenAI17771778client = OpenAI()17791780with client.responses.connect() as connection:1781    # Use the same typed parameters as client.responses.create(...).1782    connection.response.create(1783        model="gpt-6-astra",1784        store=False,1785        input=[1786            {1787                "type": "message",1788                "role": "user",1789                "content": [1790                    {1791                        "type": "input_text",1792                        "text": (1793                            "Find the flaky test in this run, call the tools "1794                            "you need, and keep going until you can explain "1795                            "the root cause."1796                        ),1797                    }1798                ],1799            }1800        ],1801        tools=[test_log_tool, code_search_tool],1802    )1803    first_event = connection.recv()1804    print(first_event.type)1805```18061807```ruby1808require "async"1809require "openai"1810require "json"18111812def wait_for_response(connection)1813  while (event = connection.receive)1814    case event.type.to_s1815    when "response.completed" then return event.response1816    when "response.failed", "response.incomplete", "error"1817      raise "Response failed: #{event.to_json}"1818    end1819  end1820  raise "Connection closed before the response finished"1821end18221823test_log_tool = {1824  type: "function",1825  name: "search_test_logs",1826  description: "Search test logs.",1827  parameters: {1828    type: "object",1829    properties: { query: { type: "string" } },1830    required: ["query"],1831    additionalProperties: false1832  },1833  strict: true1834}1835code_search_tool = {1836  type: "function",1837  name: "search_code",1838  description: "Search source code.",1839  parameters: {1840    type: "object",1841    properties: { query: { type: "string" } },1842    required: ["query"],1843    additionalProperties: false1844  },1845  strict: true1846}18471848client = OpenAI::Client.new1849Sync do |task|1850  task.with_timeout(120) do1851    client.responses.connect(request_options: { timeout: 10 }) do |connection|1852      connection.response.create(1853        stream_id: "main", model: "gpt-6-astra", store: false,1854        input: [1855          {1856            role: "user",1857            content: "Find the flaky test in this run, call the tools you need, and keep going until you can explain the root cause."1858          }1859        ],1860        tools: [test_log_tool, code_search_tool]1861      )1862      puts(JSON.pretty_generate(wait_for_response(connection).output.map(&:to_h)))1863    end1864  end1865end1866```186718681869## Final takeaway18701871Responses API is the foundation for building smarter, more capable OpenAI1872applications. The real advantage is that it lets developers move from one-off1873prompts to durable, tool-using, context-aware workflows that can adapt to the1874complexity of the task. Follow this guide to see higher performance in real1875deployments.
Files main
Menu

Theme