Plugin providers resolve in /model, the model picker and hermes model, aliases land on the canonical name (#69576, salvage #52549 #54705 #65968 #34368) - #116853
Merged
Conversation
Keep canonical plugin profile identity through CLI aliases, separate URL variables from credentials, and honor matching persisted configuration across registered aliases. Retain native custom and built-in routing. Retain real discovery/runtime test provenance from the contributor while omitting the already absorbed bridge and separately owned transport fix. Co-authored-by: david-bowiegxw <834563048@qq.com> Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…he model picker and hermes model resolve_provider_full() gained a plugin-profile rung in get_provider() (7072fc4) but only for profiles with a concrete base_url; a profile whose endpoint is minted at runtime (empty base_url, no URL env var — vertex-style token exchange) was still "Unknown provider" in `/model --provider`, the Desktop/TUI model picker (tui_gateway -> switch_model) and `hermes model`, while the picker listed it and the aux client already accepted it through PROVIDER_REGISTRY. Add one last rung in resolve_provider_full() that turns any registered ProviderProfile into a ProviderDef, AFTER every user-configured rung (providers:, custom_providers:, llamacpp, models.dev) so config keeps precedence, excluding only the bare ``custom`` placeholder that model-switch completes from the current endpoint. The ProviderDef builder is shared with get_provider() and keys the id on profile.name (alias switches persist under the canonical name). Tests are trimmed to three invariants proven red on origin/main: alias identity through switch_model + user-config precedence, the runtime-endpoint profile + placeholder negatives, and the persisted-alias runtime config from the salvaged commit. Salvage of #69576's proposed fix; #54705, #65968 and #34368 implemented the same tail rung. Co-authored-by: Kyzcreig <kyzcreig@users.noreply.github.com> Co-authored-by: 雾塔 <wutayunfan@gmail.com> Co-authored-by: Bosco Barros <bosco.barros@ifood.com.br>
…and the model picker
Contributor
૮ >ﻌ< ა ci reviewran on c81d909 — docs: plugin profiles and their aliases resolve in /model -- debug infoCI timingsCI timings · View report · View jobWall time 8m39s vs 8m14s (+5.1%). 8 job(s) slower, 3 faster, 2 unchanged.
|
This was referenced Sep 20, 2026
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.
Out-of-tree model-provider plugins now resolve everywhere a provider NAME is resolved at switch time —
/model --provider <plugin|alias>, the Desktop/TUI model picker (tui_gateway→switch_model) andhermes model— including profiles whose endpoint is minted at runtime, and an alias switch lands on the profile's canonical name.Part of #116408. Closes #69576.
What changed
hermes_cli/providers.py::resolve_provider_fullgains a last rung: any registeredProviderProfilebecomes aProviderDefafter every user-configured rung (providers:,custom_providers:, managed llamacpp, models.dev), so config keeps precedence. Only the barecustomplaceholder (aliasesollama/local/vllm) is excluded — model-switch completes it from the current endpoint, as before.get_provider()and the new rung share one builder (_plugin_profile_pdef): theProviderDef.idisprofile.name(not the requested alias), URL-shaped env vars (*_BASE_URL/*_URL) are the endpoint override rather than credentials, and a profile with an env-configured endpoint resolves at theget_provider()rung (@WolframRavenwolf, fix(providers): resolve ProviderProfile identity consistently #52549).hermes_cli/runtime_provider.py: a persistedmodel.providerwritten under a profile alias is the same registered provider as its canonical name, so itsbase_url/api_modeoverrides apply (@WolframRavenwolf, fix(providers): resolve ProviderProfile identity consistently #52549 — compares the two registry rows' sharedProviderConfig.id; does not touch_detect_api_mode_for_url/ profileapi_modepropagation, which [Bug]: provider plugins' ProviderProfile.api_mode dropped at runtime — anthropic_messages plugins with non-/anthropic base_url 404 #53054's lane owns).website/docs/developer-guide/model-provider-plugin.mdintegration table row for/model --provider+ model picker switch.tests/hermes_cli/test_provider_profile_identity.py— three invariants over a real plugin dir under the test HERMES_HOME (discovery + auth mirror real, only the remote model probe stubbed), all red onorigin/main:providers:block wins,custom/ollama/custom:<x>placeholders stayNone,Root cause
get_provider()'s plugin rung (7072fc4) admitted only profiles with a literalbase_urland returnedid=<requested alias>; a profile with an emptybase_url(endpoint computed at runtime, vertex-style) never reached any rung ofresolve_provider_full, soswitch_model()rejected it asUnknown provider, while the picker listed it and the aux client already accepted it through thePROVIDER_REGISTRYmirror.Live probe (temp
HERMES_HOME, real plugin dir, real imports,providers*/hermes_cli*/agent*purged)Profiles:
example-key(base_url set, aliasexample-alias,anthropic_messages),example-runtime(empty base_url, api_key auth).76fe8f7)resolve_provider_fullresolve_provider_fullresolve_provider_fullswitch_model(--provider)switch_model(--provider)switch_model(--provider)Unknown provider 'example-runtime'❌tui_gateway.server._apply_model_switch(Desktop/TUI picker RPC)Unknown provider❌model_override.provider=example-runtimefor both ✅aux.resolve_provider_clientPROVIDER_REGISTRYmirror)custom,ollama,vllm,custom:nope(no custom_providers)no-such-providernous,openai-codex,anthropic,openrouter,custom:foo,kimi-coding-cn,azure-foundry,vertexresolve_provider_fulldictvertex-ai(bundled profile alias)resolve_provider_fullTests:
scripts/run_tests.sh tests/hermes_cli/ tests/agent/test_auxiliary_client_resolve_dedup.py tests/providers/— the only failures (test_dashboard_auth_gate×4,test_cmd_update::test_venv_repair_path_refreshes_memory_provider[uvnot on PATH],test_local_runtime_recovery::test_reparented_router_keeps_its_endpoint[live-guard]) reproduce identically on a pristineorigin/mainworktree.Salvage / credit
fix(providers): preserve profile aliases and endpoint configuration— @WolframRavenwolf (fix(providers): resolve ProviderProfile identity consistently #52549, authorship preserved; its 266-line test file is replaced by the three invariants above in the follow-up commit; fix(providers): resolve ProviderProfile identity consistently #52549 carriesCo-authored-by@david-bowiegxw for the discovery fixture provenance).resolve_provider_fullfallback; main had since landed it inget_provider()for concrete-endpoint profiles (7072fc4 by @greyvito), so what remained was the runtime-endpoint case + alias identity.hermes_cli/auth_plugin_providers.py::sync_plugin_provider_registryruns at auth import, on registry miss (registry_lookup) and after discovery, and the probe showsresolve_provider_clientgreen on base for name, alias and runtime-endpoint profiles even withhermes_cli.authimported beforeprovidersdiscovery. Nothing to salvage; close as implemented-on-main with credit for the diagnosis.vertex-aialias regression; superseded by this PR.Not covered
api_modepropagation intoProviderConfig/_detect_api_mode_for_urlfallback order — owned by [Bug]: provider plugins' ProviderProfile.api_mode dropped at runtime — anthropic_messages plugins with non-/anthropic base_url 404 #53054's lane (fix(providers): a registered transport is reachable, and a late plugin profile is not dropped #116154 / fix(providers): gate plugin api_mode by endpoint (#53054) #53055); fix(providers): resolve ProviderProfile identity consistently #52549'sruntime_provider.pyhunk here is identity-only.model.provider: <alias>in config.yaml still reportsrequested_provider=<alias>; only the resolved identity/base_url/api_mode are canonical.Infographic