hermes - ✅(Solved) Fix _ensure_runtime_credentials() silently resets api_mode, breaking providers that require non-default transport [2 pull requests, 3 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#17574Fetched 2026-04-30 06:46:40
View on GitHub
Comments
3
Participants
2
Timeline
10
Reactions
0
Timeline (top)
labeled ×4commented ×3cross-referenced ×2referenced ×1

Error Message

  1. Send a second message — 404 error

Root Cause

In cli.py, _ensure_runtime_credentials() calls resolve_runtime_provider() which returns api_mode='chat_completions' as the default for kimi-coding. This value is then unconditionally written to self.api_mode at line 3256:

# cli.py ~L3221
resolved_api_mode = runtime.get("api_mode", self.api_mode)
# ...
# cli.py ~L3256
self.api_mode = resolved_api_mode

The /model command had correctly set api_mode="anthropic_messages", but the per-turn credential refresh destroys it.

Fix Action

Fix / Workaround

Local Workaround

We patched cli.py with a provider-specific transport lock after line 3262 and in _resolve_turn_agent_config():

PR fix notes

PR #17590: fix(cli): resolve runtime credentials for current model

Description (problem / solution / changelog)

Summary

  • Pass the current CLI model into runtime credential resolution.
  • Keep fallback credential resolution aligned with the fallback model being selected.
  • Add regression coverage for mid-session /model switches that require a non-default api_mode.

Root cause

HermesCLI._ensure_runtime_credentials() re-resolved provider credentials without passing the active model. Providers whose transport depends on the selected model could therefore recompute api_mode from stale persisted config instead of the current /model selection.

Fix

Forward target_model=self.model during normal runtime resolution and target_model=_fb_model when falling through to an auth fallback.

Regression coverage

Added tests/cli/test_runtime_credentials.py to assert that _ensure_runtime_credentials() passes the active model to resolve_runtime_provider() and invalidates the cached agent when routing changes.

Testing

  • scripts/run_tests.sh tests/cli/test_runtime_credentials.py -q
  • scripts/run_tests.sh tests/cli/test_runtime_credentials.py tests/hermes_cli/test_runtime_provider_resolution.py -q

Closes #17574

Changed files

  • cli.py (modified, +5/-1)
  • tests/cli/test_runtime_credentials.py (added, +63/-0)

PR #17596: fix(cli): preserve model-specific api_mode across credential refresh

Description (problem / solution / changelog)

Problem

_ensure_runtime_credentials() unconditionally overwrites self.api_mode with resolve_runtime_provider()s return value on every turn. The resolver defaults to "chat_completions" for most providers, but some models require "anthropic_messages" (e.g. kimi-for-coding).

When a user runs /model kimi-for-coding, it correctly sets api_mode="anthropic_messages". But on the next turn, _ensure_runtime_credentials() resets it back to "chat_completions", causing a 404 error (OpenAI-format traffic sent to an Anthropic-format endpoint).

Repro

  1. Start a session with any provider
  2. /model kimi-for-coding
  3. Send a message → works
  4. Send a second message → 404 error

Root Cause

resolve_runtime_provider() always returns an api_mode (defaulting to "chat_completions"), so the fallback runtime.get("api_mode", self.api_mode) never uses self.api_mode. The /model commands correctly set transport is unconditionally overwritten.

Fix

Only overwrite self.api_mode when:

  • We are already at the default ("chat_completions") — nothing to preserve
  • The resolver returns a non-default value — it has important info

This preserves model-specific transport modes set by /model while still allowing the resolver to communicate non-default transports.

Related

Fixes #17574

Changed files

  • cli.py (modified, +7/-1)

Code Example

# cli.py ~L3221
resolved_api_mode = runtime.get("api_mode", self.api_mode)
# ...
# cli.py ~L3256
self.api_mode = resolved_api_mode

---

if self.provider == "kimi-coding" or self.model == "kimi-for-coding":
    self.provider = "kimi-coding"
    self.model = "kimi-for-coding"
    self.base_url = "https://api.kimi.com/coding/"
    self.api_mode = "anthropic_messages"
    self._explicit_base_url = "https://api.kimi.com/coding/"
RAW_BUFFERClick to expand / collapse

Bug Description

After using /model kimi-for-coding in an interactive session, the first turn works correctly, but the second turn fails with 404 because _ensure_runtime_credentials() silently overwrites api_mode from anthropic_messages back to chat_completions.

Steps to Reproduce

  1. Start a session with any provider (e.g., MiniMax)
  2. Run /model kimi-for-coding
  3. Send a message — it works
  4. Send a second message — 404 error

Root Cause

In cli.py, _ensure_runtime_credentials() calls resolve_runtime_provider() which returns api_mode='chat_completions' as the default for kimi-coding. This value is then unconditionally written to self.api_mode at line 3256:

# cli.py ~L3221
resolved_api_mode = runtime.get("api_mode", self.api_mode)
# ...
# cli.py ~L3256
self.api_mode = resolved_api_mode

The /model command had correctly set api_mode="anthropic_messages", but the per-turn credential refresh destroys it.

Expected Behavior

When a user explicitly switches to a model that requires a specific transport mode (e.g., kimi-for-codinganthropic_messages), that transport mode should persist across turns.

Actual Behavior

api_mode reverts to chat_completions on every turn after _ensure_runtime_credentials(), causing OpenAI-format traffic to be sent to an Anthropic-format endpoint. Kimi returns 404.

Environment

  • Hermes Agent: latest main (as of 2026-04-29)
  • Provider: kimi-coding
  • Model: kimi-for-coding
  • Transport: anthropic_messages

Local Workaround

We patched cli.py with a provider-specific transport lock after line 3262 and in _resolve_turn_agent_config():

if self.provider == "kimi-coding" or self.model == "kimi-for-coding":
    self.provider = "kimi-coding"
    self.model = "kimi-for-coding"
    self.base_url = "https://api.kimi.com/coding/"
    self.api_mode = "anthropic_messages"
    self._explicit_base_url = "https://api.kimi.com/coding/"

This works but is a hack. A proper fix would be for resolve_runtime_provider() to preserve an explicitly-configured api_mode when the provider/model match, or for _ensure_runtime_credentials() to treat api_mode as sticky.

Impact

This is not Kimi-specific. Any future provider requiring a non-default api_mode (e.g., Codex codex_responses, or other Anthropic-adapter endpoints) will hit the same pattern. The failure is silent — users see 404s and assume the endpoint is broken.

Suggested Fix

Option A: resolve_runtime_provider() should accept an explicit_api_mode parameter and return it when the provider/model match.

Option B: _ensure_runtime_credentials() should compare the resolved api_mode against the current self.api_mode and only overwrite when the model/provider has actually changed.

extent analysis

TL;DR

To fix the issue, modify _ensure_runtime_credentials() to preserve the explicitly configured api_mode when the provider and model match.

Guidance

  • Identify the api_mode being overwritten and determine if it's due to _ensure_runtime_credentials() calling resolve_runtime_provider().
  • Consider implementing Option A: modify resolve_runtime_provider() to accept an explicit_api_mode parameter and return it when the provider/model match.
  • Alternatively, implement Option B: modify _ensure_runtime_credentials() to compare the resolved api_mode against the current self.api_mode and only overwrite when the model/provider has actually changed.
  • Verify the fix by testing the /model kimi-for-coding command with multiple turns and checking that the api_mode remains consistent.

Example

# Modified _ensure_runtime_credentials() function
def _ensure_runtime_credentials(self):
    # ...
    resolved_api_mode = runtime.get("api_mode", self.api_mode)
    if self.provider == "kimi-coding" and self.model == "kimi-for-coding" and self.api_mode == "anthropic_messages":
        self.api_mode = "anthropic_messages"
    else:
        self.api_mode = resolved_api_mode
    # ...

Notes

The provided local workaround is a temporary solution and may not be scalable. A proper fix should be implemented to handle the api_mode preservation for all providers and models.

Recommendation

Apply workaround by modifying _ensure_runtime_credentials() to preserve the explicitly configured api_mode when the provider and model match, as this is a more targeted solution that addresses the root cause of the issue.

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 _ensure_runtime_credentials() silently resets api_mode, breaking providers that require non-default transport [2 pull requests, 3 comments, 2 participants]