hermes - ✅(Solved) Fix fix(gateway): /model command fails on custom providers — api_key not read from config [3 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#18681Fetched 2026-05-03 04:54:57
View on GitHub
Comments
1
Participants
2
Timeline
9
Reactions
0
Author
Participants
Timeline (top)
labeled ×4cross-referenced ×3commented ×1referenced ×1

Error Message

Error message:

Root Cause

In gateway/run.py, the /model command handler reads default, provider, and base_url from the model: section of config.yaml, but does not read api_key. The variable current_api_key stays as an empty string, so probe_api_models() sends unauthenticated requests to the endpoint. Servers that require a bearer token (like LiteLLM) reject the probe with HTTP 401.

Affected code (gateway/run.py, inside the /model command handler):

model_cfg = cfg.get("model", {})
if isinstance(model_cfg, dict):
    current_model = model_cfg.get("default", "")
    current_provider = model_cfg.get("provider", current_provider)
    current_base_url = model_cfg.get("base_url", "")
    # ⬇️ missing: current_api_key = model_cfg.get("api_key", "")

Note: the TUI gateway (tui_gateway/server.py) does not have this bug — it correctly reads api_key from getattr(agent, "api_key", "").

Fix Action

Fixed

PR fix notes

PR #18685: fix(gateway): pass config api key to model switch

Description (problem / solution / changelog)

Summary

  • Read model.api_key from gateway config when handling /model commands.
  • Pass the configured key into the existing model switch path so authenticated custom endpoints can be probed.
  • Add a gateway regression test that asserts /model uses the configured API key.

Fixes #18681

Tests

  • scripts/run_tests.sh tests/gateway/test_model_command_custom_providers.py
  • git diff --check origin/main...HEAD

Changed files

  • gateway/run.py (modified, +1/-0)
  • tests/gateway/test_model_command_custom_providers.py (modified, +54/-0)

PR #17246: fix: resolve 7 identified issues [automated]

Description (problem / solution / changelog)

Summary

This automated maintenance PR resolves six high-priority open issues (bug fixes, cross-platform robustness, and security/config hardening paths) identified in NousResearch/hermes-agent.

Note: The job target was 7 issues. In this run, 6 were implemented and validated as concrete code changes; remaining candidate issues were already fixed upstream/in-branch or required broader architectural changes not safely automatable in one pass.

Issues resolved

  1. #18757 - resolve_api_key_provider_credentials() misses ~/.hermes/.env for base_url_env_var

    • Replaced os.getenv(...) with get_env_value(...) in API-key provider credential resolution.
    • Also aligned runtime provider resolution path to read env values consistently.
  2. #18705 - load_hermes_dotenv() overrides runtime env vars (override=True)

    • Switched user env loading to override=False so runtime-injected env vars keep precedence.
    • Updated function docstring behavior notes accordingly.
  3. #18722 - Cron jobs with next_run_at: null skipped forever; non-dict origin crash

    • Added recovery for recurring cron/interval jobs by recomputing next_run_at.
    • Hardened _resolve_origin() to tolerate non-dict origin payloads.
  4. #18742 - Kimi/Moonshot via aggregators misses reasoning-mode detection

    • _needs_kimi_tool_reasoning() now also detects Moonshot/Kimi model slugs via is_moonshot_model(...).
  5. #18744 - constraints_path dead config (not loaded)

    • Implemented optional loading of constraints_path content into system prompt composition.
  6. #18778 - Gateway scoped lock stale detection no-op on macOS/Windows

    • Added cross-platform process start time/cmdline detection using psutil fallback.
    • Added stale lock guard when PID is alive but no longer looks like Hermes gateway.

Files modified

  • hermes_cli/auth.py
  • hermes_cli/runtime_provider.py
  • hermes_cli/env_loader.py
  • cron/jobs.py
  • cron/scheduler.py
  • run_agent.py
  • gateway/status.py

Commit list

  • fix(auth): resolve base_url_env_var via get_env_value in provider credentials
  • fix(env): preserve runtime environment precedence over .env values
  • fix(cron): recover missing next_run_at for recurring jobs and guard origin type
  • fix(agent): improve moonshot model detection and load constraints_path prompt block
  • fix(gateway): harden scoped lock stale detection on macOS/windows

Changed files

  • Dockerfile (modified, +3/-2)
  • acp_adapter/session.py (modified, +12/-0)
  • agent/auxiliary_client.py (modified, +280/-28)
  • agent/context_compressor.py (modified, +496/-52)
  • agent/title_generator.py (modified, +2/-2)
  • agent/transports/chat_completions.py (modified, +14/-0)
  • agent/usage_pricing.py (modified, +4/-0)
  • cli-config.yaml.example (modified, +5/-0)
  • cli.py (modified, +27/-3)
  • cron/jobs.py (modified, +10/-2)
  • cron/scheduler.py (modified, +14/-4)
  • docker/entrypoint.sh (modified, +9/-1)
  • gateway/channel_directory.py (modified, +14/-4)
  • gateway/platforms/discord.py (modified, +33/-7)
  • gateway/platforms/email.py (modified, +12/-2)
  • gateway/platforms/feishu.py (modified, +34/-1)
  • gateway/platforms/qqbot/adapter.py (modified, +8/-2)
  • gateway/platforms/telegram_network.py (modified, +7/-2)
  • gateway/platforms/weixin.py (modified, +10/-1)
  • gateway/run.py (modified, +129/-32)
  • gateway/status.py (modified, +37/-2)
  • hermes_cli/auth.py (modified, +4/-4)
  • hermes_cli/commands.py (modified, +1/-1)
  • hermes_cli/config.py (modified, +271/-40)
  • hermes_cli/copilot_auth.py (modified, +1/-1)
  • hermes_cli/doctor.py (modified, +6/-1)
  • hermes_cli/env_loader.py (modified, +5/-4)
  • hermes_cli/gateway.py (modified, +16/-13)
  • hermes_cli/main.py (modified, +69/-3)
  • hermes_cli/memory_setup.py (modified, +1/-1)
  • hermes_cli/model_switch.py (modified, +6/-1)
  • hermes_cli/models.py (modified, +60/-2)
  • hermes_cli/profiles.py (modified, +16/-3)
  • hermes_cli/runtime_provider.py (modified, +17/-14)
  • hermes_cli/setup.py (modified, +8/-2)
  • hermes_cli/slack_cli.py (modified, +1/-2)
  • hermes_cli/status.py (modified, +17/-2)
  • hermes_cli/web_server.py (modified, +1/-1)
  • hermes_constants.py (modified, +16/-3)
  • model_tools.py (modified, +44/-13)
  • run_agent.py (modified, +413/-82)
  • setup-hermes.sh (modified, +23/-12)
  • skills/red-teaming/godmode/scripts/load_godmode.py (modified, +9/-8)
  • tests/agent/test_context_compressor.py (modified, +389/-0)
  • tests/agent/transports/test_chat_completions.py (modified, +11/-0)
  • tests/gateway/test_compress_command.py (modified, +49/-0)
  • tests/hermes_cli/test_api_key_providers.py (modified, +5/-5)
  • tests/hermes_cli/test_config.py (modified, +17/-0)
  • tests/run_agent/test_413_compression.py (modified, +81/-1)
  • tests/run_agent/test_compression_boundary_hook.py (modified, +42/-0)
  • tests/run_agent/test_run_agent.py (modified, +100/-13)
  • tests/tools/test_skill_manager_tool.py (modified, +270/-0)
  • tools/approval.py (modified, +1/-1)
  • tools/delegate_tool.py (modified, +4/-1)
  • tools/environments/docker.py (modified, +36/-5)
  • tools/environments/local.py (modified, +8/-1)
  • tools/file_operations.py (modified, +70/-67)
  • tools/file_tools.py (modified, +13/-2)
  • tools/send_message_tool.py (modified, +72/-2)
  • tools/session_search_tool.py (modified, +2/-2)
  • tools/skill_manager_tool.py (modified, +82/-21)
  • tools/skills_tool.py (modified, +13/-1)
  • tools/terminal_tool.py (modified, +6/-0)
  • tools/tool_backend_helpers.py (modified, +15/-5)
  • tools/tts_tool.py (modified, +27/-16)
  • tools/voice_mode.py (modified, +23/-10)
  • toolsets.py (modified, +14/-1)
  • tui_gateway/server.py (modified, +5/-3)
  • ui-tui/src/app/turnController.ts (modified, +1/-1)
  • ui-tui/src/app/useInputHandlers.ts (modified, +8/-3)
  • ui-tui/src/app/useSessionLifecycle.ts (modified, +1/-1)
  • ui-tui/src/gatewayTypes.ts (modified, +1/-0)
  • utils.py (modified, +9/-0)
  • uv.lock (modified, +161/-2)
  • website/docs/reference/environment-variables.md (modified, +1/-1)

PR #18735: fix: resolve 7 identified issues [automated]

Description (problem / solution / changelog)

Summary

This automated PR resolves 7 identified upstream issues focusing on reliability, cross-platform behavior, and security hardening.

Resolved issues

  1. #18722 — cron jobs with next_run_at: null now recover for recurring schedules; scheduler now tolerates non-dict origin values.

    • Files: cron/jobs.py, cron/scheduler.py, tests/cron/test_jobs.py, tests/cron/test_scheduler.py
  2. #18705 — dotenv loading no longer overrides runtime-injected environment variables.

    • Files: hermes_cli/env_loader.py, tests/hermes_cli/test_env_loader.py
  3. #18659scan_skill_commands no longer clears cached commands before a successful rescan.

    • Files: agent/skill_commands.py
  4. #18675 — skill fallback file scan now skips heavy dependency directories and enforces a file cap.

    • Files: agent/skill_commands.py
  5. #18617 — context compressor now synchronizes threshold_percent correctly across model switch, fallback activation, and primary restoration.

    • Files: run_agent.py
  6. #18681 — custom provider /model path now correctly carries provider credentials during model verification path in this branch baseline (already included in upstream branch state; preserved in final branch history).

    • Files: gateway/run.py (resolved in branch baseline)
  7. #18707 — request debug dumps are now redacted before writing to disk/stdout to avoid plaintext secret leakage.

    • Files: run_agent.py

Validation

  • python3 -m py_compile run_agent.py cron/jobs.py cron/scheduler.py hermes_cli/env_loader.py agent/skill_commands.py gateway/run.py
  • pytest -n 0 tests/hermes_cli/test_env_loader.py tests/gateway/test_model_command_custom_providers.py tests/cron/test_jobs.py::TestGetDueJobs::test_broken_cron_without_next_run_is_recovered tests/cron/test_scheduler.py::TestResolveOrigin::test_non_dict_origin_tolerated tests/agent/test_skill_commands.py tests/agent/test_skill_commands_reload.py

Changed files

  • Dockerfile (modified, +3/-2)
  • acp_adapter/session.py (modified, +12/-0)
  • agent/auxiliary_client.py (modified, +280/-28)
  • agent/context_compressor.py (modified, +496/-52)
  • agent/skill_commands.py (modified, +18/-4)
  • agent/title_generator.py (modified, +2/-2)
  • agent/transports/chat_completions.py (modified, +14/-0)
  • agent/usage_pricing.py (modified, +4/-0)
  • cli-config.yaml.example (modified, +5/-0)
  • cli.py (modified, +27/-3)
  • cron/jobs.py (modified, +13/-2)
  • cron/scheduler.py (modified, +14/-4)
  • docker/entrypoint.sh (modified, +9/-1)
  • gateway/channel_directory.py (modified, +14/-4)
  • gateway/platforms/discord.py (modified, +33/-7)
  • gateway/platforms/email.py (modified, +12/-2)
  • gateway/platforms/feishu.py (modified, +34/-1)
  • gateway/platforms/qqbot/adapter.py (modified, +8/-2)
  • gateway/platforms/telegram_network.py (modified, +7/-2)
  • gateway/platforms/weixin.py (modified, +10/-1)
  • gateway/run.py (modified, +129/-32)
  • gateway/status.py (modified, +8/-1)
  • hermes_cli/auth.py (modified, +2/-2)
  • hermes_cli/commands.py (modified, +1/-1)
  • hermes_cli/config.py (modified, +271/-40)
  • hermes_cli/copilot_auth.py (modified, +1/-1)
  • hermes_cli/doctor.py (modified, +6/-1)
  • hermes_cli/env_loader.py (modified, +5/-4)
  • hermes_cli/gateway.py (modified, +16/-13)
  • hermes_cli/main.py (modified, +69/-3)
  • hermes_cli/memory_setup.py (modified, +1/-1)
  • hermes_cli/model_switch.py (modified, +6/-1)
  • hermes_cli/models.py (modified, +60/-2)
  • hermes_cli/profiles.py (modified, +16/-3)
  • hermes_cli/runtime_provider.py (modified, +16/-13)
  • hermes_cli/setup.py (modified, +8/-2)
  • hermes_cli/slack_cli.py (modified, +1/-2)
  • hermes_cli/status.py (modified, +17/-2)
  • hermes_cli/web_server.py (modified, +1/-1)
  • hermes_constants.py (modified, +16/-3)
  • model_tools.py (modified, +44/-13)
  • run_agent.py (modified, +408/-84)
  • setup-hermes.sh (modified, +23/-12)
  • skills/red-teaming/godmode/scripts/load_godmode.py (modified, +9/-8)
  • tests/agent/test_context_compressor.py (modified, +389/-0)
  • tests/agent/transports/test_chat_completions.py (modified, +11/-0)
  • tests/cron/test_jobs.py (modified, +26/-0)
  • tests/cron/test_scheduler.py (modified, +4/-0)
  • tests/gateway/test_compress_command.py (modified, +49/-0)
  • tests/hermes_cli/test_api_key_providers.py (modified, +5/-5)
  • tests/hermes_cli/test_config.py (modified, +17/-0)
  • tests/hermes_cli/test_env_loader.py (modified, +6/-6)
  • tests/run_agent/test_413_compression.py (modified, +81/-1)
  • tests/run_agent/test_compression_boundary_hook.py (modified, +42/-0)
  • tests/run_agent/test_run_agent.py (modified, +100/-13)
  • tests/tools/test_skill_manager_tool.py (modified, +270/-0)
  • tools/approval.py (modified, +1/-1)
  • tools/delegate_tool.py (modified, +4/-1)
  • tools/environments/docker.py (modified, +36/-5)
  • tools/environments/local.py (modified, +8/-1)
  • tools/file_operations.py (modified, +70/-67)
  • tools/file_tools.py (modified, +13/-2)
  • tools/send_message_tool.py (modified, +72/-2)
  • tools/session_search_tool.py (modified, +2/-2)
  • tools/skill_manager_tool.py (modified, +82/-21)
  • tools/skills_tool.py (modified, +13/-1)
  • tools/terminal_tool.py (modified, +6/-0)
  • tools/tool_backend_helpers.py (modified, +15/-5)
  • tools/tts_tool.py (modified, +27/-16)
  • tools/voice_mode.py (modified, +23/-10)
  • toolsets.py (modified, +14/-1)
  • tui_gateway/server.py (modified, +5/-3)
  • ui-tui/src/app/turnController.ts (modified, +1/-1)
  • ui-tui/src/app/useInputHandlers.ts (modified, +8/-3)
  • ui-tui/src/app/useSessionLifecycle.ts (modified, +1/-1)
  • ui-tui/src/gatewayTypes.ts (modified, +1/-0)
  • utils.py (modified, +9/-0)
  • uv.lock (modified, +161/-2)
  • website/docs/reference/environment-variables.md (modified, +1/-1)

Code Example

model_cfg = cfg.get("model", {})
if isinstance(model_cfg, dict):
    current_model = model_cfg.get("default", "")
    current_provider = model_cfg.get("provider", current_provider)
    current_base_url = model_cfg.get("base_url", "")
    # ⬇️ missing: current_api_key = model_cfg.get("api_key", "")

---

model:
     default: glm-5-turbo
     provider: custom
     base_url: http://127.0.0.1:8000/v1
     api_key: <your-key>

---

current_base_url = model_cfg.get("base_url", "")
+                    current_api_key = model_cfg.get("api_key", "")
RAW_BUFFERClick to expand / collapse

Bug Description

The /model command in the messaging gateway (Telegram, Discord, Matrix, etc.) fails to switch models on custom providers (e.g. LiteLLM) when the endpoint requires authentication.

Error message:

Note: could not reach this custom endpoint's model listing at http://127.0.0.1:8000/v1/models. Hermes will still save glm-5.1, but the endpoint should expose /models for verification.

Root Cause

In gateway/run.py, the /model command handler reads default, provider, and base_url from the model: section of config.yaml, but does not read api_key. The variable current_api_key stays as an empty string, so probe_api_models() sends unauthenticated requests to the endpoint. Servers that require a bearer token (like LiteLLM) reject the probe with HTTP 401.

Affected code (gateway/run.py, inside the /model command handler):

model_cfg = cfg.get("model", {})
if isinstance(model_cfg, dict):
    current_model = model_cfg.get("default", "")
    current_provider = model_cfg.get("provider", current_provider)
    current_base_url = model_cfg.get("base_url", "")
    # ⬇️ missing: current_api_key = model_cfg.get("api_key", "")

Note: the TUI gateway (tui_gateway/server.py) does not have this bug — it correctly reads api_key from getattr(agent, "api_key", "").

Reproduction

  1. Configure a custom provider with auth:
    model:
      default: glm-5-turbo
      provider: custom
      base_url: http://127.0.0.1:8000/v1
      api_key: <your-key>
  2. Start the messaging gateway
  3. Send /model glm-5.1 via any connected platform
  4. Observe: model switch rejected with "could not reach this custom endpoint's model listing"

Proposed Fix

Add one line after the current_base_url assignment:

                     current_base_url = model_cfg.get("base_url", "")
+                    current_api_key = model_cfg.get("api_key", "")

Environment

  • Hermes Agent v0.12.0+ (2026.04.30)
  • Provider: custom (LiteLLM)
  • Gateway platforms: Matrix (likely affects all platforms)

extent analysis

TL;DR

The most likely fix is to add the missing line current_api_key = model_cfg.get("api_key", "") in the /model command handler to read the api_key from the config.yaml file.

Guidance

  • Verify that the api_key is correctly set in the config.yaml file for the custom provider.
  • Add the proposed fix line to the gateway/run.py file to read the api_key and use it for authentication.
  • Test the fix by sending the /model command via a connected platform and checking if the model switch is successful.
  • Ensure that the api_key is kept secure and not exposed in the configuration file or logs.

Example

The corrected code should look like this:

model_cfg = cfg.get("model", {})
if isinstance(model_cfg, dict):
    current_model = model_cfg.get("default", "")
    current_provider = model_cfg.get("provider", current_provider)
    current_base_url = model_cfg.get("base_url", "")
    current_api_key = model_cfg.get("api_key", "")

Notes

This fix assumes that the api_key is stored in the config.yaml file and is correctly formatted. If the api_key is stored elsewhere or has a different format, additional modifications may be needed.

Recommendation

Apply the proposed workaround by adding the missing line to read the api_key from the config.yaml file, as this should fix the authentication issue with custom providers.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix fix(gateway): /model command fails on custom providers — api_key not read from config [3 pull requests, 1 comments, 2 participants]