codex-sdk-python 0.104.0__tar.gz → 0.105.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/PKG-INFO +108 -23
  2. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/README.md +107 -22
  3. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/pyproject.toml +2 -2
  4. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/__init__.py +1 -1
  5. codex_sdk_python-0.105.0/src/codex_sdk/integrations/pydantic_ai_model.py +1228 -0
  6. codex_sdk_python-0.104.0/src/codex_sdk/integrations/pydantic_ai_model.py +0 -655
  7. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/abort.py +0 -0
  8. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/app_server.py +0 -0
  9. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/codex.py +0 -0
  10. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/config_overrides.py +0 -0
  11. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/events.py +0 -0
  12. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/exceptions.py +0 -0
  13. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/exec.py +0 -0
  14. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/hooks.py +0 -0
  15. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/integrations/__init__.py +0 -0
  16. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/integrations/pydantic_ai.py +0 -0
  17. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/items.py +0 -0
  18. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/options.py +0 -0
  19. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/telemetry.py +0 -0
  20. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/thread.py +0 -0
  21. {codex_sdk_python-0.104.0 → codex_sdk_python-0.105.0}/src/codex_sdk/tool_envelope.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: codex-sdk-python
3
- Version: 0.104.0
3
+ Version: 0.105.0
4
4
  Summary: Python SDK for the Codex CLI agent with async threads, streaming events, and structured outputs
5
5
  Keywords: codex,sdk,python,api,cli,agent,async,streaming
6
6
  Author: Vectorfy Co
@@ -44,7 +44,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
44
44
  <td><strong>Lifecycle</strong></td>
45
45
  <td>
46
46
  <a href="#ci-cd"><img src="https://img.shields.io/badge/CI%2FCD-Active-16a34a?style=flat&logo=githubactions&logoColor=white" alt="CI/CD badge" /></a>
47
- <img src="https://img.shields.io/badge/Release-0.104.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.104.0 badge" />
47
+ <img src="https://img.shields.io/badge/Release-0.105.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.105.0 badge" />
48
48
  <a href="#license"><img src="https://img.shields.io/badge/License-Apache--2.0-0f766e?style=flat&logo=apache&logoColor=white" alt="License badge" /></a>
49
49
  </td>
50
50
  </tr>
@@ -73,7 +73,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
73
73
  </div>
74
74
 
75
75
  - Runtime dependency-free: uses only the Python standard library.
76
- - Codex CLI binaries are downloaded separately; use `scripts/setup_binary.py` from the repo or install the Codex CLI and set `codex_path_override`.
76
+ - Codex CLI binaries can be sourced either from the vendored `src/codex_sdk/vendor/` tree (when present) or from a system-installed `codex` binary (`codex_path_override` supported).
77
77
  - Async-first API with sync helpers, streaming events, and structured output.
78
78
  - Python 3.8/3.9 support is deprecated and will be removed in a future release; use Python 3.10+.
79
79
 
@@ -168,6 +168,8 @@ python examples/app_server_turn_session.py
168
168
  python examples/config_overrides.py
169
169
  python examples/hooks_streaming.py
170
170
  python examples/notify_hook.py
171
+ python examples/pydantic_ai_run_compat.py
172
+ python examples/pydantic_ai_run_stream_compat.py
171
173
  ```
172
174
 
173
175
  <a id="features"></a>
@@ -185,6 +187,15 @@ python examples/notify_hook.py
185
187
  | ![Abort](https://img.shields.io/badge/Abort-Signals-ef4444?style=flat&logo=gnubash&logoColor=white) | Cancel running turns via `AbortController` and `AbortSignal`. |
186
188
  | ![Telemetry](https://img.shields.io/badge/Telemetry-Logfire%20Spans-f97316?style=flat&logo=simpleicons&logoColor=white) | Optional spans if Logfire is installed and initialized. |
187
189
 
190
+ ### Execution surfaces and transports
191
+
192
+ | Surface | Primary transport | Typical use |
193
+ | ------- | ----------------- | ----------- |
194
+ | `Codex` + `Thread` | `codex exec --experimental-json` (JSONL over stdio) | Conversational turns, streaming item events, structured output (`run_json` / `run_pydantic`). |
195
+ | `AppServerClient` | `codex app-server` (JSON-RPC over stdio) | Full app-server protocol: thread management, turn sessions, approvals, account/config/skills APIs. |
196
+ | `CodexModel` (PydanticAI provider) | `codex app-server` (JSON-RPC over stdio) | Tool-call planning + text generation through app-server turn sessions with incremental stream events. |
197
+ | `codex_handoff_tool` (PydanticAI tool) | `Thread.run(...)` on top of `codex exec` | Delegate repository-aware tasks from another model to Codex. |
198
+
188
199
  <a id="configuration"></a>
189
200
  ## ![Configuration](https://img.shields.io/badge/Configuration-Options%20%26%20Env-0ea5e9?style=for-the-badge&logo=json&logoColor=white)
190
201
 
@@ -312,6 +323,10 @@ For richer integrations (thread fork, requirements, explicit skill input), use t
312
323
  protocol. The client handles the initialize/initialized handshake and gives you access to
313
324
  JSON-RPC notifications.
314
325
 
326
+ `AppServerClient` starts `codex app-server` and multiplexes notifications + server-initiated
327
+ requests (for example approval requests in `turn_session(...)`) on top of the same stdio
328
+ connection.
329
+
315
330
  ```python
316
331
  import asyncio
317
332
  from codex_sdk import AppServerClient, AppServerOptions
@@ -427,6 +442,11 @@ If you are working from source and the vendor directory is missing, run
427
442
  `python scripts/setup_binary.py` to fetch and assemble the platform `@openai/codex`
428
443
  artifacts into `src/codex_sdk/vendor/`.
429
444
 
445
+ `scripts/setup_binary.py` behavior:
446
+ - Resolves `CODEX_NPM_VERSION` when set; otherwise resolves latest `@openai/codex`.
447
+ - Tries legacy `@openai/codex-sdk` package first, then falls back to per-target `@openai/codex@<version>-<suffix>` artifacts.
448
+ - Rebuilds `src/codex_sdk/vendor/` for all supported targets and validates current-platform binary presence.
449
+
430
450
  <a id="auth"></a>
431
451
  ## ![Auth](https://img.shields.io/badge/Auth%20%26%20Credentials-Access-2563eb?style=for-the-badge&logo=gnubash&logoColor=white)
432
452
 
@@ -633,6 +653,8 @@ Example scripts under `examples/`:
633
653
  - `notify_hook.py`: notify script for CLI callbacks.
634
654
  - `pydantic_ai_model_provider.py`: Codex as a PydanticAI model provider.
635
655
  - `pydantic_ai_handoff.py`: Codex as a PydanticAI tool.
656
+ - `pydantic_ai_run_compat.py`: minimal compatibility harness for `Agent.run(...)`.
657
+ - `pydantic_ai_run_stream_compat.py`: minimal compatibility harness for `Agent.run_stream(...)`.
636
658
 
637
659
  <a id="sandbox"></a>
638
660
  ## ![Sandbox](https://img.shields.io/badge/Sandbox-Permissions%20%26%20Safety-1f2937?style=for-the-badge&logo=gnubash&logoColor=white)
@@ -655,6 +677,9 @@ Additional controls:
655
677
 
656
678
  This SDK offers two ways to integrate with PydanticAI:
657
679
 
680
+ Note: starting in `0.105.0`, `CodexModel` is app-server-only and no longer supports
681
+ the legacy `CodexModel(codex=...)` fallback path.
682
+
658
683
  ### 1) Codex as a PydanticAI model provider
659
684
 
660
685
  Use `CodexModel` to delegate tool-call planning and text generation to Codex, while PydanticAI executes tools and validates outputs.
