Codex CLI drops id and status fields from assistant messages when using Responses API, breaking multi-turn conversations
What version of Codex CLI is running?
codex-cli 0.104.0 (also reproduced on 0.88.0)
What subscription do you have?
N/A (custom model provider via OpenAI-compatible Responses API)
Which model were you using?
Reproduced with vLLM-backed models on OpenAI-compatible Responses API endpoints
What platform is your computer?
Darwin 24.6.0 arm64 arm
What terminal emulator and version are you using (if applicable)?
ghostty 1.2.3
What issue are you seeing?
When Codex CLI is used against an OpenAI-compatible Responses API server (for example vLLM), multi-turn conversations fail because assistant messages are replayed into the next turn without id and status.
For assistant messages with output_text content, strict validators (for example Pydantic with OpenAI SDK response types) expect a ResponseOutputMessageParam shape that includes required fields such as id and status. Missing these fields causes large validation failures (for example many Input should be a valid string union-matching errors).
Observed behavior:
{
"type": "message",
"role": "assistant",
"content": [
{ "type": "output_text", "text": "Hi!" }
]
}
This breaks strict multi-turn parsing on compatible servers.
What steps can reproduce the bug?
- Configure Codex CLI with a custom provider:
# ~/.codex/config.toml
model = "<your-model>"
model_provider = "custom"
[model_providers.custom]
base_url = "http://your-vllm-server/v1"
env_key = "API_KEY"
- Start a conversation (first turn succeeds).
- Send a second turn.
- The request fails with validation errors on strict servers (for example:
502 Bad Gateway: 178 validation errors and repeated Input should be a valid string).
Minimal local repro (no server needed):
from pydantic import BaseModel
from openai.types.responses import ResponseInputItemParam, ResponseOutputItem
from typing import TypeAlias
ResponseInputOutputItem: TypeAlias = ResponseInputItemParam | ResponseOutputItem
class TestRequest(BaseModel):
input: str | list[ResponseInputOutputItem]
# Codex-like payload (fails)
TestRequest(input=[
{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "hello"}]},
{"type": "message", "role": "assistant", "content": [{"type": "output_text", "text": "Hi!"}]},
{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "what?"}]}
])
# Payload with id/status preserved (succeeds)
TestRequest(input=[
{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "hello"}]},
{"type": "message", "role": "assistant", "id": "msg_001", "status": "completed", "content": [{"type": "output_text", "text": "Hi!"}]},
{"type": "message", "role": "user", "content": [{"type": "input_text", "text": "what?"}]}
])
What is the expected behavior?
Codex CLI should preserve id and status from assistant response messages when constructing subsequent turns' input arrays.
Expected assistant item shape:
{
"type": "message",
"role": "assistant",
"id": "msg_example123",
"status": "completed",
"content": [
{ "type": "output_text", "text": "Hi!" }
]
}
Additional information
- Server versions observed: vLLM 0.14.1 (also reported on 0.15.0 / 0.15.1)
- OpenAI Python SDK: >= 1.99.1
- Related reports:
- https://github.com/openai/codex/issues/3841
- https://github.com/vllm-project/vllm/issues/33089
- Possibly related/overlapping Codex issue: https://github.com/openai/codex/issues/12230
8 Comments
Can you say more about your use case? Which responses API are you using? It sounds like it may be making wrong assumptions.
@etraut-openai Hi, as I mentioned already, the LLM API Server was self-hosted with vLLM. ("Reproduced with vLLM-backed models on OpenAI-compatible Responses API endpoints")
I think https://github.com/openai/codex/issues/12230 also have the same issue with the same situation.
Also, the self-hosted vLLM API Server returns with preserving 'id', and 'status' when I directly called to the vLLM API Server.
In the multi-turn conversation scenario, codex cli drop the fields from the previous turn's output when it flows to the next turn's input.
<img width="702" height="278" alt="Image" src="https://github.com/user-attachments/assets/4acf1c9d-6869-4e52-a1c7-6877ef12cb2b" />
Ah, thanks for the clarification. I'm not familiar with vLLM. I recommend reporting this issue to the maintainers of that project. You can also try switching to ollama or LMStudio, which have responses API endpoints that work fine with Codex.
It's not vllm's fault. codex sending requests to backend didn't follow the /v1/responses API spec defined by openai. https://developers.openai.com/api/reference/resources/responses/methods/create
The API spec here clearly say that id and status fields are required.
As @zhuangqh mentioned, it is from Codex. Codex didn't followed the OpenAI Responses API Schema. @etraut-openai
vLLM just did the validation check following OpenAI Responses API Schema.
In support of this comment please note that simply making the offending fields optional in https://github.com/openai/openai-python "solves" the issue. vllm just depends on that official openai python library and uses its type definitions (coming directly from openai) for validation.
I put together a fix for this here:
https://github.com/openai/codex/compare/main...JaysonGeng:codex:fix/preserve-responses-message-metadata
Root cause:
store=trueHTTP requests.response.createrequests were still dropping assistant message metadata.idandstatus.What changed:
response.createbodiesstatus: "completed"for replayed assistant messages so they remain valid output-item inputs on full-create requestsValidation:
cargo test -p codex-api openai_preserves_assistant_message_id_and_status_in_request_body -- --exactCARGO_INCREMENTAL=0 cargo test -p codex-core responses_websocket_v2_creates_without_previous_response_id_when_non_input_fields_change -- --exactjust fmtCARGO_INCREMENTAL=0 just fix -p codex-apiCARGO_INCREMENTAL=0 just fix -p codex-coregit diff --checkNote:
just argument-comment-lintstill isn’t runnable in this environment becausebazelis not installed.Upstream PRs are still invitation-only from my account, so I pushed this to my fork and can open a PR immediately if an OpenAI maintainer sends an invite or prefers a different handoff.
This bug is the reason I am still using Claude Code. This bug prevents Codex from working with providers that correctly implement the responses API spec. Please fix Codex so it aligns with the official responses API spec.