fix(auxiliary): resolve named custom providers and 'main' alias in auxiliary routing#5978
Merged
fix(auxiliary): resolve named custom providers and 'main' alias in auxiliary routing#5978
Conversation
…e match Captions in photo bursts and media group albums were silently dropped when a shorter caption happened to be a substring of an existing one (e.g. "Meeting" lost inside "Meeting agenda"). Extract a shared _merge_caption static helper that splits on "\n\n" and uses exact match with whitespace normalisation, then use it in both _enqueue_photo_event and _queue_media_group_event. Adds 13 unit tests covering the fixed bug scenarios. Cherry-picked from PR #2671 by Dilee.
Move _merge_caption helper from TelegramAdapter to BasePlatformAdapter so all adapters inherit it. Fix the same substring-containment bug in: - gateway/platforms/base.py (photo burst merging) - gateway/run.py (priority photo follow-up merging) - gateway/platforms/feishu.py (media batch merging) The original fix only covered telegram.py. The same bug existed in base.py and run.py (pure substring check) and feishu.py (list membership without whitespace normalization).
…xiliary routing Two bugs caused auxiliary tasks (vision, compression, etc.) to fail when using named custom providers defined in config.yaml: 1. 'provider: main' was hardcoded to 'custom', which only checks legacy OPENAI_BASE_URL env vars. Now reads _read_main_provider() to resolve to the actual provider (e.g., 'custom:beans', 'openrouter', 'deepseek'). 2. Named custom provider names (e.g., 'beans') fell through to PROVIDER_REGISTRY which doesn't know about config.yaml entries. Now checks _get_named_custom_provider() before the registry fallback. Fixes both resolve_provider_client() and _normalize_vision_provider() so the fix covers all auxiliary tasks (vision, compression, web_extract, session_search, etc.). Adds 13 unit tests. Reported by Laura via Discord.
e7529fb to
25b6797
Compare
teknium1
pushed a commit
that referenced
this pull request
Apr 8, 2026
Users on non-aggregator providers (DeepSeek, Alibaba, ZAI, Gemini, etc.) had vision silently fail because resolve_vision_provider_client()'s auto path only iterates _VISION_AUTO_PROVIDER_ORDER (openrouter, nous, codex, anthropic, custom). Their main provider was never tried. Mirror the same non-aggregator main-provider-first check that _resolve_auto() already has for non-vision tasks. Combined with the named custom provider fix in #5978, this also covers users whose main provider is a named custom endpoint. Cherry-picked from PR #5376 by Mibay. Closes #5366.
This was referenced Apr 8, 2026
teknium1
pushed a commit
that referenced
this pull request
Apr 8, 2026
…llback Users on non-aggregator providers (DeepSeek, Alibaba, ZAI, Gemini, etc.) had vision silently fail because resolve_vision_provider_client()'s auto path only iterates _VISION_AUTO_PROVIDER_ORDER (openrouter, nous, codex, anthropic, custom). Their main provider was never tried. Mirror the same non-aggregator main-provider-first check that _resolve_auto() already has for non-vision tasks. Combined with the named custom provider fix in #5978, this also covers users whose main provider is a named custom endpoint. Add vision-specific API fallback in call_llm: if the auto-resolved main provider returns 400/422 (model doesn't support vision), fall back through the strict vision backends which use known vision-capable models. This handles the case where the user's main model is text-only. Cherry-picked from PR #5376 by Mibay. Closes #5366.
teknium1
pushed a commit
that referenced
this pull request
Apr 8, 2026
…tive provider Simplify the vision auto-detection chain from 5 backends (openrouter, nous, codex, anthropic, custom) down to 3: 1. OpenRouter (known vision-capable default model) 2. Nous Portal (known vision-capable default model) 3. Active provider + model (whatever the user is running) 4. Stop This is simpler and more predictable. The active provider step uses resolve_provider_client() which handles all provider types including named custom providers (from #5978). Removed the complex preferred-provider promotion logic and API-level fallback — the chain is short enough that it doesn't need them. Based on PR #5376 by Mibay. Closes #5366.
teknium1
pushed a commit
that referenced
this pull request
Apr 8, 2026
…tive provider Simplify the vision auto-detection chain from 5 backends (openrouter, nous, codex, anthropic, custom) down to 3: 1. OpenRouter (known vision-capable default model) 2. Nous Portal (known vision-capable default model) 3. Active provider + model (whatever the user is running) 4. Stop This is simpler and more predictable. The active provider step uses resolve_provider_client() which handles all provider types including named custom providers (from #5978). Removed the complex preferred-provider promotion logic and API-level fallback — the chain is short enough that it doesn't need them. Based on PR #5376 by Mibay. Closes #5366.
jooray
added a commit
to jooray/hermes-agent
that referenced
this pull request
Apr 8, 2026
* upstream/main: (245 commits) fix: preserve existing thresholds, remove pre-read byte guard fix(tools): address PR review — remove _extract_raw_output, BudgetConfig everywhere, read_file hardening feat(budget): make tool result persistence thresholds configurable wip: tool result fixes -- persistence fix(minimax): correct context lengths, model catalog, thinking guard, aux model, and config base_url fix(vision): simplify vision auto-detection to openrouter → nous → active provider feat(agent): add jittered retry backoff feat(cron): track delivery failures in job status (NousResearch#6042) feat(feishu): add interactive card approval buttons (NousResearch#6043) fix: provider/model resolution — salvage 4 PRs + MiniMax aux URL fix (NousResearch#5983) feat: use mimo-v2-pro for non-vision auxiliary tasks on Nous free tier (NousResearch#6018) feat(tools): add "no_mcp" sentinel to exclude MCP servers per platform fix: use camelCase structuredContent attr, prefer structured over text test(mcp): add structured_content preservation tests fix(mcp): preserve structured_content in tool call results fix(auxiliary): resolve named custom providers and 'main' alias in auxiliary routing (NousResearch#5978) fix: CLI/UX batch — ChatConsole errors, curses scroll, skin-aware banner, git state banner (NousResearch#5974) fix: add _profile_arg tests + move STT language to config.yaml fix(discord): discard empty placeholder on voice transcription + force STT language fix(gateway): discard empty placeholder when voice transcription succeeds ... # Conflicts: # cron/scheduler.py # hermes_cli/tools_config.py # toolsets.py
DiscoStew6082
pushed a commit
to DiscoStew6082/hermes-agent
that referenced
this pull request
Apr 9, 2026
…xiliary routing (NousResearch#5978) * fix(telegram): replace substring caption check with exact line-by-line match Captions in photo bursts and media group albums were silently dropped when a shorter caption happened to be a substring of an existing one (e.g. "Meeting" lost inside "Meeting agenda"). Extract a shared _merge_caption static helper that splits on "\n\n" and uses exact match with whitespace normalisation, then use it in both _enqueue_photo_event and _queue_media_group_event. Adds 13 unit tests covering the fixed bug scenarios. Cherry-picked from PR NousResearch#2671 by Dilee. * fix: extend caption substring fix to all platforms Move _merge_caption helper from TelegramAdapter to BasePlatformAdapter so all adapters inherit it. Fix the same substring-containment bug in: - gateway/platforms/base.py (photo burst merging) - gateway/run.py (priority photo follow-up merging) - gateway/platforms/feishu.py (media batch merging) The original fix only covered telegram.py. The same bug existed in base.py and run.py (pure substring check) and feishu.py (list membership without whitespace normalization). * fix(auxiliary): resolve named custom providers and 'main' alias in auxiliary routing Two bugs caused auxiliary tasks (vision, compression, etc.) to fail when using named custom providers defined in config.yaml: 1. 'provider: main' was hardcoded to 'custom', which only checks legacy OPENAI_BASE_URL env vars. Now reads _read_main_provider() to resolve to the actual provider (e.g., 'custom:beans', 'openrouter', 'deepseek'). 2. Named custom provider names (e.g., 'beans') fell through to PROVIDER_REGISTRY which doesn't know about config.yaml entries. Now checks _get_named_custom_provider() before the registry fallback. Fixes both resolve_provider_client() and _normalize_vision_provider() so the fix covers all auxiliary tasks (vision, compression, web_extract, session_search, etc.). Adds 13 unit tests. Reported by Laura via Discord. --------- Co-authored-by: Dilee <uzmpsk.dilekakbas@gmail.com>
DiscoStew6082
pushed a commit
to DiscoStew6082/hermes-agent
that referenced
this pull request
Apr 9, 2026
…tive provider Simplify the vision auto-detection chain from 5 backends (openrouter, nous, codex, anthropic, custom) down to 3: 1. OpenRouter (known vision-capable default model) 2. Nous Portal (known vision-capable default model) 3. Active provider + model (whatever the user is running) 4. Stop This is simpler and more predictable. The active provider step uses resolve_provider_client() which handles all provider types including named custom providers (from NousResearch#5978). Removed the complex preferred-provider promotion logic and API-level fallback — the chain is short enough that it doesn't need them. Based on PR NousResearch#5376 by Mibay. Closes NousResearch#5366.
dbmizrahi
pushed a commit
to dbmizrahi/hermes-agent
that referenced
this pull request
Apr 10, 2026
…xiliary routing (NousResearch#5978) * fix(telegram): replace substring caption check with exact line-by-line match Captions in photo bursts and media group albums were silently dropped when a shorter caption happened to be a substring of an existing one (e.g. "Meeting" lost inside "Meeting agenda"). Extract a shared _merge_caption static helper that splits on "\n\n" and uses exact match with whitespace normalisation, then use it in both _enqueue_photo_event and _queue_media_group_event. Adds 13 unit tests covering the fixed bug scenarios. Cherry-picked from PR NousResearch#2671 by Dilee. * fix: extend caption substring fix to all platforms Move _merge_caption helper from TelegramAdapter to BasePlatformAdapter so all adapters inherit it. Fix the same substring-containment bug in: - gateway/platforms/base.py (photo burst merging) - gateway/run.py (priority photo follow-up merging) - gateway/platforms/feishu.py (media batch merging) The original fix only covered telegram.py. The same bug existed in base.py and run.py (pure substring check) and feishu.py (list membership without whitespace normalization). * fix(auxiliary): resolve named custom providers and 'main' alias in auxiliary routing Two bugs caused auxiliary tasks (vision, compression, etc.) to fail when using named custom providers defined in config.yaml: 1. 'provider: main' was hardcoded to 'custom', which only checks legacy OPENAI_BASE_URL env vars. Now reads _read_main_provider() to resolve to the actual provider (e.g., 'custom:beans', 'openrouter', 'deepseek'). 2. Named custom provider names (e.g., 'beans') fell through to PROVIDER_REGISTRY which doesn't know about config.yaml entries. Now checks _get_named_custom_provider() before the registry fallback. Fixes both resolve_provider_client() and _normalize_vision_provider() so the fix covers all auxiliary tasks (vision, compression, web_extract, session_search, etc.). Adds 13 unit tests. Reported by Laura via Discord. --------- Co-authored-by: Dilee <uzmpsk.dilekakbas@gmail.com>
dbmizrahi
pushed a commit
to dbmizrahi/hermes-agent
that referenced
this pull request
Apr 10, 2026
…tive provider Simplify the vision auto-detection chain from 5 backends (openrouter, nous, codex, anthropic, custom) down to 3: 1. OpenRouter (known vision-capable default model) 2. Nous Portal (known vision-capable default model) 3. Active provider + model (whatever the user is running) 4. Stop This is simpler and more predictable. The active provider step uses resolve_provider_client() which handles all provider types including named custom providers (from NousResearch#5978). Removed the complex preferred-provider promotion logic and API-level fallback — the chain is short enough that it doesn't need them. Based on PR NousResearch#5376 by Mibay. Closes NousResearch#5366.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes auxiliary task routing (vision, compression, web_extract, session_search, etc.) for users on named custom providers.
Bug: Setting
auxiliary.vision.provider: mainorauxiliary.vision.provider: beans(a named custom provider fromcustom_providersin config.yaml) fails with:Root cause — two bugs in
auxiliary_client.py:mainalias hardcoded to"custom"— only checks legacyOPENAI_BASE_URLenv vars, missing the user's actual provider config entirelyPROVIDER_REGISTRY.get("beans")→ None → "unknown provider", never consultingcustom_providersfrom config.yamlFix — 3 targeted changes (+34 lines):
resolve_provider_client()main alias_read_main_provider()→ resolve to actual provider nameresolve_provider_client()before PROVIDER_REGISTRY_get_named_custom_provider()for config.yaml entries_normalize_vision_provider()main aliasTest results
provider: mainandprovider: beansresolve correctlyRelated PRs
This fix is more comprehensive and handles both bugs in a single change.
Reported by Laura via Discord.