codex-as-api 0.6.4__tar.gz → 0.6.5__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_as_api-0.6.4 → codex_as_api-0.6.5}/PKG-INFO +47 -19
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/README.md +46 -18
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/RELEASES.md +40 -0
- codex_as_api-0.6.5/config/codex-upstream-contract.json +86 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/config/model-capabilities.json +12 -12
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/pyproject.toml +3 -1
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/__init__.py +1 -1
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/anthropic_adapter.py +5 -4
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/auth.py +133 -21
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/messages.py +1 -1
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/protocol.py +2 -1
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/provider.py +59 -57
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/server.py +5 -3
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/conftest.py +1 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_anthropic_adapter.py +1 -4
- codex_as_api-0.6.5/tests/test_auth.py +730 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_codex_config.py +4 -4
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_messages.py +0 -1
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_model_capabilities.py +34 -3
- codex_as_api-0.6.5/tests/test_package_versions.py +94 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_protocol.py +0 -3
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_provider.py +11 -5
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_server.py +80 -6
- codex_as_api-0.6.4/tests/test_auth.py +0 -326
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/.gitignore +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/LICENSE +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/THIRD_PARTY_NOTICES.md +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/config/o200k_base.tiktoken +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/requirements-server.txt +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/requirements.txt +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/codex_config.py +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/model_capabilities.py +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/src/codex_as_api/o200k_tokenizer.py +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/__init__.py +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/fixtures/o200k_base_encode_ordinary.json +0 -0
- {codex_as_api-0.6.4 → codex_as_api-0.6.5}/tests/test_o200k_tokenizer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codex-as-api
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.5
|
|
4
4
|
Summary: Use ChatGPT/Codex OAuth as a local OpenAI-compatible API server.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Eunho-J/codex-as-api
|
|
6
6
|
Project-URL: Repository, https://github.com/Eunho-J/codex-as-api
|
|
@@ -165,7 +165,7 @@ Environment variables (Python, Rust, and TypeScript):
|
|
|
165
165
|
| `CODEX_AS_API_PORT` | `18080` | Listen port |
|
|
166
166
|
| `CODEX_AS_API_MODEL` | `~/.codex/config.toml` `model`, else `gpt-5.5` | Model identifier passed to Codex backend |
|
|
167
167
|
| `CODEX_AS_API_AUTH_PATH` | `~/.codex/auth.json` | Path to OAuth credentials file |
|
|
168
|
-
| `CODEX_AS_API_CODEX_CLI_VERSION` |
|
|
168
|
+
| `CODEX_AS_API_CODEX_CLI_VERSION` | `0.147.0` | Override the validated Codex compatibility baseline identified in backend request `User-Agent` headers |
|
|
169
169
|
| `CODEX_AS_API_RESPONSES_LITE` | `auto` | Responses Lite mode: `auto`, `on`, or `off` |
|
|
170
170
|
| `CODEX_AS_API_CODEX_METADATA` | `off` | Add Codex-style per-turn `client_metadata` and related backend headers |
|
|
171
171
|
| `CODEX_HOME` | `~/.codex` | Codex home directory used for `auth.json` and `config.toml` discovery |
|
|
@@ -177,8 +177,8 @@ model = "gpt-5.6-sol"
|
|
|
177
177
|
model_reasoning_effort = "high"
|
|
178
178
|
|
|
179
179
|
# Optional overrides. Without them, known models use the bundled Codex catalog values.
|
|
180
|
-
model_context_window =
|
|
181
|
-
model_auto_compact_token_limit =
|
|
180
|
+
model_context_window = 272000
|
|
181
|
+
model_auto_compact_token_limit = 244800
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
`CODEX_AS_API_MODEL` overrides the Codex config model. A request-level `reasoning_effort` overrides `model_reasoning_effort`; when both are omitted, known models use the Codex catalog default. The effective model, reasoning setting, and context settings are exposed from `/health`; context settings are also returned by Anthropic token-count responses.
|
|
@@ -198,7 +198,7 @@ model_auto_compact_token_limit = 334800
|
|
|
198
198
|
| `gpt-5.3-codex-spark` | Ultra-fast coding model |
|
|
199
199
|
| `gpt-5.2` | Previous generation model |
|
|
200
200
|
|
|
201
|
-
Model capability behavior is driven by `config/model-capabilities.json` across Python, TypeScript, and Rust. The public `gpt-5.6` alias uses Sol's private Codex capability entry. The GPT-5.6 entries use the official Codex Responses Lite contract and a
|
|
201
|
+
Model capability behavior is driven by `config/model-capabilities.json` across Python, TypeScript, and Rust. The public `gpt-5.6` alias uses Sol's private Codex capability entry. The GPT-5.6 entries use the official Codex Responses Lite contract and a 272,000-token **Codex OAuth** context-window maximum; do not substitute the larger public API context figures for this backend. Larger config overrides are clamped to 272,000. Unknown models use conservative behavior: classic Responses payloads, no assumed parallel tool support, no automatic verbosity, reasoning-effort, or service-tier fields, and, without config overrides, the legacy 200,000-token context / 160,000-token compact thresholds.
|
|
202
202
|
|
|
203
203
|
To use a different port:
|
|
204
204
|
|
|
@@ -411,7 +411,7 @@ Health check. Returns auth availability, configured model and reasoning effort,
|
|
|
411
411
|
|
|
412
412
|
```bash
|
|
413
413
|
curl http://localhost:18080/health
|
|
414
|
-
# {"status":"ok","auth_available":true,"model":"gpt-5.6-sol","reasoning_effort":"high","codex_config_path":"/Users/me/.codex/config.toml","context_window":
|
|
414
|
+
# {"status":"ok","auth_available":true,"model":"gpt-5.6-sol","reasoning_effort":"high","codex_config_path":"/Users/me/.codex/config.toml","context_window":272000,"auto_compact_token_limit":244800}
|
|
415
415
|
```
|
|
416
416
|
|
|
417
417
|
## Codex-Specific Features
|
|
@@ -422,7 +422,7 @@ These features are extensions beyond the standard OpenAI API, designed for Codex
|
|
|
422
422
|
|
|
423
423
|
`prompt_cache_key` keeps related prefixes in the same backend cache family. Use one stable, privacy-safe key per conversation or application prefix.
|
|
424
424
|
|
|
425
|
-
Official Codex 0.
|
|
425
|
+
Official Codex 0.147.0 [defaults this field to its Responses metadata session ID](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/core/src/client.rs#L475-L487), and [projects the same value into `client_metadata.session_id`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/core/src/responses_metadata.rs#L219-L228), unless an explicit override is present. This proxy follows the same precedence on Chat requests: explicit `prompt_cache_key`, then a non-empty `client_metadata.session_id`, then omission. It does not generate a process-wide session or reuse `thread_id` as the cache key.
|
|
426
426
|
|
|
427
427
|
The private Codex OAuth HTTP and WebSocket request structures do not contain public GPT-5.6 `prompt_cache_options` or content-block `prompt_cache_breakpoint` fields. This proxy treats explicit `null` as omitted and rejects non-null controls with HTTP 400 instead of forwarding a request that the private route rejects or silently pretending the requested cache policy was applied. Use a public Responses API client when explicit cache policy or breakpoints are required. See OpenAI's [public prompt caching guide](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-breakpoints).
|
|
428
428
|
|
|
@@ -485,7 +485,7 @@ The mapping is intentionally transport-aware:
|
|
|
485
485
|
| `service_tier: "fast"` | Send `service_tier: "priority"` |
|
|
486
486
|
| `service_tier: "default"` | Omit the field |
|
|
487
487
|
|
|
488
|
-
Authenticated tests on July 10, 2026 verified both official continuation paths with `gpt-5.6-sol`: a direct private Responses WebSocket completed a second delta request using the exact prior `response.id`, and the private HTTP endpoint completed the same continuation when the full prior input/output history was replayed. The proxy implements the HTTP replay strategy. Direct HTTP forwarding of `previous_response_id`, Pro, public cache controls, and `safety_identifier` was rejected and is not used. See OpenAI's [reasoning mode documentation](https://developers.openai.com/api/docs/guides/reasoning#reasoning-mode) and the
|
|
488
|
+
Authenticated tests on July 10, 2026 verified both official continuation paths with `gpt-5.6-sol`: a direct private Responses WebSocket completed a second delta request using the exact prior `response.id`, and the private HTTP endpoint completed the same continuation when the full prior input/output history was replayed. The proxy implements the HTTP replay strategy. Direct HTTP forwarding of `previous_response_id`, Pro, public cache controls, and `safety_identifier` was rejected and is not used. See OpenAI's [reasoning mode documentation](https://developers.openai.com/api/docs/guides/reasoning#reasoning-mode) and the Codex 0.147.0 [HTTP/WebSocket request structures](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/common.rs#L251-L307).
|
|
489
489
|
|
|
490
490
|
### `responses_lite`
|
|
491
491
|
|
|
@@ -539,7 +539,7 @@ The installation ID and process window ID remain stable, while `turn_id` and `x-
|
|
|
539
539
|
|
|
540
540
|
Non-streaming responses and the final streaming finish chunk expose the real upstream Responses ID as `response_id`. The provider keeps up to 256 completed chains in a process-local LRU store. Passing a known ID as `previous_response_id` prepends the saved semantic input and exact prior `response.output_item.done` items—including encrypted reasoning and tool items—to the new input, then sends one full private HTTP request. The ID itself is never forwarded and is never converted to `thread_id`.
|
|
541
541
|
|
|
542
|
-
That event source is intentional: the
|
|
542
|
+
That event source is intentional: the Codex 0.147.0 SSE parser [takes semantic items from `response.output_item.done`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/sse/responses.rs#L330-L341), while its [`response.completed` shape contains the response ID, usage, and `end_turn`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/sse/responses.rs#L112-L160), not replay history. The authenticated private HTTP rollout likewise returned an empty `response.completed.output`; the proxy therefore commits the completed output-item events instead of treating that extra field as conversation state.
|
|
543
543
|
|
|
544
544
|
Only a real `response.completed` event commits a chain. Branches from an older retained ID are supported. Restarting the server or evicting an old entry removes that local state; an unknown ID returns HTTP 400 before any upstream request.
|
|
545
545
|
|
|
@@ -740,7 +740,7 @@ HTTP Server (FastAPI / Axum / Express)
|
|
|
740
740
|
```
|
|
741
741
|
|
|
742
742
|
The provider handles:
|
|
743
|
-
- Token loading and
|
|
743
|
+
- Token loading, proactive refresh five minutes before expiry, and refresh on 401
|
|
744
744
|
- OpenAI Responses API over SSE
|
|
745
745
|
- `prompt_cache_key` and cache read/write accounting
|
|
746
746
|
- GPT-5.6 reasoning effort/context plus `standard` mode compatibility
|
|
@@ -753,20 +753,32 @@ The provider handles:
|
|
|
753
753
|
|
|
754
754
|
## Release & package publishing
|
|
755
755
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
756
|
+
The `Release` GitHub Actions workflow runs on a pushed `v*` tag. It rejects a
|
|
757
|
+
tag that does not exactly match every Python, npm, and Rust version surface,
|
|
758
|
+
runs the complete cross-runtime gate, and then publishes PyPI, npmjs, the
|
|
759
|
+
scoped GitHub npm package, platform Rust binaries, and one GitHub Release.
|
|
759
760
|
|
|
760
|
-
|
|
761
|
+
The workflow uses registry-supported OIDC for PyPI and npmjs. No `PYPI_TOKEN`,
|
|
762
|
+
`NPM_TOKEN`, personal access token, or repository secret is required. One-time
|
|
763
|
+
registry setup is still required:
|
|
761
764
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
+
- Create GitHub environments named `pypi` and `npm`; add deployment protection
|
|
766
|
+
rules if desired.
|
|
767
|
+
- On PyPI, add a trusted publisher for project `codex-as-api`, owner `Eunho-J`,
|
|
768
|
+
repository `codex-as-api`, workflow `release.yml`, environment `pypi`.
|
|
769
|
+
- On npmjs, add a GitHub Actions trusted publisher for package `codex-as-api`,
|
|
770
|
+
owner `Eunho-J`, repository `codex-as-api`, workflow `release.yml`,
|
|
771
|
+
environment `npm`, with `npm publish` allowed.
|
|
772
|
+
- GitHub Packages and GitHub Releases use the job-scoped automatic
|
|
773
|
+
`GITHUB_TOKEN`; repository policy must allow the workflow's declared
|
|
774
|
+
`packages: write` and `contents: write` permissions.
|
|
765
775
|
|
|
766
|
-
|
|
776
|
+
After bumping every version and passing the local gate, push the matching tag:
|
|
767
777
|
|
|
768
778
|
```bash
|
|
769
|
-
|
|
779
|
+
python scripts/check_package_versions.py --tag v0.6.5
|
|
780
|
+
git tag v0.6.5
|
|
781
|
+
git push origin v0.6.5
|
|
770
782
|
```
|
|
771
783
|
|
|
772
784
|
## Tests
|
|
@@ -797,6 +809,22 @@ npm test
|
|
|
797
809
|
|
|
798
810
|
## Release Notes
|
|
799
811
|
|
|
812
|
+
### v0.6.5
|
|
813
|
+
|
|
814
|
+
- Align GPT-5.6 alias, Sol, Terra, and Luna context limits with Codex `0.147.0`
|
|
815
|
+
at 272,000 tokens and derive the 244,800-token automatic compact threshold.
|
|
816
|
+
- Pin the verified upstream request, Responses Lite, header, and model contract
|
|
817
|
+
to `openai/codex` commit
|
|
818
|
+
`be6e8eac029b183056b7e4402879f15d2c85f61b`; track its new fractional SSE
|
|
819
|
+
rollout-budget field without claiming an unapproved facade mapping.
|
|
820
|
+
- Refresh OAuth credentials five minutes before expiry, coalesce concurrent
|
|
821
|
+
refreshes, reload changed credentials after 401, and preserve upstream HTTP
|
|
822
|
+
status codes across all three servers.
|
|
823
|
+
- Replace startup npm version discovery with deterministic compatibility and
|
|
824
|
+
package-version identity in the Codex-style `User-Agent`.
|
|
825
|
+
- Add full cross-runtime CI plus tag-gated OIDC publishing to PyPI and npmjs,
|
|
826
|
+
`GITHUB_TOKEN` publishing to GitHub Packages, and GitHub Release assets.
|
|
827
|
+
|
|
800
828
|
### v0.6.4
|
|
801
829
|
|
|
802
830
|
- Remove process-global generated Codex session/thread identities and require
|
|
@@ -131,7 +131,7 @@ Environment variables (Python, Rust, and TypeScript):
|
|
|
131
131
|
| `CODEX_AS_API_PORT` | `18080` | Listen port |
|
|
132
132
|
| `CODEX_AS_API_MODEL` | `~/.codex/config.toml` `model`, else `gpt-5.5` | Model identifier passed to Codex backend |
|
|
133
133
|
| `CODEX_AS_API_AUTH_PATH` | `~/.codex/auth.json` | Path to OAuth credentials file |
|
|
134
|
-
| `CODEX_AS_API_CODEX_CLI_VERSION` |
|
|
134
|
+
| `CODEX_AS_API_CODEX_CLI_VERSION` | `0.147.0` | Override the validated Codex compatibility baseline identified in backend request `User-Agent` headers |
|
|
135
135
|
| `CODEX_AS_API_RESPONSES_LITE` | `auto` | Responses Lite mode: `auto`, `on`, or `off` |
|
|
136
136
|
| `CODEX_AS_API_CODEX_METADATA` | `off` | Add Codex-style per-turn `client_metadata` and related backend headers |
|
|
137
137
|
| `CODEX_HOME` | `~/.codex` | Codex home directory used for `auth.json` and `config.toml` discovery |
|
|
@@ -143,8 +143,8 @@ model = "gpt-5.6-sol"
|
|
|
143
143
|
model_reasoning_effort = "high"
|
|
144
144
|
|
|
145
145
|
# Optional overrides. Without them, known models use the bundled Codex catalog values.
|
|
146
|
-
model_context_window =
|
|
147
|
-
model_auto_compact_token_limit =
|
|
146
|
+
model_context_window = 272000
|
|
147
|
+
model_auto_compact_token_limit = 244800
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
`CODEX_AS_API_MODEL` overrides the Codex config model. A request-level `reasoning_effort` overrides `model_reasoning_effort`; when both are omitted, known models use the Codex catalog default. The effective model, reasoning setting, and context settings are exposed from `/health`; context settings are also returned by Anthropic token-count responses.
|
|
@@ -164,7 +164,7 @@ model_auto_compact_token_limit = 334800
|
|
|
164
164
|
| `gpt-5.3-codex-spark` | Ultra-fast coding model |
|
|
165
165
|
| `gpt-5.2` | Previous generation model |
|
|
166
166
|
|
|
167
|
-
Model capability behavior is driven by `config/model-capabilities.json` across Python, TypeScript, and Rust. The public `gpt-5.6` alias uses Sol's private Codex capability entry. The GPT-5.6 entries use the official Codex Responses Lite contract and a
|
|
167
|
+
Model capability behavior is driven by `config/model-capabilities.json` across Python, TypeScript, and Rust. The public `gpt-5.6` alias uses Sol's private Codex capability entry. The GPT-5.6 entries use the official Codex Responses Lite contract and a 272,000-token **Codex OAuth** context-window maximum; do not substitute the larger public API context figures for this backend. Larger config overrides are clamped to 272,000. Unknown models use conservative behavior: classic Responses payloads, no assumed parallel tool support, no automatic verbosity, reasoning-effort, or service-tier fields, and, without config overrides, the legacy 200,000-token context / 160,000-token compact thresholds.
|
|
168
168
|
|
|
169
169
|
To use a different port:
|
|
170
170
|
|
|
@@ -377,7 +377,7 @@ Health check. Returns auth availability, configured model and reasoning effort,
|
|
|
377
377
|
|
|
378
378
|
```bash
|
|
379
379
|
curl http://localhost:18080/health
|
|
380
|
-
# {"status":"ok","auth_available":true,"model":"gpt-5.6-sol","reasoning_effort":"high","codex_config_path":"/Users/me/.codex/config.toml","context_window":
|
|
380
|
+
# {"status":"ok","auth_available":true,"model":"gpt-5.6-sol","reasoning_effort":"high","codex_config_path":"/Users/me/.codex/config.toml","context_window":272000,"auto_compact_token_limit":244800}
|
|
381
381
|
```
|
|
382
382
|
|
|
383
383
|
## Codex-Specific Features
|
|
@@ -388,7 +388,7 @@ These features are extensions beyond the standard OpenAI API, designed for Codex
|
|
|
388
388
|
|
|
389
389
|
`prompt_cache_key` keeps related prefixes in the same backend cache family. Use one stable, privacy-safe key per conversation or application prefix.
|
|
390
390
|
|
|
391
|
-
Official Codex 0.
|
|
391
|
+
Official Codex 0.147.0 [defaults this field to its Responses metadata session ID](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/core/src/client.rs#L475-L487), and [projects the same value into `client_metadata.session_id`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/core/src/responses_metadata.rs#L219-L228), unless an explicit override is present. This proxy follows the same precedence on Chat requests: explicit `prompt_cache_key`, then a non-empty `client_metadata.session_id`, then omission. It does not generate a process-wide session or reuse `thread_id` as the cache key.
|
|
392
392
|
|
|
393
393
|
The private Codex OAuth HTTP and WebSocket request structures do not contain public GPT-5.6 `prompt_cache_options` or content-block `prompt_cache_breakpoint` fields. This proxy treats explicit `null` as omitted and rejects non-null controls with HTTP 400 instead of forwarding a request that the private route rejects or silently pretending the requested cache policy was applied. Use a public Responses API client when explicit cache policy or breakpoints are required. See OpenAI's [public prompt caching guide](https://developers.openai.com/api/docs/guides/prompt-caching#prompt-cache-breakpoints).
|
|
394
394
|
|
|
@@ -451,7 +451,7 @@ The mapping is intentionally transport-aware:
|
|
|
451
451
|
| `service_tier: "fast"` | Send `service_tier: "priority"` |
|
|
452
452
|
| `service_tier: "default"` | Omit the field |
|
|
453
453
|
|
|
454
|
-
Authenticated tests on July 10, 2026 verified both official continuation paths with `gpt-5.6-sol`: a direct private Responses WebSocket completed a second delta request using the exact prior `response.id`, and the private HTTP endpoint completed the same continuation when the full prior input/output history was replayed. The proxy implements the HTTP replay strategy. Direct HTTP forwarding of `previous_response_id`, Pro, public cache controls, and `safety_identifier` was rejected and is not used. See OpenAI's [reasoning mode documentation](https://developers.openai.com/api/docs/guides/reasoning#reasoning-mode) and the
|
|
454
|
+
Authenticated tests on July 10, 2026 verified both official continuation paths with `gpt-5.6-sol`: a direct private Responses WebSocket completed a second delta request using the exact prior `response.id`, and the private HTTP endpoint completed the same continuation when the full prior input/output history was replayed. The proxy implements the HTTP replay strategy. Direct HTTP forwarding of `previous_response_id`, Pro, public cache controls, and `safety_identifier` was rejected and is not used. See OpenAI's [reasoning mode documentation](https://developers.openai.com/api/docs/guides/reasoning#reasoning-mode) and the Codex 0.147.0 [HTTP/WebSocket request structures](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/common.rs#L251-L307).
|
|
455
455
|
|
|
456
456
|
### `responses_lite`
|
|
457
457
|
|
|
@@ -505,7 +505,7 @@ The installation ID and process window ID remain stable, while `turn_id` and `x-
|
|
|
505
505
|
|
|
506
506
|
Non-streaming responses and the final streaming finish chunk expose the real upstream Responses ID as `response_id`. The provider keeps up to 256 completed chains in a process-local LRU store. Passing a known ID as `previous_response_id` prepends the saved semantic input and exact prior `response.output_item.done` items—including encrypted reasoning and tool items—to the new input, then sends one full private HTTP request. The ID itself is never forwarded and is never converted to `thread_id`.
|
|
507
507
|
|
|
508
|
-
That event source is intentional: the
|
|
508
|
+
That event source is intentional: the Codex 0.147.0 SSE parser [takes semantic items from `response.output_item.done`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/sse/responses.rs#L330-L341), while its [`response.completed` shape contains the response ID, usage, and `end_turn`](https://github.com/openai/codex/blob/be6e8eac029b183056b7e4402879f15d2c85f61b/codex-rs/codex-api/src/sse/responses.rs#L112-L160), not replay history. The authenticated private HTTP rollout likewise returned an empty `response.completed.output`; the proxy therefore commits the completed output-item events instead of treating that extra field as conversation state.
|
|
509
509
|
|
|
510
510
|
Only a real `response.completed` event commits a chain. Branches from an older retained ID are supported. Restarting the server or evicting an old entry removes that local state; an unknown ID returns HTTP 400 before any upstream request.
|
|
511
511
|
|
|
@@ -706,7 +706,7 @@ HTTP Server (FastAPI / Axum / Express)
|
|
|
706
706
|
```
|
|
707
707
|
|
|
708
708
|
The provider handles:
|
|
709
|
-
- Token loading and
|
|
709
|
+
- Token loading, proactive refresh five minutes before expiry, and refresh on 401
|
|
710
710
|
- OpenAI Responses API over SSE
|
|
711
711
|
- `prompt_cache_key` and cache read/write accounting
|
|
712
712
|
- GPT-5.6 reasoning effort/context plus `standard` mode compatibility
|
|
@@ -719,20 +719,32 @@ The provider handles:
|
|
|
719
719
|
|
|
720
720
|
## Release & package publishing
|
|
721
721
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
722
|
+
The `Release` GitHub Actions workflow runs on a pushed `v*` tag. It rejects a
|
|
723
|
+
tag that does not exactly match every Python, npm, and Rust version surface,
|
|
724
|
+
runs the complete cross-runtime gate, and then publishes PyPI, npmjs, the
|
|
725
|
+
scoped GitHub npm package, platform Rust binaries, and one GitHub Release.
|
|
725
726
|
|
|
726
|
-
|
|
727
|
+
The workflow uses registry-supported OIDC for PyPI and npmjs. No `PYPI_TOKEN`,
|
|
728
|
+
`NPM_TOKEN`, personal access token, or repository secret is required. One-time
|
|
729
|
+
registry setup is still required:
|
|
727
730
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
+
- Create GitHub environments named `pypi` and `npm`; add deployment protection
|
|
732
|
+
rules if desired.
|
|
733
|
+
- On PyPI, add a trusted publisher for project `codex-as-api`, owner `Eunho-J`,
|
|
734
|
+
repository `codex-as-api`, workflow `release.yml`, environment `pypi`.
|
|
735
|
+
- On npmjs, add a GitHub Actions trusted publisher for package `codex-as-api`,
|
|
736
|
+
owner `Eunho-J`, repository `codex-as-api`, workflow `release.yml`,
|
|
737
|
+
environment `npm`, with `npm publish` allowed.
|
|
738
|
+
- GitHub Packages and GitHub Releases use the job-scoped automatic
|
|
739
|
+
`GITHUB_TOKEN`; repository policy must allow the workflow's declared
|
|
740
|
+
`packages: write` and `contents: write` permissions.
|
|
731
741
|
|
|
732
|
-
|
|
742
|
+
After bumping every version and passing the local gate, push the matching tag:
|
|
733
743
|
|
|
734
744
|
```bash
|
|
735
|
-
|
|
745
|
+
python scripts/check_package_versions.py --tag v0.6.5
|
|
746
|
+
git tag v0.6.5
|
|
747
|
+
git push origin v0.6.5
|
|
736
748
|
```
|
|
737
749
|
|
|
738
750
|
## Tests
|
|
@@ -763,6 +775,22 @@ npm test
|
|
|
763
775
|
|
|
764
776
|
## Release Notes
|
|
765
777
|
|
|
778
|
+
### v0.6.5
|
|
779
|
+
|
|
780
|
+
- Align GPT-5.6 alias, Sol, Terra, and Luna context limits with Codex `0.147.0`
|
|
781
|
+
at 272,000 tokens and derive the 244,800-token automatic compact threshold.
|
|
782
|
+
- Pin the verified upstream request, Responses Lite, header, and model contract
|
|
783
|
+
to `openai/codex` commit
|
|
784
|
+
`be6e8eac029b183056b7e4402879f15d2c85f61b`; track its new fractional SSE
|
|
785
|
+
rollout-budget field without claiming an unapproved facade mapping.
|
|
786
|
+
- Refresh OAuth credentials five minutes before expiry, coalesce concurrent
|
|
787
|
+
refreshes, reload changed credentials after 401, and preserve upstream HTTP
|
|
788
|
+
status codes across all three servers.
|
|
789
|
+
- Replace startup npm version discovery with deterministic compatibility and
|
|
790
|
+
package-version identity in the Codex-style `User-Agent`.
|
|
791
|
+
- Add full cross-runtime CI plus tag-gated OIDC publishing to PyPI and npmjs,
|
|
792
|
+
`GITHUB_TOKEN` publishing to GitHub Packages, and GitHub Release assets.
|
|
793
|
+
|
|
766
794
|
### v0.6.4
|
|
767
795
|
|
|
768
796
|
- Remove process-global generated Codex session/thread identities and require
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## v0.6.5
|
|
4
|
+
|
|
5
|
+
### Codex 0.147 compatibility
|
|
6
|
+
|
|
7
|
+
- Align GPT-5.6 alias, Sol, Terra, and Luna context limits with the stable
|
|
8
|
+
Codex 0.147 catalog at 272,000 tokens. Automatic compact defaults now derive
|
|
9
|
+
to 244,800 tokens.
|
|
10
|
+
- Pin a structured compatibility fixture to `openai/codex` 0.147.0 commit
|
|
11
|
+
`be6e8eac029b183056b7e4402879f15d2c85f61b`, covering the model fields,
|
|
12
|
+
Responses request path, Lite behavior, and originator header. The fractional
|
|
13
|
+
`codex_rollout_budget_units` usage field is tracked as upstream-only because
|
|
14
|
+
this facade has no approved public mapping for it.
|
|
15
|
+
- Replace the moving startup `npm view @openai/codex version` lookup with a
|
|
16
|
+
deterministic Codex compatibility baseline and `codex-as-api` package
|
|
17
|
+
version in the request `User-Agent`.
|
|
18
|
+
|
|
19
|
+
### Authentication and errors
|
|
20
|
+
|
|
21
|
+
- Refresh OAuth access tokens five minutes before expiry, coalesce concurrent
|
|
22
|
+
refresh work, and reload credentials changed by another request before
|
|
23
|
+
rotating a refresh token after HTTP 401.
|
|
24
|
+
- Preserve the existing root or nested auth-file layout, reject account
|
|
25
|
+
switches and conflicting token claims, and compare the credential snapshot
|
|
26
|
+
again before persisting a refresh response.
|
|
27
|
+
- Preserve upstream HTTP statuses, including rate-limit and overload responses,
|
|
28
|
+
in Python and TypeScript to match Rust.
|
|
29
|
+
|
|
30
|
+
### CI and publishing
|
|
31
|
+
|
|
32
|
+
- Add pull-request and push CI for Python tests, Ruff, mypy, package builds,
|
|
33
|
+
TypeScript tests/build/package checks, and Rust format, Clippy, tests, and
|
|
34
|
+
release builds.
|
|
35
|
+
- Add a tag-triggered release workflow that requires exact tag/package version
|
|
36
|
+
agreement and the full cross-runtime gate before publishing.
|
|
37
|
+
- Publish PyPI and npmjs through trusted-publisher OIDC, GitHub Packages and
|
|
38
|
+
GitHub Releases through the automatic repository `GITHUB_TOKEN`, and attach
|
|
39
|
+
Python/npm distributions plus Linux, macOS, and Windows Rust binaries.
|
|
40
|
+
- Remove the manual npm workflow that could report success after silently
|
|
41
|
+
skipping npmjs publication when `NPM_TOKEN` was absent.
|
|
42
|
+
|
|
3
43
|
## v0.6.4
|
|
4
44
|
|
|
5
45
|
### Codex identity and cache affinity
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"upstream": {
|
|
3
|
+
"repository": "openai/codex",
|
|
4
|
+
"version": "0.147.0",
|
|
5
|
+
"tag": "rust-v0.147.0",
|
|
6
|
+
"commit": "be6e8eac029b183056b7e4402879f15d2c85f61b"
|
|
7
|
+
},
|
|
8
|
+
"models": [
|
|
9
|
+
{
|
|
10
|
+
"slug": "gpt-5.6",
|
|
11
|
+
"context_window": 272000,
|
|
12
|
+
"max_context_window": 272000,
|
|
13
|
+
"default_reasoning_effort": "low",
|
|
14
|
+
"use_responses_lite": true,
|
|
15
|
+
"support_verbosity": true,
|
|
16
|
+
"default_verbosity": "low",
|
|
17
|
+
"supports_parallel_tool_calls": true,
|
|
18
|
+
"supports_image_detail_original": true,
|
|
19
|
+
"service_tiers": ["priority"]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"slug": "gpt-5.6-sol",
|
|
23
|
+
"context_window": 272000,
|
|
24
|
+
"max_context_window": 272000,
|
|
25
|
+
"default_reasoning_effort": "low",
|
|
26
|
+
"use_responses_lite": true,
|
|
27
|
+
"support_verbosity": true,
|
|
28
|
+
"default_verbosity": "low",
|
|
29
|
+
"supports_parallel_tool_calls": true,
|
|
30
|
+
"supports_image_detail_original": true,
|
|
31
|
+
"service_tiers": ["priority"]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"slug": "gpt-5.6-terra",
|
|
35
|
+
"context_window": 272000,
|
|
36
|
+
"max_context_window": 272000,
|
|
37
|
+
"default_reasoning_effort": "medium",
|
|
38
|
+
"use_responses_lite": true,
|
|
39
|
+
"support_verbosity": true,
|
|
40
|
+
"default_verbosity": "low",
|
|
41
|
+
"supports_parallel_tool_calls": true,
|
|
42
|
+
"supports_image_detail_original": true,
|
|
43
|
+
"service_tiers": ["priority"]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"slug": "gpt-5.6-luna",
|
|
47
|
+
"context_window": 272000,
|
|
48
|
+
"max_context_window": 272000,
|
|
49
|
+
"default_reasoning_effort": "medium",
|
|
50
|
+
"use_responses_lite": true,
|
|
51
|
+
"support_verbosity": true,
|
|
52
|
+
"default_verbosity": "low",
|
|
53
|
+
"supports_parallel_tool_calls": true,
|
|
54
|
+
"supports_image_detail_original": true,
|
|
55
|
+
"service_tiers": ["priority"]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"responses_request": {
|
|
59
|
+
"path": "/responses",
|
|
60
|
+
"method": "POST",
|
|
61
|
+
"streaming_accept": "text/event-stream",
|
|
62
|
+
"reasoning_encrypted_content_include": "reasoning.encrypted_content"
|
|
63
|
+
},
|
|
64
|
+
"responses_lite": {
|
|
65
|
+
"header": {
|
|
66
|
+
"name": "x-openai-internal-codex-responses-lite",
|
|
67
|
+
"value": "true"
|
|
68
|
+
},
|
|
69
|
+
"reasoning_context": "all_turns",
|
|
70
|
+
"parallel_tool_calls": false
|
|
71
|
+
},
|
|
72
|
+
"headers": {
|
|
73
|
+
"originator": {
|
|
74
|
+
"name": "originator",
|
|
75
|
+
"value": "codex_cli_rs"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"sse_usage": {
|
|
79
|
+
"tracking": "upstream-only; this facade has no approved public mapping",
|
|
80
|
+
"event_type": "response.completed",
|
|
81
|
+
"usage_path": ["response", "usage"],
|
|
82
|
+
"field": "codex_rollout_budget_units",
|
|
83
|
+
"value_type": "number",
|
|
84
|
+
"minimum": 0
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
"support_verbosity": true,
|
|
8
8
|
"default_verbosity": "low",
|
|
9
9
|
"default_reasoning_effort": "low",
|
|
10
|
-
"context_window":
|
|
11
|
-
"max_context_window":
|
|
10
|
+
"context_window": 272000,
|
|
11
|
+
"max_context_window": 272000,
|
|
12
12
|
"service_tiers": ["priority"],
|
|
13
13
|
"default_service_tier": null,
|
|
14
|
-
"source": "
|
|
14
|
+
"source": "gpt-5.6 alias to gpt-5.6-sol; openai/codex@be6e8eac029b183056b7e4402879f15d2c85f61b"
|
|
15
15
|
},
|
|
16
16
|
"gpt-5.6-sol": {
|
|
17
17
|
"use_responses_lite": true,
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"support_verbosity": true,
|
|
21
21
|
"default_verbosity": "low",
|
|
22
22
|
"default_reasoning_effort": "low",
|
|
23
|
-
"context_window":
|
|
24
|
-
"max_context_window":
|
|
23
|
+
"context_window": 272000,
|
|
24
|
+
"max_context_window": 272000,
|
|
25
25
|
"service_tiers": ["priority"],
|
|
26
26
|
"default_service_tier": null,
|
|
27
|
-
"source": "openai/codex
|
|
27
|
+
"source": "openai/codex@be6e8eac029b183056b7e4402879f15d2c85f61b"
|
|
28
28
|
},
|
|
29
29
|
"gpt-5.6-terra": {
|
|
30
30
|
"use_responses_lite": true,
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"support_verbosity": true,
|
|
34
34
|
"default_verbosity": "low",
|
|
35
35
|
"default_reasoning_effort": "medium",
|
|
36
|
-
"context_window":
|
|
37
|
-
"max_context_window":
|
|
36
|
+
"context_window": 272000,
|
|
37
|
+
"max_context_window": 272000,
|
|
38
38
|
"service_tiers": ["priority"],
|
|
39
39
|
"default_service_tier": null,
|
|
40
|
-
"source": "openai/codex
|
|
40
|
+
"source": "openai/codex@be6e8eac029b183056b7e4402879f15d2c85f61b"
|
|
41
41
|
},
|
|
42
42
|
"gpt-5.6-luna": {
|
|
43
43
|
"use_responses_lite": true,
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"support_verbosity": true,
|
|
47
47
|
"default_verbosity": "low",
|
|
48
48
|
"default_reasoning_effort": "medium",
|
|
49
|
-
"context_window":
|
|
50
|
-
"max_context_window":
|
|
49
|
+
"context_window": 272000,
|
|
50
|
+
"max_context_window": 272000,
|
|
51
51
|
"service_tiers": ["priority"],
|
|
52
52
|
"default_service_tier": null,
|
|
53
|
-
"source": "openai/codex
|
|
53
|
+
"source": "openai/codex@be6e8eac029b183056b7e4402879f15d2c85f61b"
|
|
54
54
|
},
|
|
55
55
|
"gpt-5.5": {
|
|
56
56
|
"use_responses_lite": false,
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codex-as-api"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.5"
|
|
8
8
|
description = "Use ChatGPT/Codex OAuth as a local OpenAI-compatible API server."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -42,12 +42,14 @@ packages = ["src/codex_as_api"]
|
|
|
42
42
|
|
|
43
43
|
[tool.hatch.build.targets.wheel.force-include]
|
|
44
44
|
"config/model-capabilities.json" = "codex_as_api/model-capabilities.json"
|
|
45
|
+
"config/codex-upstream-contract.json" = "codex_as_api/codex-upstream-contract.json"
|
|
45
46
|
"config/o200k_base.tiktoken" = "codex_as_api/o200k_base.tiktoken"
|
|
46
47
|
"THIRD_PARTY_NOTICES.md" = "codex_as_api/THIRD_PARTY_NOTICES.md"
|
|
47
48
|
|
|
48
49
|
[tool.hatch.build.targets.sdist]
|
|
49
50
|
include = [
|
|
50
51
|
"/config/model-capabilities.json",
|
|
52
|
+
"/config/codex-upstream-contract.json",
|
|
51
53
|
"/config/o200k_base.tiktoken",
|
|
52
54
|
"/src/codex_as_api",
|
|
53
55
|
"/tests",
|
|
@@ -2,10 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import uuid
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
from .messages import Message, MessageRole, ToolCall, ToolSchema, Usage, AssistantResponse
|
|
5
|
+
from collections.abc import Iterator
|
|
6
|
+
from typing import Any
|
|
8
7
|
|
|
8
|
+
from .messages import AssistantResponse, Message, MessageRole, ToolCall, ToolSchema
|
|
9
9
|
|
|
10
10
|
# ---------------------------------------------------------------------------
|
|
11
11
|
# Request conversion: Anthropic → internal
|
|
@@ -278,7 +278,8 @@ def _string_list(value: Any) -> list[str] | None:
|
|
|
278
278
|
def _anthropic_web_search_parameters(tool: dict[str, Any]) -> dict[str, Any]:
|
|
279
279
|
if _string_list(tool.get("blocked_domains")):
|
|
280
280
|
raise ValueError(
|
|
281
|
-
"Anthropic web_search blocked_domains is not supported by OpenAI Responses web_search;
|
|
281
|
+
"Anthropic web_search blocked_domains is not supported by OpenAI Responses web_search; "
|
|
282
|
+
"use allowed_domains instead"
|
|
282
283
|
)
|
|
283
284
|
|
|
284
285
|
openai_tool: dict[str, Any] = {"type": "web_search", "external_web_access": True}
|