From 09e12e3c6062810f0e4165f55170f5d9ca8c8ac9 Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Thu, 30 Apr 2026 16:18:00 +0000 Subject: [PATCH] fix(streaming): handle list fallback_providers config in addition to single fallback_model dict From PR #1339. Co-authored-by: Jim Dawdy --- api/streaming.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/api/streaming.py b/api/streaming.py index 3d3b778a..9987401c 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -1701,19 +1701,25 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta _toolsets = _resolve_cli_toolsets(_cfg) # Fallback model from profile config (e.g. for rate-limit recovery) - _fallback = _cfg.get('fallback_model') or None + _fallback = _cfg.get('fallback_model') or _cfg.get('fallback_providers') or None + _fallback_resolved = None if _fallback: - # Resolve the fallback through our provider logic too - fb_model = _fallback.get('model', '') - fb_provider = _fallback.get('provider', '') - fb_base_url = _fallback.get('base_url') - _fallback_resolved = { - 'model': fb_model, - 'provider': fb_provider, - 'base_url': fb_base_url, - } - else: - _fallback_resolved = None + # Normalize: support both single dict (legacy) and list (chained fallback). + # Use the first valid entry as the fallback passed to AIAgent. + _fb_entry = None + if isinstance(_fallback, list): + for _entry in _fallback: + if isinstance(_entry, dict) and _entry.get('model'): + _fb_entry = _entry + break + elif isinstance(_fallback, dict) and _fallback.get('model'): + _fb_entry = _fallback + if _fb_entry: + _fallback_resolved = { + 'model': _fb_entry.get('model', ''), + 'provider': _fb_entry.get('provider', ''), + 'base_url': _fb_entry.get('base_url'), + } # Build kwargs defensively — guard newer params so the WebUI # degrades gracefully when run against an older hermes-agent build.