mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(opencode): strip /v1 from base_url on mid-session /model switch to Anthropic-routed models (#11286)
PR #4918 fixed the double-/v1 bug at fresh agent init by stripping the trailing /v1 from OpenCode base URLs when api_mode is anthropic_messages (so the Anthropic SDK's own /v1/messages doesn't land on /v1/v1/messages). The same logic was missing from the /model mid-session switch path. Repro: start a session on opencode-go with GLM-5 (or any chat_completions model), then `/model minimax-m2.7`. switch_model() correctly sets api_mode=anthropic_messages via opencode_model_api_mode(), but base_url passes through as https://opencode.ai/zen/go/v1. The Anthropic SDK then POSTs to https://opencode.ai/zen/go/v1/v1/messages, which returns the OpenCode website 404 HTML page (title 'Not Found | opencode'). Same bug affects `/model claude-sonnet-4-6` on opencode-zen. Verified upstream: POST /v1/messages returns clean JSON 401 with x-api-key auth (route works), while POST /v1/v1/messages returns the exact HTML 404 users reported. Fix mirrors runtime_provider.resolve_runtime_provider: - hermes_cli/model_switch.py::switch_model() strips /v1 after the OpenCode api_mode override when the resolved mode is anthropic_messages. - run_agent.py::AIAgent.switch_model() applies the same strip as defense-in-depth, so any direct caller can't reintroduce the double-/v1. Tests: 9 new regression tests in tests/hermes_cli/test_model_switch_opencode_anthropic.py covering minimax on opencode-go, claude on opencode-zen, chat_completions (GLM/Kimi/Gemini) keeping /v1 intact, codex_responses (GPT) keeping /v1 intact, trailing-slash handling, and the agent-level defense-in-depth.
This commit is contained in:
parent
7fd508979e
commit
ab33ce1c86
3 changed files with 282 additions and 0 deletions
14
run_agent.py
14
run_agent.py
|
|
@ -1674,12 +1674,26 @@ class AIAgent:
|
|||
turn-scoped).
|
||||
"""
|
||||
import logging
|
||||
import re as _re
|
||||
from hermes_cli.providers import determine_api_mode
|
||||
|
||||
# ── Determine api_mode if not provided ──
|
||||
if not api_mode:
|
||||
api_mode = determine_api_mode(new_provider, base_url)
|
||||
|
||||
# Defense-in-depth: ensure OpenCode base_url doesn't carry a trailing
|
||||
# /v1 into the anthropic_messages client, which would cause the SDK to
|
||||
# hit /v1/v1/messages. `model_switch.switch_model()` already strips
|
||||
# this, but we guard here so any direct callers (future code paths,
|
||||
# tests) can't reintroduce the double-/v1 404 bug.
|
||||
if (
|
||||
api_mode == "anthropic_messages"
|
||||
and new_provider in ("opencode-zen", "opencode-go")
|
||||
and isinstance(base_url, str)
|
||||
and base_url
|
||||
):
|
||||
base_url = _re.sub(r"/v1/?$", "", base_url)
|
||||
|
||||
old_model = self.model
|
||||
old_provider = self.provider
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue