codex-python 0.2.3__tar.gz → 0.2.8__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.2.8/LICENSE +22 -0
- codex_python-0.2.8/PKG-INFO +130 -0
- codex_python-0.2.8/README.md +110 -0
- codex_python-0.2.8/codex/__init__.py +34 -0
- codex_python-0.2.8/codex/api.py +93 -0
- codex_python-0.2.8/codex/config.py +82 -0
- codex_python-0.2.8/codex/event.py +16 -0
- codex_python-0.2.8/codex/native.py +35 -0
- codex_python-0.2.8/codex/protocol/types.py +1539 -0
- codex_python-0.2.8/codex/py.typed +1 -0
- {codex_python-0.2.3 → codex_python-0.2.8/crates/codex_native}/Cargo.lock +59 -30
- codex_python-0.2.8/crates/codex_native/Cargo.toml +39 -0
- codex_python-0.2.8/pyproject.toml +65 -0
- codex_python-0.2.3/Cargo.toml +0 -25
- codex_python-0.2.3/PKG-INFO +0 -4
- codex_python-0.2.3/pyproject.toml +0 -9
- {codex_python-0.2.3 → codex_python-0.2.8/crates/codex_native}/src/lib.rs +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 gersmann
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codex-python
|
|
3
|
+
Version: 0.2.8
|
|
4
|
+
Classifier: Programming Language :: Python :: 3
|
|
5
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Typing :: Typed
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Requires-Dist: pydantic>=2.11.7
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Summary: A minimal Python library scaffold for codex-python
|
|
13
|
+
Keywords: codex,library,scaffold
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
16
|
+
Project-URL: Homepage, https://github.com/gersmann/codex-python
|
|
17
|
+
Project-URL: Repository, https://github.com/gersmann/codex-python
|
|
18
|
+
Project-URL: Issues, https://github.com/gersmann/codex-python/issues
|
|
19
|
+
|
|
20
|
+
# codex-python
|
|
21
|
+
|
|
22
|
+
Native Python bindings for Codex (in‑process execution). Ships as a single package (`codex-python`) with platform wheels that include the native extension.
|
|
23
|
+
|
|
24
|
+
- Python: 3.12–3.13 (CI also attempts 3.14)
|
|
25
|
+
- Import name: `codex`
|
|
26
|
+
- PyPI: https://pypi.org/project/codex-python/
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
pip install codex-python
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If there’s no prebuilt wheel for your platform/Python, pip will build from source. You’ll need a Rust toolchain and maturin; see “Developing” below.
|
|
35
|
+
|
|
36
|
+
## Quickstart
|
|
37
|
+
|
|
38
|
+
Run a prompt and collect structured events (typed):
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
from codex.api import run_exec, CodexClient
|
|
42
|
+
from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
|
|
43
|
+
|
|
44
|
+
cfg = CodexConfig(
|
|
45
|
+
model="gpt-5",
|
|
46
|
+
model_provider="openai",
|
|
47
|
+
approval_policy=ApprovalPolicy.ON_REQUEST,
|
|
48
|
+
sandbox_mode=SandboxMode.WORKSPACE_WRITE,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# One-shot
|
|
52
|
+
events = run_exec("Explain this repo", config=cfg)
|
|
53
|
+
|
|
54
|
+
# Conversation (streaming)
|
|
55
|
+
client = CodexClient(config=cfg)
|
|
56
|
+
for ev in client.start_conversation("Add a smoke test"):
|
|
57
|
+
print(ev.id, ev.msg)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Notes
|
|
61
|
+
- `Event.msg` is typed as a union `EventMsg` (also available at `codex.EventMsg`).
|
|
62
|
+
- For raw dict streaming from the native layer, use `codex.native.start_exec_stream`.
|
|
63
|
+
|
|
64
|
+
## Configuration (Pydantic)
|
|
65
|
+
|
|
66
|
+
Use `CodexConfig` to pass overrides mirrored from Rust `ConfigOverrides`.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
|
|
70
|
+
|
|
71
|
+
cfg = CodexConfig(
|
|
72
|
+
model="gpt-5",
|
|
73
|
+
model_provider="openai",
|
|
74
|
+
approval_policy=ApprovalPolicy.ON_REQUEST,
|
|
75
|
+
sandbox_mode=SandboxMode.WORKSPACE_WRITE,
|
|
76
|
+
cwd="/path/to/project",
|
|
77
|
+
include_apply_patch_tool=True,
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `CodexConfig.to_dict()` emits only fields you set, with enums serialized to kebab‑case strings expected by the core.
|
|
82
|
+
- For tests and introspection, `codex.native.preview_config(config_overrides=..., load_default_config=...)` returns a compact snapshot of the effective configuration.
|
|
83
|
+
|
|
84
|
+
## Troubleshooting
|
|
85
|
+
|
|
86
|
+
- “codex_native extension not installed”
|
|
87
|
+
- Install with `pip install codex-python` (wheel) or build locally (see below).
|
|
88
|
+
- maturin develop fails without a virtualenv
|
|
89
|
+
- Use `python -m venv .venv && source .venv/bin/activate` (or conda), or run `make dev-native` which falls back to build+pip install when no venv is present.
|
|
90
|
+
|
|
91
|
+
## Developing
|
|
92
|
+
|
|
93
|
+
Prerequisites
|
|
94
|
+
- Python 3.12/3.13
|
|
95
|
+
- Rust toolchain (cargo)
|
|
96
|
+
- maturin (for native builds)
|
|
97
|
+
- uv (optional, for fast Python builds and dev tooling)
|
|
98
|
+
|
|
99
|
+
Common tasks
|
|
100
|
+
- Lint: `make lint` (ruff + mypy)
|
|
101
|
+
- Test: `make test` (pytest)
|
|
102
|
+
- Format: `make fmt`
|
|
103
|
+
- Build native locally: `make dev-native`
|
|
104
|
+
- Generate protocol types from upstream: `make gen-protocol`
|
|
105
|
+
|
|
106
|
+
Protocol types
|
|
107
|
+
- `make gen-protocol` generates TS types (via Codex or cargo) into `.generated/ts` and then writes Pydantic models to `codex/protocol/types.py`.
|
|
108
|
+
- Generated models use `model_config = ConfigDict(extra='allow')` and place it at the end of each class.
|
|
109
|
+
|
|
110
|
+
Releasing
|
|
111
|
+
- Bump `codex/__init__.py` and `crates/codex_native/Cargo.toml` versions.
|
|
112
|
+
- Update `CHANGELOG.md`.
|
|
113
|
+
- Tag and push: `git tag -a vX.Y.Z -m "codex-python X.Y.Z" && git push origin vX.Y.Z`.
|
|
114
|
+
- GitHub Actions (publish.yml) builds native wheels across platforms and an sdist, then publishes them via Trusted Publishing (OIDC).
|
|
115
|
+
|
|
116
|
+
Project layout
|
|
117
|
+
```
|
|
118
|
+
.
|
|
119
|
+
├── codex/ # Python package
|
|
120
|
+
├── crates/codex_native/ # PyO3 native extension
|
|
121
|
+
├── scripts/ # generators and helpers
|
|
122
|
+
├── .github/workflows/ # CI, publish, native wheels
|
|
123
|
+
└── Makefile # common tasks
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Links
|
|
127
|
+
- Codex repo: https://github.com/openai/codex
|
|
128
|
+
- uv: https://docs.astral.sh/uv/
|
|
129
|
+
- maturin: https://www.maturin.rs/
|
|
130
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# codex-python
|
|
2
|
+
|
|
3
|
+
Native Python bindings for Codex (in‑process execution). Ships as a single package (`codex-python`) with platform wheels that include the native extension.
|
|
4
|
+
|
|
5
|
+
- Python: 3.12–3.13 (CI also attempts 3.14)
|
|
6
|
+
- Import name: `codex`
|
|
7
|
+
- PyPI: https://pypi.org/project/codex-python/
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
pip install codex-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If there’s no prebuilt wheel for your platform/Python, pip will build from source. You’ll need a Rust toolchain and maturin; see “Developing” below.
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
Run a prompt and collect structured events (typed):
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
from codex.api import run_exec, CodexClient
|
|
23
|
+
from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
|
|
24
|
+
|
|
25
|
+
cfg = CodexConfig(
|
|
26
|
+
model="gpt-5",
|
|
27
|
+
model_provider="openai",
|
|
28
|
+
approval_policy=ApprovalPolicy.ON_REQUEST,
|
|
29
|
+
sandbox_mode=SandboxMode.WORKSPACE_WRITE,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# One-shot
|
|
33
|
+
events = run_exec("Explain this repo", config=cfg)
|
|
34
|
+
|
|
35
|
+
# Conversation (streaming)
|
|
36
|
+
client = CodexClient(config=cfg)
|
|
37
|
+
for ev in client.start_conversation("Add a smoke test"):
|
|
38
|
+
print(ev.id, ev.msg)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Notes
|
|
42
|
+
- `Event.msg` is typed as a union `EventMsg` (also available at `codex.EventMsg`).
|
|
43
|
+
- For raw dict streaming from the native layer, use `codex.native.start_exec_stream`.
|
|
44
|
+
|
|
45
|
+
## Configuration (Pydantic)
|
|
46
|
+
|
|
47
|
+
Use `CodexConfig` to pass overrides mirrored from Rust `ConfigOverrides`.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
from codex.config import CodexConfig, ApprovalPolicy, SandboxMode
|
|
51
|
+
|
|
52
|
+
cfg = CodexConfig(
|
|
53
|
+
model="gpt-5",
|
|
54
|
+
model_provider="openai",
|
|
55
|
+
approval_policy=ApprovalPolicy.ON_REQUEST,
|
|
56
|
+
sandbox_mode=SandboxMode.WORKSPACE_WRITE,
|
|
57
|
+
cwd="/path/to/project",
|
|
58
|
+
include_apply_patch_tool=True,
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- `CodexConfig.to_dict()` emits only fields you set, with enums serialized to kebab‑case strings expected by the core.
|
|
63
|
+
- For tests and introspection, `codex.native.preview_config(config_overrides=..., load_default_config=...)` returns a compact snapshot of the effective configuration.
|
|
64
|
+
|
|
65
|
+
## Troubleshooting
|
|
66
|
+
|
|
67
|
+
- “codex_native extension not installed”
|
|
68
|
+
- Install with `pip install codex-python` (wheel) or build locally (see below).
|
|
69
|
+
- maturin develop fails without a virtualenv
|
|
70
|
+
- Use `python -m venv .venv && source .venv/bin/activate` (or conda), or run `make dev-native` which falls back to build+pip install when no venv is present.
|
|
71
|
+
|
|
72
|
+
## Developing
|
|
73
|
+
|
|
74
|
+
Prerequisites
|
|
75
|
+
- Python 3.12/3.13
|
|
76
|
+
- Rust toolchain (cargo)
|
|
77
|
+
- maturin (for native builds)
|
|
78
|
+
- uv (optional, for fast Python builds and dev tooling)
|
|
79
|
+
|
|
80
|
+
Common tasks
|
|
81
|
+
- Lint: `make lint` (ruff + mypy)
|
|
82
|
+
- Test: `make test` (pytest)
|
|
83
|
+
- Format: `make fmt`
|
|
84
|
+
- Build native locally: `make dev-native`
|
|
85
|
+
- Generate protocol types from upstream: `make gen-protocol`
|
|
86
|
+
|
|
87
|
+
Protocol types
|
|
88
|
+
- `make gen-protocol` generates TS types (via Codex or cargo) into `.generated/ts` and then writes Pydantic models to `codex/protocol/types.py`.
|
|
89
|
+
- Generated models use `model_config = ConfigDict(extra='allow')` and place it at the end of each class.
|
|
90
|
+
|
|
91
|
+
Releasing
|
|
92
|
+
- Bump `codex/__init__.py` and `crates/codex_native/Cargo.toml` versions.
|
|
93
|
+
- Update `CHANGELOG.md`.
|
|
94
|
+
- Tag and push: `git tag -a vX.Y.Z -m "codex-python X.Y.Z" && git push origin vX.Y.Z`.
|
|
95
|
+
- GitHub Actions (publish.yml) builds native wheels across platforms and an sdist, then publishes them via Trusted Publishing (OIDC).
|
|
96
|
+
|
|
97
|
+
Project layout
|
|
98
|
+
```
|
|
99
|
+
.
|
|
100
|
+
├── codex/ # Python package
|
|
101
|
+
├── crates/codex_native/ # PyO3 native extension
|
|
102
|
+
├── scripts/ # generators and helpers
|
|
103
|
+
├── .github/workflows/ # CI, publish, native wheels
|
|
104
|
+
└── Makefile # common tasks
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Links
|
|
108
|
+
- Codex repo: https://github.com/openai/codex
|
|
109
|
+
- uv: https://docs.astral.sh/uv/
|
|
110
|
+
- maturin: https://www.maturin.rs/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""codex
|
|
2
|
+
|
|
3
|
+
Python interface for the Codex CLI.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from codex import run_exec
|
|
7
|
+
events = run_exec("explain this codebase to me")
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .api import (
|
|
11
|
+
CodexClient,
|
|
12
|
+
CodexError,
|
|
13
|
+
CodexNativeError,
|
|
14
|
+
Conversation,
|
|
15
|
+
run_exec,
|
|
16
|
+
)
|
|
17
|
+
from .config import CodexConfig
|
|
18
|
+
from .event import Event
|
|
19
|
+
from .protocol.types import EventMsg
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"__version__",
|
|
23
|
+
"CodexError",
|
|
24
|
+
"CodexNativeError",
|
|
25
|
+
"CodexClient",
|
|
26
|
+
"Conversation",
|
|
27
|
+
"run_exec",
|
|
28
|
+
"Event",
|
|
29
|
+
"EventMsg",
|
|
30
|
+
"CodexConfig",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# Package version. Kept in sync with Cargo.toml via CI before builds.
|
|
34
|
+
__version__ = "0.2.7"
|
|
@@ -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
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, cast
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ApprovalPolicy(str, Enum):
|
|
10
|
+
"""Approval policy for executing shell commands.
|
|
11
|
+
|
|
12
|
+
Matches Rust enum `AskForApproval` (serde kebab-case):
|
|
13
|
+
- "untrusted": auto-approve safe read-only commands, ask otherwise
|
|
14
|
+
- "on-failure": sandbox by default; ask only if the sandboxed run fails
|
|
15
|
+
- "on-request": model decides (default)
|
|
16
|
+
- "never": never ask the user
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
UNTRUSTED = "untrusted"
|
|
20
|
+
ON_FAILURE = "on-failure"
|
|
21
|
+
ON_REQUEST = "on-request"
|
|
22
|
+
NEVER = "never"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SandboxMode(str, Enum):
|
|
26
|
+
"""High-level sandbox mode override.
|
|
27
|
+
|
|
28
|
+
Matches Rust enum `SandboxMode` (serde kebab-case):
|
|
29
|
+
- "read-only"
|
|
30
|
+
- "workspace-write"
|
|
31
|
+
- "danger-full-access"
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
READ_ONLY = "read-only"
|
|
35
|
+
WORKSPACE_WRITE = "workspace-write"
|
|
36
|
+
DANGER_FULL_ACCESS = "danger-full-access"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class CodexConfig(BaseModel):
|
|
40
|
+
"""Configuration overrides for Codex.
|
|
41
|
+
|
|
42
|
+
This mirrors `codex_core::config::ConfigOverrides` and is intentionally
|
|
43
|
+
conservative: only values present (not None) are passed to the native core.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Model selection
|
|
47
|
+
model: str | None = Field(default=None, description="Model slug, e.g. 'gpt-5' or 'o3'.")
|
|
48
|
+
model_provider: str | None = Field(
|
|
49
|
+
default=None, description="Provider key from config, e.g. 'openai'."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Safety/Execution
|
|
53
|
+
approval_policy: ApprovalPolicy | None = Field(default=None)
|
|
54
|
+
sandbox_mode: SandboxMode | None = Field(default=None)
|
|
55
|
+
|
|
56
|
+
# Environment
|
|
57
|
+
cwd: str | None = Field(default=None, description="Working directory for the session.")
|
|
58
|
+
config_profile: str | None = Field(
|
|
59
|
+
default=None, description="Config profile key to use (from profiles.*)."
|
|
60
|
+
)
|
|
61
|
+
codex_linux_sandbox_exe: str | None = Field(
|
|
62
|
+
default=None, description="Absolute path to codex-linux-sandbox (Linux only)."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# UX / features
|
|
66
|
+
base_instructions: str | None = Field(default=None, description="Override base instructions.")
|
|
67
|
+
include_plan_tool: bool | None = Field(default=None)
|
|
68
|
+
include_apply_patch_tool: bool | None = Field(default=None)
|
|
69
|
+
include_view_image_tool: bool | None = Field(default=None)
|
|
70
|
+
show_raw_agent_reasoning: bool | None = Field(default=None)
|
|
71
|
+
tools_web_search_request: bool | None = Field(default=None)
|
|
72
|
+
|
|
73
|
+
def to_dict(self) -> dict[str, Any]:
|
|
74
|
+
"""Return overrides as a plain dict with None values removed.
|
|
75
|
+
|
|
76
|
+
Enum fields are emitted as their string values.
|
|
77
|
+
"""
|
|
78
|
+
return cast(dict[str, Any], self.model_dump(exclude_none=True))
|
|
79
|
+
|
|
80
|
+
# Pydantic v2 config. `use_enum_values=True` ensures enums dump as strings.
|
|
81
|
+
# Place at end of class, extra='allow' per style.
|
|
82
|
+
model_config = ConfigDict(extra="allow", validate_assignment=True, use_enum_values=True)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from pydantic.config import ConfigDict
|
|
5
|
+
|
|
6
|
+
from .protocol.types import EventMsg
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Event(BaseModel):
|
|
10
|
+
"""Protocol event envelope with typed `msg` (union of EventMsg_*)."""
|
|
11
|
+
|
|
12
|
+
id: str
|
|
13
|
+
msg: EventMsg
|
|
14
|
+
|
|
15
|
+
# Allow forward compatibility with additional envelope fields
|
|
16
|
+
model_config = ConfigDict(extra="allow")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any, cast
|
|
2
|
+
|
|
3
|
+
from codex_native import preview_config as _preview_config
|
|
4
|
+
from codex_native import run_exec_collect as _run_exec_collect
|
|
5
|
+
from codex_native import start_exec_stream as _start_exec_stream
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def run_exec_collect(
|
|
9
|
+
prompt: str,
|
|
10
|
+
*,
|
|
11
|
+
config_overrides: dict[str, Any] | None = None,
|
|
12
|
+
load_default_config: bool = True,
|
|
13
|
+
) -> list[dict]:
|
|
14
|
+
"""Run Codex natively (in‑process) and return a list of events as dicts."""
|
|
15
|
+
return cast(list[dict], _run_exec_collect(prompt, config_overrides, load_default_config))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def start_exec_stream(
|
|
19
|
+
prompt: str,
|
|
20
|
+
*,
|
|
21
|
+
config_overrides: dict[str, Any] | None = None,
|
|
22
|
+
load_default_config: bool = True,
|
|
23
|
+
) -> Any:
|
|
24
|
+
"""Return a native streaming iterator over Codex events (dicts)."""
|
|
25
|
+
return _start_exec_stream(prompt, config_overrides, load_default_config)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def preview_config(
|
|
29
|
+
*, config_overrides: dict[str, Any] | None = None, load_default_config: bool = True
|
|
30
|
+
) -> dict:
|
|
31
|
+
"""Return an effective config snapshot (selected fields) from native.
|
|
32
|
+
|
|
33
|
+
Useful for tests to validate override mapping without running Codex.
|
|
34
|
+
"""
|
|
35
|
+
return cast(dict, _preview_config(config_overrides, load_default_config))
|