Preserve reasoning across calls
Conversation state and reasoning state serve different purposes. Passing messages across calls gives the model the visible conversation history. On supported models, persisted reasoning also lets the model render compatible reasoning items from earlier turns into its next context.
Persisted reasoning provides continuity; it does not expose the model's raw reasoning. The reasoning items remain opaque, and the API does not return their reasoning text. Set reasoning.context to control which available reasoning items the model can use:
The GPT-5.6 model family supports all_turns and uses it by default. Earlier models default to current_turn. Omit reasoning.context or set it to auto to use the selected model's default.
| Value | Behavior |
|---|---|
auto | Uses the selected model's default. Omitting reasoning.context has the same effect as auto. |
current_turn | Makes reasoning from the active turn available, but does not render reasoning from earlier turns into the next sample. |
all_turns | Renders available, compatible reasoning items from earlier turns into the next sample. GPT-5.6 models support this value. |
The response's reasoning.context field contains the effective mode, either current_turn or all_turns. Check this field on each response to confirm which mode the model used. The setting does not create reasoning items that are not already available.
all_turns has an effect only when the request has access to earlier response items. Use previous_response_id, attach the response to a conversation, or manually replay the complete response history. On the first request, current_turn and all_turns behave the same because no earlier reasoning exists.
Persisted reasoning can be reused only within the same model family. For example, gpt-5.6-sol, gpt-5.6-terra, and gpt-5.6-luna can reuse each other's reasoning, but reasoning does not carry between the GPT-5.6 and GPT-5.5 families.
When you switch model families, the API omits incompatible reasoning from the model's context, even when reasoning.context is all_turns.
Continue reasoning with stored responses
Use previous_response_id for the shortest stateful integration:
Preserve reasoning with a previous response
import OpenAI from "openai";
const client = new OpenAI();
const first = await client.responses.create({
model: "gpt-5.6",
input: "Inspect this repository and identify the likely bug.",
reasoning: { context: "current_turn" },
});
const second = await client.responses.create({
model: "gpt-5.6",
previous_response_id: first.id,
input: "Now patch the bug and explain the change.",
reasoning: { context: "all_turns" },
});
console.log(second.output_text);from openai import OpenAI
client = OpenAI()
model = "gpt-5.6"
first = client.responses.create(
model=model,
input="Inspect this repository and identify the likely bug.",
reasoning={"context": "current_turn"},
)
second = client.responses.create(
model=model,
previous_response_id=first.id,
input="Now patch the bug and explain the change.",
reasoning={"context": "all_turns"},
)
print(second.output_text)package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
model := "gpt-5.6"
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: model,
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Inspect this repository and identify the likely bug."),
},
Reasoning: responses.ReasoningParam{
Context: responses.ReasoningContextCurrentTurn,
},
})
if err != nil {
panic(err)
}
second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: model,
PreviousResponseID: openai.String(first.ID),
Input: responses.ResponseNewParamsInputUnion{
OfString: openai.String("Now patch the bug and explain the change."),
},
Reasoning: responses.ReasoningParam{
Context: responses.ReasoningContextAllTurns,
},
})
if err != nil {
panic(err)
}
fmt.Println(second.OutputText())
}import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.responses.ResponseCreateParams;
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-5.6")
.input("Inspect this repository and identify the likely bug.")
.reasoning(
Reasoning.builder()
.putAdditionalProperty("context", JsonValue.from("current_turn"))
.build())
.build());
var second =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-5.6")
.input("Now patch the bug and explain the change.")
.previousResponseId(first.id())
.reasoning(
Reasoning.builder()
.putAdditionalProperty("context", JsonValue.from("all_turns"))
.build())
.build());
second.output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));require "openai"
client = OpenAI::Client.new
first = client.responses.create(
model: "gpt-5.6",
input: "Inspect this repository and identify the likely bug.",
reasoning: {context: :current_turn}
)
second = client.responses.create(
model: "gpt-5.6",
previous_response_id: first.id,
input: "Now patch the bug and explain the change.",
reasoning: {context: :all_turns}
)
puts(second.output_text)Use current_turn when replaying older response items that the model no longer needs. Those reasoning items can remain in the API payload for continuity, but the service does not render them into the new sample. This can reduce the rendered context for long-running workflows.
Preserve reasoning without stored responses
When you create a response in stateless mode, reasoning items in the response's output array include an encrypted_content property by default. Stateless mode applies when store is false or when your organization uses Zero Data Retention (ZDR). The API still accepts the legacy reasoning.encrypted_content value in include for compatibility, but doesn't require it.
The following request returns encrypted reasoning content without specifying include:
curl https://api.openai.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"store": false,
"reasoning": {"effort": "medium"},
"input": "What is the weather like today?",
"tools": [ ... function config here ... ]
}'Reasoning items in the output array will include an encrypted_content property containing encrypted reasoning tokens that you can pass to future calls.
To use all_turns with store: false, preserve every output item, append the next user message, and replay the complete history:
Preserve reasoning without storing responses
import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const client = new OpenAI();
/** @type {OpenAI.Responses.ResponseInput} */
const history = [
{
role: "user",
content: "Inspect this repository and identify the likely bug.",
},
];
const first = await client.responses.create({
model: "gpt-5.6",
store: false,
input: history,
reasoning: { context: "current_turn" },
});
// Keep replayable output, including encrypted reasoning and assistant phase.
history.push(...toResponseInputItems(first.output));
history.push({
role: "user",
content: "Now patch the bug and explain the change.",
});
const second = await client.responses.create({
model: "gpt-5.6",
store: false,
input: history,
reasoning: { context: "all_turns" },
});
console.log(second.output_text);from openai import OpenAI
client = OpenAI()
model = "gpt-5.6"
history = [
{
"role": "user",
"content": "Inspect this repository and identify the likely bug.",
}
]
first = client.responses.create(
model=model,
store=False,
input=history,
reasoning={"context": "current_turn"},
)
# Keep every output item, including encrypted reasoning and assistant phase.
history.extend(item.model_dump() for item in first.output)
history.append(
{
"role": "user",
"content": "Now patch the bug and explain the change.",
}
)
second = client.responses.create(
model=model,
store=False,
input=history,
reasoning={"context": "all_turns"},
)
print(second.output_text)package main
import (
"context"
"encoding/json"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
"github.com/openai/openai-go/v3/shared"
)
func main() {
client := openai.NewClient()
history := []responses.ResponseInputItemUnionParam{
responses.ResponseInputItemParamOfMessage("Inspect this repository and identify the likely bug.", responses.EasyInputMessageRoleUser),
}
first, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: history},
Reasoning: shared.ReasoningParam{Context: shared.ReasoningContextCurrentTurn},
})
if err != nil {
panic(err)
}
history = append(history, outputAsInput(first.Output)...)
history = append(history, responses.ResponseInputItemParamOfMessage(
"Now patch the bug and explain the change.",
responses.EasyInputMessageRoleUser,
))
second, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.6",
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: history},
Reasoning: shared.ReasoningParam{Context: shared.ReasoningContextAllTurns},
})
if err != nil {
panic(err)
}
fmt.Println(second.OutputText())
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return input
}import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.Reasoning;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.ArrayList;
var history = new ArrayList<ResponseInputItem>();
history.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Inspect this repository and identify the likely bug.")
.build()));
var first =
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-5.6")
.inputOfResponse(history)
.store(false)
.reasoning(
Reasoning.builder()
.putAdditionalProperty("context", JsonValue.from("current_turn"))
.build())
.build());
first.output().stream()
.map(item -> JsonValue.from(item).convert(ResponseInputItem.class))
.forEach(history::add);
history.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Now patch the bug and explain the change.")
.build()));
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-5.6")
.inputOfResponse(history)
.store(false)
.reasoning(
Reasoning.builder()
.putAdditionalProperty("context", JsonValue.from("all_turns"))
.build())
.build())
.output()
.stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));require "openai"
client = OpenAI::Client.new
history = [
{role: :user, content: "Inspect this repository and identify the likely bug."}
]
first = client.responses.create(
model: "gpt-5.6",
store: false,
input: history,
reasoning: {context: :current_turn}
)
history.concat(first.output)
history << {role: :user, content: "Now patch the bug and explain the change."}
second = client.responses.create(
model: "gpt-5.6",
store: false,
input: history,
reasoning: {context: :all_turns}
)
puts(second.output_text)Keeping reasoning items in context
When doing function calling with a reasoning model in the Responses API, we highly recommend you pass back any reasoning items returned with the last function call (in addition to the output of your function). If the model calls multiple functions consecutively, you should pass back all reasoning items, function call items, and function call output items, since the last user message. This allows the model to continue its reasoning process to produce better results in the most token-efficient manner.
The simplest way to do this is to pass in all reasoning items from a previous response into the next one. Our systems will smartly ignore any reasoning items that aren't relevant to your functions, and only retain those in context that are relevant. You can pass reasoning items from previous responses either using the previous_response_id parameter, or by manually passing in all the output items from a past response into the input of a new one.
For advanced use cases where you might be truncating and optimizing parts of the context window before passing them on to the next response, just ensure all items between the last user message and your function call output are passed into the next response untouched. This will ensure that the model has all the context it needs.
Check out this guide to learn more about manual context management.