fix: honor fallback api_mode overrides - #33197
Conversation
|
Thanks for the duplicate-context note. I updated the PR body to use the project template and link #33062. This overlaps with #16346 / #24631 / #29749 on the |
|
Ran into this exact issue today with a custom provider using Setup: custom_providers:
- name: claude-api
base_url: https://one.cmaster.org
api_mode: anthropic_messages
model: claude-haiku-4-5-20251001
key_env: ANTHROPIC_API_KEY
fallback_providers:
- provider: claude-api
model: claude-haiku-4-5-20251001
key_env: ANTHROPIC_API_KEY
base_url: https://one.cmaster.orgSymptom: When the primary model (a local Qwen via custom endpoint) went down, the fallback to Root cause (traced through source):
Workaround applied locally (essentially what this PR does): # agent/chat_completion_helpers.py — inside try_activate_fallback()
# Before:
fb_api_mode = "chat_completions"
# After:
fb_api_mode = (fb.get("api_mode") or "").strip()
if not fb_api_mode:
if fb_provider == "openai-codex":
...
elif fb_provider == "anthropic" or ...:
...
# (rest of heuristics indented inside if not fb_api_mode)
if not fb_api_mode:
fb_api_mode = "chat_completions"Also added This fix matters especially for users running Anthropic-compatible proxies (LiteLLM, One API, etc.) as fallbacks who need native Anthropic format for prompt caching — switching to the OpenAI-compatible endpoint loses Would be great to see this merged. The fix is straightforward and the behavior gap between |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the explicit fallback transport gap. Current main still has the core issue: try_activate_fallback() resolves the fallback client without entry api_mode at agent/chat_completion_helpers.py:1441, then derives the transport heuristically at :1461; gateway auth fallback similarly returns runtime["api_mode"] at gateway/run.py:1967-1985.
Problems
- The added raw-hint gate would suppress heuristics for an invalid non-empty
api_mode, while also passing that invalid value toresolve_provider_client. Validate once and treat an invalid value as absent before both operations. - The same initial-auth fallback pattern remains in
cron/scheduler.py:2937-2942,tui_gateway/server.py:4469-4474,hermes_cli/cli_agent_setup_mixin.py:60, andagent/agent_init.py:1035-1039; none applies fallback-entryapi_mode.
Suggested changes
- Share validated per-entry runtime/transport resolution across these paths and add regressions for explicit
anthropic_messagesplus invalid-mode heuristic fallback.
Automated hermes-sweeper review.
| "chat_completions", | ||
| "codex_responses", | ||
| "anthropic_messages", | ||
| "bedrock_converse", |
There was a problem hiding this comment.
This checks the raw hint rather than the validated mode above. A typo such as api_mode: anthropic_message skips the existing URL/provider/model heuristics and leaves chat_completions; normalize to a validated value first, pass None for invalid input, and gate heuristics on that normalized value.
6329532 to
34f6894
Compare
|
@teknium1 — I implemented the sweeper recommendations, rebased onto current What changed:
Validation:
Could you take another look? |
34f6894 to
2abf895
Compare
|
Follow-up: the first CI run exposed two pre-existing gateway test doubles that still used the old resolver signature. I updated them to accept and assert the fallback The same run also hit an unrelated async-delegation timing race; this PR does not touch that module, and the exact failing file passed locally on rerun. Focused CI reproduction is now 30 passed ( |
What does this PR do?
Honors explicit
fallback_providers[].api_modewhen Hermes activates a fallback provider.Custom providers can declare
api_mode: anthropic_messages,api_mode: chat_completions, or another transport mode, but fallback activation currently recomputes transport from provider/base URL/model heuristics. For Anthropic-compatible gateways whose URL does not end in/anthropic, the fallback can resolve credentials correctly while leaving the agent runtime in the wrong transport mode.This PR makes the fallback entry's explicit
api_modeauthoritative in the in-agent failover path and applies the same per-entry precedence in the gateway auth fallback path.Closest related PRs checked:
api_modeclass in the agent/runtime path.gateway/run.py::_try_resolve_fallback_provider()also preserves the per-entryapi_modehint.Related Issue
Partially addresses #33062 for fallback provider entries that declare an explicit
api_mode.Type of Change
Changes Made
agent/chat_completion_helpers.pyapi_modethrough provider client resolution.api_modeis configured.gateway/run.pyapi_modeprecedence while resolving gateway auth fallback providers.tests/run_agent/test_run_agent.pytests/gateway/test_auth_fallback.pyapi_mode.How to Test
api_modeinstead of recomputing transport from provider/base URL/model heuristics.python -m pytest tests/run_agent/test_run_agent.py::TestFallbackAnthropicProvider \ tests/gateway/test_auth_fallback.py \ -q -o 'addopts='Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs
Targeted regression command:
Current GitHub CI for this PR is green, including tests, e2e, ruff enforcement, nix checks, build jobs, attribution, and supply-chain scan.