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.
- {codex_python-0.1.1 → codex_python-0.2.0}/.github/workflows/ci.yml +11 -1
- codex_python-0.2.0/.github/workflows/native-wheels.yml +68 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/.gitignore +24 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/Makefile +33 -3
- {codex_python-0.1.1 → codex_python-0.2.0}/PKG-INFO +82 -17
- codex_python-0.2.0/README.md +169 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/codex/__init__.py +12 -8
- codex_python-0.2.0/codex/api.py +93 -0
- codex_python-0.2.0/codex/config.py +82 -0
- codex_python-0.2.0/codex/event.py +16 -0
- codex_python-0.2.0/codex/native.py +56 -0
- codex_python-0.2.0/codex/protocol/types.py +1719 -0
- codex_python-0.2.0/crates/codex_native/Cargo.toml +25 -0
- codex_python-0.2.0/crates/codex_native/src/lib.rs +332 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/pyproject.toml +7 -1
- codex_python-0.2.0/scripts/generate_protocol_py.py +353 -0
- codex_python-0.1.1/CHANGELOG.md +0 -27
- codex_python-0.1.1/CODE_OF_CONDUCT.md +0 -34
- codex_python-0.1.1/CONTRIBUTING.md +0 -53
- codex_python-0.1.1/README.md +0 -105
- codex_python-0.1.1/codex/api.py +0 -165
- codex_python-0.1.1/tests/test_api.py +0 -27
- codex_python-0.1.1/tests/test_client.py +0 -37
- codex_python-0.1.1/tests/test_version.py +0 -7
- {codex_python-0.1.1 → codex_python-0.2.0}/.github/workflows/publish.yml +0 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/.pre-commit-config.yaml +0 -0
- {codex_python-0.1.1 → codex_python-0.2.0}/LICENSE +0 -0
- {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
|
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.
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
|
64
|
-
|
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
|
-
|
72
|
+
events = run_exec("explain this repo", config=cfg)
|
68
73
|
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
client = CodexClient(config=cfg)
|
75
|
+
for ev in client.start_conversation("add a smoke test"):
|
76
|
+
print(ev)
|
77
|
+
```
|
72
78
|
|
73
|
-
|
79
|
+
To stream raw dict events directly from the native layer:
|
74
80
|
|
75
81
|
```
|
76
|
-
from codex import
|
82
|
+
from codex.native import start_exec_stream
|
77
83
|
|
78
|
-
|
79
|
-
|
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
|
-
-
|
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
|
-
|
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
|
-
|
14
|
-
|
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
|
-
"
|
23
|
-
"CodexProcessError",
|
24
|
+
"CodexNativeError",
|
24
25
|
"CodexClient",
|
25
|
-
"
|
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.
|
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
|