Files
codex/sdk/python/docs/faq.md
Shaqayeq 0769ed5b5d python-sdk: clarify initialize metadata and async entrypoint (2026-03-16)
Normalize validated initialize metadata back onto InitializeResponse so successful metadata access exposes populated serverInfo fields even when they were derived from userAgent.

Also make async lifecycle guidance explicit in the public surface by documenting async with AsyncCodex() as the preferred entrypoint and aligning the AsyncCodex metadata error message with that model.

Co-authored-by: Codex <noreply@openai.com>
2026-03-16 15:10:12 -07:00

3.3 KiB

FAQ

Thread vs turn

  • A Thread is conversation state.
  • A Turn is one model execution inside that thread.
  • Multi-turn chat means multiple turns on the same Thread.

run() vs stream()

  • TurnHandle.run() / AsyncTurnHandle.run() is the easiest path. It consumes events until completion and returns the canonical generated app-server Turn model.
  • TurnHandle.stream() / AsyncTurnHandle.stream() yields raw notifications (Notification) so you can react event-by-event.

Choose run() for most apps. Choose stream() for progress UIs, custom timeout logic, or custom parsing.

Sync vs async clients

  • Codex is the sync public API.
  • AsyncCodex is an async replica of the same public API shape.
  • Prefer async with AsyncCodex() for async code. It is the standard path for explicit startup/shutdown, and AsyncCodex initializes lazily on context entry or first awaited API use.

If your app is not already async, stay with Codex.

Public kwargs are snake_case

Public API keyword names are snake_case. The SDK still maps them to wire camelCase under the hood.

If you are migrating older code, update these names:

  • approvalPolicy -> approval_policy
  • baseInstructions -> base_instructions
  • developerInstructions -> developer_instructions
  • modelProvider -> model_provider
  • modelProviders -> model_providers
  • sortKey -> sort_key
  • sourceKinds -> source_kinds
  • outputSchema -> output_schema
  • sandboxPolicy -> sandbox_policy

Why only thread_start(...) and thread_resume(...)?

The public API keeps only explicit lifecycle calls:

  • thread_start(...) to create new threads
  • thread_resume(thread_id, ...) to continue existing threads

This avoids duplicate ways to do the same operation and keeps behavior explicit.

Why does constructor fail?

Codex() is eager: it starts transport and calls initialize in __init__.

Common causes:

  • published runtime package (codex-cli-bin) is not installed
  • local codex_bin override points to a missing file
  • local auth/session is missing
  • incompatible/old app-server

Maintainers stage releases by building the SDK once and the runtime once per platform with the same pinned runtime version. Publish codex-cli-bin as platform wheels only; do not publish an sdist:

cd sdk/python
python scripts/update_sdk_artifacts.py generate-types
python scripts/update_sdk_artifacts.py \
  stage-sdk \
  /tmp/codex-python-release/codex-app-server-sdk \
  --runtime-version 1.2.3
python scripts/update_sdk_artifacts.py \
  stage-runtime \
  /tmp/codex-python-release/codex-cli-bin \
  /path/to/codex \
  --runtime-version 1.2.3

Why does a turn "hang"?

A turn is complete only when turn/completed arrives for that turn ID.

  • run() waits for this automatically.
  • With stream(), keep consuming notifications until completion.

How do I retry safely?

Use retry_on_overload(...) for transient overload failures (ServerBusyError).

Do not blindly retry all errors. For InvalidParamsError or MethodNotFoundError, fix inputs/version compatibility instead.

Common pitfalls

  • Starting a new thread for every prompt when you wanted continuity.
  • Forgetting to close() (or not using context managers).
  • Assuming run() returns extra SDK-only fields instead of the generated Turn model.
  • Mixing SDK input classes with raw dicts incorrectly.