openai-codex-sdk: FileChangeItem.status Literal rejects 'in_progress' from streaming patch updates

Open 💬 1 comment Opened Apr 14, 2026 by DRCmod

Summary

openai-codex-sdk==0.1.11 crashes when consuming the streamed event loop on any agent-mode run that uses the patch/edit tool on a non-trivial file. The Codex CLI emits FileChangeItem payloads with status=\"in_progress\" while a patch is being applied, but the SDK's Pydantic model only allows \"completed\" or \"failed\". Pydantic raises ValidationError inside the async iterator, terminating the stream before any file changes reach the caller.

Version / environment

  • openai-codex-sdk==0.1.11
  • Python 3.12, Linux (WSL2)
  • pydantic 2.x

Repro

Any agent-mode call where the model edits a file. Minimal pseudo-repro:

from openai_codex_sdk import Codex
codex = Codex()
thread = codex.start_thread({\"model\": \"gpt-5.4\", \"sandbox_mode\": \"workspace-write\", \"working_directory\": \"/tmp/scratch\"})
streamed = await thread.run_streamed(\"Create hello.py with print('hi')\")
async for event in streamed.events:   # raises ValidationError on first patch update
    ...

Error

1 validation error for FileChangeItem
status
  Input should be 'completed' or 'failed' [type=literal_error, input_value='in_progress', input_type=str]
    For further information visit https://errors.pydantic.dev/2.13/v/literal_error

Root cause

openai_codex_sdk/types.py:

# line 108
PatchApplyStatus = Literal[\"completed\", \"failed\"]

# line 111
class FileChangeItem(BaseModel):
    ...
    status: PatchApplyStatus  # line 117

CommandExecutionStatus already includes intermediate states; PatchApplyStatus is the outlier.

Suggested fix

PatchApplyStatus = Literal[\"in_progress\", \"completed\", \"failed\"]

(Or whatever the canonical set of states the CLI emits for apply_patch updates is — happy to PR if the maintainers confirm the desired set.)

Workaround

Monkey-patch and rebuild the model before opening a thread:

from typing import Literal
from openai_codex_sdk import types as _t
_t.PatchApplyStatus = Literal[\"in_progress\", \"completed\", \"failed\"]
_t.FileChangeItem.model_fields[\"status\"].annotation = _t.PatchApplyStatus
_t.FileChangeItem.model_rebuild(force=True)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