@@ -682,11 +707,20 @@ print(result.output)
682
707
  ```
683
708
 
684
709
  How it works:
710
+ - `CodexModel` keeps a persistent app-server session and starts/reuses threads based on
711
+ `thread_reuse_mode` (`"run"` by default, `"always"` optional).
685
712
  - `CodexModel` builds a JSON schema envelope with `tool_calls` and `final`.
686
713
  - Codex emits tool calls as JSON strings; PydanticAI runs them.
687
714
  - If `allow_text_output` is true, Codex can place final text in `final`.
688
- - Streaming APIs (`Agent.run_stream_events()`, `Agent.run_stream_sync()`) are supported; Codex
689
- emits streamed responses as a single chunk once the turn completes.
715
+ - Streaming APIs emit incremental events while app-server turn notifications arrive.
716
+
717
+ Provider options:
718
+ - `performance_profile`: `"balanced"` (default) or `"max"`.
719
+ - `thread_reuse_mode`: `"run"` (default) or `"always"`.
720
+
721
+ Lifecycle:
722
+ - `CodexModel` owns an app-server client by default; call `await model.close()` in
723
+ long-lived processes to release resources.
690
724
 
691
725
  Safety defaults (you can override with your own `ThreadOptions`):
692
726
  - `sandbox_mode="read-only"`
@@ -749,38 +783,49 @@ If `logfire` is installed and initialized, the SDK emits spans:
749
783
  If Logfire is missing or not initialized, the span context manager is a no-op.
750
784
 
751
785
  <a id="architecture"></a>
752
- <a id="acheature"></a>
753
786
  ## ![Architecture](https://img.shields.io/badge/Architecture-Stack%20map-1f2937?style=for-the-badge&logo=serverless&logoColor=white)
754
787
 
755
- ### System components
788
+ ### System components and transport paths
756
789
 
757
790
  ```mermaid
758
791
  flowchart LR
759
792
  subgraph App[Your Python App]
760
793
  U[User Code]
761
- T[Thread API]
794
+ T[Codex + Thread API]
795
+ A[AppServerClient API]
796
+ PM[PydanticAI CodexModel]
797
+ PH[PydanticAI codex_handoff_tool]
762
798
  end
763
799
 
764
800
  subgraph SDK[Codex SDK]
765
801
  C[Codex]
766
802
  E[CodexExec]
767
- P[Event Parser]
803
+ P[Thread Event Parser]
804
+ R[JSON-RPC Client]
768
805
  end
769
806
 
770
- subgraph CLI[Bundled Codex CLI]
807
+ subgraph CLI[Codex CLI]
771
808
  X["codex exec --experimental-json"]
809
+ S["codex app-server"]
772
810
  end
773
811
 
774
812
  FS[(Filesystem)]
775
813
  NET[(Network)]
776
814
 
777
815
  U --> T --> C --> E --> X
816
+ U --> A --> R --> S
817
+ U --> PM --> R
818
+ U --> PH --> C
778
819
  X -->|JSONL events| P --> T
820
+ S -->|JSON-RPC messages| R --> A
821
+ S -->|JSON-RPC messages| R --> PM
779
822
  X --> FS
780
823
  X --> NET
824
+ S --> FS
825
+ S --> NET
781
826
  ```
782
827
 
783
- ### Streaming event lifecycle
828
+ ### Thread API streaming lifecycle (`codex exec`)
784
829
 
785
830
  ```mermaid
786
831
  sequenceDiagram
@@ -803,21 +848,41 @@ sequenceDiagram
803
848
  Thread-->>Dev: turn.completed / turn.failed
804
849
  ```
805
850
 
806
- ### PydanticAI model-provider loop
851
+ ### App-server lifecycle (`codex app-server`)
852
+
853
+ ```mermaid
854
+ sequenceDiagram
855
+ participant Dev as Developer
856
+ participant App as AppServerClient
857
+ participant CLI as codex app-server
858
+
859
+ Dev->>App: start()
860
+ App->>CLI: spawn process
861
+ App->>CLI: initialize
862
+ CLI-->>App: initialize result
863
+ App->>CLI: initialized (notification)
864
+ Dev->>App: turn_session(thread_id, input)
865
+ App->>CLI: turn/start
866
+ CLI-->>App: thread/turn/item notifications
867
+ CLI-->>App: request (approval needed)
868
+ App-->>CLI: response (approve/reject)
869
+ CLI-->>App: turn completed notification
870
+ App-->>Dev: final turn payload
871
+ ```
872
+
873
+ ### PydanticAI model-provider loop (current implementation)
807
874
 
808
875
  ```mermaid
809
876
  sequenceDiagram
810
877
  participant Agent as PydanticAI Agent
811
878
  participant Model as CodexModel
812
- participant SDK as Codex SDK
813
- participant CLI as codex exec
879
+ participant App as Codex app-server
814
880
  participant Tools as User Tools
815
881
 
816
882
  Agent->>Model: request(messages, tools)
