feat: per-provider max_tokens via custom_providers models.<model>.max_tokens - #28786
feat: per-provider max_tokens via custom_providers models.<model>.max_tokens#28786pty819 wants to merge 1 commit into
Conversation
…model>.max_tokens Adds a new lookup function get_custom_provider_max_tokens() parallel to the existing get_custom_provider_context_length(). When model.max_tokens is unset globally, the agent init path now falls back to checking custom_providers for a per-provider max_tokens override, matched by base_url + model name. This allows users to set a provider-scoped output-token cap without affecting fallback providers in the chain. Closes NousResearch#28782
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused patch. The underlying gap still exists on current main for custom_providers[].models.<model>.max_tokens, but this implementation needs rework before it is safe to salvage.
Problems
- The patch resolves the nested cap only during agent initialization. Current main sends
agent.max_tokenson later requests (agent/chat_completion_helpers.py:650,:750,:782), while fallback activation and model switching change provider/model without recomputing that cap (agent/chat_completion_helpers.py:1045,agent/agent_runtime_helpers.py:1446). That can leak the primary custom provider's cap onto fallbacks, which is the behavior this PR is trying to avoid. - The new assignment is placed after the init path records
_session_init_model_config["max_tokens"]; on current main the analogous write isagent/agent_init.py:1343, so the session metadata would not reflect the effective cap. - There is no regression coverage. Current main only tests the adjacent top-level provider cap path in
tests/gateway/test_max_tokens_propagation.py:77.
Suggested changes
- Move the lookup into a shared resolution helper used by startup,
/modelswitch, and fallback activation. - Keep current precedence: explicit/env override > global
model.max_tokens> provider/model-specific cap >None. - Add targeted tests for nested per-model config, invalid values, global override precedence, and fallback/switch non-leakage.
Automated hermes-sweeper review.
| @@ -1165,6 +1165,23 @@ def init_agent( | |||
| ) | |||
There was a problem hiding this comment.
Resolving this only during init makes agent.max_tokens a sticky session-wide value; fallback activation and /model switching later change provider/model without recomputing this cap, so the primary provider's cap can still leak onto fallback providers.
| base_url=agent.base_url, | ||
| custom_providers=get_compatible_custom_providers(_agent_cfg), | ||
| ) | ||
| if _cp_max_tokens is not None: |
There was a problem hiding this comment.
Because _session_init_model_config["max_tokens"] was written just above this block, the session metadata will still record None when this nested provider cap is applied. Either resolve before recording the metadata or update the metadata after assigning agent.max_tokens.
| @@ -3229,6 +3229,66 @@ def get_custom_provider_context_length( | |||
| return None | |||
|
|
|||
There was a problem hiding this comment.
This helper mirrors context_length lookup, but max_tokens has a stronger non-leakage requirement across fallback/switch paths. It should probably be part of a shared max_tokens resolution path rather than only called from startup.
|
Thanks for the focused configuration work. This automated hermes-sweeper review is closing it under the standing policy against new user-facing
For provider-wide caps, please use the existing Closed as not-planned per standing maintainer policy ( |
Summary
Adds per-provider
max_tokenssupport tocustom_providers, mirroring the existingcontext_lengthpattern. This allows users to set a provider-scoped output-token cap without affecting fallback providers.Problem
model.max_tokensinconfig.yamlis global — it applies to all providers including fallbacks. There is no way to scopemax_tokensto a specific provider, unlikecontext_lengthwhich already supports per-provider overrides.Changes
hermes_cli/config.pyget_custom_provider_max_tokens()— mirrorsget_custom_provider_context_length()exactly. Matches bybase_url+modelname, returnsmodels.<model>.max_tokensif present and valid."max_tokens"to_KNOWN_KEYSin_normalize_custom_provider_entryso the top-level key is not flagged as unknown (defensive, for users who had it at top level).agent/agent_init.pymodel.max_tokensfallback (and before context_length resolution), adds a second fallback that checkscustom_providersfor a per-providermax_tokenswhenagent.max_tokensis stillNone.Usage
Related
Closes #28782