Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions tests/tools/test_delegate.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,58 @@ def test_direct_endpoint_auto_detects_anthropic_messages_suffix(self):
self.assertEqual(creds["api_mode"], "anthropic_messages")


@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_base_url_with_provider_carries_runtime_request_overrides(self, mock_resolve):
"""#65035: the base_url short-circuit must not drop the configured
provider's request_overrides / max_output_tokens."""
mock_resolve.return_value = {
"provider": "custom",
"base_url": "https://provider-default.example/v1",
"api_key": "provider-key",
"api_mode": "chat_completions",
"request_overrides": {"extra_body": {"thinking": {"type": "disabled"}}},
"max_output_tokens": 8192,
}
parent = _make_mock_parent(depth=0)
cfg = {
"model": "mimo-v2.5-pro",
"provider": "mimo",
"base_url": "https://api.xiaomimimo.com/v1",
"api_key": "cfg-key",
}
creds = _resolve_delegation_credentials(cfg, parent)
# Explicitly configured endpoint + key still win over the runtime's.
self.assertEqual(creds["base_url"], "https://api.xiaomimimo.com/v1")
self.assertEqual(creds["api_key"], "cfg-key")
# The provider's request personality survives the short-circuit.
self.assertEqual(
creds["request_overrides"],
{"extra_body": {"thinking": {"type": "disabled"}}},
)
self.assertEqual(creds["max_output_tokens"], 8192)

def test_bare_base_url_returns_none_overrides(self):
"""No provider alongside base_url → no overrides source; keys are
present but None (shape parity with the inherit-everything path)."""
parent = _make_mock_parent(depth=0)
cfg = {"model": "m", "provider": "", "base_url": "http://localhost:1234/v1", "api_key": "k"}
creds = _resolve_delegation_credentials(cfg, parent)
self.assertIsNone(creds["request_overrides"])
self.assertIsNone(creds["max_output_tokens"])

@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_base_url_survives_runtime_resolution_failure(self, mock_resolve):
"""Best-effort: the explicit endpoint worked before this change even
when the provider can't resolve — a resolution failure must not
break it, only skip the overrides."""
mock_resolve.side_effect = RuntimeError("MIMO_API_KEY not set")
parent = _make_mock_parent(depth=0)
cfg = {"model": "m", "provider": "mimo", "base_url": "https://api.xiaomimimo.com/v1", "api_key": "k"}
creds = _resolve_delegation_credentials(cfg, parent)
self.assertEqual(creds["base_url"], "https://api.xiaomimimo.com/v1")
self.assertIsNone(creds["request_overrides"])
self.assertIsNone(creds["max_output_tokens"])

@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_provider_resolution_failure_raises_valueerror(self, mock_resolve):
"""When provider resolution fails, ValueError is raised with helpful message."""
Expand Down
30 changes: 30 additions & 0 deletions tools/delegate_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -4531,12 +4531,42 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:
if configured_api_mode in {"chat_completions", "codex_responses", "anthropic_messages"}:
api_mode = configured_api_mode

# A provider configured ALONGSIDE base_url means the user wants that
# provider's request personality on an explicit endpoint. This
# short-circuit runs before the resolve_runtime_provider() call below,
# so without this block the runtime-carried request_overrides
# (extra_body / extra_headers, e.g. `thinking: {type: disabled}`) and
# max_output_tokens are silently dropped for subagents (#65035).
# Best-effort: the explicit endpoint worked before this change even
# when the provider can't resolve, so a resolution failure only skips
# the overrides — it must not fail the dispatch.
request_overrides = None
max_output_tokens = None
if configured_provider:
try:
from hermes_cli.runtime_provider import resolve_runtime_provider

runtime = resolve_runtime_provider(
requested=configured_provider, target_model=configured_model
)
request_overrides = dict(runtime.get("request_overrides") or {}) or None
max_output_tokens = runtime.get("max_output_tokens")
except Exception as exc:
logger.debug(
"delegation.base_url: runtime resolution for provider '%s' "
"failed; proceeding without request_overrides: %s",
configured_provider,
exc,
)

return {
"model": configured_model,
"provider": provider,
"base_url": configured_base_url,
"api_key": api_key,
"api_mode": api_mode,
"request_overrides": request_overrides,
"max_output_tokens": max_output_tokens,
}

if not configured_provider:
Expand Down
Loading