codex-python 0.1.1__tar.gz → 0.2.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 (28) hide show
  1. {codex_python-0.1.1 → codex_python-0.2.0}/.github/workflows/ci.yml +11 -1
  2. codex_python-0.2.0/.github/workflows/native-wheels.yml +68 -0
  3. {codex_python-0.1.1 → codex_python-0.2.0}/.gitignore +24 -0
  4. {codex_python-0.1.1 → codex_python-0.2.0}/Makefile +33 -3
  5. {codex_python-0.1.1 → codex_python-0.2.0}/PKG-INFO +82 -17
  6. codex_python-0.2.0/README.md +169 -0
  7. {codex_python-0.1.1 → codex_python-0.2.0}/codex/__init__.py +12 -8
  8. codex_python-0.2.0/codex/api.py +93 -0
  9. codex_python-0.2.0/codex/config.py +82 -0
  10. codex_python-0.2.0/codex/event.py +16 -0
  11. codex_python-0.2.0/codex/native.py +56 -0
  12. codex_python-0.2.0/codex/protocol/types.py +1719 -0
  13. codex_python-0.2.0/crates/codex_native/Cargo.toml +25 -0
  14. codex_python-0.2.0/crates/codex_native/src/lib.rs +332 -0
  15. {codex_python-0.1.1 → codex_python-0.2.0}/pyproject.toml +7 -1
  16. codex_python-0.2.0/scripts/generate_protocol_py.py +353 -0
  17. codex_python-0.1.1/CHANGELOG.md +0 -27
  18. codex_python-0.1.1/CODE_OF_CONDUCT.md +0 -34
  19. codex_python-0.1.1/CONTRIBUTING.md +0 -53
  20. codex_python-0.1.1/README.md +0 -105
  21. codex_python-0.1.1/codex/api.py +0 -165
  22. codex_python-0.1.1/tests/test_api.py +0 -27
  23. codex_python-0.1.1/tests/test_client.py +0 -37
  24. codex_python-0.1.1/tests/test_version.py +0 -7
  25. {codex_python-0.1.1 → codex_python-0.2.0}/.github/workflows/publish.yml +0 -0
  26. {codex_python-0.1.1 → codex_python-0.2.0}/.pre-commit-config.yaml +0 -0
  27. {codex_python-0.1.1 → codex_python-0.2.0}/LICENSE +0 -0
  28. {codex_python-0.1.1 → codex_python-0.2.0}/codex/py.typed +0 -0
@@ -26,9 +26,19 @@ jobs:
26
26
  with:
27
27
  version: latest
28
28
 
29
+ - name: Set up Rust (for native extension)
30
+ uses: dtolnay/rust-toolchain@stable
31
+
32
+ - name: Install maturin
33
+ run: |
34
+ python -m pip install --upgrade pip
35
+ pip install maturin
36
+
37
+ - name: Build native extension (editable)
38
+ run: make dev-native
39
+
29
40
  - name: Lint
30
41
  run: make lint
31
42
 
32
43
  - name: Test
33
44
  run: make test
