hermes-bsd/website/docs/developer-guide/provider-runtime.md

207 lines
8.6 KiB
Markdown
Raw Permalink Normal View History

---
sidebar_position: 4
title: "Provider Runtime Resolution"
description: "How Hermes resolves providers, credentials, API modes, and auxiliary models at runtime"
---
# Provider Runtime Resolution
Hermes has a shared provider runtime resolver used across:
- CLI
- gateway
- cron jobs
- ACP
- auxiliary model calls
Primary implementation:
- `hermes_cli/runtime_provider.py` — credential resolution, `_resolve_custom_runtime()`
- `hermes_cli/auth.py` — provider registry, `resolve_provider()`
- `hermes_cli/model_switch.py` — shared `/model` switch pipeline (CLI + gateway)
- `agent/auxiliary_client.py` — auxiliary model routing
feat(providers): make all 33 providers pluggable under plugins/model-providers/ Every provider profile is now a self-contained plugin under plugins/model-providers/<name>/, mirroring the plugins/platforms/ pattern established for IRC and Teams. The ProviderProfile ABC stays in providers/; the per-provider profile data moves out. - plugins/model-providers/<name>/__init__.py calls register_provider() - plugins/model-providers/<name>/plugin.yaml declares kind: model-provider - providers/__init__.py._discover_providers() lazily scans bundled plugins then $HERMES_HOME/plugins/model-providers/<name>/ (user override path) - User plugins with the same name override bundled ones (last-writer-wins in register_provider) - Legacy providers/<name>.py layout still supported for back-compat with out-of-tree editable installs - Hermes PluginManager: new kind=model-provider; skipped like memory plugins (providers/ discovery owns them); standalone plugins with register_provider+ProviderProfile in their __init__.py auto-coerce to this kind (same heuristic as memory providers) - skip_names extended to include 'model-providers' so the general PluginManager doesn't double-scan the category - 4 new tests in tests/providers/test_plugin_discovery.py covering bundled discovery, user override, and general-loader isolation - Docs updated: website/docs/developer-guide/adding-providers.md, provider-runtime.md, providers/README.md, plugins/model-providers/README.md No API break: auth.py / config.py / doctor.py / models.py / runtime_provider.py / model_metadata.py / auxiliary_client.py / chat_completions.py / run_agent.py all still consume providers via get_provider_profile() / list_providers() — they just now see plugin-discovered entries instead of pkgutil-iterated ones. Third parties can now drop a single directory into ~/.hermes/plugins/model-providers/<name>/ to add or override an inference provider without touching the repo.
2026-05-05 13:36:08 -07:00
- `providers/` — ABC + registry entry points (`ProviderProfile`, `register_provider`, `get_provider_profile`, `list_providers`)
- `plugins/model-providers/<name>/` — per-provider plugins (bundled) that declare `api_mode`, `base_url`, `env_vars`, `fallback_models` and register themselves into the registry on first access. User plugins at `$HERMES_HOME/plugins/model-providers/<name>/` override bundled ones of the same name.
feat: provider modules — ProviderProfile ABC, 33 providers, fetch_models, transport single-path Introduces providers/ package — single source of truth for every inference provider. Adding a simple api-key provider now requires one providers/<name>.py file with zero edits anywhere else. What this PR ships: - providers/ package (ProviderProfile ABC + 33 profiles across 4 api_modes) - ProviderProfile declarative fields: name, api_mode, aliases, display_name, env_vars, base_url, models_url, auth_type, fallback_models, hostname, default_headers, fixed_temperature, default_max_tokens, default_aux_model - 4 overridable hooks: prepare_messages, build_extra_body, build_api_kwargs_extras, fetch_models - chat_completions.build_kwargs: profile path via _build_kwargs_from_profile, legacy flag path retained for lmstudio/tencent-tokenhub (which have session-aware reasoning probing that doesn't map cleanly to hooks yet) - run_agent.py: profile path for all registered providers; legacy path variable scoping fixed (all flags defined before branching) - Auto-wires: auth.PROVIDER_REGISTRY, models.CANONICAL_PROVIDERS, doctor health checks, config.OPTIONAL_ENV_VARS, model_metadata._URL_TO_PROVIDER - GeminiProfile: thinking_config translation (native + openai-compat nested) - New tests/providers/ (79 tests covering profile declarations, transport parity, hook overrides, e2e kwargs assembly) Deltas vs original PR (salvaged onto current main): - Added profiles: alibaba-coding-plan, azure-foundry, minimax-oauth (were added to main since original PR) - Skipped profiles: lmstudio, tencent-tokenhub stay on legacy path (their reasoning_effort probing has no clean hook equivalent yet) - Removed lmstudio alias from custom profile (it's a separate provider now) - Skipped openrouter/custom from PROVIDER_REGISTRY auto-extension (resolve_provider special-cases them; adding breaks runtime resolution) - runtime_provider: profile.api_mode only as fallback when URL detection finds nothing (was breaking minimax /v1 override) - Preserved main's legacy-path improvements: deepseek reasoning_content preserve, gemini Gemma skip, OpenRouter response caching, Anthropic 1M beta recovery, etc. - Kept agent/copilot_acp_client.py in place (rejected PR's relocation — main has 7 fixes landed since; relocation would revert them) - _API_KEY_PROVIDER_AUX_MODELS alias kept for backward compat with existing test imports Co-authored-by: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Closes #14418
2026-05-05 10:18:49 -07:00
feat(providers): make all 33 providers pluggable under plugins/model-providers/ Every provider profile is now a self-contained plugin under plugins/model-providers/<name>/, mirroring the plugins/platforms/ pattern established for IRC and Teams. The ProviderProfile ABC stays in providers/; the per-provider profile data moves out. - plugins/model-providers/<name>/__init__.py calls register_provider() - plugins/model-providers/<name>/plugin.yaml declares kind: model-provider - providers/__init__.py._discover_providers() lazily scans bundled plugins then $HERMES_HOME/plugins/model-providers/<name>/ (user override path) - User plugins with the same name override bundled ones (last-writer-wins in register_provider) - Legacy providers/<name>.py layout still supported for back-compat with out-of-tree editable installs - Hermes PluginManager: new kind=model-provider; skipped like memory plugins (providers/ discovery owns them); standalone plugins with register_provider+ProviderProfile in their __init__.py auto-coerce to this kind (same heuristic as memory providers) - skip_names extended to include 'model-providers' so the general PluginManager doesn't double-scan the category - 4 new tests in tests/providers/test_plugin_discovery.py covering bundled discovery, user override, and general-loader isolation - Docs updated: website/docs/developer-guide/adding-providers.md, provider-runtime.md, providers/README.md, plugins/model-providers/README.md No API break: auth.py / config.py / doctor.py / models.py / runtime_provider.py / model_metadata.py / auxiliary_client.py / chat_completions.py / run_agent.py all still consume providers via get_provider_profile() / list_providers() — they just now see plugin-discovered entries instead of pkgutil-iterated ones. Third parties can now drop a single directory into ~/.hermes/plugins/model-providers/<name>/ to add or override an inference provider without touching the repo.
2026-05-05 13:36:08 -07:00
`get_provider_profile()` in `providers/` returns a `ProviderProfile` for a given provider id. `runtime_provider.py` calls this at resolution time to get the canonical `base_url`, `env_vars` priority list, `api_mode`, and `fallback_models` without needing to duplicate that data in multiple files. Adding a new plugin under `plugins/model-providers/<your-provider>/` (or `$HERMES_HOME/plugins/model-providers/<your-provider>/`) that calls `register_provider()` is enough for `runtime_provider.py` to pick it up — no branch needed in the resolver itself.
docs: pluggable surfaces coverage — model-provider guide, full plugin map, opt-in fix (#20749) * docs(providers): add model-provider-plugin authoring guide + fix stale refs New docs: - website/docs/developer-guide/model-provider-plugin.md — full authoring guide (directory layout, minimal example, ProviderProfile fields, overridable hooks, user overrides, api_mode selection, auth types, testing, pip distribution) - Wired into website/sidebars.ts under 'Extending' - Cross-references added in: - guides/build-a-hermes-plugin.md (tip block) - developer-guide/adding-providers.md - developer-guide/provider-runtime.md User guide: - user-guide/features/plugins.md: Plugin types table grows from 3 to 4 with 'Model providers' row Stale comment cleanup (providers/*.py → plugins/model-providers/<name>/): - hermes_cli/main.py:_is_profile_api_key_provider docstring - hermes_cli/doctor.py:_build_apikey_providers_list docstring - hermes_cli/auth.py: PROVIDER_REGISTRY + alias auto-extension comments - hermes_cli/models.py: CANONICAL_PROVIDERS auto-extension comment AGENTS.md: - Project-structure tree: added plugins/model-providers/ row - New section: 'Model-provider plugins' explaining discovery, override semantics, PluginManager integration, kind auto-coerce heuristic Verified: docusaurus build succeeds, new page renders, all 3 cross-links resolve. 347/347 targeted tests pass (tests/providers/, tests/hermes_cli/test_plugins.py, tests/hermes_cli/test_runtime_provider_resolution.py, tests/run_agent/test_provider_parity.py). * docs(plugins): add 'pluggable interfaces at a glance' maps to plugins.md + build-a-hermes-plugin Devs landing on either the user-guide plugin page or the build-a-plugin guide now get an upfront table of every distinct pluggable surface with a link to the right authoring doc. Previously they'd have to read the full general-plugin guide to discover that model providers / platforms / memory / context engines are separate systems. user-guide/features/plugins.md: - New 'Pluggable interfaces — where to go for each' section below the existing 4-kinds table - 10 rows covering every register_* surface (tool, hook, slash command, CLI subcommand, skill, model provider, platform, memory, context engine, image-gen) - Explicit note: TTS/STT are NOT plugin-extensible yet — documented with a pointer to the current config.yaml 'command providers' pattern and a note that register_tts_provider()/register_stt_provider() may come later guides/build-a-hermes-plugin.md: - New :::info 'Not sure which guide you need?' map at the top so devs see all pluggable interfaces before investing in this 737-line general-plugin walkthrough - Existing bottom :::tip expanded to include platform adapters alongside model/memory/context plugins Verified: - All 8 cross-doc links in the new plugins.md table resolve in a docusaurus build (SUCCESS, no new broken links) - TTS link corrected (features/voice → features/tts; latter exists) - Pre-existing broken links/anchors (cron-script-only, llms.txt, adding-platform-adapters#step-by-step-checklist) are unchanged * docs(plugins): correct TTS/STT pluggability \u2014 they ARE plugins (command-providers) Previous commit incorrectly said TTS/STT 'aren't plugin-extensible'. They are, via the config-driven command-provider pattern \u2014 any CLI that reads text and writes audio (or vice versa for STT) is automatically a plugin with zero Python. The tts.md docs cover this extensively and I missed it. plugins.md: - TTS row: 'Config-driven (not a Python plugin)', points at tts.md#custom-command-providers - STT row: points at tts.md#voice-message-transcription-stt (STT docs live in tts.md despite the filename) - Expanded note: TTS/STT use config-driven shell-command templates as their plugin surface (full tts.providers.<name> registry for TTS; HERMES_LOCAL_STT_COMMAND escape hatch for STT) - Any CLI that reads/writes files is automatically a plugin \u2014 no Python register_* API needed - Future register_tts_provider()/register_stt_provider() hooks mentioned as nice-to-have for SDK/streaming cases, not as the primary story build-a-hermes-plugin.md: - Same map update: TTS/STT rows explicit, footer note corrected Verified: - tts.md anchors (custom-command-providers, voice-message-transcription-stt) exist and resolve in docusaurus build (SUCCESS, no new broken links) * docs(plugins): expand pluggable interfaces table with MCP / event hooks / shell hooks / skill taps Broadened the scope beyond Python register_* hooks. Hermes has MULTIPLE plugin-style extension surfaces; they're now all in one table instead of being scattered across feature docs. Added rows for: - **MCP servers** — config.yaml mcp_servers.<name> auto-registers external tools from any MCP server. Huge extensibility surface, previously not linked from the plugin map. - **Gateway event hooks** — drop HOOK.yaml + handler.py into ~/.hermes/hooks/<name>/ to fire on gateway:startup, session:*, agent:*, command:* events. Separate from Python plugin hooks. - **Shell hooks** — hooks: block in config.yaml runs shell commands on events (notifications, auditing, etc.). - **Skill sources (taps)** — hermes skills tap add <repo> to pull in new skill registries beyond the built-in sources. Both docs updated: - user-guide/features/plugins.md: table column renamed to 'How' (mixes Python API + config-driven + drop-in-dir surfaces accurately) - guides/build-a-hermes-plugin.md: :::info map at top mirrors the new surfaces with a forward-link to the consolidated table Note block rewritten: instead of singling out TTS/STT as the 'different style' exception, now honestly describes that Hermes deliberately supports three plugin styles — Python APIs, config-driven commands, and drop-in manifest directories — and devs should pick the one that fits their integration. Not included (considered and rejected): - Transport layer (register_transport) — internal, not user-facing - Tool-call parsers — internal, VLLM phase-2 thing - Cloud browser providers — hardcoded registry, not drop-in yet - Terminal backends — hardcoded if/elif, not drop-in yet - Skill sources (the ABC) — hardcoded list, only taps are user-extensible Verified: - All 5 new anchors resolve (gateway-event-hooks, shell-hooks, skills-hub, custom-command-providers, voice-message-transcription-stt) - Docusaurus build SUCCESS, zero new broken links - Same 3 pre-existing broken links on main (cron-script-only, llms.txt, adding-platform-adapters#step-by-step-checklist) * docs(plugins): cover every pluggable surface in both the overview and how-to Both plugins.md and build-a-hermes-plugin.md now cover every extension surface end-to-end \u2014 general plugin APIs, specialized plugin types, config-driven surfaces \u2014 with concrete authoring patterns for each. plugins.md: - 'What plugins can do' table grows from 9 rows (general ctx.register_* only) to 14 rows covering register_platform, register_image_gen_provider, register_context_engine, MemoryProvider subclass, register_provider (model). Each row links to its full authoring guide. - New 'Plugin sub-categories' section under Plugin Discovery explains how plugins/platforms/, plugins/image_gen/, plugins/memory/, plugins/context_engine/, plugins/model-providers/ are routed to different loaders \u2014 PluginManager vs the per-category own-loader systems. - Explicit mention of user-override semantics at ~/.hermes/plugins/model-providers/ and ~/.hermes/plugins/memory/. build-a-hermes-plugin.md: - New '## Specialized plugin types' section (5 sub-sections): - Model provider plugins \u2014 ProviderProfile + plugin.yaml example, auto-wiring summary, link to full guide - Platform plugins \u2014 BasePlatformAdapter + register_platform() skeleton - Memory provider plugins \u2014 MemoryProvider subclass example - Context engine plugins \u2014 ContextEngine subclass example - Image-generation backends \u2014 ImageGenProvider + kind: backend example - New '## Non-Python extension surfaces' section (5 sub-sections): - MCP servers \u2014 config.yaml mcp_servers.<name> example - Gateway event hooks \u2014 HOOK.yaml + handler.py example - Shell hooks \u2014 hooks: block in config.yaml example - Skill sources (taps) \u2014 hermes skills tap add example - TTS / STT command templates \u2014 tts.providers.<name> with type: command - Distribute via pip / NixOS promoted from ### to ## (they were orphaned after the reorganization) Each specialized / non-Python section has a concrete, copy-pasteable example plus a 'Full guide:' link to the authoritative doc. Devs arriving at the build-a-hermes-plugin guide now see every extension surface at their disposal, not just the general tool/hook/slash-command surface. Verified: - Docusaurus build SUCCESS, zero new broken links - All new cross-links (developer-guide/model-provider-plugin, adding-platform-adapters, memory-provider-plugin, context-engine-plugin, user-guide/features/mcp, skills#skills-hub, hooks#gateway-event-hooks, hooks#shell-hooks, tts#custom-command-providers, tts#voice-message-transcription-stt) resolve - Same 3 pre-existing broken links on main (cron-script-only, llms.txt, adding-platform-adapters#step-by-step-checklist) * docs(plugins): fix opt-in inconsistency — not every plugin is gated The 'Every plugin is disabled by default' statement was wrong. Several plugin categories intentionally bypass plugins.enabled: - Bundled platform plugins (IRC, Teams) auto-load so shipped gateway channels are available out of the box. Activation per channel is via gateway.platforms.<name>.enabled. - Bundled backends (plugins/image_gen/*) auto-load so the default backend 'just works'. Selection via <category>.provider config. - Memory providers are all discovered; one is active via memory.provider. - Context engines are all discovered; one is active via context.engine. - Model providers: all 33 discovered at first get_provider_profile(); user picks via --provider / config. The plugins.enabled allow-list specifically gates: - Standalone plugins (general tools/hooks/slash commands) - User-installed backends - User-installed platforms (third-party gateway adapters) - Pip entry-point backends Which matches the actual code in hermes_cli/plugins.py:737 where the bundled+backend/platform check bypasses the allow-list. Rewrote '## Plugins are opt-in' to: - Retitle to 'Plugins are opt-in (with a few exceptions)' - Narrow opening claim to 'General plugins and user-installed backends are disabled by default' - Added 'What the allow-list does NOT gate' subsection with a full table of which bypass the gate and how they're activated instead - Fixed migration section wording (bundled platform/backend plugins never needed grandfathering) Verified: docusaurus build SUCCESS, zero new broken links.
2026-05-06 07:24:42 -07:00
If you are trying to add a new first-class inference provider, read [Adding Providers](./adding-providers.md) and the [Model Provider Plugin guide](./model-provider-plugin.md) alongside this page.
2026-03-14 19:22:47 -07:00
## Resolution precedence
At a high level, provider resolution uses:
1. explicit CLI/runtime request
2. `config.yaml` model/provider config
3. environment variables
4. provider-specific defaults or auto resolution
That ordering matters because Hermes treats the saved model/provider choice as the source of truth for normal runs. This prevents a stale shell export from silently overriding the endpoint a user last selected in `hermes model`.
## Providers
docs: round 2 audit — messaging, developer-guide, guides, integrations (#22858) Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/, guides/, and integrations/ against the live registries and gateway code. messaging/ - index.md: API Server toolset is hermes-api-server (was 'hermes (default)'); Google Chat slug is hermes-google_chat (underscore — plugin name uses _). - google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such extra); list the actual deps (google-cloud-pubsub, google-api-python-client, google-auth, google-auth-oauthlib). - qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is silently ignored by the adapter); QQ_STT_BASE_URL is not read directly — baseUrl lives under platforms.qqbot.extra.stt. - teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline plugin must be enabled), not a built-in subcommand. - sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default SMS_WEBHOOK_HOST). - open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to per-profile .env, not 'hermes config set' (same pattern fixed in api-server.md last round). Also bumped example ports to 8650+ to dodge the default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646) collision. developer-guide/ - architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py, gateway/run.py replaced with 'large file' to stop drifting. - agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)'). - gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway platform tree updated (qqbot is a sub-package, not qqbot.py; added yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/ (always active)' was wrong — it's an empty extension point and _register_builtin_hooks() is a no-op stub. - acp-internals.md: drop fictional 'message_callback' from the bridged- callbacks list; clarify thinking_callback is currently set to None. - provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry, NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama Cloud, LM Studio, Tencent TokenHub. Fallback section described only the legacy single-pair model — corrected to the canonical list-form fallback_providers chain. - environments.md: parsers list missing llama4_json and the deepseek_v31 alias; both register via @register_parser. - browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py which doesn't exist in-repo. - contributing.md: tinker-atropos is a git submodule — note that 'git submodule update --init' is required if cloning without --recurse-submodules. guides/ - operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is positional (not --schedule), the script-only flag is --no-agent (not --script-only), and there's no --command flag. Replaced with a real example that creates the script under ~/.hermes/scripts/ and uses the actual flags. Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'. - automation-templates.md: 'cron create --skills "a,b"' doesn't work — the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST rewrite. - minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently fails because --region isn't registered on the auth-add argparse spec. Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for China-region access. - cron-script-only.md: 'hermes send' is fictional — replaced the comparison- table mention with a webhook-subscription pointer; also fixed the dead link to /guides/pipe-script-output (page doesn't exist). - cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed at 'hermes gateway' (foreground) / 'hermes gateway start' (service). - local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right knob is the HERMES_API_TIMEOUT env var. - python-library.md: run_conversation() return dict has only final_response and messages — task_id is stored on the agent instance, not echoed back. - use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in one quoted string, so cmd.exe gets a single arg instead of the multi-token command line it needs. Removed the surrounding quotes — argparse nargs='*' collects each token correctly. integrations/ - providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist); actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 -> api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai) refreshed. Fallback section rewritten to lead with the canonical fallback_providers list form (was leading with the legacy fallback_model single dict); supported-providers list extended to include azure-foundry, alibaba-coding-plan, lmstudio. index.md - '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with integrations/index.md ('19+') and undercounted — bumped to 20+ and added Weixin/QQ Bot/Yuanbao/Google Chat to the list. Validation: 'npm run build' clean (exit 0); broken-link count unchanged at 155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
2026-05-09 15:00:24 -07:00
Current provider families include (see `plugins/model-providers/` for the complete bundled set):
- OpenRouter
- Nous Portal
- OpenAI Codex
docs: fix 40+ discrepancies between documentation and codebase (#5818) Comprehensive audit of all ~100 doc pages against the actual code, fixing: Reference docs: - HERMES_API_TIMEOUT default 900 -> 1800 (env-vars) - TERMINAL_DOCKER_IMAGE default python:3.11 -> nikolaik/python-nodejs (env-vars) - compression.summary_model default shown as gemini -> actually empty string (env-vars) - Add missing GOOGLE_API_KEY, GEMINI_API_KEY, GEMINI_BASE_URL env vars (env-vars) - Add missing /branch (/fork) slash command (slash-commands) - Fix hermes-cli tool count 39 -> 38 (toolsets-reference) - Fix hermes-api-server drop list to include text_to_speech (toolsets-reference) - Fix total tool count 47 -> 48, standalone 14 -> 15 (tools-reference) User guide: - web_extract.timeout default 30 -> 360 (configuration) - Remove display.theme_mode (not implemented in code) (configuration) - Remove display.background_process_notifications (not in defaults) (configuration) - Browser inactivity timeout 300/5min -> 120/2min (browser) - Screenshot path browser_screenshots -> cache/screenshots (browser) - batch_runner default model claude-sonnet-4-20250514 -> claude-sonnet-4.6 - Add minimax to TTS provider list (voice-mode) - Remove credential_pool_strategies from auth.json example (credential-pools) - Fix Slack token path platforms/slack/ -> root ~/.hermes/ (slack) - Fix Matrix store path for new installs (matrix) - Fix WhatsApp session path for new installs (whatsapp) - Fix HomeAssistant config from gateway.json to config.yaml (homeassistant) - Fix WeCom gateway start command (wecom) Developer guide: - Fix tool/toolset counts in architecture overview - Update line counts: main.py ~5500, setup.py ~3100, run.py ~7500, mcp_tool ~2200 - Replace nonexistent agent/memory_store.py with memory_manager.py + memory_provider.py - Update _discover_tools() list: remove honcho_tools, add skill_manager_tool - Add session_search and delegate_task to intercepted tools list (agent-loop) - Fix budget warning: two-tier system (70% caution, 90% warning) (agent-loop) - Fix gateway auth order (per-platform first, global last) (gateway-internals) - Fix email_adapter.py -> email.py, add webhook.py + api_server.py (gateway-internals) - Add 7 missing providers to provider-runtime list Other: - Add Docker --cap-add entries to security doc - Fix Python version 3.10+ -> 3.11+ (contributing) - Fix AGENTS.md discovery claim (not hierarchical walk) (tips) - Fix cron 'add' -> canonical 'create' (cron-internals) - Add pre_api_request/post_api_request hooks to plugin guide - Add Google/Gemini provider to providers page - Clarify OPENAI_BASE_URL deprecation (providers)
2026-04-07 10:17:44 -07:00
- Copilot / Copilot ACP
- Anthropic (native)
docs: round 2 audit — messaging, developer-guide, guides, integrations (#22858) Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/, guides/, and integrations/ against the live registries and gateway code. messaging/ - index.md: API Server toolset is hermes-api-server (was 'hermes (default)'); Google Chat slug is hermes-google_chat (underscore — plugin name uses _). - google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such extra); list the actual deps (google-cloud-pubsub, google-api-python-client, google-auth, google-auth-oauthlib). - qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is silently ignored by the adapter); QQ_STT_BASE_URL is not read directly — baseUrl lives under platforms.qqbot.extra.stt. - teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline plugin must be enabled), not a built-in subcommand. - sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default SMS_WEBHOOK_HOST). - open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to per-profile .env, not 'hermes config set' (same pattern fixed in api-server.md last round). Also bumped example ports to 8650+ to dodge the default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646) collision. developer-guide/ - architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py, gateway/run.py replaced with 'large file' to stop drifting. - agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)'). - gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway platform tree updated (qqbot is a sub-package, not qqbot.py; added yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/ (always active)' was wrong — it's an empty extension point and _register_builtin_hooks() is a no-op stub. - acp-internals.md: drop fictional 'message_callback' from the bridged- callbacks list; clarify thinking_callback is currently set to None. - provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry, NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama Cloud, LM Studio, Tencent TokenHub. Fallback section described only the legacy single-pair model — corrected to the canonical list-form fallback_providers chain. - environments.md: parsers list missing llama4_json and the deepseek_v31 alias; both register via @register_parser. - browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py which doesn't exist in-repo. - contributing.md: tinker-atropos is a git submodule — note that 'git submodule update --init' is required if cloning without --recurse-submodules. guides/ - operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is positional (not --schedule), the script-only flag is --no-agent (not --script-only), and there's no --command flag. Replaced with a real example that creates the script under ~/.hermes/scripts/ and uses the actual flags. Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'. - automation-templates.md: 'cron create --skills "a,b"' doesn't work — the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST rewrite. - minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently fails because --region isn't registered on the auth-add argparse spec. Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for China-region access. - cron-script-only.md: 'hermes send' is fictional — replaced the comparison- table mention with a webhook-subscription pointer; also fixed the dead link to /guides/pipe-script-output (page doesn't exist). - cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed at 'hermes gateway' (foreground) / 'hermes gateway start' (service). - local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right knob is the HERMES_API_TIMEOUT env var. - python-library.md: run_conversation() return dict has only final_response and messages — task_id is stored on the agent instance, not echoed back. - use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in one quoted string, so cmd.exe gets a single arg instead of the multi-token command line it needs. Removed the surrounding quotes — argparse nargs='*' collects each token correctly. integrations/ - providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist); actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 -> api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai) refreshed. Fallback section rewritten to lead with the canonical fallback_providers list form (was leading with the legacy fallback_model single dict); supported-providers list extended to include azure-foundry, alibaba-coding-plan, lmstudio. index.md - '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with integrations/index.md ('19+') and undercounted — bumped to 20+ and added Weixin/QQ Bot/Yuanbao/Google Chat to the list. Validation: 'npm run build' clean (exit 0); broken-link count unchanged at 155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
2026-05-09 15:00:24 -07:00
- Google / Gemini (`gemini`, `google-gemini-cli`)
- Alibaba / DashScope (`alibaba`, `alibaba-coding-plan`)
docs: fix 40+ discrepancies between documentation and codebase (#5818) Comprehensive audit of all ~100 doc pages against the actual code, fixing: Reference docs: - HERMES_API_TIMEOUT default 900 -> 1800 (env-vars) - TERMINAL_DOCKER_IMAGE default python:3.11 -> nikolaik/python-nodejs (env-vars) - compression.summary_model default shown as gemini -> actually empty string (env-vars) - Add missing GOOGLE_API_KEY, GEMINI_API_KEY, GEMINI_BASE_URL env vars (env-vars) - Add missing /branch (/fork) slash command (slash-commands) - Fix hermes-cli tool count 39 -> 38 (toolsets-reference) - Fix hermes-api-server drop list to include text_to_speech (toolsets-reference) - Fix total tool count 47 -> 48, standalone 14 -> 15 (tools-reference) User guide: - web_extract.timeout default 30 -> 360 (configuration) - Remove display.theme_mode (not implemented in code) (configuration) - Remove display.background_process_notifications (not in defaults) (configuration) - Browser inactivity timeout 300/5min -> 120/2min (browser) - Screenshot path browser_screenshots -> cache/screenshots (browser) - batch_runner default model claude-sonnet-4-20250514 -> claude-sonnet-4.6 - Add minimax to TTS provider list (voice-mode) - Remove credential_pool_strategies from auth.json example (credential-pools) - Fix Slack token path platforms/slack/ -> root ~/.hermes/ (slack) - Fix Matrix store path for new installs (matrix) - Fix WhatsApp session path for new installs (whatsapp) - Fix HomeAssistant config from gateway.json to config.yaml (homeassistant) - Fix WeCom gateway start command (wecom) Developer guide: - Fix tool/toolset counts in architecture overview - Update line counts: main.py ~5500, setup.py ~3100, run.py ~7500, mcp_tool ~2200 - Replace nonexistent agent/memory_store.py with memory_manager.py + memory_provider.py - Update _discover_tools() list: remove honcho_tools, add skill_manager_tool - Add session_search and delegate_task to intercepted tools list (agent-loop) - Fix budget warning: two-tier system (70% caution, 90% warning) (agent-loop) - Fix gateway auth order (per-platform first, global last) (gateway-internals) - Fix email_adapter.py -> email.py, add webhook.py + api_server.py (gateway-internals) - Add 7 missing providers to provider-runtime list Other: - Add Docker --cap-add entries to security doc - Fix Python version 3.10+ -> 3.11+ (contributing) - Fix AGENTS.md discovery claim (not hierarchical walk) (tips) - Fix cron 'add' -> canonical 'create' (cron-internals) - Add pre_api_request/post_api_request hooks to plugin guide - Add Google/Gemini provider to providers page - Clarify OPENAI_BASE_URL deprecation (providers)
2026-04-07 10:17:44 -07:00
- DeepSeek
- Z.AI
docs: round 2 audit — messaging, developer-guide, guides, integrations (#22858) Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/, guides/, and integrations/ against the live registries and gateway code. messaging/ - index.md: API Server toolset is hermes-api-server (was 'hermes (default)'); Google Chat slug is hermes-google_chat (underscore — plugin name uses _). - google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such extra); list the actual deps (google-cloud-pubsub, google-api-python-client, google-auth, google-auth-oauthlib). - qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is silently ignored by the adapter); QQ_STT_BASE_URL is not read directly — baseUrl lives under platforms.qqbot.extra.stt. - teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline plugin must be enabled), not a built-in subcommand. - sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default SMS_WEBHOOK_HOST). - open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to per-profile .env, not 'hermes config set' (same pattern fixed in api-server.md last round). Also bumped example ports to 8650+ to dodge the default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646) collision. developer-guide/ - architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py, gateway/run.py replaced with 'large file' to stop drifting. - agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)'). - gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway platform tree updated (qqbot is a sub-package, not qqbot.py; added yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/ (always active)' was wrong — it's an empty extension point and _register_builtin_hooks() is a no-op stub. - acp-internals.md: drop fictional 'message_callback' from the bridged- callbacks list; clarify thinking_callback is currently set to None. - provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry, NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama Cloud, LM Studio, Tencent TokenHub. Fallback section described only the legacy single-pair model — corrected to the canonical list-form fallback_providers chain. - environments.md: parsers list missing llama4_json and the deepseek_v31 alias; both register via @register_parser. - browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py which doesn't exist in-repo. - contributing.md: tinker-atropos is a git submodule — note that 'git submodule update --init' is required if cloning without --recurse-submodules. guides/ - operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is positional (not --schedule), the script-only flag is --no-agent (not --script-only), and there's no --command flag. Replaced with a real example that creates the script under ~/.hermes/scripts/ and uses the actual flags. Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'. - automation-templates.md: 'cron create --skills "a,b"' doesn't work — the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST rewrite. - minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently fails because --region isn't registered on the auth-add argparse spec. Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for China-region access. - cron-script-only.md: 'hermes send' is fictional — replaced the comparison- table mention with a webhook-subscription pointer; also fixed the dead link to /guides/pipe-script-output (page doesn't exist). - cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed at 'hermes gateway' (foreground) / 'hermes gateway start' (service). - local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right knob is the HERMES_API_TIMEOUT env var. - python-library.md: run_conversation() return dict has only final_response and messages — task_id is stored on the agent instance, not echoed back. - use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in one quoted string, so cmd.exe gets a single arg instead of the multi-token command line it needs. Removed the surrounding quotes — argparse nargs='*' collects each token correctly. integrations/ - providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist); actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 -> api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai) refreshed. Fallback section rewritten to lead with the canonical fallback_providers list form (was leading with the legacy fallback_model single dict); supported-providers list extended to include azure-foundry, alibaba-coding-plan, lmstudio. index.md - '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with integrations/index.md ('19+') and undercounted — bumped to 20+ and added Weixin/QQ Bot/Yuanbao/Google Chat to the list. Validation: 'npm run build' clean (exit 0); broken-link count unchanged at 155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
2026-05-09 15:00:24 -07:00
- Kimi / Moonshot (`kimi-coding`, `kimi-coding-cn`)
- MiniMax (`minimax`, `minimax-cn`, `minimax-oauth`)
docs: fix 40+ discrepancies between documentation and codebase (#5818) Comprehensive audit of all ~100 doc pages against the actual code, fixing: Reference docs: - HERMES_API_TIMEOUT default 900 -> 1800 (env-vars) - TERMINAL_DOCKER_IMAGE default python:3.11 -> nikolaik/python-nodejs (env-vars) - compression.summary_model default shown as gemini -> actually empty string (env-vars) - Add missing GOOGLE_API_KEY, GEMINI_API_KEY, GEMINI_BASE_URL env vars (env-vars) - Add missing /branch (/fork) slash command (slash-commands) - Fix hermes-cli tool count 39 -> 38 (toolsets-reference) - Fix hermes-api-server drop list to include text_to_speech (toolsets-reference) - Fix total tool count 47 -> 48, standalone 14 -> 15 (tools-reference) User guide: - web_extract.timeout default 30 -> 360 (configuration) - Remove display.theme_mode (not implemented in code) (configuration) - Remove display.background_process_notifications (not in defaults) (configuration) - Browser inactivity timeout 300/5min -> 120/2min (browser) - Screenshot path browser_screenshots -> cache/screenshots (browser) - batch_runner default model claude-sonnet-4-20250514 -> claude-sonnet-4.6 - Add minimax to TTS provider list (voice-mode) - Remove credential_pool_strategies from auth.json example (credential-pools) - Fix Slack token path platforms/slack/ -> root ~/.hermes/ (slack) - Fix Matrix store path for new installs (matrix) - Fix WhatsApp session path for new installs (whatsapp) - Fix HomeAssistant config from gateway.json to config.yaml (homeassistant) - Fix WeCom gateway start command (wecom) Developer guide: - Fix tool/toolset counts in architecture overview - Update line counts: main.py ~5500, setup.py ~3100, run.py ~7500, mcp_tool ~2200 - Replace nonexistent agent/memory_store.py with memory_manager.py + memory_provider.py - Update _discover_tools() list: remove honcho_tools, add skill_manager_tool - Add session_search and delegate_task to intercepted tools list (agent-loop) - Fix budget warning: two-tier system (70% caution, 90% warning) (agent-loop) - Fix gateway auth order (per-platform first, global last) (gateway-internals) - Fix email_adapter.py -> email.py, add webhook.py + api_server.py (gateway-internals) - Add 7 missing providers to provider-runtime list Other: - Add Docker --cap-add entries to security doc - Fix Python version 3.10+ -> 3.11+ (contributing) - Fix AGENTS.md discovery claim (not hierarchical walk) (tips) - Fix cron 'add' -> canonical 'create' (cron-internals) - Add pre_api_request/post_api_request hooks to plugin guide - Add Google/Gemini provider to providers page - Clarify OPENAI_BASE_URL deprecation (providers)
2026-04-07 10:17:44 -07:00
- Kilo Code
- Hugging Face
- OpenCode Zen / OpenCode Go
docs: round 2 audit — messaging, developer-guide, guides, integrations (#22858) Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/, guides/, and integrations/ against the live registries and gateway code. messaging/ - index.md: API Server toolset is hermes-api-server (was 'hermes (default)'); Google Chat slug is hermes-google_chat (underscore — plugin name uses _). - google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such extra); list the actual deps (google-cloud-pubsub, google-api-python-client, google-auth, google-auth-oauthlib). - qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is silently ignored by the adapter); QQ_STT_BASE_URL is not read directly — baseUrl lives under platforms.qqbot.extra.stt. - teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline plugin must be enabled), not a built-in subcommand. - sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default SMS_WEBHOOK_HOST). - open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to per-profile .env, not 'hermes config set' (same pattern fixed in api-server.md last round). Also bumped example ports to 8650+ to dodge the default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646) collision. developer-guide/ - architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py, gateway/run.py replaced with 'large file' to stop drifting. - agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)'). - gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway platform tree updated (qqbot is a sub-package, not qqbot.py; added yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/ (always active)' was wrong — it's an empty extension point and _register_builtin_hooks() is a no-op stub. - acp-internals.md: drop fictional 'message_callback' from the bridged- callbacks list; clarify thinking_callback is currently set to None. - provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry, NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama Cloud, LM Studio, Tencent TokenHub. Fallback section described only the legacy single-pair model — corrected to the canonical list-form fallback_providers chain. - environments.md: parsers list missing llama4_json and the deepseek_v31 alias; both register via @register_parser. - browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py which doesn't exist in-repo. - contributing.md: tinker-atropos is a git submodule — note that 'git submodule update --init' is required if cloning without --recurse-submodules. guides/ - operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is positional (not --schedule), the script-only flag is --no-agent (not --script-only), and there's no --command flag. Replaced with a real example that creates the script under ~/.hermes/scripts/ and uses the actual flags. Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'. - automation-templates.md: 'cron create --skills "a,b"' doesn't work — the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST rewrite. - minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently fails because --region isn't registered on the auth-add argparse spec. Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for China-region access. - cron-script-only.md: 'hermes send' is fictional — replaced the comparison- table mention with a webhook-subscription pointer; also fixed the dead link to /guides/pipe-script-output (page doesn't exist). - cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed at 'hermes gateway' (foreground) / 'hermes gateway start' (service). - local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right knob is the HERMES_API_TIMEOUT env var. - python-library.md: run_conversation() return dict has only final_response and messages — task_id is stored on the agent instance, not echoed back. - use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in one quoted string, so cmd.exe gets a single arg instead of the multi-token command line it needs. Removed the surrounding quotes — argparse nargs='*' collects each token correctly. integrations/ - providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist); actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 -> api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai) refreshed. Fallback section rewritten to lead with the canonical fallback_providers list form (was leading with the legacy fallback_model single dict); supported-providers list extended to include azure-foundry, alibaba-coding-plan, lmstudio. index.md - '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with integrations/index.md ('19+') and undercounted — bumped to 20+ and added Weixin/QQ Bot/Yuanbao/Google Chat to the list. Validation: 'npm run build' clean (exit 0); broken-link count unchanged at 155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
2026-05-09 15:00:24 -07:00
- AWS Bedrock
- Azure Foundry
- NVIDIA NIM
- xAI (Grok)
- Arcee
- GMI Cloud
- StepFun
- Qwen OAuth
- Xiaomi
- Ollama Cloud
- LM Studio
- Tencent TokenHub
- Custom (`provider: custom`) — first-class provider for any OpenAI-compatible endpoint
- Named custom providers (`custom_providers` list in config.yaml)
## Output of runtime resolution
The runtime resolver returns data such as:
- `provider`
- `api_mode`
- `base_url`
- `api_key`
- `source`
- provider-specific metadata like expiry/refresh info
## Why this matters
This resolver is the main reason Hermes can share auth/runtime logic between:
- `hermes chat`
- gateway message handling
- cron jobs running in fresh sessions
- ACP editor sessions
- auxiliary model tasks
remove Vercel AI Gateway and Vercel Sandbox (#33067) * remove Vercel AI Gateway provider and Vercel Sandbox terminal backend Both Vercel-hosted integrations are removed end-to-end. Users on the AI Gateway should switch to OpenRouter or one of the other aggregators (Nous Portal, Kilo Code). Users on the Vercel Sandbox backend should switch to Docker, Modal, Daytona, or SSH. What's removed: - `plugins/model-providers/ai-gateway/` provider plugin - `hermes_cli/vercel_auth.py` Vercel-Sandbox auth helper - `tools/environments/vercel_sandbox.py` terminal backend - `ai-gateway` provider wiring across auth, doctor, setup, models, config, status, providers, main, web_server, model_normalize, dump - `vercel_sandbox` backend wiring across terminal_tool, file_tools, code_execution_tool, file_operations, approval, skills_tool, environments/local, credential_files, lazy_deps, prompt_builder, cli, gateway/run - `AI_GATEWAY_BASE_URL` constant, `_AI_GATEWAY_HEADERS` auxiliary-client header set, run_agent base-URL header/reasoning special-cases - `[vercel]` pyproject extra and `vercel`/`vercel-workers` from uv.lock - env vars: `AI_GATEWAY_API_KEY`, `AI_GATEWAY_BASE_URL`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`, `VERCEL_TEAM_ID`, `VERCEL_OIDC_TOKEN`, `TERMINAL_VERCEL_RUNTIME` - Tests: deletes test_ai_gateway_models.py and test_vercel_sandbox_environment.py; scrubs references across 23 surviving test files (no entire tests deleted unless they were dedicated to AI Gateway / Sandbox) - Docs: provider tables, env-var reference, setup guides, security notes, tool config, terminal-backend tables — English plus zh-Hans i18n parity - `hermes-agent` skill: provider table entry and remote-backend list What stays (intentional): - `popular-web-designs/templates/vercel.md` — CSS design reference, unrelated to Vercel-the-AI-product - `x-vercel-id` in `stream_diag.py` headers — generic Vercel CDN response header, useful diag signal on any Vercel-hosted endpoint - `vercel-labs/agent-browser` URL in browser config — lightpanda browser project, different OSS effort - `userStories.json` historical contributor entry mentioning Vercel Sandbox — archive, not active docs Validation: - 1153 tests in the 22 targeted files pass (`scripts/run_tests.sh`) - Full repo `py_compile` clean - Live import of every touched module + invariant check (no `ai-gateway` in `PROVIDER_REGISTRY`, no `_AI_GATEWAY_HEADERS`, no `vercel_sandbox` in `_REMOTE_TERMINAL_BACKENDS`) * test: convert profile-count check from change-detector to invariant The hardcoded "== 34" assertion broke when ai-gateway was removed. Per AGENTS.md change-detector-test guidance, assert the relationship (registry count >= number of plugin dirs) instead of a literal count. Counts shift when providers are added/removed; that's expected.
2026-05-27 00:43:32 -07:00
## OpenRouter and custom OpenAI-compatible base URLs
remove Vercel AI Gateway and Vercel Sandbox (#33067) * remove Vercel AI Gateway provider and Vercel Sandbox terminal backend Both Vercel-hosted integrations are removed end-to-end. Users on the AI Gateway should switch to OpenRouter or one of the other aggregators (Nous Portal, Kilo Code). Users on the Vercel Sandbox backend should switch to Docker, Modal, Daytona, or SSH. What's removed: - `plugins/model-providers/ai-gateway/` provider plugin - `hermes_cli/vercel_auth.py` Vercel-Sandbox auth helper - `tools/environments/vercel_sandbox.py` terminal backend - `ai-gateway` provider wiring across auth, doctor, setup, models, config, status, providers, main, web_server, model_normalize, dump - `vercel_sandbox` backend wiring across terminal_tool, file_tools, code_execution_tool, file_operations, approval, skills_tool, environments/local, credential_files, lazy_deps, prompt_builder, cli, gateway/run - `AI_GATEWAY_BASE_URL` constant, `_AI_GATEWAY_HEADERS` auxiliary-client header set, run_agent base-URL header/reasoning special-cases - `[vercel]` pyproject extra and `vercel`/`vercel-workers` from uv.lock - env vars: `AI_GATEWAY_API_KEY`, `AI_GATEWAY_BASE_URL`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`, `VERCEL_TEAM_ID`, `VERCEL_OIDC_TOKEN`, `TERMINAL_VERCEL_RUNTIME` - Tests: deletes test_ai_gateway_models.py and test_vercel_sandbox_environment.py; scrubs references across 23 surviving test files (no entire tests deleted unless they were dedicated to AI Gateway / Sandbox) - Docs: provider tables, env-var reference, setup guides, security notes, tool config, terminal-backend tables — English plus zh-Hans i18n parity - `hermes-agent` skill: provider table entry and remote-backend list What stays (intentional): - `popular-web-designs/templates/vercel.md` — CSS design reference, unrelated to Vercel-the-AI-product - `x-vercel-id` in `stream_diag.py` headers — generic Vercel CDN response header, useful diag signal on any Vercel-hosted endpoint - `vercel-labs/agent-browser` URL in browser config — lightpanda browser project, different OSS effort - `userStories.json` historical contributor entry mentioning Vercel Sandbox — archive, not active docs Validation: - 1153 tests in the 22 targeted files pass (`scripts/run_tests.sh`) - Full repo `py_compile` clean - Live import of every touched module + invariant check (no `ai-gateway` in `PROVIDER_REGISTRY`, no `_AI_GATEWAY_HEADERS`, no `vercel_sandbox` in `_REMOTE_TERMINAL_BACKENDS`) * test: convert profile-count check from change-detector to invariant The hardcoded "== 34" assertion broke when ai-gateway was removed. Per AGENTS.md change-detector-test guidance, assert the relationship (registry count >= number of plugin dirs) instead of a literal count. Counts shift when providers are added/removed; that's expected.
2026-05-27 00:43:32 -07:00
Hermes contains logic to avoid leaking the wrong API key to a custom endpoint when multiple provider keys exist (e.g. `OPENROUTER_API_KEY` and `OPENAI_API_KEY`).
Each provider's API key is scoped to its own base URL:
- `OPENROUTER_API_KEY` is only sent to `openrouter.ai` endpoints
- `OPENAI_API_KEY` is used for custom endpoints and as a fallback
Hermes also distinguishes between:
- a real custom endpoint selected by the user
- the OpenRouter fallback path used when no custom endpoint is configured
That distinction is especially important for:
- local model servers
remove Vercel AI Gateway and Vercel Sandbox (#33067) * remove Vercel AI Gateway provider and Vercel Sandbox terminal backend Both Vercel-hosted integrations are removed end-to-end. Users on the AI Gateway should switch to OpenRouter or one of the other aggregators (Nous Portal, Kilo Code). Users on the Vercel Sandbox backend should switch to Docker, Modal, Daytona, or SSH. What's removed: - `plugins/model-providers/ai-gateway/` provider plugin - `hermes_cli/vercel_auth.py` Vercel-Sandbox auth helper - `tools/environments/vercel_sandbox.py` terminal backend - `ai-gateway` provider wiring across auth, doctor, setup, models, config, status, providers, main, web_server, model_normalize, dump - `vercel_sandbox` backend wiring across terminal_tool, file_tools, code_execution_tool, file_operations, approval, skills_tool, environments/local, credential_files, lazy_deps, prompt_builder, cli, gateway/run - `AI_GATEWAY_BASE_URL` constant, `_AI_GATEWAY_HEADERS` auxiliary-client header set, run_agent base-URL header/reasoning special-cases - `[vercel]` pyproject extra and `vercel`/`vercel-workers` from uv.lock - env vars: `AI_GATEWAY_API_KEY`, `AI_GATEWAY_BASE_URL`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`, `VERCEL_TEAM_ID`, `VERCEL_OIDC_TOKEN`, `TERMINAL_VERCEL_RUNTIME` - Tests: deletes test_ai_gateway_models.py and test_vercel_sandbox_environment.py; scrubs references across 23 surviving test files (no entire tests deleted unless they were dedicated to AI Gateway / Sandbox) - Docs: provider tables, env-var reference, setup guides, security notes, tool config, terminal-backend tables — English plus zh-Hans i18n parity - `hermes-agent` skill: provider table entry and remote-backend list What stays (intentional): - `popular-web-designs/templates/vercel.md` — CSS design reference, unrelated to Vercel-the-AI-product - `x-vercel-id` in `stream_diag.py` headers — generic Vercel CDN response header, useful diag signal on any Vercel-hosted endpoint - `vercel-labs/agent-browser` URL in browser config — lightpanda browser project, different OSS effort - `userStories.json` historical contributor entry mentioning Vercel Sandbox — archive, not active docs Validation: - 1153 tests in the 22 targeted files pass (`scripts/run_tests.sh`) - Full repo `py_compile` clean - Live import of every touched module + invariant check (no `ai-gateway` in `PROVIDER_REGISTRY`, no `_AI_GATEWAY_HEADERS`, no `vercel_sandbox` in `_REMOTE_TERMINAL_BACKENDS`) * test: convert profile-count check from change-detector to invariant The hardcoded "== 34" assertion broke when ai-gateway was removed. Per AGENTS.md change-detector-test guidance, assert the relationship (registry count >= number of plugin dirs) instead of a literal count. Counts shift when providers are added/removed; that's expected.
2026-05-27 00:43:32 -07:00
- non-OpenRouter OpenAI-compatible APIs
- switching providers without re-running setup
- config-saved custom endpoints that should keep working even when `OPENAI_BASE_URL` is not exported in the current shell
## Native Anthropic path
Anthropic is not just "via OpenRouter" anymore.
When provider resolution selects `anthropic`, Hermes uses:
- `api_mode = anthropic_messages`
- the native Anthropic Messages API
- `agent/anthropic_adapter.py` for translation
Credential resolution for native Anthropic now prefers refreshable Claude Code credentials over copied env tokens when both are present. In practice that means:
- Claude Code credential files are treated as the preferred source when they include refreshable auth
- manual `ANTHROPIC_TOKEN` / `CLAUDE_CODE_OAUTH_TOKEN` values still work as explicit overrides
- Hermes preflights Anthropic credential refresh before native Messages API calls
- Hermes still retries once on a 401 after rebuilding the Anthropic client, as a fallback path
## OpenAI Codex path
Codex uses a separate Responses API path:
- `api_mode = codex_responses`
- dedicated credential resolution and auth store support
## Auxiliary model routing
Auxiliary tasks such as:
- vision
- web extraction summarization
- context compression summaries
- skills hub operations
- MCP helper operations
- memory flushes
can use their own provider/model routing rather than the main conversational model.
When an auxiliary task is configured with provider `main`, Hermes resolves that through the same shared runtime path as normal chat. In practice that means:
- env-driven custom endpoints still work
- custom endpoints saved via `hermes model` / `config.yaml` also work
- auxiliary routing can tell the difference between a real saved custom endpoint and the OpenRouter fallback
## Fallback models
docs: round 2 audit — messaging, developer-guide, guides, integrations (#22858) Cross-checked 75 docs pages under user-guide/messaging/, developer-guide/, guides/, and integrations/ against the live registries and gateway code. messaging/ - index.md: API Server toolset is hermes-api-server (was 'hermes (default)'); Google Chat slug is hermes-google_chat (underscore — plugin name uses _). - google_chat.md: drop bogus 'pip install hermes-agent[google_chat]' (no such extra); list the actual deps (google-cloud-pubsub, google-api-python-client, google-auth, google-auth-oauthlib). - qqbot.md: config namespace is platforms.qqbot (was platforms.qq, which is silently ignored by the adapter); QQ_STT_BASE_URL is not read directly — baseUrl lives under platforms.qqbot.extra.stt. - teams-meetings.md: 'hermes teams-pipeline' is plugin-gated (teams_pipeline plugin must be enabled), not a built-in subcommand. - sms.md: example log line 0.0.0.0:8080 -> 127.0.0.1:8080 (default SMS_WEBHOOK_HOST). - open-webui.md: API_SERVER_* are env vars, not YAML keys — write them to per-profile .env, not 'hermes config set' (same pattern fixed in api-server.md last round). Also bumped example ports to 8650+ to dodge the default webhook (8644)/wecom-callback (8645)/msgraph-webhook (8646) collision. developer-guide/ - architecture.md: tool/toolset counts (61/52 -> 70+/~28); LOC stamps for run_agent.py, cli.py, hermes_cli/main.py, setup.py, mcp_tool.py, gateway/run.py replaced with 'large file' to stop drifting. - agent-loop.md: same LOC drift (~13,700 -> 'a large file (15k+ lines)'). - gateway-internals.md: '14+ external messaging platforms' -> '20+'; gateway platform tree updated (qqbot is a sub-package, not qqbot.py; added yuanbao.py, feishu_comment.py, msgraph_webhook.py); 'gateway/builtin_hooks/ (always active)' was wrong — it's an empty extension point and _register_builtin_hooks() is a no-op stub. - acp-internals.md: drop fictional 'message_callback' from the bridged- callbacks list; clarify thinking_callback is currently set to None. - provider-runtime.md: provider list was missing AWS Bedrock, Azure Foundry, NVIDIA NIM, xAI, Arcee, GMI Cloud, StepFun, Qwen OAuth, Xiaomi, Ollama Cloud, LM Studio, Tencent TokenHub. Fallback section described only the legacy single-pair model — corrected to the canonical list-form fallback_providers chain. - environments.md: parsers list missing llama4_json and the deepseek_v31 alias; both register via @register_parser. - browser-supervisor.md: drop reference to scripts/browser_supervisor_e2e.py which doesn't exist in-repo. - contributing.md: tinker-atropos is a git submodule — note that 'git submodule update --init' is required if cloning without --recurse-submodules. guides/ - operate-teams-meeting-pipeline.md: cron flags were all wrong — schedule is positional (not --schedule), the script-only flag is --no-agent (not --script-only), and there's no --command flag. Replaced with a real example that creates the script under ~/.hermes/scripts/ and uses the actual flags. Also replaced fictional 'hermes cron show <name>' with 'hermes cron status'. - automation-templates.md: 'cron create --skills "a,b"' doesn't work — the flag is --skill (singular, repeatable). Fixed all 5 occurrences via AST rewrite. - minimax-oauth.md: 'hermes auth add minimax-oauth --region cn' silently fails because --region isn't registered on the auth-add argparse spec. Pointed users at the minimax-cn provider (or MINIMAX_CN_API_KEY env) for China-region access. - cron-script-only.md: 'hermes send' is fictional — replaced the comparison- table mention with a webhook-subscription pointer; also fixed the dead link to /guides/pipe-script-output (page doesn't exist). - cron-troubleshooting.md: 'hermes serve' isn't a real subcommand. Pointed at 'hermes gateway' (foreground) / 'hermes gateway start' (service). - local-ollama-setup.md: 'agent.api_timeout' is not a config key. The right knob is the HERMES_API_TIMEOUT env var. - python-library.md: run_conversation() return dict has only final_response and messages — task_id is stored on the agent instance, not echoed back. - use-mcp-with-hermes.md: '--args /c "npx -y …"' wraps the npx command in one quoted string, so cmd.exe gets a single arg instead of the multi-token command line it needs. Removed the surrounding quotes — argparse nargs='*' collects each token correctly. integrations/ - providers.md: Bedrock guardrail YAML keys were 'id'/'version' (don't exist); actual keys are guardrail_identifier/guardrail_version (matches DEFAULT_CONFIG and the run_agent.py reader). GMI default base URL (api.gmi.ai/v1 -> api.gmi-serving.com/v1) and portal URL (inference.gmi.ai -> www.gmicloud.ai) refreshed. Fallback section rewritten to lead with the canonical fallback_providers list form (was leading with the legacy fallback_model single dict); supported-providers list extended to include azure-foundry, alibaba-coding-plan, lmstudio. index.md - '68 built-in tools' -> '70+'; '15+ platforms' was both inconsistent with integrations/index.md ('19+') and undercounted — bumped to 20+ and added Weixin/QQ Bot/Yuanbao/Google Chat to the list. Validation: 'npm run build' clean (exit 0); broken-link count unchanged at 155 (same as round-1 post-skill-regen baseline). 24 files, +132/-89.
2026-05-09 15:00:24 -07:00
Hermes supports a configured fallback provider chain — a list of `(provider, model)` entries tried in order when the primary model encounters errors. The legacy single-pair `fallback_model` dict is still accepted for back-compat (and migrated on first write).
docs: fallback providers + /background command documentation * docs: comprehensive fallback providers documentation - New dedicated page: user-guide/features/fallback-providers.md covering both primary model fallback and auxiliary task fallback systems - Updated configuration.md with fallback_model config section - Updated environment-variables.md noting fallback is config-only - Fleshed out developer-guide/provider-runtime.md fallback section with internal architecture details (trigger points, activation flow, config flow) - Added cross-reference from provider-routing.md distinguishing OpenRouter sub-provider routing from Hermes-level model fallback - Added new page to sidebar under Integrations * docs: comprehensive /background command documentation - Added Background Sessions section to cli.md covering how it works (daemon threads, isolated sessions, config inheritance, Rich panel output, bell notification, concurrent tasks) - Added Background Sessions section to messaging/index.md covering messaging-specific behavior (async execution, result delivery back to same chat, fire-and-forget pattern) - Documented background_process_notifications config (all/result/error/off) in messaging docs and configuration.md - Added HERMES_BACKGROUND_NOTIFICATIONS env var to reference page - Fixed inconsistency in slash-commands.md: /background was listed as messaging-only but works in both CLI and messaging. Moved it to the 'both surfaces' note. - Expanded one-liner table descriptions with detail and cross-references
2026-03-15 06:24:28 -07:00
### How it works internally
1. **Storage**: `AIAgent.__init__` stores the `fallback_model` dict and sets `_fallback_activated = False`.
2. **Trigger points**: `_try_activate_fallback()` is called from three places in the main retry loop in `run_agent.py`:
- After max retries on invalid API responses (None choices, missing content)
- On non-retryable client errors (HTTP 401, 403, 404)
- After max retries on transient errors (HTTP 429, 500, 502, 503)
3. **Activation flow** (`_try_activate_fallback`):
- Returns `False` immediately if already activated or not configured
- Calls `resolve_provider_client()` from `auxiliary_client.py` to build a new client with proper auth
- Determines `api_mode`: `codex_responses` for openai-codex, `anthropic_messages` for anthropic, `chat_completions` for everything else
- Swaps in-place: `self.model`, `self.provider`, `self.base_url`, `self.api_mode`, `self.client`, `self._client_kwargs`
- For anthropic fallback: builds a native Anthropic client instead of OpenAI-compatible
- Re-evaluates prompt caching (enabled for Claude models on OpenRouter)
- Sets `_fallback_activated = True` — prevents firing again
- Resets retry count to 0 and continues the loop
4. **Config flow**:
- CLI: `cli.py` reads `CLI_CONFIG["fallback_model"]` → passes to `AIAgent(fallback_model=...)`
- Gateway: `gateway/run.py._load_fallback_model()` reads `config.yaml` → passes to `AIAgent`
- Validation: both `provider` and `model` keys must be non-empty, or fallback is disabled
### What does NOT support fallback
- **Subagent delegation** (`tools/delegate_tool.py`): subagents inherit the parent's provider but not the fallback config
- **Auxiliary tasks**: use their own independent provider auto-detection chain (see Auxiliary model routing above)
docs: resync reference, user-guide, developer-guide, and messaging pages against code (#17738) Broad drift audit against origin/main (b52b63396). Reference pages (most user-visible drift): - slash-commands: add /busy, /curator, /footer, /indicator, /redraw, /steer that were missing; drop non-existent /terminal-setup; fix /q footnote (resolves to /queue, not /quit); extend CLI-only list with all 24 CLI-only commands in the registry - cli-commands: add dedicated sections for hermes curator / fallback / hooks (new subcommands not previously documented); remove stale hermes honcho standalone section (the plugin registers dynamically via hermes memory); list curator/fallback/hooks in top-level table; fix completion to include fish - toolsets-reference: document the real 52-toolset count; split browser vs browser-cdp; add discord / discord_admin / spotify / yuanbao; correct hermes-cli tool count from 36 to 38; fix misleading claim that hermes-homeassistant adds tools (it's identical to hermes-cli) - tools-reference: bump tool count 55 -> 68; add 7 Spotify, 5 Yuanbao, 2 Discord toolsets; move browser_cdp/browser_dialog to their own browser-cdp toolset section - environment-variables: add 40+ user-facing HERMES_* vars that were undocumented (--yolo, --accept-hooks, --ignore-*, inference model override, agent/stream/checkpoint timeouts, OAuth trace, per-platform batch tuning for Telegram/Discord/Matrix/Feishu/WeCom, cron knobs, gateway restart/connect timeouts); dedupe the Cron Scheduler section; replace stale QQ_SANDBOX with QQ_PORTAL_HOST User-guide (top level): - cli.md: compression preserves last 20 turns, not 4 (protect_last_n: 20) - configuration.md: display.platforms is the canonical per-platform override key; tool_progress_overrides is deprecated and auto-migrated - profiles.md: model.default is the config key, not model.model - sessions.md: CLI/TUI session IDs use 6-char hex, gateway uses 8 - checkpoints-and-rollback.md: destructive-command list now matches _DESTRUCTIVE_PATTERNS (adds rmdir, cp, install, dd) - docker.md: the container runs as non-root hermes (UID 10000) via gosu; fix install command (uv pip); add missing --insecure on the dashboard compose example (required for non-loopback bind) - security.md: systemctl danger pattern also matches 'restart' - index.md: built-in tool count 47 -> 68 - integrations/index.md: 6 STT providers, 8 memory providers - integrations/providers.md: drop fictional dashscope/qwen aliases Features: - overview.md: 9 image models (not 8), 9 TTS providers (not 5), 8 memory providers (Supermemory was missing) - tool-gateway.md: 9 image models - tools.md: extend common-toolsets list with search / messaging / spotify / discord / debugging / safe - fallback-providers.md: add 6 real providers from PROVIDER_REGISTRY (lmstudio, kimi-coding-cn, stepfun, alibaba-coding-plan, tencent-tokenhub, azure-foundry) - plugins.md: Available Hooks table now includes on_session_finalize, on_session_reset, subagent_stop - built-in-plugins.md: add the 7 bundled plugins the page didn't mention (spotify, google_meet, three image_gen providers, two dashboard examples) - web-dashboard.md: add --insecure and --tui flags - cron.md: hermes cron create takes positional schedule/prompt, not flags Messaging: - telegram.md: TELEGRAM_WEBHOOK_SECRET is now REQUIRED when TELEGRAM_WEBHOOK_URL is set (gateway refuses to start without it per GHSA-3vpc-7q5r-276h). Biggest user-visible drift in the batch. - discord.md: HERMES_DISCORD_TEXT_BATCH_SPLIT_DELAY_SECONDS default is 2.0, not 0.1 - dingtalk.md: document DINGTALK_REQUIRE_MENTION / FREE_RESPONSE_CHATS / MENTION_PATTERNS / HOME_CHANNEL / ALLOW_ALL_USERS that the adapter supports - bluebubbles.md: drop fictional BLUEBUBBLES_SEND_READ_RECEIPTS env var; the setting lives in platforms.bluebubbles.extra only - qqbot.md: drop dead QQ_SANDBOX; add real QQ_PORTAL_HOST and QQ_GROUP_ALLOWED_USERS - wecom-callback.md: replace 'hermes gateway start' (service-only) with 'hermes gateway' for first-time setup Developer-guide: - architecture.md: refresh tool/toolset counts (61/52), terminal backend count (7), line counts for run_agent.py (~13.7k), cli.py (~11.5k), main.py (~10.4k), setup.py (~3.5k), gateway/run.py (~12.2k), mcp_tool.py (~3.1k); add yuanbao adapter, bump platform adapter count 18 -> 20 - agent-loop.md: run_agent.py line count 10.7k -> 13.7k - tools-runtime.md: add vercel_sandbox backend - adding-tools.md: remove stale 'Discovery import added to model_tools.py' checklist item (registry auto-discovery) - adding-platform-adapters.md: mark send_typing / get_chat_info as concrete base methods; only connect/disconnect/send are abstract - acp-internals.md: ACP sessions now persist to SessionDB (~/.hermes/state.db); acp.run_agent call uses use_unstable_protocol=True - cron-internals.md: gateway runs scheduler in a dedicated background thread via _start_cron_ticker, not on a maintenance cycle; locking is cross-process via fcntl.flock (Unix) / msvcrt.locking (Windows) - gateway-internals.md: gateway/run.py ~12k lines - provider-runtime.md: cron DOES support fallback (run_job reads fallback_providers from config) - session-storage.md: SCHEMA_VERSION = 11 (not 9); add migrations 10 and 11 (trigram FTS, inline-mode FTS5 re-index); add api_call_count column to Sessions DDL; document messages_fts_trigram and state_meta in the architecture tree - context-compression-and-caching.md: remove the obsolete 'context pressure warnings' section (warnings were removed for causing models to give up early) - context-engine-plugin.md: compress() signature now includes focus_topic param - extending-the-cli.md: _build_tui_layout_children signature now includes model_picker_widget; add to default layout Also fixed three pre-existing broken links/anchors the build warned about (docker.md -> api-server.md, yuanbao.md -> cron-jobs.md and tips#background-tasks, nix-setup.md -> #container-aware-cli). Regenerated per-skill pages via website/scripts/generate-skill-docs.py so catalog tables and sidebar are consistent with current SKILL.md frontmatter. docusaurus build: clean, no broken links or anchors.
2026-04-29 20:55:59 -07:00
Cron jobs **do** support fallback: `run_job()` reads `fallback_providers` (or legacy `fallback_model`) from `config.yaml` and passes it to `AIAgent(fallback_model=...)`, matching the gateway's `_load_fallback_model()` pattern. See [Cron Internals](./cron-internals.md).
docs: fallback providers + /background command documentation * docs: comprehensive fallback providers documentation - New dedicated page: user-guide/features/fallback-providers.md covering both primary model fallback and auxiliary task fallback systems - Updated configuration.md with fallback_model config section - Updated environment-variables.md noting fallback is config-only - Fleshed out developer-guide/provider-runtime.md fallback section with internal architecture details (trigger points, activation flow, config flow) - Added cross-reference from provider-routing.md distinguishing OpenRouter sub-provider routing from Hermes-level model fallback - Added new page to sidebar under Integrations * docs: comprehensive /background command documentation - Added Background Sessions section to cli.md covering how it works (daemon threads, isolated sessions, config inheritance, Rich panel output, bell notification, concurrent tasks) - Added Background Sessions section to messaging/index.md covering messaging-specific behavior (async execution, result delivery back to same chat, fire-and-forget pattern) - Documented background_process_notifications config (all/result/error/off) in messaging docs and configuration.md - Added HERMES_BACKGROUND_NOTIFICATIONS env var to reference page - Fixed inconsistency in slash-commands.md: /background was listed as messaging-only but works in both CLI and messaging. Moved it to the 'both surfaces' note. - Expanded one-liner table descriptions with detail and cross-references
2026-03-15 06:24:28 -07:00
### Test coverage
Fallback behavior is exercised across several suites:
- `tests/run_agent/test_fallback_credential_isolation.py` — credential isolation between primary and fallback
- `tests/hermes_cli/test_fallback_cmd.py` — the `/fallback` CLI command
- `tests/gateway/test_fallback_eviction.py` — gateway eviction of failed providers
## Related docs
- [Agent Loop Internals](./agent-loop.md)
- [ACP Internals](./acp-internals.md)
- [Context Compression & Prompt Caching](./context-compression-and-caching.md)