fix(custom-providers): propagate model field from config so API receives the correct model name#7916
Conversation
…o API receives the correct model name Fixes NousResearch#7828 When a custom_providers entry carries a `model` field, that value was silently dropped by `_get_named_custom_provider` and `_resolve_named_custom_runtime`. Callers received a runtime dict with `base_url`, `api_key`, and `api_mode` — but no `model`. As a result, `hermes chat --model <provider-name>` sent the *provider name* (e.g. "my-dashscope-provider") as the model string to the API instead of the configured model (e.g. "qwen3.6-plus"), producing: Error code: 400 - {'error': {'message': 'Model Not Exist'}} Setting the provider as the *default* model in config.yaml worked because that path writes `model.default` and the agent reads it back directly, bypassing the broken runtime resolution path. Changes: 1. hermes_cli/runtime_provider.py — _get_named_custom_provider() Reads `entry.get("model")` and includes it in the result dict so the value is available to callers. 2. hermes_cli/runtime_provider.py — _resolve_named_custom_runtime() Propagates `custom_provider["model"]` into the returned runtime dict. 3. cli.py — _ensure_runtime_credentials() After resolving runtime, if `runtime["model"]` is set, assign it to `self.model` so the AIAgent is initialised with the correct model name rather than the provider name the user typed on the CLI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re: Tests / test — Cancelled after 10mThis is a CI timeout, not a test failure introduced by this PR. What happenedThe workflow sets Evidence: every step before Our diff touches exactly two files:
Neither file has unit tests that import the changed functions in a way that would cause a hang or infinite loop. This is a pre-existing CI issueThe A quick fix for the workflow would be raising the limit to |
The cherry-picked fix from PR #7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR #7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
|
Merged via PR #7935. Your commit was cherry-picked onto current main with your authorship preserved in git log. During E2E testing I found that the model propagation was placed after the credential pool early-return in |
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
The cherry-picked fix from PR NousResearch#7916 placed model propagation after the credential pool early-return in _resolve_named_custom_runtime(), making it dead code when a pool is active (which happens whenever custom_providers has an api_key that auto-seeds the pool). - Inject model into pool_result before returning - Add 5 regression tests covering direct path, pool path, empty model, and absent model scenarios - Add 'model' to _VALID_CUSTOM_PROVIDER_FIELDS for config validation
Problem
Fixes #7828
When a
custom_providersentry inconfig.yamldefines amodelfield, that value was silently discarded:Running
hermes chat --model my-dashscopefailed with:because the agent sent the string
"my-dashscope"(the provider name) as the model to the API instead of"qwen3.6-plus"(the configured model). Setting the provider as the default model worked around the bug because that path readsmodel.defaultdirectly and never goes through_resolve_named_custom_runtime.Root Cause
_get_named_custom_provider()built its result dict fromentry.get("name"),entry.get("base_url"),entry.get("api_key"), andentry.get("api_mode")— but never touchedentry.get("model"). The field was present inconfig.yamlbut dropped before any caller could see it._resolve_named_custom_runtime()therefore had no model to propagate, andcli.py's_ensure_runtime_credentials()never updatedself.modelfrom the runtime result.Fix
Three small, surgical changes:
1.
hermes_cli/runtime_provider.py—_get_named_custom_provider()Reads the
modelfield from the config entry and stores it in the result dict so callers can access it.2.
hermes_cli/runtime_provider.py—_resolve_named_custom_runtime()Propagates the model name into the dict returned by
resolve_runtime_provider().3.
cli.py—_ensure_runtime_credentials()After resolving credentials, overrides
self.modelwith the configured model name so the AIAgent is initialised with the value the API actually expects, not the provider name the user typed.Behaviour after fix
name == modelin configname != modelin configmodelfield in entry