codex-python 0.1.0__tar.gz → 0.1.2__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.0 → codex_python-0.1.2}/.github/workflows/publish.yml +3 -4
- {codex_python-0.1.0 → codex_python-0.1.2}/.gitignore +11 -0
- codex_python-0.1.2/Makefile +66 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/PKG-INFO +31 -3
- {codex_python-0.1.0 → codex_python-0.1.2}/README.md +29 -2
- {codex_python-0.1.0 → codex_python-0.1.2}/codex/__init__.py +1 -1
- {codex_python-0.1.0 → codex_python-0.1.2}/codex/api.py +17 -1
- codex_python-0.1.2/codex/protocol/runtime.py +80 -0
- codex_python-0.1.2/codex/protocol/types.py +1595 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/pyproject.toml +5 -1
- codex_python-0.1.2/scripts/generate_protocol_py.py +353 -0
- codex_python-0.1.2/test/AddConversationListenerParams.ts +6 -0
- codex_python-0.1.2/test/AddConversationSubscriptionResponse.ts +5 -0
- codex_python-0.1.2/test/AgentMessageDeltaEvent.ts +5 -0
- codex_python-0.1.2/test/AgentMessageEvent.ts +5 -0
- codex_python-0.1.2/test/AgentReasoningDeltaEvent.ts +5 -0
- codex_python-0.1.2/test/AgentReasoningEvent.ts +5 -0
- codex_python-0.1.2/test/AgentReasoningRawContentDeltaEvent.ts +5 -0
- codex_python-0.1.2/test/AgentReasoningRawContentEvent.ts +5 -0
- codex_python-0.1.2/test/AgentReasoningSectionBreakEvent.ts +5 -0
- codex_python-0.1.2/test/Annotations.ts +9 -0
- codex_python-0.1.2/test/ApplyPatchApprovalParams.ts +21 -0
- codex_python-0.1.2/test/ApplyPatchApprovalRequestEvent.ts +18 -0
- codex_python-0.1.2/test/ApplyPatchApprovalResponse.ts +6 -0
- codex_python-0.1.2/test/ArchiveConversationParams.ts +9 -0
- codex_python-0.1.2/test/ArchiveConversationResponse.ts +5 -0
- codex_python-0.1.2/test/AskForApproval.ts +9 -0
- codex_python-0.1.2/test/AudioContent.ts +9 -0
- codex_python-0.1.2/test/AuthMode.ts +5 -0
- codex_python-0.1.2/test/AuthStatusChangeNotification.ts +10 -0
- codex_python-0.1.2/test/BackgroundEventEvent.ts +5 -0
- codex_python-0.1.2/test/BlobResourceContents.ts +5 -0
- codex_python-0.1.2/test/CallToolResult.ts +10 -0
- codex_python-0.1.2/test/CancelLoginChatGptParams.ts +5 -0
- codex_python-0.1.2/test/CancelLoginChatGptResponse.ts +5 -0
- codex_python-0.1.2/test/ClientRequest.ts +22 -0
- codex_python-0.1.2/test/ContentBlock.ts +10 -0
- codex_python-0.1.2/test/ContentItem.ts +5 -0
- codex_python-0.1.2/test/ConversationHistoryResponseEvent.ts +11 -0
- codex_python-0.1.2/test/ConversationId.ts +5 -0
- codex_python-0.1.2/test/ConversationSummary.ts +10 -0
- codex_python-0.1.2/test/CustomPrompt.ts +5 -0
- codex_python-0.1.2/test/EmbeddedResource.ts +13 -0
- codex_python-0.1.2/test/EmbeddedResourceResource.ts +7 -0
- codex_python-0.1.2/test/ErrorEvent.ts +5 -0
- codex_python-0.1.2/test/EventMsg.ts +41 -0
- codex_python-0.1.2/test/ExecApprovalRequestEvent.ts +21 -0
- codex_python-0.1.2/test/ExecCommandApprovalParams.ts +11 -0
- codex_python-0.1.2/test/ExecCommandApprovalResponse.ts +6 -0
- codex_python-0.1.2/test/ExecCommandBeginEvent.ts +18 -0
- codex_python-0.1.2/test/ExecCommandEndEvent.ts +33 -0
- codex_python-0.1.2/test/ExecCommandOutputDeltaEvent.ts +18 -0
- codex_python-0.1.2/test/ExecOneOffCommandParams.ts +23 -0
- codex_python-0.1.2/test/ExecOutputStream.ts +5 -0
- codex_python-0.1.2/test/FileChange.ts +5 -0
- codex_python-0.1.2/test/FunctionCallOutputPayload.ts +5 -0
- codex_python-0.1.2/test/GetAuthStatusParams.ts +13 -0
- codex_python-0.1.2/test/GetAuthStatusResponse.ts +6 -0
- codex_python-0.1.2/test/GetHistoryEntryResponseEvent.ts +10 -0
- codex_python-0.1.2/test/GetUserAgentResponse.ts +5 -0
- codex_python-0.1.2/test/GetUserSavedConfigResponse.ts +6 -0
- codex_python-0.1.2/test/GitDiffToRemoteParams.ts +5 -0
- codex_python-0.1.2/test/GitDiffToRemoteResponse.ts +6 -0
- codex_python-0.1.2/test/GitSha.ts +5 -0
- codex_python-0.1.2/test/HistoryEntry.ts +5 -0
- codex_python-0.1.2/test/ImageContent.ts +9 -0
- codex_python-0.1.2/test/InputItem.ts +5 -0
- codex_python-0.1.2/test/InputMessageKind.ts +5 -0
- codex_python-0.1.2/test/InterruptConversationParams.ts +6 -0
- codex_python-0.1.2/test/InterruptConversationResponse.ts +6 -0
- codex_python-0.1.2/test/ListConversationsParams.ts +13 -0
- codex_python-0.1.2/test/ListConversationsResponse.ts +11 -0
- codex_python-0.1.2/test/ListCustomPromptsResponseEvent.ts +9 -0
- codex_python-0.1.2/test/LocalShellAction.ts +6 -0
- codex_python-0.1.2/test/LocalShellExecAction.ts +5 -0
- codex_python-0.1.2/test/LocalShellStatus.ts +5 -0
- codex_python-0.1.2/test/LoginChatGptCompleteNotification.ts +5 -0
- codex_python-0.1.2/test/LoginChatGptResponse.ts +9 -0
- codex_python-0.1.2/test/LogoutChatGptResponse.ts +5 -0
- codex_python-0.1.2/test/McpInvocation.ts +18 -0
- codex_python-0.1.2/test/McpListToolsResponseEvent.ts +13 -0
- codex_python-0.1.2/test/McpToolCallBeginEvent.ts +10 -0
- codex_python-0.1.2/test/McpToolCallEndEvent.ts +15 -0
- codex_python-0.1.2/test/NewConversationParams.ts +47 -0
- codex_python-0.1.2/test/NewConversationResponse.ts +6 -0
- codex_python-0.1.2/test/ParsedCommand.ts +5 -0
- codex_python-0.1.2/test/PatchApplyBeginEvent.ts +18 -0
- codex_python-0.1.2/test/PatchApplyEndEvent.ts +21 -0
- codex_python-0.1.2/test/PlanItemArg.ts +6 -0
- codex_python-0.1.2/test/Profile.ts +17 -0
- codex_python-0.1.2/test/ReasoningEffort.ts +8 -0
- codex_python-0.1.2/test/ReasoningItemContent.ts +5 -0
- codex_python-0.1.2/test/ReasoningItemReasoningSummary.ts +5 -0
- codex_python-0.1.2/test/ReasoningSummary.ts +10 -0
- codex_python-0.1.2/test/RemoveConversationListenerParams.ts +5 -0
- codex_python-0.1.2/test/RemoveConversationSubscriptionResponse.ts +5 -0
- codex_python-0.1.2/test/RequestId.ts +5 -0
- codex_python-0.1.2/test/ResourceLink.ts +11 -0
- codex_python-0.1.2/test/ResponseItem.ts +20 -0
- codex_python-0.1.2/test/ResumeConversationParams.ts +14 -0
- codex_python-0.1.2/test/ResumeConversationResponse.ts +7 -0
- codex_python-0.1.2/test/ReviewDecision.ts +8 -0
- codex_python-0.1.2/test/Role.ts +8 -0
- codex_python-0.1.2/test/SandboxMode.ts +5 -0
- codex_python-0.1.2/test/SandboxPolicy.ts +29 -0
- codex_python-0.1.2/test/SandboxSettings.ts +8 -0
- codex_python-0.1.2/test/SendUserMessageParams.ts +7 -0
- codex_python-0.1.2/test/SendUserMessageResponse.ts +5 -0
- codex_python-0.1.2/test/SendUserTurnParams.ts +11 -0
- codex_python-0.1.2/test/SendUserTurnResponse.ts +5 -0
- codex_python-0.1.2/test/ServerNotification.ts +7 -0
- codex_python-0.1.2/test/ServerRequest.ts +11 -0
- codex_python-0.1.2/test/SessionConfiguredEvent.ts +28 -0
- codex_python-0.1.2/test/StepStatus.ts +5 -0
- codex_python-0.1.2/test/StreamErrorEvent.ts +5 -0
- codex_python-0.1.2/test/TaskCompleteEvent.ts +5 -0
- codex_python-0.1.2/test/TaskStartedEvent.ts +5 -0
- codex_python-0.1.2/test/TextContent.ts +9 -0
- codex_python-0.1.2/test/TextResourceContents.ts +5 -0
- codex_python-0.1.2/test/TokenCountEvent.ts +6 -0
- codex_python-0.1.2/test/TokenUsage.ts +5 -0
- codex_python-0.1.2/test/TokenUsageInfo.ts +6 -0
- codex_python-0.1.2/test/Tool.ts +11 -0
- codex_python-0.1.2/test/ToolAnnotations.ts +15 -0
- codex_python-0.1.2/test/ToolInputSchema.ts +9 -0
- codex_python-0.1.2/test/ToolOutputSchema.ts +10 -0
- codex_python-0.1.2/test/Tools.ts +8 -0
- codex_python-0.1.2/test/TurnAbortReason.ts +5 -0
- codex_python-0.1.2/test/TurnAbortedEvent.ts +6 -0
- codex_python-0.1.2/test/TurnDiffEvent.ts +5 -0
- codex_python-0.1.2/test/UpdatePlanArgs.ts +6 -0
- codex_python-0.1.2/test/UserMessageEvent.ts +6 -0
- codex_python-0.1.2/test/UserSavedConfig.ts +34 -0
- codex_python-0.1.2/test/Verbosity.ts +9 -0
- codex_python-0.1.2/test/WebSearchAction.ts +5 -0
- codex_python-0.1.2/test/WebSearchBeginEvent.ts +5 -0
- codex_python-0.1.2/test/WebSearchEndEvent.ts +5 -0
- codex_python-0.1.2/test/index.ts +128 -0
- codex_python-0.1.2/test/serde_json/JsonValue.ts +3 -0
- codex_python-0.1.0/CHANGELOG.md +0 -17
- codex_python-0.1.0/CODE_OF_CONDUCT.md +0 -34
- codex_python-0.1.0/CONTRIBUTING.md +0 -54
- codex_python-0.1.0/Makefile +0 -37
- {codex_python-0.1.0 → codex_python-0.1.2}/.github/workflows/ci.yml +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/.pre-commit-config.yaml +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/LICENSE +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/codex/py.typed +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/tests/test_api.py +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/tests/test_client.py +0 -0
- {codex_python-0.1.0 → codex_python-0.1.2}/tests/test_version.py +0 -0
@@ -7,6 +7,7 @@ on:
|
|
7
7
|
|
8
8
|
permissions:
|
9
9
|
contents: read
|
10
|
+
id-token: write
|
10
11
|
|
11
12
|
jobs:
|
12
13
|
build-and-publish:
|
@@ -28,7 +29,5 @@ jobs:
|
|
28
29
|
- name: Build distribution
|
29
30
|
run: uv build
|
30
31
|
|
31
|
-
- name: Publish to PyPI
|
32
|
-
|
33
|
-
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
34
|
-
run: uv publish --token "$PYPI_API_TOKEN"
|
32
|
+
- name: Publish to PyPI (Trusted Publishing)
|
33
|
+
run: uv publish --trusted-publishing=always
|
@@ -0,0 +1,66 @@
|
|
1
|
+
.PHONY: help venv fmt lint test build publish clean
|
2
|
+
|
3
|
+
help:
|
4
|
+
@echo "Common targets:"
|
5
|
+
@echo " make lint - Run ruff and mypy"
|
6
|
+
@echo " make test - Run pytest"
|
7
|
+
@echo " make build - Build sdist and wheel with uv"
|
8
|
+
@echo " make publish - Publish to PyPI via uv (uses PYPI_API_TOKEN)"
|
9
|
+
@echo " make clean - Remove build artifacts"
|
10
|
+
@echo " make gen-protocol - Generate Python protocol bindings from codex-rs"
|
11
|
+
|
12
|
+
venv:
|
13
|
+
uv venv --python 3.13
|
14
|
+
@echo "Run: . .venv/bin/activate"
|
15
|
+
|
16
|
+
fmt:
|
17
|
+
uv run --group dev ruff format .
|
18
|
+
|
19
|
+
lint:
|
20
|
+
uv run --group dev ruff format .
|
21
|
+
uv run --group dev ruff check --fix --unsafe-fixes .
|
22
|
+
uv run --group dev mypy codex
|
23
|
+
|
24
|
+
test:
|
25
|
+
uv run --group dev pytest
|
26
|
+
|
27
|
+
build:
|
28
|
+
uv build
|
29
|
+
|
30
|
+
publish: build
|
31
|
+
@# Load local environment if present
|
32
|
+
@set -e; \
|
33
|
+
if [ -f .env ]; then set -a; . ./.env; set +a; fi; \
|
34
|
+
if [ -n "$${UV_PUBLISH_TOKEN:-}" ]; then \
|
35
|
+
echo "Publishing with token (UV_PUBLISH_TOKEN)"; \
|
36
|
+
uv publish --token "$${UV_PUBLISH_TOKEN}"; \
|
37
|
+
elif [ -n "$${PYPI_API_TOKEN:-}" ]; then \
|
38
|
+
echo "Publishing with token (PYPI_API_TOKEN)"; \
|
39
|
+
uv publish --token "$${PYPI_API_TOKEN}"; \
|
40
|
+
elif [ -n "$${UV_PUBLISH_USERNAME:-}" ] && [ -n "$${UV_PUBLISH_PASSWORD:-}" ]; then \
|
41
|
+
echo "Publishing with username/password (UV_PUBLISH_USERNAME)"; \
|
42
|
+
uv publish --username "$${UV_PUBLISH_USERNAME}" --password "$${UV_PUBLISH_PASSWORD}"; \
|
43
|
+
elif [ -n "$${PYPI_USERNAME:-}" ] && [ -n "$${PYPI_PASSWORD:-}" ]; then \
|
44
|
+
echo "Publishing with username/password (PYPI_USERNAME)"; \
|
45
|
+
uv publish --username "$${PYPI_USERNAME}" --password "$${PYPI_PASSWORD}"; \
|
46
|
+
else \
|
47
|
+
echo "No credentials found. Set UV_PUBLISH_TOKEN or PYPI_API_TOKEN, or UV_PUBLISH_USERNAME/UV_PUBLISH_PASSWORD (or PYPI_USERNAME/PYPI_PASSWORD)."; \
|
48
|
+
exit 1; \
|
49
|
+
fi
|
50
|
+
|
51
|
+
clean:
|
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
|
+
echo "Using 'codex generate-types'"; \
|
59
|
+
codex generate-types --out .generated/ts; \
|
60
|
+
else \
|
61
|
+
echo "Using cargo run -p codex-protocol-ts"; \
|
62
|
+
cd codex-proj/codex-rs && cargo run -p codex-protocol-ts -- --out ../../.generated/ts; \
|
63
|
+
fi
|
64
|
+
@echo "Generating Python bindings ..."
|
65
|
+
@python3 scripts/generate_protocol_py.py .generated/ts
|
66
|
+
@$(MAKE) fmt
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: codex-python
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
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,6 +36,7 @@ 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
|
@@ -70,6 +71,18 @@ Options:
|
|
70
71
|
- Full auto: `run_exec("scaffold a cli", full_auto=True)`
|
71
72
|
- Run in another dir: `run_exec("...", cd="/path/to/project")`
|
72
73
|
|
74
|
+
Streaming JSON events (no PyO3 required):
|
75
|
+
|
76
|
+
```
|
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
|
+
|
73
86
|
Using a client with defaults:
|
74
87
|
|
75
88
|
```
|
@@ -113,8 +126,10 @@ export PYPI_API_TOKEN="pypi-XXXX" # create at https://pypi.org/manage/account/t
|
|
113
126
|
uv publish --token "$PYPI_API_TOKEN"
|
114
127
|
```
|
115
128
|
|
116
|
-
- GitHub Actions
|
117
|
-
|
129
|
+
- GitHub Actions (Trusted Publishing): enable PyPI Trusted Publishing for
|
130
|
+
`gersmann/codex-python` and push a tag like `v0.1.0`. No token is needed.
|
131
|
+
The workflow at `.github/workflows/publish.yml` requests an OIDC token and
|
132
|
+
runs `uv publish --trusted-publishing=always` on `v*` tags.
|
118
133
|
|
119
134
|
### Dev tooling
|
120
135
|
|
@@ -123,6 +138,19 @@ uv publish --token "$PYPI_API_TOKEN"
|
|
123
138
|
- Format: `make fmt` (ruff formatter)
|
124
139
|
- Pre-commit: `uvx pre-commit install && uvx pre-commit run --all-files`
|
125
140
|
|
141
|
+
### Protocol bindings (from codex-rs)
|
142
|
+
|
143
|
+
- Prereq: Rust toolchain (`cargo`) installed.
|
144
|
+
- Generate Python types from the upstream protocol with:
|
145
|
+
|
146
|
+
```
|
147
|
+
make gen-protocol
|
148
|
+
```
|
149
|
+
|
150
|
+
This will:
|
151
|
+
- run `codex-proj/codex-rs/protocol-ts` to emit TypeScript types under `.generated/ts/`
|
152
|
+
- convert them to Python `TypedDict`/`Literal` aliases at `codex/protocol/types.py`
|
153
|
+
|
126
154
|
## Project Layout
|
127
155
|
|
128
156
|
```
|
@@ -30,6 +30,18 @@ Options:
|
|
30
30
|
- Full auto: `run_exec("scaffold a cli", full_auto=True)`
|
31
31
|
- Run in another dir: `run_exec("...", cd="/path/to/project")`
|
32
32
|
|
33
|
+
Streaming JSON events (no PyO3 required):
|
34
|
+
|
35
|
+
```
|
36
|
+
from codex.protocol.runtime import stream_exec_events
|
37
|
+
|
38
|
+
for event in stream_exec_events("explain this repo", full_auto=True):
|
39
|
+
# event is a dict with shape {"id": str, "msg": {...}}
|
40
|
+
print(event)
|
41
|
+
```
|
42
|
+
|
43
|
+
The event payload matches the Pydantic models in `codex.protocol.types` (e.g., `EventMsg`).
|
44
|
+
|
33
45
|
Using a client with defaults:
|
34
46
|
|
35
47
|
```
|
@@ -73,8 +85,10 @@ export PYPI_API_TOKEN="pypi-XXXX" # create at https://pypi.org/manage/account/t
|
|
73
85
|
uv publish --token "$PYPI_API_TOKEN"
|
74
86
|
```
|
75
87
|
|
76
|
-
- GitHub Actions
|
77
|
-
|
88
|
+
- GitHub Actions (Trusted Publishing): enable PyPI Trusted Publishing for
|
89
|
+
`gersmann/codex-python` and push a tag like `v0.1.0`. No token is needed.
|
90
|
+
The workflow at `.github/workflows/publish.yml` requests an OIDC token and
|
91
|
+
runs `uv publish --trusted-publishing=always` on `v*` tags.
|
78
92
|
|
79
93
|
### Dev tooling
|
80
94
|
|
@@ -83,6 +97,19 @@ uv publish --token "$PYPI_API_TOKEN"
|
|
83
97
|
- Format: `make fmt` (ruff formatter)
|
84
98
|
- Pre-commit: `uvx pre-commit install && uvx pre-commit run --all-files`
|
85
99
|
|
100
|
+
### Protocol bindings (from codex-rs)
|
101
|
+
|
102
|
+
- Prereq: Rust toolchain (`cargo`) installed.
|
103
|
+
- Generate Python types from the upstream protocol with:
|
104
|
+
|
105
|
+
```
|
106
|
+
make gen-protocol
|
107
|
+
```
|
108
|
+
|
109
|
+
This will:
|
110
|
+
- run `codex-proj/codex-rs/protocol-ts` to emit TypeScript types under `.generated/ts/`
|
111
|
+
- convert them to Python `TypedDict`/`Literal` aliases at `codex/protocol/types.py`
|
112
|
+
|
86
113
|
## Project Layout
|
87
114
|
|
88
115
|
```
|
@@ -51,12 +51,15 @@ def run_exec(
|
|
51
51
|
prompt: str,
|
52
52
|
*,
|
53
53
|
model: str | None = None,
|
54
|
+
oss: bool = False,
|
54
55
|
full_auto: bool = False,
|
55
56
|
cd: str | None = None,
|
57
|
+
skip_git_repo_check: bool = False,
|
56
58
|
timeout: float | None = None,
|
57
59
|
env: Mapping[str, str] | None = None,
|
58
60
|
executable: str = "codex",
|
59
61
|
extra_args: Iterable[str] | None = None,
|
62
|
+
json: bool = False,
|
60
63
|
) -> str:
|
61
64
|
"""
|
62
65
|
Run `codex exec` with the given prompt and return stdout as text.
|
@@ -72,12 +75,19 @@ def run_exec(
|
|
72
75
|
cmd.extend(["--cd", cd])
|
73
76
|
if model:
|
74
77
|
cmd.extend(["-m", model])
|
78
|
+
if oss:
|
79
|
+
cmd.append("--oss")
|
75
80
|
if full_auto:
|
76
81
|
cmd.append("--full-auto")
|
82
|
+
if skip_git_repo_check:
|
83
|
+
cmd.append("--skip-git-repo-check")
|
77
84
|
if extra_args:
|
78
85
|
cmd.extend(list(extra_args))
|
79
86
|
|
80
|
-
cmd.
|
87
|
+
cmd.append("exec")
|
88
|
+
if json:
|
89
|
+
cmd.append("--json")
|
90
|
+
cmd.append(prompt)
|
81
91
|
|
82
92
|
completed = subprocess.run(
|
83
93
|
cmd,
|
@@ -123,8 +133,10 @@ class CodexClient:
|
|
123
133
|
prompt: str,
|
124
134
|
*,
|
125
135
|
model: str | None = None,
|
136
|
+
oss: bool | None = None,
|
126
137
|
full_auto: bool | None = None,
|
127
138
|
cd: str | None = None,
|
139
|
+
skip_git_repo_check: bool | None = None,
|
128
140
|
timeout: float | None = None,
|
129
141
|
env: Mapping[str, str] | None = None,
|
130
142
|
extra_args: Iterable[str] | None = None,
|
@@ -136,6 +148,8 @@ class CodexClient:
|
|
136
148
|
eff_model = model if model is not None else self.model
|
137
149
|
eff_full_auto = full_auto if full_auto is not None else self.full_auto
|
138
150
|
eff_cd = cd if cd is not None else self.cd
|
151
|
+
eff_oss = bool(oss) if oss is not None else False
|
152
|
+
eff_skip_git = bool(skip_git_repo_check) if skip_git_repo_check is not None else False
|
139
153
|
|
140
154
|
# Merge environment overlays; run_exec will merge with os.environ
|
141
155
|
merged_env: Mapping[str, str] | None
|
@@ -156,8 +170,10 @@ class CodexClient:
|
|
156
170
|
return run_exec(
|
157
171
|
prompt,
|
158
172
|
model=eff_model,
|
173
|
+
oss=eff_oss,
|
159
174
|
full_auto=eff_full_auto,
|
160
175
|
cd=eff_cd,
|
176
|
+
skip_git_repo_check=eff_skip_git,
|
161
177
|
timeout=timeout,
|
162
178
|
env=merged_env,
|
163
179
|
executable=self.executable,
|
@@ -0,0 +1,80 @@
|
|
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}")
|