817
- Model->>SDK: start_thread + run_json(prompt, output_schema)
818
- SDK->>CLI: codex exec --output-schema
819
- CLI-->>SDK: JSON envelope {tool_calls, final}
820
- SDK-->>Model: ParsedTurn
883
+ Model->>App: thread/start (if needed)
884
+ Model->>App: turn/session(input + output_schema envelope)
885
+ App-->>Model: item/updated + turn/completed notifications
821
886
  alt tool_calls present
822
887
  Model-->>Agent: ToolCallPart(s)
823
888
  Agent->>Tools: execute tool(s)
@@ -833,12 +898,18 @@ sequenceDiagram
833
898
  flowchart LR
834
899
  Agent[PydanticAI Agent] --> Tool[codex_handoff_tool]
835
900
  Tool --> SDK[Codex SDK Thread]
836
- SDK --> CLI[Codex CLI]
901
+ SDK --> CLI[codex exec]
837
902
  CLI --> SDK
838
903
  SDK --> Tool
839
904
  Tool --> Agent
840
905
  ```
841
906
 
907
+ ### Streaming semantics summary
908
+
909
+ - `Thread.run_streamed()` and `Thread.run_streamed_events()` stream incremental `ThreadEvent` values as JSONL lines arrive from `codex exec`.
910
+ - `AppServerClient.notifications()` streams incremental JSON-RPC notifications from `codex app-server`.
911
+ - `CodexModel.request_stream(...)` emits incremental events from app-server turn notifications, with compatibility handling for current and legacy PydanticAI stream interfaces.
912
+
842
913
  <a id="testing"></a>
843
914
  ## ![Testing](https://img.shields.io/badge/Testing-Pytest%20%26%20Coverage-2563eb?style=for-the-badge&logo=pytest&logoColor=white)
844
915
 
@@ -847,9 +918,12 @@ This repo uses unit tests with mocked CLI processes to keep the test suite fast
847
918
  Test focus areas:
848
919
  - `tests/test_exec.py`: CLI invocation, environment handling, config flags, abort behavior.
849
920
  - `tests/test_thread.py`: parsing, streaming, JSON schema, Pydantic validation, input normalization.
921
+ - `tests/test_app_server.py` and `tests/test_app_server_session.py`: JSON-RPC lifecycle, method wrappers, turn-session approvals/notifications.
850
922
  - `tests/test_codex.py`: resume helpers and option wiring.
923
+ - `tests/test_config_overrides.py`: `--config` serialization and merge behavior.
851
924
  - `tests/test_abort.py`: abort signal semantics.
852
925
  - `tests/test_telemetry.py`: Logfire span behavior.
926
+ - `tests/test_tool_envelope.py`: tool envelope parsing and schema normalization helpers.
853
927
  - `tests/test_pydantic_ai_*`: PydanticAI model provider and handoff integration.
854
928
 
855
929
  ### Run tests
@@ -891,10 +965,21 @@ uv run mypy src
891
965
  ## ![CI/CD](https://img.shields.io/badge/CI%2FCD-Overview-1F4B99?style=for-the-badge&logo=gnubash&logoColor=white)
892
966
 
893
967
  This repository includes GitHub Actions workflows under `.github/workflows/`.
894
- The CI pipeline runs linting, type checks, and `pytest --cov=codex_sdk`.
895
- Release automation creates GitHub releases from `CHANGELOG_SDK.md` when you push a
896
- `vX.Y.Z` tag or manually dispatch the workflow, then the publish workflow uploads
897
- the package to PyPI on release publish.
968
+
969
+ Current workflows:
970
+ - `ci.yml`: lint (`black`, `isort`, `flake8`), type-check (`mypy`), and tests (`pytest --cov=codex_sdk`) on Python 3.10/3.11/3.12.
971
+ - `release.yml`: extracts release notes from `CHANGELOG_SDK.md` and creates a GitHub Release for `vX.Y.Z`.
972
+ - `publish.yml`: builds (`uv build --no-sources`) and publishes to PyPI on release publish (or successful release workflow).
973
+ - `docs-deploy.yml`: optional docs deployment (gated by `DOCS_DEPLOY_ENABLED`).
974
+ - `uv-lock-update.yml`: scheduled weekly lockfile refresh PR.
975
+
976
+ `ci.yml` test jobs install Node.js and run:
977
+
978
+ ```bash
979
+ python scripts/setup_binary.py
980
+ ```
981
+
982
+ before `pytest`, so test runs do not depend on committed vendor binary updates.
898
983
 
899
984
  <a id="operations"></a>
900
985
  ## ![Operations](https://img.shields.io/badge/Operations-Health%20%26%20Sessions-10b981?style=for-the-badge&logo=serverless&logoColor=white)
@@ -8,7 +8,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
8
8
  <td><strong>Lifecycle</strong></td>
9
9
  <td>
10
10
  <a href="#ci-cd"><img src="https://img.shields.io/badge/CI%2FCD-Active-16a34a?style=flat&logo=githubactions&logoColor=white" alt="CI/CD badge" /></a>
11
- <img src="https://img.shields.io/badge/Release-0.104.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.104.0 badge" />
11
+ <img src="https://img.shields.io/badge/Release-0.105.0-6b7280?style=flat&logo=pypi&logoColor=white" alt="Release 0.105.0 badge" />
12
12
  <a href="#license"><img src="https://img.shields.io/badge/License-Apache--2.0-0f766e?style=flat&logo=apache&logoColor=white" alt="License badge" /></a>
13
13
  </td>
14
14
  </tr>
@@ -37,7 +37,7 @@ Embed the Codex agent in Python workflows. This SDK wraps the bundled `codex` CL
37
37
  </div>
38
38
 
39
39
  - Runtime dependency-free: uses only the Python standard library.
40
- - Codex CLI binaries are downloaded separately; use `scripts/setup_binary.py` from the repo or install the Codex CLI and set `codex_path_override`.
40
+ - Codex CLI binaries can be sourced either from the vendored `src/codex_sdk/vendor/` tree (when present) or from a system-installed `codex` binary (`codex_path_override` supported).
41
41
  - Async-first API with sync helpers, streaming events, and structured output.
42
42
  - Python 3.8/3.9 support is deprecated and will be removed in a future release; use Python 3.10+.
43
43
 
@@ -132,6 +132,8 @@ python examples/app_server_turn_session.py
132
132
  python examples/config_overrides.py
133
133
  python examples/hooks_streaming.py
134
134
  python examples/notify_hook.py
135
+ python examples/pydantic_ai_run_compat.py
136
+ python examples/pydantic_ai_run_stream_compat.py
135
137
  ```
