Skip to content

fix(auxiliary): resolve named provider credentials when base_url is set#16727

Open
thapecroth wants to merge 3 commits into
NousResearch:mainfrom
thapecroth:fix/16290-vision-provider-base-url-credentials
Open

fix(auxiliary): resolve named provider credentials when base_url is set#16727
thapecroth wants to merge 3 commits into
NousResearch:mainfrom
thapecroth:fix/16290-vision-provider-base-url-credentials

Conversation

@thapecroth

Copy link
Copy Markdown

Summary

Fixes #16290

When auxiliary.vision.provider is set to a named provider (e.g. zai) with a custom base_url, the credential pool was not consulted for that provider's API key. The provider was silently forced to custom and only OPENAI_API_KEY was checked, causing 401 errors.

Root Cause

_resolve_task_provider_model() forced provider='custom' whenever cfg_base_url was set, discarding the original named provider. resolve_vision_provider_client() then only looked up credentials from the custom pool.

Changes

  1. _resolve_task_provider_model() — when both cfg_provider and cfg_base_url are set, preserve the named provider instead of forcing 'custom'
  2. resolve_vision_provider_client() — when a named provider accompanies a base_url, resolve credentials from that provider's pool via the new _resolve_provider_api_key() helper
  3. _resolve_provider_api_key() — new helper that consults PROVIDER_REGISTRY + resolve_api_key_provider_credentials() to get the right key for a named provider

Test Coverage

8 new tests in test_vision_provider_base_url_credentials.py:

  • Provider preserved when both provider + base_url configured
  • Falls back to 'custom' when only base_url is set
  • 'auto' provider not preserved with base_url
  • ZAI_API_KEY resolved from env for provider='zai'
  • Unknown provider returns None
  • Provider with no key returns None
  • Vision client uses zai credentials with base_url
  • Custom provider skips credential pool lookup

All 96 existing auxiliary tests continue to pass.

Reproduction (before fix)

auxiliary:
  vision:
    provider: zai
    model: glm-4v
    base_url: https://open.bigmodel.cn/api/paas/v4
    api_key: ''    # leave empty, expecting auto-resolve

Previously: 401 error. After fix: ZAI_API_KEY from .env is used.

…ool use (NousResearch#15275)

Architectural fix inspired by Claude Code's SocketPool pattern.
Replaces eager import-time MCP server spawning with lazy initialization:

  - discover_mcp_tools(lazy=True): registers tool stubs from cache
    without connecting to MCP servers
  - ensure_mcp_initialized(): thread-safe singleton that connects all
    configured MCP servers on first actual tool call (no-op thereafter)
  - _register_mcp_tool_stubs(): loads cached tool schemas from
    ~/.hermes/cache/mcp_tools/ so the model sees MCP tools at session
    start without subprocess overhead
  - _save_cached_tool_definitions(): persists tool schemas after
    successful discovery for future lazy loads

Key difference from env var guard (PR NousResearch#15796): this prevents duplicates
by design — no consumer needs to remember to set an env var. Multiple
importers of model_tools in the same process share the same lazy pool.
MCP servers only spawn when a tool is actually invoked.

11 new tests cover: lazy discovery, ensure_mcp_initialized idempotency,
cache persistence, and slash_worker import safety.
Add real subprocess test that verifies importing model_tools does NOT
call register_mcp_servers at import time (the core NousResearch#15275 fix).
This catches regressions even if the mock-based tests pass.
…et (NousResearch#16290)

When auxiliary.vision.provider is set to a named provider (e.g. 'zai')
with a custom base_url, the credential pool was not consulted for that
provider's API key. Instead, the provider was silently forced to
'custom' and only OPENAI_API_KEY was checked, causing 401 errors.

Root cause: _resolve_task_provider_model() forced provider='custom'
whenever cfg_base_url was set, discarding the original named provider.
resolve_vision_provider_client() then only looked up credentials from
the 'custom' pool.

Fix:
- _resolve_task_provider_model: when both cfg_provider and cfg_base_url
  are set, preserve the named provider instead of forcing 'custom'.
- resolve_vision_provider_client: when a named provider accompanies a
  base_url, resolve credentials from that provider's pool via the new
  _resolve_provider_api_key() helper before falling back to 'custom'.
- Added 8 tests covering the new behavior and edge cases.

Fixes NousResearch#16290
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tools Tool registry, model_tools, toolsets tool/vision Vision analysis and image generation provider/zai ZAI provider labels Apr 27, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing fix for #16290 alongside PRs #16389, #16308, and #16317 — all address the same _resolve_task_provider_model() forcing provider to 'custom' when base_url is set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists provider/zai ZAI provider tool/vision Vision analysis and image generation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: auxiliary.vision with provider=zai and custom base_url fails to auto-resolve ZAI_API_KEY

2 participants