Skip to content

fix(auxiliary): support named custom providers in auxiliary tasks / 辅助任务支持命名自定义 provider - #37261

Closed
WenhuaXia wants to merge 1 commit into
NousResearch:mainfrom
WenhuaXia:fix/custom-provider-vision-auxiliary
Closed

fix(auxiliary): support named custom providers in auxiliary tasks / 辅助任务支持命名自定义 provider#37261
WenhuaXia wants to merge 1 commit into
NousResearch:mainfrom
WenhuaXia:fix/custom-provider-vision-auxiliary

Conversation

@WenhuaXia

Copy link
Copy Markdown

Summary / 概述

辅助任务现在可以正确解析命名自定义 provider(custom:name),修复了 vision(图像识别)、goal_judge 等任务在使用自定义 provider 时静默失效的问题。

Auxiliary tasks can now correctly resolve named custom providers (custom:name), fixing silent failures in vision, goal_judge, and other tasks when using custom providers.

Root Cause / 根因

_normalize_aux_provider() would strip custom:qwencustom, forcing all named custom providers through the anonymous-custom path (reads model.base_url + OPENAI_API_KEY from env). Users with custom_providers in config but no OPENAI_API_KEY env var set would get broken auxiliary tasks.

_normalize_aux_provider() 会把 custom:qwen 强制 strip 成 custom,导致所有命名自定义 provider 都走匿名 custom 路径(读环境变量 OPENAI_API_KEY)。如果用户没设置这个环境变量,辅助任务就静默失败。

Changes / 改动

  1. Remove the early return in _normalize_aux_provider()custom:name is now preserved intact so resolve_provider_client can route through the named-custom-provider branch, which reads from custom_providers in config.yaml.

    移除 _normalize_aux_provider() 中 strip custom:name 的 early return。resolve_provider_client 现在可以正确走 named custom provider 分支,从 custom_providers 读取 base_url + api_key。

  2. Add fallback in _resolve_custom_runtime() — when requested="custom" falls back to OpenRouter (because no bare custom entry exists), try resolve_runtime_provider(requested=None) to pick up the user's actual main provider as a safety net.

    _resolve_custom_runtime() 增加 fallback:当 custom 回退到 OpenRouter 时,尝试用 requested=None 重新解析用户实际的主 provider 作为兜底。

Affected Tasks / 影响范围

Any auxiliary task that uses custom:name as provider:

  • vision (image recognition / 图像识别)
  • goal_judge (automatic goal continuation / 目标自动延续)
  • compression, web_extract, etc.

所有使用 custom:name 作为 provider 的辅助任务:

  • vision(图像识别)
  • goal_judge(目标自动延续)
  • compression、web_extract 等

Testing / 测试

All existing tests pass (32 tests in test_auxiliary_client.py + test_auxiliary_named_custom_providers.py).

所有已有测试通过(test_auxiliary_client.py + test_auxiliary_named_custom_providers.py 共 32 个测试)。

Related: #37182

@WenhuaXia
WenhuaXia force-pushed the fix/custom-provider-vision-auxiliary branch from d06f1e0 to 7fc9103 Compare June 2, 2026 08:04
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/config Config system, migrations, profiles labels Jun 2, 2026
@WenhuaXia
WenhuaXia force-pushed the fix/custom-provider-vision-auxiliary branch from 7fc9103 to b965f35 Compare June 6, 2026 14:31
@WenhuaXia
WenhuaXia force-pushed the fix/custom-provider-vision-auxiliary branch 5 times, most recently from d76a090 to 23bdcc4 Compare June 21, 2026 19:49
辅助任务现在可以正确解析命名自定义 provider(custom:name)。

Before this fix, _normalize_aux_provider() would strip the "custom:" prefix
and return bare "custom", which routes through the anonymous-custom path
(reading model.base_url + OPENAI_API_KEY from config/env).  Users with
named custom_providers (e.g. custom:qwen) but no OPENAI_API_KEY set would
silently get "Goal judge is not configured" or broken vision tasks.

Two changes:
1. Remove the early return in _normalize_aux_provider() that stripped
   custom:xxx → custom.  Named custom providers are now preserved intact
   so resolve_provider_client can route them through the named-custom-provider
   branch which reads custom_providers from config.yaml.
2. Add a fallback in _resolve_custom_runtime(): when requested="custom"
   falls back to OpenRouter (because no bare "custom" entry exists), try
   resolve_runtime_provider(requested=None) to pick up the user's actual
   main provider.  This is a safety net for code paths that still call
   with bare "custom".

Affected tasks: vision, goal_judge, compression, web_extract, etc.
Any auxiliary task that uses "custom:name" as provider now works.

修复前:_normalize_aux_provider() 会把 custom:qwen 强制 strip 成 "custom",
导致所有带命名自定义 provider 的辅助任务(vision、goal_judge 等)都走匿名
custom 路径(读环境变量 OPENAI_BASE_URL/API_KEY)。用户如果没有设置这些
环境变量,辅助任务就静默失败。

修复后:
1. 移除 strip 逻辑,保留 custom:name 完整字符串,让 resolve_provider_client
   走 named custom provider 分支,从 custom_providers 读取 base_url + api_key。
2. 在 _resolve_custom_runtime() 增加 fallback:当 "custom" 回退到 OpenRouter
   时,尝试用 requested=None 重新解析用户实际的主 provider 作为兜底。

影响范围:vision(图像识别)、goal_judge、compression、web_extract 等
所有使用 custom:name 作为 provider 的辅助任务现在都正常工作。

Fixes: custom provider vision tasks broken, goal judge unavailable
Related: NousResearch#37182
@WenhuaXia
WenhuaXia force-pushed the fix/custom-provider-vision-auxiliary branch from 23bdcc4 to f273e3f Compare July 8, 2026 15:36
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for tracing the named custom-provider failure mode. This is now covered on current main by a later auxiliary-routing fix, so this PR is redundant.

  • Automated hermes-sweeper review verified agent/auxiliary_client.py:4227-4255: custom:<name> main providers pass their resolved runtime endpoint and credentials into auxiliary routing.
  • agent/auxiliary_client.py:4632-4695 builds the custom auxiliary client from those explicit values instead of falling back through bare custom resolution.
  • Commit 92da7a9970548340f0d538ef94d7af543d1dc7a5 (fix(auxiliary): reuse main_runtime credentials for named custom providers) implemented this behavior and is contained in release v2026.7.7.
  • Regression coverage is present in tests/agent/test_auxiliary_named_custom_providers.py:496-563.

Closing as implemented on main.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added sweeper:implemented-on-main Sweeper: behavior already present on current main sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:implemented-on-main Sweeper: behavior already present on current main sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants