hermes: keep quality routes on hosted models
All checks were successful
Tests / Declarative: Post Actions passed: 250

This commit is contained in:
jenkins 2026-08-12 02:52:27 -03:00
parent a72c2b008d
commit 3af729849e
3 changed files with 35 additions and 23 deletions

View File

@ -303,7 +303,7 @@ data:
classifier_target = "classifier" classifier_target = "classifier"
# Switchyard falls through this list after a request-local target failure. # Switchyard falls through this list after a request-local target failure.
# Keep both xhigh providers first so recovery can escalate, never downgrade. # Keep both xhigh providers first so recovery can escalate, never downgrade.
targets = ["claude_opus_xhigh", "codex_sol_xhigh", "claude_sonnet_high", "codex_sol_high", "claude_opus_high", "codex_terra_high", "claude_sonnet_medium", "codex_sol_medium", "codex_terra_medium", "local_qwen_medium", "claude_haiku_low", "codex_luna_low", "codex_terra_low", "local_qwen_low"] targets = ["claude_opus_xhigh", "codex_sol_xhigh", "claude_sonnet_high", "codex_sol_high", "claude_opus_high", "codex_terra_high", "claude_sonnet_medium", "codex_sol_medium", "codex_terra_medium", "claude_haiku_low", "codex_luna_low", "codex_terra_low"]
default_target = "claude_sonnet_high" default_target = "claude_sonnet_high"
session_affinity = false session_affinity = false
recent_turn_window = 12 recent_turn_window = 12
@ -331,23 +331,24 @@ data:
the fastest target at the safety floor, never below it. An explicit the fastest target at the safety floor, never below it. An explicit
available provider or model wins at the safety floor. available provider or model wins at the safety floor.
3. Use local Qwen only at low or medium for low-risk summaries, formatting, 3. This quality-first triage route must use a hosted Codex or Claude target.
lookup, and continuity. Prefer Codex for implementation, debugging, tests, The local Qwen model remains the routing classifier, but its 32K context and
commands, and repository work. Prefer Claude for diagnosis, architecture, tool protocol are not eligible for foreground triage execution. Prefer
ambiguity, synthesis, risk analysis, adversarial analysis, and independent Codex for implementation, debugging, tests, commands, and repository work.
review. Anthropic means Claude; OpenAI means Codex. Never select a provider Prefer Claude for diagnosis, architecture, ambiguity, synthesis, risk
stated to be unavailable, failed, exhausted, rate-limited, or out of analysis, adversarial analysis, and independent review. Anthropic means
capacity; use the other provider at the same floor. Claude; OpenAI means Codex. Never select a provider stated to be
unavailable, failed, exhausted, rate-limited, or out of capacity; use the
other provider at the same floor.
4. Map exactly: Codex low=codex_luna_low, medium=codex_terra_medium, 4. Map exactly: Codex low=codex_luna_low, medium=codex_terra_medium,
high=codex_sol_high, xhigh=codex_sol_xhigh; Claude low=claude_haiku_low, high=codex_sol_high, xhigh=codex_sol_xhigh; Claude low=claude_haiku_low,
medium=claude_sonnet_medium, high=claude_sonnet_high, medium=claude_sonnet_medium, high=claude_sonnet_high,
xhigh=claude_opus_xhigh; local low=local_qwen_low and local xhigh=claude_opus_xhigh. Re-evaluate every boundary and resolve "continue"
medium=local_qwen_medium. Re-evaluate every boundary and resolve "continue"
or "do it" from recent context. or "do it" from recent context.
""" """
response_schema = ''' response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["claude_sonnet_high","codex_sol_high","codex_terra_medium","claude_sonnet_medium","codex_terra_high","codex_sol_medium","claude_opus_high","codex_sol_xhigh","claude_opus_xhigh","codex_luna_low","claude_haiku_low","local_qwen_medium","local_qwen_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false} {"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["claude_sonnet_high","codex_sol_high","codex_terra_medium","claude_sonnet_medium","codex_terra_high","codex_sol_medium","claude_opus_high","codex_sol_xhigh","claude_opus_xhigh","codex_luna_low","claude_haiku_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
''' '''
[routes.auto_deep.policy] [routes.auto_deep.policy]
@ -361,7 +362,7 @@ data:
classifier_target = "classifier" classifier_target = "classifier"
# Switchyard falls through this list after a request-local target failure. # Switchyard falls through this list after a request-local target failure.
# Keep both xhigh providers first so recovery can escalate, never downgrade. # Keep both xhigh providers first so recovery can escalate, never downgrade.
targets = ["codex_sol_xhigh", "claude_opus_xhigh", "codex_sol_high", "claude_opus_high", "claude_sonnet_high", "codex_terra_high", "codex_sol_medium", "claude_sonnet_medium", "codex_terra_medium", "local_qwen_medium", "codex_luna_low", "claude_haiku_low", "codex_terra_low", "local_qwen_low"] targets = ["codex_sol_xhigh", "claude_opus_xhigh", "codex_sol_high", "claude_opus_high", "claude_sonnet_high", "codex_terra_high", "codex_sol_medium", "claude_sonnet_medium", "codex_terra_medium", "codex_luna_low", "claude_haiku_low", "codex_terra_low"]
default_target = "codex_sol_high" default_target = "codex_sol_high"
session_affinity = false session_affinity = false
recent_turn_window = 16 recent_turn_window = 16
@ -389,23 +390,24 @@ data:
the fastest target at the safety floor, never below it. An explicit the fastest target at the safety floor, never below it. An explicit
available provider or model wins at the safety floor. available provider or model wins at the safety floor.
3. Use local Qwen only at low or medium for low-risk lookup, formatting, and 3. This owner-only engineering route must use a hosted Codex or Claude
continuity. Prefer Codex for implementation, debugging, tests, commands, target. The local Qwen model remains the routing classifier, but its 32K
and repository changes. Prefer Claude for architecture, ambiguity, context and tool protocol are not eligible for foreground agent execution.
synthesis, risk analysis, adversarial analysis, and independent review. Prefer Codex for implementation, debugging, tests, commands, and repository
Anthropic means Claude; OpenAI means Codex. Never select a provider stated changes. Prefer Claude for architecture, ambiguity, synthesis, risk
to be unavailable, failed, exhausted, rate-limited, or out of capacity; use analysis, adversarial analysis, and independent review. Anthropic means
the other provider at the same floor. Claude; OpenAI means Codex. Never select a provider stated to be
unavailable, failed, exhausted, rate-limited, or out of capacity; use the
other provider at the same floor.
4. Map exactly: Codex low=codex_luna_low, medium=codex_terra_medium, 4. Map exactly: Codex low=codex_luna_low, medium=codex_terra_medium,
high=codex_sol_high, xhigh=codex_sol_xhigh; Claude low=claude_haiku_low, high=codex_sol_high, xhigh=codex_sol_xhigh; Claude low=claude_haiku_low,
medium=claude_sonnet_medium, high=claude_sonnet_high, medium=claude_sonnet_medium, high=claude_sonnet_high,
xhigh=claude_opus_xhigh; local low=local_qwen_low and local xhigh=claude_opus_xhigh. Re-evaluate every boundary and resolve "continue"
medium=local_qwen_medium. Re-evaluate every boundary and resolve "continue"
or "do it" from recent context. or "do it" from recent context.
""" """
response_schema = ''' response_schema = '''
{"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["codex_sol_high","claude_opus_high","claude_sonnet_high","codex_terra_high","codex_sol_xhigh","claude_opus_xhigh","codex_terra_medium","claude_sonnet_medium","codex_sol_medium","codex_luna_low","claude_haiku_low","local_qwen_medium","local_qwen_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false} {"type":"object","properties":{"decision":{"type":"object","properties":{"target":{"type":"string","enum":["codex_sol_high","claude_opus_high","claude_sonnet_high","codex_terra_high","codex_sol_xhigh","claude_opus_xhigh","codex_terra_medium","claude_sonnet_medium","codex_sol_medium","codex_luna_low","claude_haiku_low","codex_terra_low"]}},"required":["target"],"additionalProperties":false}},"required":["decision"],"additionalProperties":false}
''' '''
[routes.auto_maximum.policy] [routes.auto_maximum.policy]

View File

@ -22,7 +22,7 @@ spec:
labels: labels:
app: hermes-switchyard app: hermes-switchyard
annotations: annotations:
ai.bstein.dev/config-rev: "20260812-auto-response-budget" ai.bstein.dev/config-rev: "20260812-quality-route-local-exclusion"
prometheus.io/scrape: "true" prometheus.io/scrape: "true"
prometheus.io/port: "9005" prometheus.io/port: "9005"
prometheus.io/path: /metrics prometheus.io/path: /metrics

View File

@ -855,6 +855,16 @@ def test_local_flux_runtime_and_gpu_handoff_are_flux_managed():
leading_targets = set(routes[route_name]["targets"][:2]) leading_targets = set(routes[route_name]["targets"][:2])
assert leading_targets == {"codex_sol_xhigh", "claude_opus_xhigh"} assert leading_targets == {"codex_sol_xhigh", "claude_opus_xhigh"}
assert "max_output_tokens" not in routes[route_name] assert "max_output_tokens" not in routes[route_name]
for route_name in ("auto_deep", "auto_maximum"):
targets = routes[route_name]["targets"]
selector_targets = routes[route_name]["response_schema"]
assert not any(target.startswith("local_") for target in targets)
assert "local_qwen" not in selector_targets
assert "not eligible for foreground" in routes[route_name]["prompt"]
for route_name in ("auto_fast", "auto_balanced", "manual_local_qwen"):
assert any(
target.startswith("local_") for target in routes[route_name]["targets"]
)
assert "max_output_tokens" not in routes["worker_auto_maximum"] assert "max_output_tokens" not in routes["worker_auto_maximum"]
model_gate = _documents(HERMES / "model-gate-configmap.yaml")[0]["data"][ model_gate = _documents(HERMES / "model-gate-configmap.yaml")[0]["data"][
"model_gate.py" "model_gate.py"