codex-as-api 0.6.2__tar.gz → 0.6.3__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.2 → codex_as_api-0.6.3}/PKG-INFO +16 -4
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/README.md +15 -3
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/RELEASES.md +16 -1
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/pyproject.toml +1 -1
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/__init__.py +1 -1
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/anthropic_adapter.py +9 -3
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/server.py +1 -1
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_anthropic_adapter.py +24 -3
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_server.py +60 -1
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/.gitignore +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/LICENSE +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/THIRD_PARTY_NOTICES.md +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/config/model-capabilities.json +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/config/o200k_base.tiktoken +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/requirements-server.txt +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/requirements.txt +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/auth.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/codex_config.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/messages.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/model_capabilities.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/o200k_tokenizer.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/protocol.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/src/codex_as_api/provider.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/__init__.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/conftest.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/fixtures/o200k_base_encode_ordinary.json +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_auth.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_codex_config.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_messages.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_model_capabilities.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_o200k_tokenizer.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_protocol.py +0 -0
- {codex_as_api-0.6.2 → codex_as_api-0.6.3}/tests/test_provider.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.3
|
|
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
|
|
@@ -444,7 +444,7 @@ GPT-5.6 requests can instead use the public Responses-shaped object:
|
|
|
444
444
|
- Responses Lite uses `all_turns` as the Codex wire default. An explicitly different context is rejected instead of silently overwritten; use `responses_lite: false` when the backend route supports classic Responses and another context is required.
|
|
445
445
|
- Remote compact keeps its existing private Codex `reasoning_effort` field but does not accept public `reasoning.mode` or `reasoning.context`.
|
|
446
446
|
|
|
447
|
-
Anthropic `thinking` values map as `enabled → high`, `adaptive → medium`, and `disabled → none`. Claude Code's `output_config.effort` takes precedence over
|
|
447
|
+
Anthropic `thinking` values map as `enabled → high`, `adaptive → medium`, and `disabled → none`. Claude Code's `output_config.effort` takes precedence over adaptive or enabled thinking and supports `low`, `medium`, `high`, `xhigh`, and `max`. Call-level `thinking.disabled` takes precedence over ambient `output_config.effort`, so Claude Code WebSearch/WebFetch auxiliary calls use `none` instead of failing the compatibility check with HTTP 400. The supported reasoning context and verbosity extensions are also available on `/v1/messages`, image generation, and inspection requests; Pro and non-null public cache policy/breakpoints or `safety_identifier` fail explicitly on the private Codex provider.
|
|
448
448
|
|
|
449
449
|
The pinned official Codex HTTP request has no `stop` field. Omitted, `null`, and empty stop values are omitted from the private request; any non-empty OpenAI `stop` or Anthropic `stop_sequences` value returns HTTP 400 before the private transport starts.
|
|
450
450
|
|
|
@@ -647,9 +647,13 @@ The `/v1/messages` endpoint implements the Anthropic Messages gateway shape used
|
|
|
647
647
|
Start the proxy first. `CODEX_AS_API_MODEL` is the fallback used when Claude Code sends a built-in Anthropic model name:
|
|
648
648
|
|
|
649
649
|
```bash
|
|
650
|
-
CODEX_AS_API_MODEL=gpt-5.6-terra
|
|
650
|
+
CODEX_AS_API_MODEL=gpt-5.6-terra \
|
|
651
|
+
CODEX_AS_API_RESPONSES_LITE=off \
|
|
652
|
+
codex-as-api
|
|
651
653
|
```
|
|
652
654
|
|
|
655
|
+
`CODEX_AS_API_RESPONSES_LITE=off` is required for Claude Code hosted WebSearch on GPT-5.6. Official Codex Responses Lite uses a client-side standalone `web.run` tool, while this gateway receives Anthropic's hosted `web_search` declaration and has no standalone executor; classic Responses preserves that hosted tool. WebFetch does not use a hosted Responses tool, but still needs the disabled-thinking precedence fix when process-level effort is enabled.
|
|
656
|
+
|
|
653
657
|
To keep the built-in Fable, Opus, Sonnet, and Haiku rows and append one GPT row, launch the GPT-routed Claude Code process with these variables:
|
|
654
658
|
|
|
655
659
|
```bash
|
|
@@ -720,7 +724,7 @@ The provider handles:
|
|
|
720
724
|
## Release & package publishing
|
|
721
725
|
|
|
722
726
|
- Bump versions in `pyproject.toml`, `src/codex_as_api/__init__.py`, `src/codex_as_api/server.py`, `ts/package.json`, `ts/package-lock.json`, `rust/Cargo.toml`, and `rust/Cargo.lock`.
|
|
723
|
-
- Publish a GitHub Release such as `v0.6.
|
|
727
|
+
- Publish a GitHub Release such as `v0.6.3` from the matching commit.
|
|
724
728
|
- The manually-dispatched `Publish npm packages` workflow builds/tests the TypeScript package, runs `npm pack --dry-run`, publishes `codex-as-api` to npmjs when `NPM_TOKEN` is configured, and publishes `@eunho-j/codex-as-api` to GitHub Packages with `GITHUB_TOKEN`.
|
|
725
729
|
|
|
726
730
|
Publishing to npmjs requires an authenticated npm session (`npm login` beforehand; `npm whoami` should succeed). From the repository root, the publish itself is one command:
|
|
@@ -763,6 +767,14 @@ npm test
|
|
|
763
767
|
|
|
764
768
|
## Release Notes
|
|
765
769
|
|
|
770
|
+
### v0.6.3
|
|
771
|
+
|
|
772
|
+
- Accept Claude Code auxiliary requests that combine ambient `output_config.effort` with call-level `thinking.disabled`.
|
|
773
|
+
- Give explicit disabled thinking precedence and send Codex reasoning effort `none` instead of returning HTTP 400.
|
|
774
|
+
- Document and test `CODEX_AS_API_RESPONSES_LITE=off` for Claude Code hosted WebSearch on GPT-5.6; WebFetch needs no Responses Lite override.
|
|
775
|
+
- Preserve fail-loudly validation for invalid effort values and unsupported `output_config` fields.
|
|
776
|
+
- Add Python, TypeScript, and Rust adapter regressions, streamed `/v1/messages` coverage, and a `/count_tokens` regression for the WebSearch/WebFetch request shape.
|
|
777
|
+
|
|
766
778
|
### v0.6.2
|
|
767
779
|
|
|
768
780
|
- Fix `/v1/messages/count_tokens` overcounting that could trigger Claude Code autocompaction on every turn.
|
|
@@ -410,7 +410,7 @@ GPT-5.6 requests can instead use the public Responses-shaped object:
|
|
|
410
410
|
- Responses Lite uses `all_turns` as the Codex wire default. An explicitly different context is rejected instead of silently overwritten; use `responses_lite: false` when the backend route supports classic Responses and another context is required.
|
|
411
411
|
- Remote compact keeps its existing private Codex `reasoning_effort` field but does not accept public `reasoning.mode` or `reasoning.context`.
|
|
412
412
|
|
|
413
|
-
Anthropic `thinking` values map as `enabled → high`, `adaptive → medium`, and `disabled → none`. Claude Code's `output_config.effort` takes precedence over
|
|
413
|
+
Anthropic `thinking` values map as `enabled → high`, `adaptive → medium`, and `disabled → none`. Claude Code's `output_config.effort` takes precedence over adaptive or enabled thinking and supports `low`, `medium`, `high`, `xhigh`, and `max`. Call-level `thinking.disabled` takes precedence over ambient `output_config.effort`, so Claude Code WebSearch/WebFetch auxiliary calls use `none` instead of failing the compatibility check with HTTP 400. The supported reasoning context and verbosity extensions are also available on `/v1/messages`, image generation, and inspection requests; Pro and non-null public cache policy/breakpoints or `safety_identifier` fail explicitly on the private Codex provider.
|
|
414
414
|
|
|
415
415
|
The pinned official Codex HTTP request has no `stop` field. Omitted, `null`, and empty stop values are omitted from the private request; any non-empty OpenAI `stop` or Anthropic `stop_sequences` value returns HTTP 400 before the private transport starts.
|
|
416
416
|
|
|
@@ -613,9 +613,13 @@ The `/v1/messages` endpoint implements the Anthropic Messages gateway shape used
|
|
|
613
613
|
Start the proxy first. `CODEX_AS_API_MODEL` is the fallback used when Claude Code sends a built-in Anthropic model name:
|
|
614
614
|
|
|
615
615
|
```bash
|
|
616
|
-
CODEX_AS_API_MODEL=gpt-5.6-terra
|
|
616
|
+
CODEX_AS_API_MODEL=gpt-5.6-terra \
|
|
617
|
+
CODEX_AS_API_RESPONSES_LITE=off \
|
|
618
|
+
codex-as-api
|
|
617
619
|
```
|
|
618
620
|
|
|
621
|
+
`CODEX_AS_API_RESPONSES_LITE=off` is required for Claude Code hosted WebSearch on GPT-5.6. Official Codex Responses Lite uses a client-side standalone `web.run` tool, while this gateway receives Anthropic's hosted `web_search` declaration and has no standalone executor; classic Responses preserves that hosted tool. WebFetch does not use a hosted Responses tool, but still needs the disabled-thinking precedence fix when process-level effort is enabled.
|
|
622
|
+
|
|
619
623
|
To keep the built-in Fable, Opus, Sonnet, and Haiku rows and append one GPT row, launch the GPT-routed Claude Code process with these variables:
|
|
620
624
|
|
|
621
625
|
```bash
|
|
@@ -686,7 +690,7 @@ The provider handles:
|
|
|
686
690
|
## Release & package publishing
|
|
687
691
|
|
|
688
692
|
- Bump versions in `pyproject.toml`, `src/codex_as_api/__init__.py`, `src/codex_as_api/server.py`, `ts/package.json`, `ts/package-lock.json`, `rust/Cargo.toml`, and `rust/Cargo.lock`.
|
|
689
|
-
- Publish a GitHub Release such as `v0.6.
|
|
693
|
+
- Publish a GitHub Release such as `v0.6.3` from the matching commit.
|
|
690
694
|
- The manually-dispatched `Publish npm packages` workflow builds/tests the TypeScript package, runs `npm pack --dry-run`, publishes `codex-as-api` to npmjs when `NPM_TOKEN` is configured, and publishes `@eunho-j/codex-as-api` to GitHub Packages with `GITHUB_TOKEN`.
|
|
691
695
|
|
|
692
696
|
Publishing to npmjs requires an authenticated npm session (`npm login` beforehand; `npm whoami` should succeed). From the repository root, the publish itself is one command:
|
|
@@ -729,6 +733,14 @@ npm test
|
|
|
729
733
|
|
|
730
734
|
## Release Notes
|
|
731
735
|
|
|
736
|
+
### v0.6.3
|
|
737
|
+
|
|
738
|
+
- Accept Claude Code auxiliary requests that combine ambient `output_config.effort` with call-level `thinking.disabled`.
|
|
739
|
+
- Give explicit disabled thinking precedence and send Codex reasoning effort `none` instead of returning HTTP 400.
|
|
740
|
+
- Document and test `CODEX_AS_API_RESPONSES_LITE=off` for Claude Code hosted WebSearch on GPT-5.6; WebFetch needs no Responses Lite override.
|
|
741
|
+
- Preserve fail-loudly validation for invalid effort values and unsupported `output_config` fields.
|
|
742
|
+
- Add Python, TypeScript, and Rust adapter regressions, streamed `/v1/messages` coverage, and a `/count_tokens` regression for the WebSearch/WebFetch request shape.
|
|
743
|
+
|
|
732
744
|
### v0.6.2
|
|
733
745
|
|
|
734
746
|
- Fix `/v1/messages/count_tokens` overcounting that could trigger Claude Code autocompaction on every turn.
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
+
## v0.6.3
|
|
4
|
+
|
|
5
|
+
### Claude Code WebSearch/WebFetch auxiliary calls
|
|
6
|
+
|
|
7
|
+
- Fix HTTP 400 responses when a Claude Code session with ambient effort sends a WebSearch/WebFetch auxiliary request containing both `output_config.effort` and call-level `thinking: {"type":"disabled"}`.
|
|
8
|
+
- Give explicit disabled thinking precedence over valid ambient effort and forward Codex reasoning effort `none` across Python, TypeScript, and Rust.
|
|
9
|
+
- Require and document `CODEX_AS_API_RESPONSES_LITE=off` for Claude Code hosted WebSearch on GPT-5.6 because official Responses Lite relies on a standalone `web.run` executor; WebFetch does not require this override.
|
|
10
|
+
- Continue rejecting empty, non-string, or unsupported effort values and unsupported `output_config` fields rather than silently discarding malformed requests.
|
|
11
|
+
|
|
12
|
+
### Validation
|
|
13
|
+
|
|
14
|
+
- Adapter tests cover every valid Claude Code effort value paired with disabled thinking while retaining invalid-value failures.
|
|
15
|
+
- Streamed `/v1/messages` tests across all three runtimes and a local `/count_tokens` test reproduce the Claude Code 2.1.209 request shape and prove provider-backed requests reach the classic Codex wire with reasoning effort `none`.
|
|
16
|
+
- A real GPT-5.6 Sol Codex OAuth WebSearch completed with HTTP 200 and structured `server_tool_use`, `web_search_tool_result`, and terminal SSE events.
|
|
17
|
+
|
|
3
18
|
## v0.6.2
|
|
4
19
|
|
|
5
20
|
### Claude Code count_tokens autocompact fix
|
|
@@ -9,7 +24,7 @@
|
|
|
9
24
|
- Count tool calls, tool-result identifiers, reasoning content, and normalized tool schemas once while excluding model IDs, output limits, stream flags, metadata, and other non-model request controls.
|
|
10
25
|
- Keep the existing image estimate separate so URL and inline base64 images are counted once without tokenizing the base64 payload as text.
|
|
11
26
|
- Keep token counting local and OAuth-free. No `tiktoken` package dependency or first-run encoding download is introduced.
|
|
12
|
-
- Record the upstream synchronization point as `tiktoken` 0.13.0 commit `08a5f3b2c987ada4fc5aa1f16c643c203fa8acaa`, checked on 2026-07-14, with the official rank-file SHA-256 verified
|
|
27
|
+
- Record the upstream synchronization point as `tiktoken` 0.13.0 commit `08a5f3b2c987ada4fc5aa1f16c643c203fa8acaa`, checked on 2026-07-14, with the official rank-file SHA-256 verified during release validation.
|
|
13
28
|
|
|
14
29
|
### Validation
|
|
15
30
|
|
|
@@ -341,13 +341,19 @@ def _convert_reasoning_effort(thinking: dict[str, Any] | None, output_config: ob
|
|
|
341
341
|
raise ValueError("output_config.task_budget is not supported by the Codex OAuth backend")
|
|
342
342
|
raw_effort = output_config.get("effort")
|
|
343
343
|
if raw_effort is not None:
|
|
344
|
-
if raw_effort not in {
|
|
344
|
+
if not isinstance(raw_effort, str) or raw_effort not in {
|
|
345
|
+
"low",
|
|
346
|
+
"medium",
|
|
347
|
+
"high",
|
|
348
|
+
"xhigh",
|
|
349
|
+
"max",
|
|
350
|
+
}:
|
|
345
351
|
raise ValueError("output_config.effort must be one of: low, medium, high, xhigh, max")
|
|
346
352
|
output_effort = raw_effort
|
|
347
353
|
|
|
348
354
|
thinking_effort = _convert_thinking(thinking)
|
|
349
|
-
if thinking_effort == "none"
|
|
350
|
-
|
|
355
|
+
if thinking_effort == "none":
|
|
356
|
+
return "none"
|
|
351
357
|
return output_effort or thinking_effort
|
|
352
358
|
|
|
353
359
|
|
|
@@ -392,13 +392,34 @@ class TestAnthropicRequestToInternal:
|
|
|
392
392
|
)
|
|
393
393
|
assert converted == effort
|
|
394
394
|
|
|
395
|
-
|
|
396
|
-
|
|
395
|
+
@pytest.mark.parametrize("effort", ["low", "medium", "high", "xhigh", "max"])
|
|
396
|
+
def test_disabled_thinking_overrides_output_config_effort(self, effort):
|
|
397
|
+
_, _, _, _, converted, _ = anthropic_request_to_internal(
|
|
398
|
+
model="test",
|
|
399
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
400
|
+
thinking={"type": "disabled"},
|
|
401
|
+
output_config={"effort": effort},
|
|
402
|
+
)
|
|
403
|
+
assert converted == "none"
|
|
404
|
+
|
|
405
|
+
def test_disabled_thinking_preserves_output_config_format(self):
|
|
406
|
+
_, _, _, _, converted, text = anthropic_request_to_internal(
|
|
407
|
+
model="test",
|
|
408
|
+
messages=[{"role": "user", "content": "hi"}],
|
|
409
|
+
thinking={"type": "disabled"},
|
|
410
|
+
output_config={"effort": "high", "format": {"type": "json_object"}},
|
|
411
|
+
)
|
|
412
|
+
assert converted == "none"
|
|
413
|
+
assert text == {"format": {"type": "json_object"}}
|
|
414
|
+
|
|
415
|
+
@pytest.mark.parametrize("effort", ["", 1, [], {}, "ultra"])
|
|
416
|
+
def test_disabled_thinking_does_not_bypass_output_config_effort_validation(self, effort):
|
|
417
|
+
with pytest.raises(ValueError, match="output_config.effort"):
|
|
397
418
|
anthropic_request_to_internal(
|
|
398
419
|
model="test",
|
|
399
420
|
messages=[{"role": "user", "content": "hi"}],
|
|
400
421
|
thinking={"type": "disabled"},
|
|
401
|
-
output_config={"effort":
|
|
422
|
+
output_config={"effort": effort},
|
|
402
423
|
)
|
|
403
424
|
|
|
404
425
|
def test_output_config_task_budget_fails_loudly(self):
|
|
@@ -1569,6 +1569,30 @@ def test_messages_count_tokens_counts_normalized_tools_without_provider_call(cli
|
|
|
1569
1569
|
assert body["context_window"] >= body["auto_compact_token_limit"]
|
|
1570
1570
|
|
|
1571
1571
|
|
|
1572
|
+
def test_messages_count_tokens_accepts_disabled_thinking_with_ambient_effort(client, monkeypatch):
|
|
1573
|
+
import codex_as_api.server as server_mod
|
|
1574
|
+
|
|
1575
|
+
def fail_provider_call():
|
|
1576
|
+
raise AssertionError("count_tokens must not call the Codex backend")
|
|
1577
|
+
|
|
1578
|
+
monkeypatch.setattr(server_mod, "_get_provider", fail_provider_call)
|
|
1579
|
+
response = client.post(
|
|
1580
|
+
"/v1/messages/count_tokens",
|
|
1581
|
+
json={
|
|
1582
|
+
"model": "gpt-5.6-sol",
|
|
1583
|
+
"max_tokens": 1024,
|
|
1584
|
+
"stream": True,
|
|
1585
|
+
"messages": [{"role": "user", "content": "search the web"}],
|
|
1586
|
+
"tools": [{"type": "web_search_20250305", "name": "web_search"}],
|
|
1587
|
+
"thinking": {"type": "disabled"},
|
|
1588
|
+
"output_config": {"effort": "high"},
|
|
1589
|
+
},
|
|
1590
|
+
)
|
|
1591
|
+
|
|
1592
|
+
assert response.status_code == 200, response.text
|
|
1593
|
+
assert response.json()["input_tokens"] > 0
|
|
1594
|
+
|
|
1595
|
+
|
|
1572
1596
|
def test_messages_count_tokens_large_ascii_payload_is_not_double_counted(client):
|
|
1573
1597
|
resp = client.post(
|
|
1574
1598
|
"/v1/messages/count_tokens",
|
|
@@ -2088,6 +2112,40 @@ def test_anthropic_latest_claude_code_shape_routes_known_gpt_effort_and_fast_mod
|
|
|
2088
2112
|
assert "speed" not in outbound
|
|
2089
2113
|
|
|
2090
2114
|
|
|
2115
|
+
def test_anthropic_disabled_thinking_overrides_ambient_effort_for_web_auxiliary_stream(
|
|
2116
|
+
client,
|
|
2117
|
+
recording_backend: RecordingBackend,
|
|
2118
|
+
monkeypatch,
|
|
2119
|
+
):
|
|
2120
|
+
monkeypatch.setenv(RESPONSES_LITE_ENV, "off")
|
|
2121
|
+
response = client.post(
|
|
2122
|
+
"/v1/messages",
|
|
2123
|
+
json={
|
|
2124
|
+
"model": "gpt-5.6-sol",
|
|
2125
|
+
"max_tokens": 1024,
|
|
2126
|
+
"stream": True,
|
|
2127
|
+
"system": "system",
|
|
2128
|
+
"messages": [{"role": "user", "content": "search the web"}],
|
|
2129
|
+
"tools": [{"type": "web_search_20250305", "name": "web_search"}],
|
|
2130
|
+
"thinking": {"type": "disabled"},
|
|
2131
|
+
"output_config": {"effort": "high"},
|
|
2132
|
+
},
|
|
2133
|
+
)
|
|
2134
|
+
|
|
2135
|
+
assert response.status_code == 200, response.text
|
|
2136
|
+
outbound = recording_backend.requests.get(timeout=1)["body"]
|
|
2137
|
+
assert outbound["reasoning"]["effort"] == "none"
|
|
2138
|
+
assert "context" not in outbound["reasoning"]
|
|
2139
|
+
assert outbound["tools"] == [{"type": "web_search", "external_web_access": True}]
|
|
2140
|
+
events = [
|
|
2141
|
+
json.loads(line.removeprefix("data: "))
|
|
2142
|
+
for line in response.text.splitlines()
|
|
2143
|
+
if line.startswith("data: {")
|
|
2144
|
+
]
|
|
2145
|
+
assert events[0]["type"] == "message_start"
|
|
2146
|
+
assert events[-1]["type"] == "message_stop"
|
|
2147
|
+
|
|
2148
|
+
|
|
2091
2149
|
def test_anthropic_output_config_format_reaches_codex_text_format(
|
|
2092
2150
|
client,
|
|
2093
2151
|
recording_backend: RecordingBackend,
|
|
@@ -2251,6 +2309,7 @@ def test_anthropic_unrepresentable_latest_controls_fail_before_upstream(
|
|
|
2251
2309
|
@pytest.mark.parametrize(
|
|
2252
2310
|
"unsupported",
|
|
2253
2311
|
[
|
|
2312
|
+
{"thinking": {"type": "disabled"}, "output_config": {"effort": []}},
|
|
2254
2313
|
{"output_config": {"format": "json"}},
|
|
2255
2314
|
{"output_config": {"format": {"type": "json_object", "extra": True}}},
|
|
2256
2315
|
{
|
|
@@ -2267,7 +2326,7 @@ def test_anthropic_unrepresentable_latest_controls_fail_before_upstream(
|
|
|
2267
2326
|
},
|
|
2268
2327
|
],
|
|
2269
2328
|
)
|
|
2270
|
-
def
|
|
2329
|
+
def test_anthropic_routes_reject_invalid_controls_and_unknown_image_sources(
|
|
2271
2330
|
client,
|
|
2272
2331
|
recording_backend: RecordingBackend,
|
|
2273
2332
|
route,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|