codex-python 0.3.0__tar.gz → 1.0.0b2__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 (34) hide show
  1. codex_python-1.0.0b2/PKG-INFO +154 -0
  2. codex_python-1.0.0b2/README.md +135 -0
  3. codex_python-1.0.0b2/codex/__init__.py +85 -0
  4. codex_python-1.0.0b2/codex/_binary.py +42 -0
  5. codex_python-1.0.0b2/codex/codex.py +26 -0
  6. codex_python-1.0.0b2/codex/errors.py +17 -0
  7. codex_python-1.0.0b2/codex/events.py +66 -0
  8. codex_python-1.0.0b2/codex/exec.py +313 -0
  9. codex_python-1.0.0b2/codex/items.py +110 -0
  10. codex_python-1.0.0b2/codex/options.py +57 -0
  11. codex_python-1.0.0b2/codex/output_schema_file.py +34 -0
  12. codex_python-1.0.0b2/codex/thread.py +170 -0
  13. codex_python-1.0.0b2/codex/vendor/.gitkeep +0 -0
  14. codex_python-1.0.0b2/crates/codex_native/Cargo.lock +204 -0
  15. codex_python-1.0.0b2/crates/codex_native/Cargo.toml +17 -0
  16. codex_python-1.0.0b2/crates/codex_native/codex/__init__.py +8 -0
  17. codex_python-1.0.0b2/crates/codex_native/src/lib.rs +12 -0
  18. {codex_python-0.3.0 → codex_python-1.0.0b2}/pyproject.toml +5 -6
  19. codex_python-0.3.0/PKG-INFO +0 -358
  20. codex_python-0.3.0/README.md +0 -338
  21. codex_python-0.3.0/codex/__init__.py +0 -31
  22. codex_python-0.3.0/codex/client.py +0 -410
  23. codex_python-0.3.0/codex/config.py +0 -326
  24. codex_python-0.3.0/codex/event.py +0 -29
  25. codex_python-0.3.0/codex/exec.py +0 -138
  26. codex_python-0.3.0/codex/native.py +0 -85
  27. codex_python-0.3.0/codex/protocol/_base_model.py +0 -8
  28. codex_python-0.3.0/codex/protocol/types.py +0 -1561
  29. codex_python-0.3.0/crates/codex_native/Cargo.lock +0 -3600
  30. codex_python-0.3.0/crates/codex_native/Cargo.toml +0 -48
  31. codex_python-0.3.0/crates/codex_native/src/bin/protocol_schema.rs +0 -170
  32. codex_python-0.3.0/crates/codex_native/src/lib.rs +0 -1176
  33. {codex_python-0.3.0 → codex_python-1.0.0b2}/LICENSE +0 -0
  34. {codex_python-0.3.0 → codex_python-1.0.0b2}/codex/py.typed +0 -0
