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.
Files changed (150) hide show
  1. {codex_python-0.1.0 → codex_python-0.1.2}/.github/workflows/publish.yml +3 -4
  2. {codex_python-0.1.0 → codex_python-0.1.2}/.gitignore +11 -0
  3. codex_python-0.1.2/Makefile +66 -0
  4. {codex_python-0.1.0 → codex_python-0.1.2}/PKG-INFO +31 -3
  5. {codex_python-0.1.0 → codex_python-0.1.2}/README.md +29 -2
  6. {codex_python-0.1.0 → codex_python-0.1.2}/codex/__init__.py +1 -1
  7. {codex_python-0.1.0 → codex_python-0.1.2}/codex/api.py +17 -1
  8. codex_python-0.1.2/codex/protocol/runtime.py +80 -0
  9. codex_python-0.1.2/codex/protocol/types.py +1595 -0
  10. {codex_python-0.1.0 → codex_python-0.1.2}/pyproject.toml +5 -1
  11. codex_python-0.1.2/scripts/generate_protocol_py.py +353 -0
  12. codex_python-0.1.2/test/AddConversationListenerParams.ts +6 -0
  13. codex_python-0.1.2/test/AddConversationSubscriptionResponse.ts +5 -0
  14. codex_python-0.1.2/test/AgentMessageDeltaEvent.ts +5 -0
  15. codex_python-0.1.2/test/AgentMessageEvent.ts +5 -0
  16. codex_python-0.1.2/test/AgentReasoningDeltaEvent.ts +5 -0
  17. codex_python-0.1.2/test/AgentReasoningEvent.ts +5 -0
  18. codex_python-0.1.2/test/AgentReasoningRawContentDeltaEvent.ts +5 -0
  19. codex_python-0.1.2/test/AgentReasoningRawContentEvent.ts +5 -0
  20. codex_python-0.1.2/test/AgentReasoningSectionBreakEvent.ts +5 -0
  21. codex_python-0.1.2/test/Annotations.ts +9 -0
  22. codex_python-0.1.2/test/ApplyPatchApprovalParams.ts +21 -0
  23. codex_python-0.1.2/test/ApplyPatchApprovalRequestEvent.ts +18 -0
  24. codex_python-0.1.2/test/ApplyPatchApprovalResponse.ts +6 -0
  25. codex_python-0.1.2/test/ArchiveConversationParams.ts +9 -0
  26. codex_python-0.1.2/test/ArchiveConversationResponse.ts +5 -0
  27. codex_python-0.1.2/test/AskForApproval.ts +9 -0
  28. codex_python-0.1.2/test/AudioContent.ts +9 -0
  29. codex_python-0.1.2/test/AuthMode.ts +5 -0
  30. codex_python-0.1.2/test/AuthStatusChangeNotification.ts +10 -0
  31. codex_python-0.1.2/test/BackgroundEventEvent.ts +5 -0
  32. codex_python-0.1.2/test/BlobResourceContents.ts +5 -0
  33. codex_python-0.1.2/test/CallToolResult.ts +10 -0
  34. codex_python-0.1.2/test/CancelLoginChatGptParams.ts +5 -0
  35. codex_python-0.1.2/test/CancelLoginChatGptResponse.ts +5 -0
  36. codex_python-0.1.2/test/ClientRequest.ts +22 -0
  37. codex_python-0.1.2/test/ContentBlock.ts +10 -0
  38. codex_python-0.1.2/test/ContentItem.ts +5 -0
  39. codex_python-0.1.2/test/ConversationHistoryResponseEvent.ts +11 -0
  40. codex_python-0.1.2/test/ConversationId.ts +5 -0
  41. codex_python-0.1.2/test/ConversationSummary.ts +10 -0
  42. codex_python-0.1.2/test/CustomPrompt.ts +5 -0
  43. codex_python-0.1.2/test/EmbeddedResource.ts +13 -0
  44. codex_python-0.1.2/test/EmbeddedResourceResource.ts +7 -0
  45. codex_python-0.1.2/test/ErrorEvent.ts +5 -0
  46. codex_python-0.1.2/test/EventMsg.ts +41 -0
  47. codex_python-0.1.2/test/ExecApprovalRequestEvent.ts +21 -0
  48. codex_python-0.1.2/test/ExecCommandApprovalParams.ts +11 -0
  49. codex_python-0.1.2/test/ExecCommandApprovalResponse.ts +6 -0
  50. codex_python-0.1.2/test/ExecCommandBeginEvent.ts +18 -0
  51. codex_python-0.1.2/test/ExecCommandEndEvent.ts +33 -0
  52. codex_python-0.1.2/test/ExecCommandOutputDeltaEvent.ts +18 -0
  53. codex_python-0.1.2/test/ExecOneOffCommandParams.ts +23 -0
  54. codex_python-0.1.2/test/ExecOutputStream.ts +5 -0
  55. codex_python-0.1.2/test/FileChange.ts +5 -0
  56. codex_python-0.1.2/test/FunctionCallOutputPayload.ts +5 -0
  57. codex_python-0.1.2/test/GetAuthStatusParams.ts +13 -0
  58. codex_python-0.1.2/test/GetAuthStatusResponse.ts +6 -0
  59. codex_python-0.1.2/test/GetHistoryEntryResponseEvent.ts +10 -0
  60. codex_python-0.1.2/test/GetUserAgentResponse.ts +5 -0
  61. codex_python-0.1.2/test/GetUserSavedConfigResponse.ts +6 -0
  62. codex_python-0.1.2/test/GitDiffToRemoteParams.ts +5 -0
  63. codex_python-0.1.2/test/GitDiffToRemoteResponse.ts +6 -0
  64. codex_python-0.1.2/test/GitSha.ts +5 -0
  65. codex_python-0.1.2/test/HistoryEntry.ts +5 -0
  66. codex_python-0.1.2/test/ImageContent.ts +9 -0
  67. codex_python-0.1.2/test/InputItem.ts +5 -0
  68. codex_python-0.1.2/test/InputMessageKind.ts +5 -0
  69. codex_python-0.1.2/test/InterruptConversationParams.ts +6 -0
  70. codex_python-0.1.2/test/InterruptConversationResponse.ts +6 -0
  71. codex_python-0.1.2/test/ListConversationsParams.ts +13 -0
  72. codex_python-0.1.2/test/ListConversationsResponse.ts +11 -0
  73. codex_python-0.1.2/test/ListCustomPromptsResponseEvent.ts +9 -0
  74. codex_python-0.1.2/test/LocalShellAction.ts +6 -0
  75. codex_python-0.1.2/test/LocalShellExecAction.ts +5 -0
  76. codex_python-0.1.2/test/LocalShellStatus.ts +5 -0
  77. codex_python-0.1.2/test/LoginChatGptCompleteNotification.ts +5 -0
  78. codex_python-0.1.2/test/LoginChatGptResponse.ts +9 -0
  79. codex_python-0.1.2/test/LogoutChatGptResponse.ts +5 -0
  80. codex_python-0.1.2/test/McpInvocation.ts +18 -0
  81. codex_python-0.1.2/test/McpListToolsResponseEvent.ts +13 -0
  82. codex_python-0.1.2/test/McpToolCallBeginEvent.ts +10 -0
  83. codex_python-0.1.2/test/McpToolCallEndEvent.ts +15 -0
  84. codex_python-0.1.2/test/NewConversationParams.ts +47 -0
  85. codex_python-0.1.2/test/NewConversationResponse.ts +6 -0
  86. codex_python-0.1.2/test/ParsedCommand.ts +5 -0
  87. codex_python-0.1.2/test/PatchApplyBeginEvent.ts +18 -0
  88. codex_python-0.1.2/test/PatchApplyEndEvent.ts +21 -0
  89. codex_python-0.1.2/test/PlanItemArg.ts +6 -0
  90. codex_python-0.1.2/test/Profile.ts +17 -0
  91. codex_python-0.1.2/test/ReasoningEffort.ts +8 -0
  92. codex_python-0.1.2/test/ReasoningItemContent.ts +5 -0
  93. codex_python-0.1.2/test/ReasoningItemReasoningSummary.ts +5 -0
  94. codex_python-0.1.2/test/ReasoningSummary.ts +10 -0
  95. codex_python-0.1.2/test/RemoveConversationListenerParams.ts +5 -0
  96. codex_python-0.1.2/test/RemoveConversationSubscriptionResponse.ts +5 -0
  97. codex_python-0.1.2/test/RequestId.ts +5 -0
  98. codex_python-0.1.2/test/ResourceLink.ts +11 -0
  99. codex_python-0.1.2/test/ResponseItem.ts +20 -0
  100. codex_python-0.1.2/test/ResumeConversationParams.ts +14 -0
  101. codex_python-0.1.2/test/ResumeConversationResponse.ts +7 -0
  102. codex_python-0.1.2/test/ReviewDecision.ts +8 -0
  103. codex_python-0.1.2/test/Role.ts +8 -0
  104. codex_python-0.1.2/test/SandboxMode.ts +5 -0
  105. codex_python-0.1.2/test/SandboxPolicy.ts +29 -0
  106. codex_python-0.1.2/test/SandboxSettings.ts +8 -0
  107. codex_python-0.1.2/test/SendUserMessageParams.ts +7 -0
  108. codex_python-0.1.2/test/SendUserMessageResponse.ts +5 -0
  109. codex_python-0.1.2/test/SendUserTurnParams.ts +11 -0
  110. codex_python-0.1.2/test/SendUserTurnResponse.ts +5 -0
  111. codex_python-0.1.2/test/ServerNotification.ts +7 -0
  112. codex_python-0.1.2/test/ServerRequest.ts +11 -0
  113. codex_python-0.1.2/test/SessionConfiguredEvent.ts +28 -0
  114. codex_python-0.1.2/test/StepStatus.ts +5 -0
  115. codex_python-0.1.2/test/StreamErrorEvent.ts +5 -0
  116. codex_python-0.1.2/test/TaskCompleteEvent.ts +5 -0
  117. codex_python-0.1.2/test/TaskStartedEvent.ts +5 -0
  118. codex_python-0.1.2/test/TextContent.ts +9 -0
  119. codex_python-0.1.2/test/TextResourceContents.ts +5 -0
  120. codex_python-0.1.2/test/TokenCountEvent.ts +6 -0
  121. codex_python-0.1.2/test/TokenUsage.ts +5 -0
  122. codex_python-0.1.2/test/TokenUsageInfo.ts +6 -0
  123. codex_python-0.1.2/test/Tool.ts +11 -0
  124. codex_python-0.1.2/test/ToolAnnotations.ts +15 -0
  125. codex_python-0.1.2/test/ToolInputSchema.ts +9 -0
  126. codex_python-0.1.2/test/ToolOutputSchema.ts +10 -0
  127. codex_python-0.1.2/test/Tools.ts +8 -0
  128. codex_python-0.1.2/test/TurnAbortReason.ts +5 -0
  129. codex_python-0.1.2/test/TurnAbortedEvent.ts +6 -0
  130. codex_python-0.1.2/test/TurnDiffEvent.ts +5 -0
  131. codex_python-0.1.2/test/UpdatePlanArgs.ts +6 -0
  132. codex_python-0.1.2/test/UserMessageEvent.ts +6 -0
  133. codex_python-0.1.2/test/UserSavedConfig.ts +34 -0
  134. codex_python-0.1.2/test/Verbosity.ts +9 -0
  135. codex_python-0.1.2/test/WebSearchAction.ts +5 -0
  136. codex_python-0.1.2/test/WebSearchBeginEvent.ts +5 -0
  137. codex_python-0.1.2/test/WebSearchEndEvent.ts +5 -0
  138. codex_python-0.1.2/test/index.ts +128 -0
  139. codex_python-0.1.2/test/serde_json/JsonValue.ts +3 -0
  140. codex_python-0.1.0/CHANGELOG.md +0 -17
  141. codex_python-0.1.0/CODE_OF_CONDUCT.md +0 -34
  142. codex_python-0.1.0/CONTRIBUTING.md +0 -54
  143. codex_python-0.1.0/Makefile +0 -37
  144. {codex_python-0.1.0 → codex_python-0.1.2}/.github/workflows/ci.yml +0 -0
  145. {codex_python-0.1.0 → codex_python-0.1.2}/.pre-commit-config.yaml +0 -0
  146. {codex_python-0.1.0 → codex_python-0.1.2}/LICENSE +0 -0
  147. {codex_python-0.1.0 → codex_python-0.1.2}/codex/py.typed +0 -0
  148. {codex_python-0.1.0 → codex_python-0.1.2}/tests/test_api.py +0 -0
  149. {codex_python-0.1.0 → codex_python-0.1.2}/tests/test_client.py +0 -0
  150. {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
- env:
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
@@ -43,3 +43,14 @@ coverage.xml
43
43
  # uv
44
44
  .uv/
45
45
  uv.lock
46
+
47
+ # Generated artifacts
48
+ # Generated artifacts
49
+ .generated/
50
+
51
+ # Ignore new markdown files by default
52
+ *.md
53
+
54
+ # Local environment files
55
+ .env
56
+ .env.*
@@ -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.0
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: add a repository secret `PYPI_API_TOKEN` and push a tag like `v0.1.0`.
117
- The workflow at `.github/workflows/publish.yml` builds and publishes with `uv` on `v*` tags.
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: add a repository secret `PYPI_API_TOKEN` and push a tag like `v0.1.0`.
77
- The workflow at `.github/workflows/publish.yml` builds and publishes with `uv` on `v*` tags.
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
  ```
@@ -27,4 +27,4 @@ __all__ = [
27
27
  ]
28
28
 
29
29
  # Managed by Hatch via pyproject.toml [tool.hatch.version]
30
- __version__ = "0.1.0"
30
+ __version__ = "0.1.2"
@@ -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.extend(["exec", prompt])
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}")