LLM Providers
源码版本v2026.7.20
Responsibility
Turn "a provider name (nvidia, kimi, openai, openrouter...)" into "a concrete hostname, message preprocessing, extra_body, model list". Hermes does not use an inheritance hierarchy for provider abstraction; instead it uses a ProviderProfile dataclass + a set of hooks. Profiles are registered as plugins — "declare to integrate". Nous Portal, OpenRouter, OpenAI, and custom endpoints are supported.
Key Files
OMIT_TEMPERATURE:21— sentinel object meaning "do not send temperature"@dataclass ProviderProfile:38-88— provider metadata (name, aliases, base_url, auth, temperature strategy...)get_hostname / prepare_messages:98-118— hooks: which host the request goes to, how messages are preprocessedbuild_extra_body:119-175— hook: provider-specific request body fieldsfetch_models:175-232— hook: pull the list of available models for this providermodule docstring:9-28— describes the lazy-discovery mechanism (only scans plugins on first call)register_provider:53-65— register a profileget_provider_profile:65-76— lookup by name or aliaslist_providers:76-91— list all profilesplugins/model-providers/ directory— actual profile definitions (one subdirectory per provider)
Data Flow
init_agent:276takes the user-configured provider name.- It calls
get_provider_profile:65(triggering lazy discovery on first call: scanplugins/model-providers/<name>/, import it, andregister_provider). - Once it has the
ProviderProfile:get_hostname(providers/base.py:98) fixes the request hostprepare_messages(providers/base.py:111) preprocesses theapi_messagesproduced bybuild_turn_context:268build_extra_body(providers/base.py:119) adds provider-specific fields- temperature follows the profile strategy (None / OMIT_TEMPERATURE / a concrete value)
- The main loop calls the provider API with the assembled request (
retry sub-loop:1227). - Merging of a custom provider's extra_body happens in
_merge_custom_provider_extra_body:257.
Summary
The provider abstraction is "profile + hooks", not "inheritance". Adding a provider only requires creating a subdirectory in plugins/model-providers/, declaring a ProviderProfile, and calling register_provider — no need to touch base. Lazy discovery keeps startup fast and loads on demand.