Skip to content

fix(model_metadata): auto-load global custom_providers in get_model_context_length (closes #12977) (closes #13807)#17460

Open
smallerxie wants to merge 1 commit into
NousResearch:mainfrom
smallerxie:fix-custom-providers-context-length
Open

fix(model_metadata): auto-load global custom_providers in get_model_context_length (closes #12977) (closes #13807)#17460
smallerxie wants to merge 1 commit into
NousResearch:mainfrom
smallerxie:fix-custom-providers-context-length

Conversation

@smallerxie

@smallerxie smallerxie commented Apr 29, 2026

Copy link
Copy Markdown

Summary

get_model_context_length() now auto-loads the global custom_providers from config.yaml when the custom_providers parameter is None. This ensures per-model context_length overrides in custom_providers are visible to all callers — including auxiliary model resolution paths that currently don't pass custom_providers.

Symptom: a user with custom_providers defining LongCat-2.0-Preview at 1M context sees this warning on every session start:

⚠ Compression model LongCat-2.0-Preview (api.longcat.chat) context is 256,000 tokens, but the main model LongCat-2.0-Preview (custom)'s compression threshold was 500,000 tokens. Auto-lowered this session's threshold to 256,000 tokens so compression can run.

The (custom) model correctly reads 1M from custom_providers, but the compression feasibility check reads the hardcoded default because get_model_context_length never sees the user's custom_providers.

Root cause: step 0b in get_model_context_length() has a custom_providers parameter (default None). Most callers — compressor feasibility check, fallback model activation, session hygiene, context reference preprocessing — do not pass it, so the custom_providers lookup is silently skipped. The main model works because AIAgent.__init__ directly calls get_custom_provider_context_length before get_model_context_length. Auxiliary models have no such pre-step.

Fix approach: auto-load custom_providers from global config inside get_model_context_length() when the parameter is None, rather than threading it through every caller. This is the minimal fix — one file, one if branch, consistent with how the function already handles other fallback sources.

Why this PR is not a duplicate

Relationship to PR #15844 (merged)

PR #15844 added step 0b with a custom_providers= kwarg and wired it through 5 call sites (startup, /model switch, display paths). However, it did not wire the remaining call sites:

  • _check_compression_model_feasibility() in run_agent.py:2178
  • resolve_vision_provider_client() in auxiliary_client.py
  • get_title_model_context_length() in run_agent.py
  • Session hygiene and context reference preprocessing paths

These callers still pass custom_providers=None, so step 0b is silently skipped. The exact symptom described in #12977 and #13807 (compression warning) persists on main today. This PR closes the remaining gap that #15844 left open.

Relationship to PR #14023 (closed)

PR #14023 proposed the same step 0b fix but was closed because #15844 had landed. The closing comment stated:

"The fix proposed here has since been implemented on main by a broader refactor (PR #15844)"

This was incorrect — #15844 only partially addressed the issue. The auxiliary paths that #14023 would have fixed are still broken. This PR completes the work that #14023 started.

Relationship to PR #13813 (open)

PR #13813 fixes only the compression path by duplicating the providers lookup in run_agent.py's _prepare_compression(). That approach:

  • Works for compression only
  • Duplicates logic instead of fixing the root cause
  • Doesn't protect against the same bug appearing in future callers

This PR's auto-load approach is the most general solution: a single change in model_metadata.py that protects all current and future callers without requiring each one to be manually wired.

Changes

  • agent/model_metadata.py — step 0b: when custom_providers is None, auto-load from global config via get_compatible_custom_providers(). On failure, fall back to [] (empty list), preserving existing behavior.
  • tests/run_agent/test_compression_feasibility.py — 3 new tests:
    • test_custom_providers_auto_loaded_when_none: verifies auto-load resolves 1M context from mocked custom_providers
    • test_custom_providers_auto_load_failure_falls_through: verifies graceful fallback when auto-load raises
    • test_explicit_empty_custom_providers_skips_lookup: verifies [] skips auto-load entirely

Validation

Before After
Custom provider with 1M context, compression falls back to main model Warning: aux context 256K < threshold 500K No warning, correct 1M context ✓
test_compression_feasibility.py 16/16 pass 19/19 pass (+3 new)
test_model_metadata.py 93/93 pass 93/93 pass

Closes

#12977
#13807
#8785

@smallerxie smallerxie force-pushed the fix-custom-providers-context-length branch from 54fc120 to c53d3d1 Compare April 30, 2026 06:22
rxdxxxx added a commit to rxdxxxx/hermes-agent that referenced this pull request May 5, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
teknium1 pushed a commit that referenced this pull request May 5, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes #12977
Related: #13807, #17460
teknium1 pushed a commit that referenced this pull request May 5, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes #12977
Related: #13807, #17460
nickdlkk pushed a commit to nickdlkk/hermes-agent that referenced this pull request May 11, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
rmulligan pushed a commit to rmulligan/hermes-agent that referenced this pull request May 11, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
JinyuID pushed a commit to JinyuID/hermes-agent that referenced this pull request May 11, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
jsboige pushed a commit to jsboige/hermes-agent that referenced this pull request May 14, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
Each auxiliary model must be resolved with its own provider so that
provider-specific paths (e.g. Bedrock static table, OpenRouter API)
are invoked for the correct client, not inherited from the main model.

When the main model is Bedrock, passing self.provider unconditionally
to get_model_context_length() for the aux model caused the Bedrock
static table hard-intercept (step 1b) to fire for non-Bedrock models,
returning BEDROCK_DEFAULT_CONTEXT_LENGTH=128K instead of the model's
real context window — triggering a false compression warning every session.

Fix: pass _aux_cfg_provider when explicitly set, falling back to
self.provider only when the aux provider is unset or "auto".

Closes NousResearch#12977
Related: NousResearch#13807, NousResearch#17460
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 loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants