From edcb2935e471b2c10b0023379c1d697c5d6e123f Mon Sep 17 00:00:00 2001 From: jenkins Date: Wed, 12 Aug 2026 01:21:20 -0300 Subject: [PATCH] hermes: normalize Codex response budgets --- services/hermes/agent-deployment.yaml | 2 +- services/hermes/scripts/codex_broker.py | 11 +++++++++++ testing/tests/test_hermes_chat_quality.py | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/services/hermes/agent-deployment.yaml b/services/hermes/agent-deployment.yaml index 824527879..89d952b9f 100644 --- a/services/hermes/agent-deployment.yaml +++ b/services/hermes/agent-deployment.yaml @@ -25,7 +25,7 @@ spec: ai.bstein.dev/execution: Hermes Kanban with durable direct Codex and Claude Code CLI workers ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available - ai.bstein.dev/config-rev: "20260811-switchyard-responses-output" + ai.bstein.dev/config-rev: "20260812-codex-budget-normalization" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: hermes-agent vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens diff --git a/services/hermes/scripts/codex_broker.py b/services/hermes/scripts/codex_broker.py index 0f810bcd4..d2e0108e5 100644 --- a/services/hermes/scripts/codex_broker.py +++ b/services/hermes/scripts/codex_broker.py @@ -124,6 +124,17 @@ def _validate_payload(payload: Any) -> dict[str, Any]: payload["input"] = [response_input] elif not isinstance(response_input, list) or not response_input: raise ValueError("non-empty Responses input list required") + # Switchyard uses ``max_output_tokens`` to bound the tiny classifier call, + # but its Responses translation can also copy that internal option onto the + # selected provider request. The first-party subscription Codex endpoint + # does not accept any of the public API token-budget aliases. Let Codex use + # its own response budget instead of turning a healthy fallback into a 400. + for token_budget_key in ( + "max_output_tokens", + "max_completion_tokens", + "max_tokens", + ): + payload.pop(token_budget_key, None) # Tenant conversations must not enter the owner's server-side history. payload["store"] = False payload["stream"] = True diff --git a/testing/tests/test_hermes_chat_quality.py b/testing/tests/test_hermes_chat_quality.py index 2c3f44ff7..a5cc0b592 100644 --- a/testing/tests/test_hermes_chat_quality.py +++ b/testing/tests/test_hermes_chat_quality.py @@ -525,10 +525,16 @@ def test_codex_broker_auth_and_request_contract(tmp_path: Path, monkeypatch): "input": "route this chat turn", "store": True, "stream": False, + "max_output_tokens": 96, + "max_completion_tokens": 96, + "max_tokens": 96, } ) assert payload["store"] is False assert payload["stream"] is True + assert "max_output_tokens" not in payload + assert "max_completion_tokens" not in payload + assert "max_tokens" not in payload assert payload["input"] == [ { "type": "message",