@@ -0,0 +1,154 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-python
3
+ Version: 1.0.0b2
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
+ License-File: LICENSE
11
+ Summary: Python SDK for Codex CLI with bundled platform binaries
12
+ Keywords: codex,sdk,cli,automation
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
+ Project-URL: Homepage, https://github.com/gersmann/codex-python
16
+ Project-URL: Issues, https://github.com/gersmann/codex-python/issues
17
+ Project-URL: Repository, https://github.com/gersmann/codex-python
18
+
19
+ # codex-python
20
+
21
+ Python SDK for Codex with bundled `codex` binaries inside platform wheels.
22
+
23
+ The SDK mirrors the TypeScript SDK behavior:
24
+ - Spawns `codex exec --experimental-json`
25
+ - Streams JSONL events
26
+ - Supports thread resume, structured output schemas, images, sandbox/model options
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install codex-python
32
+ ```
33
+
34
+ ## Quickstart
35
+
36
+ ```python
37
+ from codex import Codex
38
+
39
+ client = Codex()
40
+ thread = client.start_thread()
41
+
42
+ result = thread.run("Diagnose the failing tests and propose a fix")
43
+ print(result.final_response)
44
+ print(result.items)
45
+ ```
46
+
47
+ ## Streaming
48
+
49
+ ```python
50
+ from codex import Codex
51
+
52
+ client = Codex()
53
+ thread = client.start_thread()
54
+
55
+ stream = thread.run_streamed("Investigate this bug")
56
+ for event in stream.events:
57
+ if event["type"] == "item.completed":
58
+ print(event["item"])
59
+ elif event["type"] == "turn.completed":
60
+ print(event["usage"])
61
+ ```
62
+
63
+ ## Structured output
64
+
65
+ ```python
66
+ from codex import Codex, TurnOptions
67
+
68
+ schema = {
69
+ "type": "object",
70
+ "properties": {"summary": {"type": "string"}},
71
+ "required": ["summary"],
72
+ "additionalProperties": False,
73
+ }
74
+
75
+ client = Codex()
76
+ thread = client.start_thread()
77
+ result = thread.run("Summarize repository status", TurnOptions(output_schema=schema))
78
+ print(result.final_response)
79
+ ```
80
+
81
+ ## Input with local images
82
+
83
+ ```python
84
+ from codex import Codex
85
+
86
+ client = Codex()
87
+ thread = client.start_thread()
88
+ result = thread.run(
89
+ [
90
+ {"type": "text", "text": "Describe these screenshots"},
91
+ {"type": "local_image", "path": "./ui.png"},
92
+ {"type": "local_image", "path": "./diagram.jpg"},
93
+ ]
94
+ )
95
+ ```
96
+
97
+ ## Resume a thread
98
+
99
+ ```python
100
+ from codex import Codex
101
+
102
+ client = Codex()
103
+ thread = client.resume_thread("thread_123")
104
+ thread.run("Continue from previous context")
105
+ ```
106
+
107
+ ## Options
108
+
109
+ - `CodexOptions`: `codex_path_override`, `base_url`, `api_key`, `config`, `env`
110
+ - `ThreadOptions`: `model`, `sandbox_mode`, `working_directory`, `skip_git_repo_check`, `model_reasoning_effort`, `network_access_enabled`, `web_search_mode`, `web_search_enabled`, `approval_policy`, `additional_directories`
111
+ - `TurnOptions`: `output_schema`, `signal`
112
+
113
+ ## Cancellation
114
+
115
+ ```python
116
+ import threading
117
+
118
+ from codex import Codex, TurnOptions
119
+
120
+ cancel = threading.Event()
121
+
122
+ client = Codex()
123
+ thread = client.start_thread()
124
+ stream = thread.run_streamed("Long running task", TurnOptions(signal=cancel))
125
+
126
+ cancel.set()
127
+ for event in stream.events:
128
+ print(event)
129
+ ```
130
+
131
+ ## Bundled binary behavior
132
+
133
+ By default, the SDK resolves the bundled binary at:
134
+
135
+ `codex/vendor/<target-triple>/codex/{codex|codex.exe}`
136
+
137
+ If the bundled binary is not present (for example in a source checkout), the SDK falls back to
138
+ `codex` on `PATH`.
139
+
140
+ You can always override with `CodexOptions(codex_path_override=...)`.
141
+
142
+ ## Development
143
+
144
+ ```bash
145
+ make lint
146
+ make test
147
+ ```
148
+
149
+ If you want to test vendored-binary behavior locally, fetch binaries into `codex/vendor`:
150
+
151
+ ```bash
152
+ python scripts/fetch_codex_binary.py --target-triple x86_64-unknown-linux-musl
153
+ ```
154
+
@@ -0,0 +1,135 @@
1
+ # codex-python
2
+
3
+ Python SDK for Codex with bundled `codex` binaries inside platform wheels.
4
+
5
+ The SDK mirrors the TypeScript SDK behavior:
6
+ - Spawns `codex exec --experimental-json`
7
+ - Streams JSONL events
8
+ - Supports thread resume, structured output schemas, images, sandbox/model options
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pip install codex-python
14
+ ```
15
+
16
+ ## Quickstart
17
+
18
+ ```python
19
+ from codex import Codex
20
+
21
+ client = Codex()
22
+ thread = client.start_thread()
23
+
24
+ result = thread.run("Diagnose the failing tests and propose a fix")
25
+ print(result.final_response)
26
+ print(result.items)
27
+ ```
28
+
29
+ ## Streaming
30
+
31
+ ```python
32
+ from codex import Codex
33
+
34
+ client = Codex()
35
+ thread = client.start_thread()
36
+
37
+ stream = thread.run_streamed("Investigate this bug")
38
+ for event in stream.events:
39
+ if event["type"] == "item.completed":
40
+ print(event["item"])
41
+ elif event["type"] == "turn.completed":
42
+ print(event["usage"])
43
+ ```
44
+
45
+ ## Structured output
46
+
47
+ ```python
48
+ from codex import Codex, TurnOptions
49
+
50
+ schema = {
51
+ "type": "object",
52
+ "properties": {"summary": {"type": "string"}},
53
+ "required": ["summary"],
54
+ "additionalProperties": False,
55
+ }
56
+
57
+ client = Codex()
58
+ thread = client.start_thread()
59
+ result = thread.run("Summarize repository status", TurnOptions(output_schema=schema))
60
+ print(result.final_response)
61
+ ```
62
+
63
+ ## Input with local images
64
+
65
+ ```python
66
+ from codex import Codex
67
+
68
+ client = Codex()
69
+ thread = client.start_thread()
70
+ result = thread.run(
71
+ [
72
+ {"type": "text", "text": "Describe these screenshots"},
73
+ {"type": "local_image", "path": "./ui.png"},
74
+ {"type": "local_image", "path": "./diagram.jpg"},
75
+ ]
76
+ )
77
+ ```
78
+
79
+ ## Resume a thread
80
+
81
+ ```python
82
+ from codex import Codex
83
+
84
+ client = Codex()
85
+ thread = client.resume_thread("thread_123")
86
+ thread.run("Continue from previous context")
87
+ ```
88
+
89
+ ## Options
90
+
91
+ - `CodexOptions`: `codex_path_override`, `base_url`, `api_key`, `config`, `env`
92
+ - `ThreadOptions`: `model`, `sandbox_mode`, `working_directory`, `skip_git_repo_check`, `model_reasoning_effort`, `network_access_enabled`, `web_search_mode`, `web_search_enabled`, `approval_policy`, `additional_directories`
93
+ - `TurnOptions`: `output_schema`, `signal`
94
+
95
+ ## Cancellation
96
+
97
+ ```python
98
+ import threading
99
+
100
+ from codex import Codex, TurnOptions
101
+
102
+ cancel = threading.Event()
103
+
104
+ client = Codex()
105
+ thread = client.start_thread()
106
+ stream = thread.run_streamed("Long running task", TurnOptions(signal=cancel))
107
+
108
+ cancel.set()
109
+ for event in stream.events:
110
+ print(event)
111
+ ```
112
+
113
+ ## Bundled binary behavior
114
+
115
+ By default, the SDK resolves the bundled binary at:
116
+
117
+ `codex/vendor/<target-triple>/codex/{codex|codex.exe}`
118
+
119
+ If the bundled binary is not present (for example in a source checkout), the SDK falls back to
120
+ `codex` on `PATH`.
121
+
122
+ You can always override with `CodexOptions(codex_path_override=...)`.
123
+
124
+ ## Development
125
+
126
+ ```bash
127
+ make lint
128
+ make test
129
+ ```
130
+
131
+ If you want to test vendored-binary behavior locally, fetch binaries into `codex/vendor`:
132
+
133
+ ```bash
134
+ python scripts/fetch_codex_binary.py --target-triple x86_64-unknown-linux-musl
135
+ ```
@@ -0,0 +1,85 @@
1
+ """Python SDK for embedding Codex via the bundled CLI binary."""
2
+
3
+ from codex.codex import Codex
4
+ from codex.errors import CodexError, CodexExecError, CodexParseError, ThreadRunError
5
+ from codex.events import (
6
+ ItemCompletedEvent,
7
+ ItemStartedEvent,
8
+ ItemUpdatedEvent,
9
+ ThreadError,
10
+ ThreadErrorEvent,
11
+ ThreadEvent,
12
+ ThreadStartedEvent,
13
+ TurnCompletedEvent,
14
+ TurnFailedEvent,
15
+ TurnStartedEvent,
16
+ Usage,
17
+ )
18
+ from codex.items import (
19
+ AgentMessageItem,
20
+ CommandExecutionItem,
21
+ ErrorItem,
22
+ FileChangeItem,
23
+ McpToolCallItem,
24
+ ReasoningItem,
25
+ ThreadItem,
26
+ TodoListItem,
27
+ WebSearchItem,
28
+ )
29
+ from codex.options import (
30
+ ApprovalMode,
31
+ CancelSignal,
32
+ CodexConfigObject,
33
+ CodexConfigValue,
34
+ CodexOptions,
35
+ ModelReasoningEffort,
36
+ SandboxMode,
37
+ ThreadOptions,
38
+ TurnOptions,
39
+ WebSearchMode,
40
+ )
41
+ from codex.thread import Input, RunResult, RunStreamedResult, Thread, UserInput
42
+ .0.0-beta.2"
43
+
44
+ __all__ = [
45
+ "Codex",
46
+ "CodexError",
47
+ "CodexExecError",
48
+ "CodexParseError",
49
+ "ThreadRunError",
50
+ "Thread",
51
+ "RunResult",
52
+ "RunStreamedResult",
53
+ "Input",
54
+ "UserInput",
55
+ "CodexOptions",
56
+ "ThreadOptions",
57
+ "TurnOptions",
58
+ "ApprovalMode",
59
+ "SandboxMode",
60
+ "ModelReasoningEffort",
61
+ "WebSearchMode",
62
+ "CodexConfigValue",
63
+ "CodexConfigObject",
64
+ "CancelSignal",
65
+ "ThreadEvent",
66
+ "ThreadStartedEvent",
67
+ "TurnStartedEvent",
68
+ "TurnCompletedEvent",
69
+ "TurnFailedEvent",
70
+ "ItemStartedEvent",
71
+ "ItemUpdatedEvent",
72
+ "ItemCompletedEvent",
73
+ "ThreadError",
74
+ "ThreadErrorEvent",
75
+ "Usage",
76
+ "ThreadItem",
77
+ "AgentMessageItem",
78
+ "ReasoningItem",
79
+ "CommandExecutionItem",
80
+ "FileChangeItem",
81
+ "McpToolCallItem",
82
+ "WebSearchItem",
83
+ "TodoListItem",
84
+ "ErrorItem",
85
+ ]
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ import platform
4
+ from pathlib import Path
5
+
6
+ from codex.errors import CodexExecError
7
+
8
+
9
+ def resolve_target_triple(system_name: str | None = None, machine_name: str | None = None) -> str:
10
+ system = (system_name or platform.system()).lower()
11
+ machine = (machine_name or platform.machine()).lower()
12
+
13
+ if system in {"linux", "android"}:
14
+ if machine in {"x86_64", "amd64"}:
15
+ return "x86_64-unknown-linux-musl"
16
+ if machine in {"aarch64", "arm64"}:
17
+ return "aarch64-unknown-linux-musl"
18
+ elif system == "darwin":
19
+ if machine in {"x86_64", "amd64"}:
20
+ return "x86_64-apple-darwin"
21
+ if machine in {"aarch64", "arm64"}:
22
+ return "aarch64-apple-darwin"
23
+ elif system in {"windows", "win32"}:
24
+ if machine in {"x86_64", "amd64"}:
25
+ return "x86_64-pc-windows-msvc"
26
+ if machine in {"aarch64", "arm64"}:
27
+ return "aarch64-pc-windows-msvc"
28
+
29
+ raise CodexExecError(f"Unsupported platform: {system} ({machine})")
30
+
31
+
32
+ def bundled_codex_path(target_triple: str | None = None) -> Path:
33
+ triple = target_triple or resolve_target_triple()
34
+ package_root = Path(__file__).resolve().parent
35
+ binary_name = "codex.exe" if "windows" in triple else "codex"
36
+ binary_path = package_root / "vendor" / triple / "codex" / binary_name
37
+ if not binary_path.exists():
38
+ raise CodexExecError(
39
+ "Bundled codex binary not found at "
40
+ f"{binary_path}. Install a platform wheel or provide codex_path_override."
41
+ )
42
+ return binary_path
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ from codex.exec import CodexExec
4
+ from codex.options import CodexOptions, ThreadOptions
5
+ from codex.thread import Thread
6
+
7
+
8
+ class Codex:
9
+ """Main entrypoint for interacting with Codex threads."""
10
+
11
+ def __init__(self, options: CodexOptions | None = None) -> None:
12
+ resolved = options or CodexOptions()
13
+ self._exec = CodexExec(
14
+ resolved.codex_path_override,
15
+ env_override=resolved.env,
16
+ config_overrides=resolved.config,
17
+ )
18
+ self._options = resolved
19
+
20
+ def start_thread(self, options: ThreadOptions | None = None) -> Thread:
21
+ return Thread(self._exec, self._options, options or ThreadOptions())
22
+
23
+ def resume_thread(self, id: str, options: ThreadOptions | None = None) -> Thread:
24
+ if id == "":
25
+ raise ValueError("id must be non-empty")
26
+ return Thread(self._exec, self._options, options or ThreadOptions(), id)
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class CodexError(RuntimeError):
5
+ """Base error for the Python Codex SDK."""
6
+
7
+
8
+ class CodexExecError(CodexError):
9
+ """Raised when the Codex CLI process fails."""
10
+
11
+
12
+ class CodexParseError(CodexError):
13
+ """Raised when streaming JSONL events cannot be parsed."""
14
+
15
+
16
+ class ThreadRunError(CodexError):
17
+ """Raised when a run or stream fails before turn completion."""
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal, TypedDict
4
+
5
+ from codex.items import ThreadItem
6
+
7
+
8
+ class ThreadStartedEvent(TypedDict):
9
+ type: Literal["thread.started"]
10
+ thread_id: str
11
+
12
+
13
+ class TurnStartedEvent(TypedDict):
14
+ type: Literal["turn.started"]
15
+
16
+
17
+ class Usage(TypedDict):
18
+ input_tokens: int
19
+ cached_input_tokens: int
20
+ output_tokens: int
21
+
22
+
23
+ class TurnCompletedEvent(TypedDict):
24
+ type: Literal["turn.completed"]
25
+ usage: Usage
26
+
27
+
28
+ class ThreadError(TypedDict):
29
+ message: str
30
+
31
+
32
+ class TurnFailedEvent(TypedDict):
33
+ type: Literal["turn.failed"]
34
+ error: ThreadError
35
+
36
+
37
+ class ItemStartedEvent(TypedDict):
38
+ type: Literal["item.started"]
39
+ item: ThreadItem
40
+
41
+
42
+ class ItemUpdatedEvent(TypedDict):
43
+ type: Literal["item.updated"]
44
+ item: ThreadItem
45
+
46
+
47
+ class ItemCompletedEvent(TypedDict):
48
+ type: Literal["item.completed"]
49
+ item: ThreadItem
50
+
51
+
52
+ class ThreadErrorEvent(TypedDict):
53
+ type: Literal["error"]
54
+ message: str
55
+
56
+
57
+ ThreadEvent = (
58
+ ThreadStartedEvent
59
+ | TurnStartedEvent
60
+ | TurnCompletedEvent
61
+ | TurnFailedEvent
62
+ | ItemStartedEvent
63
+ | ItemUpdatedEvent
64
+ | ItemCompletedEvent
65
+ | ThreadErrorEvent
66
+ )