34
-
@@ -0,0 +1,68 @@
1
+ name: Build Native Wheels (codex-native)
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch: {}
8
+
9
+ permissions:
10
+ contents: read
11
+ id-token: write
12
+
13
+ jobs:
14
+ build:
15
+ continue-on-error: ${{ matrix.allow-failure == true }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ os: [ubuntu-latest, macos-14, windows-latest]
20
+ python-version: ['3.12', '3.13']
21
+ include:
22
+ - os: ubuntu-latest
23
+ python-version: '3.14'
24
+ allow-failure: true
25
+ runs-on: ${{ matrix.os }}
26
+ steps:
27
+ - name: Checkout repository
28
+ uses: actions/checkout@v4
29
+
30
+ - name: Set up Rust
31
+ uses: dtolnay/rust-toolchain@stable
32
+
33
+ - name: Set up Python
34
+ uses: actions/setup-python@v5
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+
38
+ - name: Install maturin
39
+ run: |
40
+ python -m pip install --upgrade pip
41
+ pip install maturin
42
+
43
+ - name: Build wheels with maturin
44
+ env:
45
+ PYO3_USE_ABI3_FORWARD_COMPATIBILITY: '1'
46
+ run: |
47
+ maturin build -m crates/codex_native/Cargo.toml --release --interpreter python
48
+
49
+ - name: Upload wheels
50
+ uses: actions/upload-artifact@v4
51
+ with:
52
+ name: wheels-${{ matrix.os }}-${{ matrix.python-version }}
53
+ path: crates/codex_native/target/wheels/*.whl
54
+
55
+ publish:
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - name: Download all wheels
60
+ uses: actions/download-artifact@v4
61
+ with:
62
+ path: dist
63
+
64
+ - name: Publish to PyPI (Trusted Publishing)
65
+ uses: pypa/gh-action-pypi-publish@release/v1
66
+ with:
67
+ packages-dir: dist
68
+ skip-existing: true
@@ -44,6 +44,30 @@ coverage.xml
44
44
  .uv/
45
45
  uv.lock
46
46
 
47
+ # Generated artifacts
48
+ # Generated artifacts
49
+ .generated/
50
+ codex-proj/
51
+ .githooks/
52
+ test/
53
+ tests/
54
+
55
+ # Ignore new markdown files by default
56
+ *.md
57
+
58
+ # Rust build outputs
59
+ target/
60
+ crates/**/target/
61
+ crates/**/Cargo.lock
62
+
47
63
  # Local environment files
48
64
  .env
49
65
  .env.*
66
+ /.idea/inspectionProfiles/profiles_settings.xml
67
+ /.idea/inspectionProfiles/Project_Default.xml
68
+ /.idea/.gitignore
69
+ /.idea/codex-python.iml
70
+ /.idea/misc.xml
71
+ /.idea/modules.xml
72
+ /.idea/ruff.xml
73
+ /.idea/vcs.xml
@@ -7,6 +7,7 @@ help:
7
7
  @echo " make build - Build sdist and wheel with uv"
8
8
  @echo " make publish - Publish to PyPI via uv (uses PYPI_API_TOKEN)"
9
9
  @echo " make clean - Remove build artifacts"
10
+ @echo " make gen-protocol - Generate Python protocol bindings from codex-rs"
10
11
 
11
12
  venv:
12
13
  uv venv --python 3.13
@@ -16,12 +17,12 @@ fmt:
16
17
  uv run --group dev ruff format .
17
18
 
18
19
  lint:
19
- uv run --group dev ruff format --check .
20
- uv run --group dev ruff check .
20
+ uv run --group dev ruff format .
21
+ uv run --group dev ruff check --fix --unsafe-fixes .
21
22
  uv run --group dev mypy codex
22
23
 
23
24
  test:
24
- uv run --group dev pytest
25
+ @bash -lc 'uv run --group dev pytest -q; ec=$$?; if [ $$ec -eq 5 ]; then echo "No tests collected"; exit 0; else exit $$ec; fi'
25
26
 
26
27
  build:
27
28
  uv build
@@ -49,3 +50,32 @@ publish: build
49
50
 
50
51
  clean:
51
52
  rm -rf build dist *.egg-info .pytest_cache .mypy_cache .ruff_cache
53
+
54
+ gen-protocol:
55
+ @echo "Generating TypeScript protocol types via codex-proj/codex-rs ..."
56
+ @mkdir -p .generated/ts
57
+ @if command -v codex >/dev/null 2>&1; then \
58
+ if codex --help | grep -q "generate-ts"; then \
59
+ echo "Using 'codex generate-ts'"; \
60
+ codex generate-ts --out .generated/ts; \
61
+ else \
62
+ echo "'codex' installed but no generate-ts; falling back"; \
63
+ cd codex-proj/codex-rs && cargo run -p codex-protocol-ts -- --out ../../.generated/ts; \
64
+ fi; \
65
+ else \
66
+ echo "Using cargo run -p codex-protocol-ts"; \
67
+ cd codex-proj/codex-rs && cargo run -p codex-protocol-ts -- --out ../../.generated/ts; \
68
+ fi
69
+ @echo "Generating Python bindings ..."
70
+ @python3 scripts/generate_protocol_py.py .generated/ts
71
+ @$(MAKE) fmt
72
+
73
+ .PHONY: build-native dev-native
74
+
75
+ build-native:
76
+ @echo "Building native extension with maturin..."
77
+ @maturin build -m crates/codex_native/Cargo.toml --release
78
+
79
+ dev-native:
80
+ @echo "Installing native extension in dev mode..."
81
+ @maturin develop -m crates/codex_native/Cargo.toml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codex-python
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: A minimal Python library scaffold for codex-python
5
5
  Project-URL: Homepage, https://github.com/gersmann/codex-python
6
6
  Project-URL: Repository, https://github.com/gersmann/codex-python
@@ -36,15 +36,16 @@ Classifier: Programming Language :: Python :: 3 :: Only
36
36
  Classifier: Programming Language :: Python :: 3.13
37
37
  Classifier: Typing :: Typed
38
38
  Requires-Python: >=3.13
39
+ Requires-Dist: pydantic>=2.11.7
39
40
  Description-Content-Type: text/markdown
40
41
 
41
42
  # codex-python
42
43
 
43
- A minimal Python library scaffold using `uv` with Python 3.13+.
44
+ Python interface to Codex, packaged as a single distribution (`codex-python`). Platform wheels include a native extension for in‑process execution. The library consolidates on native bindings (no subprocess wrapper).
44
45
 
45
46
  ## Quickstart
46
47
 
47
- - Requires Python 3.13+.
48
+ - Requires Python 3.12+.
48
49
  - Package import name: `codex`.
49
50
  - Distribution name (PyPI): `codex-python`.
50
51
 
@@ -55,30 +56,39 @@ A minimal Python library scaffold using `uv` with Python 3.13+.
55
56
 
56
57
  ## Usage
57
58
 
58
- Basic non-interactive execution via Codex CLI:
59
+ Native, non-interactive execution with Pydantic config:
59
60
 
60
61
  ```
61
- from codex import run_exec
62
+ from codex.api import run_exec, CodexClient
63
+ from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
62
64
 
63
- out = run_exec("explain this repo")
64
- print(out)
65
- ```
65
+ cfg = CodexConfig(
66
+ model="gpt-5",
67
+ model_provider="openai",
68
+ approval_policy=ApprovalPolicy.ON_REQUEST,
69
+ sandbox_mode=SandboxMode.WORKSPACE_WRITE,
70
+ )
66
71
 
67
- Options:
72
+ events = run_exec("explain this repo", config=cfg)
68
73
 
69
- - Choose model: `run_exec("...", model="gpt-4.1")`
70
- - Full auto: `run_exec("scaffold a cli", full_auto=True)`
71
- - Run in another dir: `run_exec("...", cd="/path/to/project")`
74
+ client = CodexClient(config=cfg)
75
+ for ev in client.start_conversation("add a smoke test"):
76
+ print(ev)
77
+ ```
72
78
 
73
- Using a client with defaults:
79
+ To stream raw dict events directly from the native layer:
74
80
 
75
81
  ```
76
- from codex import CodexClient
82
+ from codex.native import start_exec_stream
77
83
 
78
- client = CodexClient(model="gpt-4.1", full_auto=True)
79
- print(client.run("explain this repo"))
84
+ for e in start_exec_stream("explain this repo", config_overrides=cfg.to_dict()):
85
+ # each `e` is a dict representing an event envelope
86
+ print(e)
80
87
  ```
81
88
 
89
+ The event payload is typed: `Event.msg` is a union `EventMsg` from `codex.protocol.types`,
90
+ and is also exported at `codex.EventMsg` for convenience.
91
+
82
92
  ### Install uv
83
93
 
84
94
  - macOS (Homebrew): `brew install uv`
@@ -125,6 +135,61 @@ uv publish --token "$PYPI_API_TOKEN"
125
135
  - Format: `make fmt` (ruff formatter)
126
136
  - Pre-commit: `uvx pre-commit install && uvx pre-commit run --all-files`
127
137
 
138
+ ### Protocol bindings (from codex-rs)
139
+
140
+ - Prereq: Rust toolchain (`cargo`) installed.
141
+ - Generate Python types from the upstream protocol with:
142
+
143
+ ```
144
+ make gen-protocol
145
+ ```
146
+
147
+ This will:
148
+ - emit TypeScript types under `.generated/ts/`
149
+ - convert them to Python Pydantic models + Literal unions at `codex/protocol/types.py`
150
+
151
+ ### Native bindings (PyO3)
152
+
153
+ - Install path
154
+
155
+ `pip install codex-python` installs a platform wheel that includes the native extension on supported platforms (Python 3.12/3.13; CI also attempts 3.14).
156
+
157
+ - Build locally (requires Rust + maturin):
158
+
159
+ ```
160
+ make dev-native
161
+ ```
162
+
163
+ - Notes:
164
+ - The native path embeds Codex directly; no subprocess.
165
+ - A helper `codex.native.preview_config(...)` returns a compact snapshot of the effective configuration (selected fields) for tests and introspection.
166
+
167
+ ### Configuration (Pydantic)
168
+
169
+ Use the `CodexConfig` Pydantic model to pass overrides which mirror the Rust `ConfigOverrides`:
170
+
171
+ ```
172
+ from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
173
+ from codex.api import run_exec, CodexClient
174
+
175
+ cfg = CodexConfig(
176
+ model="gpt-5",
177
+ model_provider="openai",
178
+ approval_policy=ApprovalPolicy.ON_REQUEST,
179
+ sandbox_mode=SandboxMode.WORKSPACE_WRITE,
180
+ cwd="/path/to/project",
181
+ include_apply_patch_tool=True,
182
+ )
183
+
184
+ events = run_exec("Explain this project", config=cfg)
185
+
186
+ client = CodexClient(config=cfg)
187
+ for ev in client.start_conversation("Add a test for feature X"):
188
+ print(ev)
189
+ ```
190
+
191
+ `CodexConfig.to_dict()` emits only set (non‑None) fields and serializes enums to their kebab‑case strings to match the native Rust types.
192
+
128
193
  ## Project Layout
129
194
 
130
195
  ```
@@ -142,4 +207,4 @@ Version is managed via `codex/__init__.py` and exposed as `__version__`. The bui
142
207
 
143
208
  ## Python Compatibility
144
209
 
145
- - Requires Python `>=3.13`.
210
+ - Supported: Python 3.12, 3.13. CI attempts 3.14 wheels when available.
@@ -0,0 +1,169 @@
1
+ # codex-python
2
+
3
+ Python interface to Codex, packaged as a single distribution (`codex-python`). Platform wheels include a native extension for in‑process execution. The library consolidates on native bindings (no subprocess wrapper).
4
+
5
+ ## Quickstart
6
+
7
+ - Requires Python 3.12+.
8
+ - Package import name: `codex`.
9
+ - Distribution name (PyPI): `codex-python`.
10
+
11
+ ### Repo
12
+
13
+ - Git: `git@github.com:gersmann/codex-python.git`
14
+ - URL: https://github.com/gersmann/codex-python
15
+
16
+ ## Usage
17
+
18
+ Native, non-interactive execution with Pydantic config:
19
+
20
+ ```
21
+ from codex.api import run_exec, CodexClient
22
+ from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
23
+
24
+ cfg = CodexConfig(
25
+ model="gpt-5",
26
+ model_provider="openai",
27
+ approval_policy=ApprovalPolicy.ON_REQUEST,
28
+ sandbox_mode=SandboxMode.WORKSPACE_WRITE,
29
+ )
30
+
31
+ events = run_exec("explain this repo", config=cfg)
32
+
33
+ client = CodexClient(config=cfg)
34
+ for ev in client.start_conversation("add a smoke test"):
35
+ print(ev)
36
+ ```
37
+
38
+ To stream raw dict events directly from the native layer:
39
+
40
+ ```
41
+ from codex.native import start_exec_stream
42
+
43
+ for e in start_exec_stream("explain this repo", config_overrides=cfg.to_dict()):
44
+ # each `e` is a dict representing an event envelope
45
+ print(e)
46
+ ```
47
+
48
+ The event payload is typed: `Event.msg` is a union `EventMsg` from `codex.protocol.types`,
49
+ and is also exported at `codex.EventMsg` for convenience.
50
+
51
+ ### Install uv
52
+
53
+ - macOS (Homebrew): `brew install uv`
54
+ - Or via install script:
55
+ - Unix/macOS: `curl -LsSf https://astral.sh/uv/install.sh | sh`
56
+ - Windows (PowerShell): `iwr https://astral.sh/uv/install.ps1 -UseBasicParsing | iex`
57
+
58
+ See: https://docs.astral.sh/uv/
59
+
60
+ ### Create a virtual env (optional)
61
+
62
+ ```
63
+ uv python install 3.13
64
+ uv venv --python 3.13
65
+ . .venv/bin/activate # or .venv\Scripts\activate on Windows
66
+ ```
67
+
68
+ ### Build
69
+
70
+ ```
71
+ uv build
72
+ ```
73
+
74
+ Artifacts appear in `dist/` (`.whl` and `.tar.gz`).
75
+
76
+ ### Publish to PyPI
77
+
78
+ - Manual:
79
+
80
+ ```
81
+ export PYPI_API_TOKEN="pypi-XXXX" # create at https://pypi.org/manage/account/token/
82
+ uv publish --token "$PYPI_API_TOKEN"
83
+ ```
84
+
85
+ - GitHub Actions (Trusted Publishing): enable PyPI Trusted Publishing for
86
+ `gersmann/codex-python` and push a tag like `v0.1.0`. No token is needed.
87
+ The workflow at `.github/workflows/publish.yml` requests an OIDC token and
88
+ runs `uv publish --trusted-publishing=always` on `v*` tags.
89
+
90
+ ### Dev tooling
91
+
92
+ - Lint: `make lint` (ruff + mypy)
93
+ - Tests: `make test` (pytest)
94
+ - Format: `make fmt` (ruff formatter)
95
+ - Pre-commit: `uvx pre-commit install && uvx pre-commit run --all-files`
96
+
97
+ ### Protocol bindings (from codex-rs)
98
+
99
+ - Prereq: Rust toolchain (`cargo`) installed.
100
+ - Generate Python types from the upstream protocol with:
101
+
102
+ ```
103
+ make gen-protocol
104
+ ```
105
+
106
+ This will:
107
+ - emit TypeScript types under `.generated/ts/`
108
+ - convert them to Python Pydantic models + Literal unions at `codex/protocol/types.py`
109
+
110
+ ### Native bindings (PyO3)
111
+
112
+ - Install path
113
+
114
+ `pip install codex-python` installs a platform wheel that includes the native extension on supported platforms (Python 3.12/3.13; CI also attempts 3.14).
115
+
116
+ - Build locally (requires Rust + maturin):
117
+
118
+ ```
119
+ make dev-native
120
+ ```
121
+
122
+ - Notes:
123
+ - The native path embeds Codex directly; no subprocess.
124
+ - A helper `codex.native.preview_config(...)` returns a compact snapshot of the effective configuration (selected fields) for tests and introspection.
125
+
126
+ ### Configuration (Pydantic)
127
+
128
+ Use the `CodexConfig` Pydantic model to pass overrides which mirror the Rust `ConfigOverrides`:
129
+
130
+ ```
131
+ from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
132
+ from codex.api import run_exec, CodexClient
133
+
134
+ cfg = CodexConfig(
135
+ model="gpt-5",
136
+ model_provider="openai",
137
+ approval_policy=ApprovalPolicy.ON_REQUEST,
138
+ sandbox_mode=SandboxMode.WORKSPACE_WRITE,
139
+ cwd="/path/to/project",
140
+ include_apply_patch_tool=True,
141
+ )
142
+
143
+ events = run_exec("Explain this project", config=cfg)
144
+
145
+ client = CodexClient(config=cfg)
146
+ for ev in client.start_conversation("Add a test for feature X"):
147
+ print(ev)
148
+ ```
149
+
150
+ `CodexConfig.to_dict()` emits only set (non‑None) fields and serializes enums to their kebab‑case strings to match the native Rust types.
151
+
152
+ ## Project Layout
153
+
154
+ ```
155
+ .
156
+ ├── codex/ # package root (import name: codex)
157
+ │ └── __init__.py # version lives here
158
+ ├── pyproject.toml # PEP 621 metadata, hatchling build backend
159
+ ├── README.md
160
+ └── .gitignore
161
+ ```
162
+
163
+ ## Versioning
164
+
165
+ Version is managed via `codex/__init__.py` and exposed as `__version__`. The build uses Hatch’s version source.
166
+
167
+ ## Python Compatibility
168
+
169
+ - Supported: Python 3.12, 3.13. CI attempts 3.14 wheels when available.
@@ -4,27 +4,31 @@ Python interface for the Codex CLI.
4
4
 
5
5
  Usage:
6
6
  from codex import run_exec
7
- output = run_exec("explain this codebase to me")
7
+ events = run_exec("explain this codebase to me")
8
8
  """
9
9
 
10
10
  from .api import (
11
11
  CodexClient,
12
12
  CodexError,
13
- CodexNotFoundError,
14
- CodexProcessError,
15
- find_binary,
13
+ CodexNativeError,
14
+ Conversation,
16
15
  run_exec,
17
16
  )
17
+ from .config import CodexConfig
18
+ from .event import Event
19
+ from .protocol.types import EventMsg
18
20
 
19
21
  __all__ = [
20
22
  "__version__",
21
23
  "CodexError",
22
- "CodexNotFoundError",
23
- "CodexProcessError",
24
+ "CodexNativeError",
24
25
  "CodexClient",
25
- "find_binary",
26
+ "Conversation",
26
27
  "run_exec",
28
+ "Event",
29
+ "EventMsg",
30
+ "CodexConfig",
27
31
  ]
28
32
 
29
33
  # Managed by Hatch via pyproject.toml [tool.hatch.version]
30
- __version__ = "0.1.1"
34
+ __version__ = "0.2.0"
@@ -0,0 +1,93 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable, Iterator, Mapping, Sequence
4
+ from dataclasses import dataclass
5
+
6
+ from .config import CodexConfig
7
+ from .event import Event
8
+ from .native import run_exec_collect as native_run_exec_collect
9
+ from .native import start_exec_stream as native_start_exec_stream
10
+
11
+
12
+ class CodexError(Exception):
13
+ """Base exception for codex-python."""
14
+
15
+
16
+ class CodexNativeError(CodexError):
17
+ """Raised when the native extension is not available or fails."""
18
+
19
+ def __init__(self) -> None:
20
+ super().__init__(
21
+ "codex_native extension not installed or failed to run. "
22
+ "Run `make dev-native` or ensure native wheels are installed."
23
+ )
24
+
25
+
26
+ @dataclass(slots=True)
27
+ class Conversation:
28
+ """A stateful conversation with Codex, streaming events natively."""
29
+
30
+ _stream: Iterable[dict]
31
+
32
+ def __iter__(self) -> Iterator[Event]:
33
+ """Yield `Event` objects from the native stream."""
34
+ for item in self._stream:
35
+ yield Event.model_validate(item)
36
+
37
+
38
+ @dataclass(slots=True)
39
+ class CodexClient:
40
+ """Lightweight, synchronous client for the native Codex core.
41
+
42
+ Provides defaults for repeated invocations and conversation management.
43
+ """
44
+
45
+ config: CodexConfig | None = None
46
+ load_default_config: bool = True
47
+ env: Mapping[str, str] | None = None
48
+ extra_args: Sequence[str] | None = None
49
+
50
+ def start_conversation(
51
+ self,
52
+ prompt: str,
53
+ *,
54
+ config: CodexConfig | None = None,
55
+ load_default_config: bool | None = None,
56
+ ) -> Conversation:
57
+ """Start a new conversation and return a streaming iterator over events."""
58
+ eff_config = config if config is not None else self.config
59
+ eff_load_default_config = (
60
+ load_default_config if load_default_config is not None else self.load_default_config
61
+ )
62
+
63
+ try:
64
+ stream = native_start_exec_stream(
65
+ prompt,
66
+ config_overrides=eff_config.to_dict() if eff_config else None,
67
+ load_default_config=eff_load_default_config,
68
+ )
69
+ return Conversation(_stream=stream)
70
+ except RuntimeError as e:
71
+ raise CodexNativeError() from e
72
+
73
+
74
+ def run_exec(
75
+ prompt: str,
76
+ *,
77
+ config: CodexConfig | None = None,
78
+ load_default_config: bool = True,
79
+ ) -> list[Event]:
80
+ """
81
+ Run a prompt through the native Codex engine and return a list of events.
82
+
83
+ - Raises CodexNativeError if the native extension is unavailable or fails.
84
+ """
85
+ try:
86
+ events = native_run_exec_collect(
87
+ prompt,
88
+ config_overrides=config.to_dict() if config else None,
89
+ load_default_config=load_default_config,
90
+ )
91
+ return [Event.model_validate(e) for e in events]
92
+ except RuntimeError as e:
93
+ raise CodexNativeError() from e