Skip to content

fix(opencode): re-derive api_mode per target model on /model switch - #16890

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-0eb15153
Apr 28, 2026
Merged

fix(opencode): re-derive api_mode per target model on /model switch#16890
teknium1 merged 2 commits into
mainfrom
hermes/hermes-0eb15153

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Salvages PR #16888 (opencode fix only — the second stacked reasoning_content commit from that PR is dropped; it is a separate concern tracked under #16844 and will be evaluated on its own).

Summary

/model deepseek-v4-flash from a minimax-m2.7 default on opencode-go / opencode-zen 404'd. The api_mode resolver honoured the persisted api_mode: anthropic_messages (set when minimax was default) before the opencode model registry, so the deepseek turn inherited anthropic_messages, stripped /v1 from base_url, and went to https://opencode.ai/zen/go/messages instead of .../v1/chat/completions.

Fixes #16878.

Changes

  • hermes_cli/runtime_provider.py — promote the opencode-zen/go branch above the configured_mode check in both api_mode resolution paths (_resolve_runtime_from_pool_entry and the API-key fallback in resolve_runtime_provider). opencode always re-derives mode from the effective target_model; other providers keep existing precedence (persisted api_mode > URL detection).
  • tests/hermes_cli/test_runtime_provider_resolution.py — rename + invert test_opencode_go_configured_api_mode_still_overrides_default (added in fix: repair OpenCode model routing and selection #4508) to lock in the new precedence. A persisted chat_completions on a minimax model no longer wins — the model dictates the mode. Escape-hatch for opencode is intentionally removed; the model name is the unambiguous signal.

Validation

Before After
minimax default → /model deepseek-v4-flash api_mode=anthropic_messages, base_url=.../zen/go (404) api_mode=chat_completions, base_url=.../zen/go/v1
deepseek default → /model minimax-m2.7 api_mode=anthropic_messages, base_url=.../zen/go unchanged
no target_model (legacy callers) unchanged unchanged

Suites: tests/hermes_cli/test_runtime_provider_resolution.py, test_model_switch_opencode_anthropic.py, test_model_switch_custom_providers.py — 109/109 pass. E2E verified against origin/main with a real config.yaml and isolated HERMES_HOME.

Credit: @Sanjays2402 for the original fix (#16888).

Sanjays2402 and others added 2 commits April 28, 2026 01:10
opencode-zen and opencode-go each serve both anthropic_messages
(e.g. minimax-m2.7) and chat_completions (e.g. deepseek-v4-flash)
models behind a single base_url. The api_mode resolver in
hermes_cli/runtime_provider.py honoured the persisted
model_cfg.api_mode (set by the previous default model) before checking
the opencode model registry, so /model deepseek-v4-flash from a session
whose default was minimax-m2.7 inherited 'anthropic_messages', stripped
'/v1' from base_url (the Anthropic SDK adds its own /v1/messages), and
404'd.

Promote the opencode detection branch above the configured_mode check
in both api_mode resolution paths:

- _resolve_runtime_from_pool_entry (pool-backed providers)
- _resolve_api_key_runtime          (api-key providers, fallback path)

Both branches now call opencode_model_api_mode(provider, effective_model)
unconditionally for opencode-zen/go before considering any persisted
api_mode, so the mode always reflects the model the user just switched
to.

Existing tests pass (12/12 in tests/hermes_cli/test_model_switch_opencode_anthropic.py).

Fixes #16878
…e api_mode

PR #16888 swaps the opencode-zen/go resolver so that api_mode is always
re-derived from the effective model before the persisted api_mode is
consulted. That's the point of the fix — a stale anthropic_messages
from a previous minimax default must not survive a /model switch to a
chat_completions target (or vice versa) and strip /v1 from base_url.

The prior test asserted the opposite precedence — that a persisted
api_mode won over model-derived mode — and was added in #4508 to lock
in escape-hatch behavior. Under the new precedence that escape hatch
no longer exists for opencode (only for providers that genuinely
support both modes at a single endpoint — and for opencode the model
name is the unambiguous signal). Rename + invert the assertion to
document the intentional behavior change.

Refs #16878.
@teknium1
teknium1 merged commit 54e24f7 into main Apr 28, 2026
11 of 12 checks passed
@teknium1
teknium1 deleted the hermes/hermes-0eb15153 branch April 28, 2026 08:14
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard labels Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: /v1 stripped from base_url when switching models via /model with opencode-go provider

3 participants