codex-python 0.1.2__py3-none-any.whl → 0.2.0__py3-none-any.whl
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/__init__.py +12 -8
- codex/api.py +61 -149
- codex/config.py +82 -0
- codex/event.py +16 -0
- codex/native.py +56 -0
- codex/protocol/types.py +413 -289
- {codex_python-0.1.2.dist-info → codex_python-0.2.0.dist-info}/METADATA +69 -30
- codex_python-0.2.0.dist-info/RECORD +11 -0
- codex/protocol/runtime.py +0 -80
- codex_python-0.1.2.dist-info/RECORD +0 -9
- {codex_python-0.1.2.dist-info → codex_python-0.2.0.dist-info}/WHEEL +0 -0
- {codex_python-0.1.2.dist-info → codex_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -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
|
@@ -41,11 +41,11 @@ Description-Content-Type: text/markdown
|
|
41
41
|
|
42
42
|
# codex-python
|
43
43
|
|
44
|
-
|
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).
|
45
45
|
|
46
46
|
## Quickstart
|
47
47
|
|
48
|
-
- Requires Python 3.
|
48
|
+
- Requires Python 3.12+.
|
49
49
|
- Package import name: `codex`.
|
50
50
|
- Distribution name (PyPI): `codex-python`.
|
51
51
|
|
@@ -56,42 +56,39 @@ A minimal Python library scaffold using `uv` with Python 3.13+.
|
|
56
56
|
|
57
57
|
## Usage
|
58
58
|
|
59
|
-
|
59
|
+
Native, non-interactive execution with Pydantic config:
|
60
60
|
|
61
61
|
```
|
62
|
-
from codex import run_exec
|
62
|
+
from codex.api import run_exec, CodexClient
|
63
|
+
from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
- Choose model: `run_exec("...", model="gpt-4.1")`
|
71
|
-
- Full auto: `run_exec("scaffold a cli", full_auto=True)`
|
72
|
-
- Run in another dir: `run_exec("...", cd="/path/to/project")`
|
65
|
+
cfg = CodexConfig(
|
66
|
+
model="gpt-5",
|
67
|
+
model_provider="openai",
|
68
|
+
approval_policy=ApprovalPolicy.ON_REQUEST,
|
69
|
+
sandbox_mode=SandboxMode.WORKSPACE_WRITE,
|
70
|
+
)
|
73
71
|
|
74
|
-
|
72
|
+
events = run_exec("explain this repo", config=cfg)
|
75
73
|
|
74
|
+
client = CodexClient(config=cfg)
|
75
|
+
for ev in client.start_conversation("add a smoke test"):
|
76
|
+
print(ev)
|
76
77
|
```
|
77
|
-
from codex.protocol.runtime import stream_exec_events
|
78
|
-
|
79
|
-
for event in stream_exec_events("explain this repo", full_auto=True):
|
80
|
-
# event is a dict with shape {"id": str, "msg": {...}}
|
81
|
-
print(event)
|
82
|
-
```
|
83
|
-
|
84
|
-
The event payload matches the Pydantic models in `codex.protocol.types` (e.g., `EventMsg`).
|
85
78
|
|
86
|
-
|
79
|
+
To stream raw dict events directly from the native layer:
|
87
80
|
|
88
81
|
```
|
89
|
-
from codex import
|
82
|
+
from codex.native import start_exec_stream
|
90
83
|
|
91
|
-
|
92
|
-
|
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)
|
93
87
|
```
|
94
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
|
+
|
95
92
|
### Install uv
|
96
93
|
|
97
94
|
- macOS (Homebrew): `brew install uv`
|
@@ -148,8 +145,50 @@ make gen-protocol
|
|
148
145
|
```
|
149
146
|
|
150
147
|
This will:
|
151
|
-
-
|
152
|
-
- convert them to Python
|
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.
|
153
192
|
|
154
193
|
## Project Layout
|
155
194
|
|
@@ -168,4 +207,4 @@ Version is managed via `codex/__init__.py` and exposed as `__version__`. The bui
|
|
168
207
|
|
169
208
|
## Python Compatibility
|
170
209
|
|
171
|
-
-
|
210
|
+
- Supported: Python 3.12, 3.13. CI attempts 3.14 wheels when available.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
codex/__init__.py,sha256=xlyhxrsoviZDinInmCg1mHhybg5gFtxuuPKe4-WKp3w,606
|
2
|
+
codex/api.py,sha256=FhRSIAu5dpwTB4sO2qjuVjH_akFoDAG-2wyAyRSGCvw,2892
|
3
|
+
codex/config.py,sha256=388mrVtzyA6t8qigS8JxFSFPJbT3A-KMDMP-YQo6rUs,2869
|
4
|
+
codex/event.py,sha256=HPS6ySBa7Pwn4gRjQKj2yUE5_kiad4WFqwmA7aEdoiI,387
|
5
|
+
codex/native.py,sha256=ukaOK5U96oaJaY80sFSUSFNhRv1Wefix_8M-BCUat7A,2063
|
6
|
+
codex/protocol/types.py,sha256=YxnQBq5sgV_JC7E0q5Hkp8EIRcpvSTnBm1Uhv4Lc4Zs,38558
|
7
|
+
codex/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
8
|
+
codex_python-0.2.0.dist-info/METADATA,sha256=hLsX65ljGft-oPgvimWlDACHJAytrB1yjSxFW97fESw,6599
|
9
|
+
codex_python-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
codex_python-0.2.0.dist-info/licenses/LICENSE,sha256=ZhGahTKhsCbPWNmZ7ugZ14LVewMo4Gh1OeIOlQabyrI,1066
|
11
|
+
codex_python-0.2.0.dist-info/RECORD,,
|
codex/protocol/runtime.py
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import json
|
4
|
-
import os
|
5
|
-
import subprocess
|
6
|
-
from collections.abc import Iterator
|
7
|
-
from typing import Any
|
8
|
-
|
9
|
-
from pydantic import BaseModel
|
10
|
-
|
11
|
-
|
12
|
-
class Event(BaseModel):
|
13
|
-
"""Protocol event envelope emitted by `codex exec --json`.
|
14
|
-
|
15
|
-
Note: `msg` is kept as a raw mapping to preserve all fields from
|
16
|
-
intersection types. If you need strong typing, try validating
|
17
|
-
against `codex.protocol.types.EventMsg` manually.
|
18
|
-
"""
|
19
|
-
|
20
|
-
id: str
|
21
|
-
msg: dict[str, Any]
|
22
|
-
|
23
|
-
|
24
|
-
def stream_exec_events(
|
25
|
-
prompt: str,
|
26
|
-
*,
|
27
|
-
executable: str = "codex",
|
28
|
-
model: str | None = None,
|
29
|
-
oss: bool = False,
|
30
|
-
full_auto: bool = False,
|
31
|
-
cd: str | None = None,
|
32
|
-
skip_git_repo_check: bool = False,
|
33
|
-
env: dict[str, str] | None = None,
|
34
|
-
) -> Iterator[Event]:
|
35
|
-
"""Spawn `codex exec --json` and yield Event objects from NDJSON stdout.
|
36
|
-
|
37
|
-
Non-event lines (config summary, prompt echo) are ignored.
|
38
|
-
"""
|
39
|
-
cmd: list[str] = [executable]
|
40
|
-
if cd:
|
41
|
-
cmd += ["--cd", cd]
|
42
|
-
if model:
|
43
|
-
cmd += ["-m", model]
|
44
|
-
if oss:
|
45
|
-
cmd.append("--oss")
|
46
|
-
if full_auto:
|
47
|
-
cmd.append("--full-auto")
|
48
|
-
if skip_git_repo_check:
|
49
|
-
cmd.append("--skip-git-repo-check")
|
50
|
-
cmd += ["exec", "--json", prompt]
|
51
|
-
|
52
|
-
with subprocess.Popen(
|
53
|
-
cmd,
|
54
|
-
stdout=subprocess.PIPE,
|
55
|
-
stderr=subprocess.PIPE,
|
56
|
-
text=True,
|
57
|
-
env={**os.environ, **(env or {})},
|
58
|
-
) as proc:
|
59
|
-
assert proc.stdout is not None
|
60
|
-
for line in proc.stdout:
|
61
|
-
line = line.strip()
|
62
|
-
if not line:
|
63
|
-
continue
|
64
|
-
try:
|
65
|
-
obj = json.loads(line)
|
66
|
-
except json.JSONDecodeError:
|
67
|
-
continue
|
68
|
-
|
69
|
-
# Filter out non-event helper lines
|
70
|
-
if not isinstance(obj, dict):
|
71
|
-
continue
|
72
|
-
if "id" in obj and "msg" in obj:
|
73
|
-
# Attempt to validate into our Pydantic Event model
|
74
|
-
yield Event.model_validate(obj)
|
75
|
-
|
76
|
-
# Drain stderr for diagnostics if the process failed
|
77
|
-
ret = proc.wait()
|
78
|
-
if ret != 0 and proc.stderr is not None:
|
79
|
-
err = proc.stderr.read()
|
80
|
-
raise RuntimeError(f"codex exec failed with {ret}: {err}")
|
@@ -1,9 +0,0 @@
|
|
1
|
-
codex/__init__.py,sha256=H12NLxWqZAOhHbkZO0rnMRhkdo_9y5DUVTmxyX2ncI0,514
|
2
|
-
codex/api.py,sha256=gabhwkBQpdu7QdA_K75m8TPpusC9a4LteyhiZN0cI1Y,5173
|
3
|
-
codex/protocol/runtime.py,sha256=lfnlkMYDg303Ug8awiu2FKwmbz3PGWnhTpFng-CsIe4,2229
|
4
|
-
codex/protocol/types.py,sha256=852vSY0cdepXcu9DOJakzhsZBYpa0xF9aqBBj9GI_hE,39108
|
5
|
-
codex/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
6
|
-
codex_python-0.1.2.dist-info/METADATA,sha256=swB6w-sW3820mh45KzPfoxlYBGIvAzWjN8N3efzySZg,5083
|
7
|
-
codex_python-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
8
|
-
codex_python-0.1.2.dist-info/licenses/LICENSE,sha256=ZhGahTKhsCbPWNmZ7ugZ14LVewMo4Gh1OeIOlQabyrI,1066
|
9
|
-
codex_python-0.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|