136
138
 
137
139
  <a id="features"></a>
@@ -149,6 +151,15 @@ python examples/notify_hook.py
149
151
  | ![Abort](https://img.shields.io/badge/Abort-Signals-ef4444?style=flat&logo=gnubash&logoColor=white) | Cancel running turns via `AbortController` and `AbortSignal`. |
150
152
  | ![Telemetry](https://img.shields.io/badge/Telemetry-Logfire%20Spans-f97316?style=flat&logo=simpleicons&logoColor=white) | Optional spans if Logfire is installed and initialized. |
151
153
 
154
+ ### Execution surfaces and transports
155
+
156
+ | Surface | Primary transport | Typical use |
157
+ | ------- | ----------------- | ----------- |
158
+ | `Codex` + `Thread` | `codex exec --experimental-json` (JSONL over stdio) | Conversational turns, streaming item events, structured output (`run_json` / `run_pydantic`). |
159
+ | `AppServerClient` | `codex app-server` (JSON-RPC over stdio) | Full app-server protocol: thread management, turn sessions, approvals, account/config/skills APIs. |
160
+ | `CodexModel` (PydanticAI provider) | `codex app-server` (JSON-RPC over stdio) | Tool-call planning + text generation through app-server turn sessions with incremental stream events. |
161
+ | `codex_handoff_tool` (PydanticAI tool) | `Thread.run(...)` on top of `codex exec` | Delegate repository-aware tasks from another model to Codex. |
162
+
152
163
  <a id="configuration"></a>
153
164
  ## ![Configuration](https://img.shields.io/badge/Configuration-Options%20%26%20Env-0ea5e9?style=for-the-badge&logo=json&logoColor=white)
154
165
 
@@ -276,6 +287,10 @@ For richer integrations (thread fork, requirements, explicit skill input), use t
276
287
  protocol. The client handles the initialize/initialized handshake and gives you access to
277
288
  JSON-RPC notifications.
278
289
 
290
+ `AppServerClient` starts `codex app-server` and multiplexes notifications + server-initiated
291
+ requests (for example approval requests in `turn_session(...)`) on top of the same stdio
292
+ connection.
293
+
279
294
  ```python
280
295
  import asyncio
281
296
  from codex_sdk import AppServerClient, AppServerOptions
@@ -391,6 +406,11 @@ If you are working from source and the vendor directory is missing, run
391
406
  `python scripts/setup_binary.py` to fetch and assemble the platform `@openai/codex`
392
407
  artifacts into `src/codex_sdk/vendor/`.
393
408
 
409
+ `scripts/setup_binary.py` behavior:
410
+ - Resolves `CODEX_NPM_VERSION` when set; otherwise resolves latest `@openai/codex`.
411
+ - Tries legacy `@openai/codex-sdk` package first, then falls back to per-target `@openai/codex@<version>-<suffix>` artifacts.
412
+ - Rebuilds `src/codex_sdk/vendor/` for all supported targets and validates current-platform binary presence.
413
+
394
414
  <a id="auth"></a>
395
415
  ## ![Auth](https://img.shields.io/badge/Auth%20%26%20Credentials-Access-2563eb?style=for-the-badge&logo=gnubash&logoColor=white)
396
416
 
@@ -597,6 +617,8 @@ Example scripts under `examples/`:
597
617
  - `notify_hook.py`: notify script for CLI callbacks.
598
618
  - `pydantic_ai_model_provider.py`: Codex as a PydanticAI model provider.
599
619
  - `pydantic_ai_handoff.py`: Codex as a PydanticAI tool.
620
+ - `pydantic_ai_run_compat.py`: minimal compatibility harness for `Agent.run(...)`.
621
+ - `pydantic_ai_run_stream_compat.py`: minimal compatibility harness for `Agent.run_stream(...)`.
600
622
 
601
623
  <a id="sandbox"></a>
602
624
  ## ![Sandbox](https://img.shields.io/badge/Sandbox-Permissions%20%26%20Safety-1f2937?style=for-the-badge&logo=gnubash&logoColor=white)
@@ -619,6 +641,9 @@ Additional controls:
619
641
 
620
642
  This SDK offers two ways to integrate with PydanticAI:
621
643
 
644
+ Note: starting in `0.105.0`, `CodexModel` is app-server-only and no longer supports
645
+ the legacy `CodexModel(codex=...)` fallback path.
646
+
622
647
  ### 1) Codex as a PydanticAI model provider
623
648
 
624
649
  Use `CodexModel` to delegate tool-call planning and text generation to Codex, while PydanticAI executes tools and validates outputs.
@@ -646,11 +671,20 @@ print(result.output)
646
671
  ```
647
672
 
648
673
  How it works:
674
+ - `CodexModel` keeps a persistent app-server session and starts/reuses threads based on
675
+ `thread_reuse_mode` (`"run"` by default, `"always"` optional).
649
676
  - `CodexModel` builds a JSON schema envelope with `tool_calls` and `final`.
650
677
  - Codex emits tool calls as JSON strings; PydanticAI runs them.
651
678
  - If `allow_text_output` is true, Codex can place final text in `final`.
652
- - Streaming APIs (`Agent.run_stream_events()`, `Agent.run_stream_sync()`) are supported; Codex
653
- emits streamed responses as a single chunk once the turn completes.
679
+ - Streaming APIs emit incremental events while app-server turn notifications arrive.
680
+
681
+ Provider options:
682
+ - `performance_profile`: `"balanced"` (default) or `"max"`.
683
+ - `thread_reuse_mode`: `"run"` (default) or `"always"`.
684
+
685
+ Lifecycle:
686
+ - `CodexModel` owns an app-server client by default; call `await model.close()` in
687
+ long-lived processes to release resources.
654
688
 
655
689
  Safety defaults (you can override with your own `ThreadOptions`):
656
690
  - `sandbox_mode="read-only"`
@@ -713,38 +747,49 @@ If `logfire` is installed and initialized, the SDK emits spans:
713
747
  If Logfire is missing or not initialized, the span context manager is a no-op.
714
748
 
715
749
  <a id="architecture"></a>
716
- <a id="acheature"></a>
717
750
  ## ![Architecture](https://img.shields.io/badge/Architecture-Stack%20map-1f2937?style=for-the-badge&logo=serverless&logoColor=white)
718
751
 
719
- ### System components
752
+ ### System components and transport paths
720
753
 
721
754
  ```mermaid
722
755
  flowchart LR
723
756
  subgraph App[Your Python App]
724
757
  U[User Code]
725
- T[Thread API]
758
+ T[Codex + Thread API]
759
+ A[AppServerClient API]
760
+ PM[PydanticAI CodexModel]
761
+ PH[PydanticAI codex_handoff_tool]
726
762
  end
727
763
 
728
764
  subgraph SDK[Codex SDK]
729
765
  C[Codex]
730
766
  E[CodexExec]
731
- P[Event Parser]
767
+ P[Thread Event Parser]
768
+ R[JSON-RPC Client]
732
769
  end
733
770
 
734
- subgraph CLI[Bundled Codex CLI]
771
+ subgraph CLI[Codex CLI]
735
772
  X["codex exec --experimental-json"]
773
+ S["codex app-server"]
736
774
  end
737
775
 
738
776
  FS[(Filesystem)]
739
777
  NET[(Network)]
740
778
 
741
779
  U --> T --> C --> E --> X
780
+ U --> A --> R --> S
781
+ U --> PM --> R
782
+ U --> PH --> C
742
783
  X -->|JSONL events| P --> T
784
+ S -->|JSON-RPC messages| R --> A
785
+ S -->|JSON-RPC messages| R --> PM
743
786
  X --> FS
744
787
  X --> NET
788
+ S --> FS
789
+ S --> NET
745
790
  ```
746
791
 
747
- ### Streaming event lifecycle
792
+ ### Thread API streaming lifecycle (`codex exec`)
748
793
 
749
794
  ```mermaid
750
795
  sequenceDiagram
@@ -767,21 +812,41 @@ sequenceDiagram
767
812
  Thread-->>Dev: turn.completed / turn.failed
768
813
  ```
769
814
 
770
- ### PydanticAI model-provider loop
815
+ ### App-server lifecycle (`codex app-server`)
816
+
817
+ ```mermaid
818
+ sequenceDiagram
819
+ participant Dev as Developer
820
+ participant App as AppServerClient
821
+ participant CLI as codex app-server
822
+
823
+ Dev->>App: start()
824
+ App->>CLI: spawn process
825
+ App->>CLI: initialize
826
+ CLI-->>App: initialize result
827
+ App->>CLI: initialized (notification)
828
+ Dev->>App: turn_session(thread_id, input)
829
+ App->>CLI: turn/start
830
+ CLI-->>App: thread/turn/item notifications
831
+ CLI-->>App: request (approval needed)
832
+ App-->>CLI: response (approve/reject)
833
+ CLI-->>App: turn completed notification
834
+ App-->>Dev: final turn payload
835
+ ```
836
+
837
+ ### PydanticAI model-provider loop (current implementation)
771
838
 
772
839
  ```mermaid
773
840
  sequenceDiagram
774
841
  participant Agent as PydanticAI Agent
775
842
  participant Model as CodexModel
776
- participant SDK as Codex SDK
777
- participant CLI as codex exec
843
+ participant App as Codex app-server
778
844
  participant Tools as User Tools
779
845
 
780
846
  Agent->>Model: request(messages, tools)
781
- Model->>SDK: start_thread + run_json(prompt, output_schema)
782
- SDK->>CLI: codex exec --output-schema
783
- CLI-->>SDK: JSON envelope {tool_calls, final}
784
- SDK-->>Model: ParsedTurn
847
+ Model->>App: thread/start (if needed)
848
+ Model->>App: turn/session(input + output_schema envelope)
849
+ App-->>Model: item/updated + turn/completed notifications
785
850
  alt tool_calls present
786
851
  Model-->>Agent: ToolCallPart(s)
787
852
  Agent->>Tools: execute tool(s)
@@ -797,12 +862,18 @@ sequenceDiagram
797
862
  flowchart LR
798
863
  Agent[PydanticAI Agent] --> Tool[codex_handoff_tool]
799
864
  Tool --> SDK[Codex SDK Thread]
800
- SDK --> CLI[Codex CLI]
865
+ SDK --> CLI[codex exec]
801
866
  CLI --> SDK
802
867
  SDK --> Tool
803
868
  Tool --> Agent
804
869
  ```
805
870
 
871
+ ### Streaming semantics summary
872
+
873
+ - `Thread.run_streamed()` and `Thread.run_streamed_events()` stream incremental `ThreadEvent` values as JSONL lines arrive from `codex exec`.
874
+ - `AppServerClient.notifications()` streams incremental JSON-RPC notifications from `codex app-server`.
875
+ - `CodexModel.request_stream(...)` emits incremental events from app-server turn notifications, with compatibility handling for current and legacy PydanticAI stream interfaces.
876
+
806
877
  <a id="testing"></a>
807
878
  ## ![Testing](https://img.shields.io/badge/Testing-Pytest%20%26%20Coverage-2563eb?style=for-the-badge&logo=pytest&logoColor=white)
808
879
 
@@ -811,9 +882,12 @@ This repo uses unit tests with mocked CLI processes to keep the test suite fast
811
882
  Test focus areas:
812
883
  - `tests/test_exec.py`: CLI invocation, environment handling, config flags, abort behavior.
813
884
  - `tests/test_thread.py`: parsing, streaming, JSON schema, Pydantic validation, input normalization.
885
+ - `tests/test_app_server.py` and `tests/test_app_server_session.py`: JSON-RPC lifecycle, method wrappers, turn-session approvals/notifications.
814
886
  - `tests/test_codex.py`: resume helpers and option wiring.
887
+ - `tests/test_config_overrides.py`: `--config` serialization and merge behavior.
815
888
  - `tests/test_abort.py`: abort signal semantics.
816
889
  - `tests/test_telemetry.py`: Logfire span behavior.
890
+ - `tests/test_tool_envelope.py`: tool envelope parsing and schema normalization helpers.
817
891
  - `tests/test_pydantic_ai_*`: PydanticAI model provider and handoff integration.
818
892
 
819
893
  ### Run tests
@@ -855,10 +929,21 @@ uv run mypy src
855
929
  ## ![CI/CD](https://img.shields.io/badge/CI%2FCD-Overview-1F4B99?style=for-the-badge&logo=gnubash&logoColor=white)
856
930
 
857
931
  This repository includes GitHub Actions workflows under `.github/workflows/`.
858
- The CI pipeline runs linting, type checks, and `pytest --cov=codex_sdk`.
859
- Release automation creates GitHub releases from `CHANGELOG_SDK.md` when you push a
860
- `vX.Y.Z` tag or manually dispatch the workflow, then the publish workflow uploads
861
- the package to PyPI on release publish.
932
+
933
+ Current workflows:
934
+ - `ci.yml`: lint (`black`, `isort`, `flake8`), type-check (`mypy`), and tests (`pytest --cov=codex_sdk`) on Python 3.10/3.11/3.12.
935
+ - `release.yml`: extracts release notes from `CHANGELOG_SDK.md` and creates a GitHub Release for `vX.Y.Z`.
936
+ - `publish.yml`: builds (`uv build --no-sources`) and publishes to PyPI on release publish (or successful release workflow).
937
+ - `docs-deploy.yml`: optional docs deployment (gated by `DOCS_DEPLOY_ENABLED`).
938
+ - `uv-lock-update.yml`: scheduled weekly lockfile refresh PR.
939
+
940
+ `ci.yml` test jobs install Node.js and run:
941
+
942
+ ```bash
943
+ python scripts/setup_binary.py
944
+ ```
945
+
946
+ before `pytest`, so test runs do not depend on committed vendor binary updates.
862
947
 
863
948
  <a id="operations"></a>
864
949
  ## ![Operations](https://img.shields.io/badge/Operations-Health%20%26%20Sessions-10b981?style=for-the-badge&logo=serverless&logoColor=white)
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["uv_build>=0.9.21,<0.11.0"]
2
+ requires = ["uv_build>=0.9.21,<0.10.0"]
3
3
  build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "codex-sdk-python"
7
- version = "0.104.0"
7
+ version = "0.105.0"
8
8
  description = "Python SDK for the Codex CLI agent with async threads, streaming events, and structured outputs"
9
9
  readme = "README.md"
10
10
  license = {text = "Apache-2.0"}
@@ -79,7 +79,7 @@ from .thread import (
79
79
  Turn,
80
80
  )
81
81
 
82
- __version__ = "0.104.0"
82
+ __version__ = "0.105.0"
83
83
 
84
84
  __all__ = [
85
85
  "AbortController",