fix(config): preserve optional custom_providers fields on v11→v12 migration#17844
Open
zicochaos wants to merge 1 commit into
Open
fix(config): preserve optional custom_providers fields on v11→v12 migration#17844zicochaos wants to merge 1 commit into
zicochaos wants to merge 1 commit into
Conversation
…ration
The v11→v12 migration in migrate_config() builds a new providers.<key>
dict by copying only name / api / api_key / default_model / transport
from the legacy custom_providers entry. Every other field that
_normalize_custom_provider_entry recognises (the runtime read-side
normaliser in this same module) — models, context_length, key_env /
api_key_env, rate_limit_delay, request_timeout_seconds,
stale_timeout_seconds — is silently dropped on upgrade.
The most painful loss is per-model context_length overrides under
`models.<m>.context_length`: a config like
custom_providers:
- name: my-provider
base_url: https://example.com/v1
model: gpt-5.4
models:
gpt-5.4: {context_length: 1050000}
would migrate cleanly into providers.my-provider with the right
api/transport/default_model — but lose the gpt-5.4 → 1050000 entry
without warning. Runtime then falls back to the 128K default for that
model, silently truncating long-context conversations.
Other dropped fields each surface their own breakage:
- key_env: api keys sourced from env vars stop being applied; runtime
receives no key for that provider.
- context_length: provider-level default context window override is lost.
- rate_limit_delay / *_timeout_seconds: rate-limiting and timeout
overrides on slow custom endpoints are lost; some self-hosted setups
rely on these for stability.
Fix: extend the new_entry construction to copy every field
_normalize_custom_provider_entry's _KNOWN_KEYS lists, with appropriate
type / value validation. Normalise api_key_env → key_env on the way
out (the alias is documented in website/docs/guides/azure-foundry.md
but the migration produced configs that needed both names to be
inspected at read time).
Adds three tests under TestCustomProviderCompatibility:
- test_v11_upgrade_preserves_optional_fields: full-shape round-trip
- test_v11_upgrade_normalises_api_key_env_alias: alias canonicalisation
- test_v11_upgrade_skips_empty_or_invalid_optional_fields: zero-value /
wrong-type / empty values must not be copied
Collaborator
1 similar comment
Collaborator
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The v11→v12 migration in
migrate_config()builds a newproviders.<key>dict by copying onlyname / api / api_key / default_model / transportfrom the legacycustom_providersentry. Every other field that_normalize_custom_provider_entryrecognises (the runtime read-side normaliser in this same module) is silently dropped on upgrade:models— per-model dict (most painful loss; see below)context_length— provider-level default context windowkey_env/api_key_env— env var name for api_keyrate_limit_delayrequest_timeout_secondsstale_timeout_secondsMotivation — the per-model
context_lengthlossA config like:
migrates cleanly into
providers.my-providerwith the rightapi,transport,api_key,default_model— but loses themodels:map entirely. Runtime then falls back to the 128K default for every model on this provider, silently truncating long-context conversations to 1/8 the configured window. There's no warning, no log message — the user only notices when the agent starts forgetting things mid-conversation or when the gateway emits the per-modelwithout declared context_lengthwarnings introduced for context-length validation.The other dropped fields each surface their own breakage:
key_env: api keys sourced from env vars stop being applied; runtime receives no key for that provider.context_length: provider-level default context window override is lost.rate_limit_delay/*_timeout_seconds: rate-limiting and timeout overrides on slow custom endpoints are lost; some self-hosted setups rely on these for stability.Fix
Extend the
new_entryconstruction to copy every field listed in_normalize_custom_provider_entry's_KNOWN_KEYS, with appropriate type/value validation matching the runtime normaliser:models: dict (preserved as-is) or list (preserved as-is — runtime normaliser converts list → dict on read)context_length,request_timeout_seconds,stale_timeout_seconds: positive int onlyrate_limit_delay: int or float, ≥ 0key_env/api_key_env: non-empty string; normalised to canonicalkey_envon the way out (the alias is documented inwebsite/docs/guides/azure-foundry.md)Empty / zero / wrong-type values are skipped — they would either confuse the runtime normaliser or display as user-meaningful overrides when they are not.
Test plan
tests/hermes_cli/test_config.py::TestCustomProviderCompatibility::test_v11_upgrade_preserves_optional_fields— full-shape round-triptests/hermes_cli/test_config.py::TestCustomProviderCompatibility::test_v11_upgrade_normalises_api_key_env_alias—api_key_env→key_envcanonicalisationtests/hermes_cli/test_config.py::TestCustomProviderCompatibility::test_v11_upgrade_skips_empty_or_invalid_optional_fields— zero-value / wrong-type / empty values must not be copiedtest_v11_upgrade_moves_custom_providers_into_providersstill passes — exact-dict assertion unchanged