fix(tools): pass target_model to resolve_runtime_provider in delegation (#15319)

When delegation.model differs from the parent model (e.g., delegating
to claude-opus-4-6 on an opencode-zen provider while the parent uses
a chat_completions model), resolve_runtime_provider needs the target
model to select the correct api_mode.  Without it, the delegate
inherits the parent's api_mode and gets 404 errors.

Supersedes #15320.
This commit is contained in:
Tranquil-Flow 2026-04-25 09:19:24 +10:00
parent 00c3d848d8
commit acfe927294
2 changed files with 22 additions and 3 deletions

View file

@ -627,7 +627,7 @@ class TestDelegationCredentialResolution(unittest.TestCase):
self.assertEqual(creds["base_url"], "https://openrouter.ai/api/v1")
self.assertEqual(creds["api_key"], "sk-or-test-key")
self.assertEqual(creds["api_mode"], "chat_completions")
mock_resolve.assert_called_once_with(requested="openrouter")
mock_resolve.assert_called_once_with(requested="openrouter", target_model="google/gemini-3-flash-preview")
def test_direct_endpoint_uses_configured_base_url_and_api_key(self):
parent = _make_mock_parent(depth=0)
@ -688,7 +688,24 @@ class TestDelegationCredentialResolution(unittest.TestCase):
self.assertEqual(creds["provider"], "nous")
self.assertEqual(creds["base_url"], "https://inference-api.nousresearch.com/v1")
self.assertEqual(creds["api_key"], "nous-agent-key-xyz")
mock_resolve.assert_called_once_with(requested="nous")
mock_resolve.assert_called_once_with(requested="nous", target_model="hermes-3-llama-3.1-8b")
@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_target_model_forwarded_for_api_mode_resolution(self, mock_resolve):
"""target_model kwarg lets resolve_runtime_provider pick the correct api_mode."""
mock_resolve.return_value = {
"provider": "opencode-zen",
"base_url": "https://opencode-zen.example/v1",
"api_key": "sk-test",
"api_mode": "anthropic_messages",
}
parent = _make_mock_parent(depth=0)
cfg = {"model": "claude-opus-4-6", "provider": "opencode-zen"}
creds = _resolve_delegation_credentials(cfg, parent)
mock_resolve.assert_called_once_with(
requested="opencode-zen", target_model="claude-opus-4-6"
)
self.assertEqual(creds["api_mode"], "anthropic_messages")
@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_provider_resolution_failure_raises_valueerror(self, mock_resolve):
@ -700,6 +717,7 @@ class TestDelegationCredentialResolution(unittest.TestCase):
_resolve_delegation_credentials(cfg, parent)
self.assertIn("openrouter", str(ctx.exception).lower())
self.assertIn("Cannot resolve", str(ctx.exception))
mock_resolve.assert_called_once_with(requested="openrouter", target_model="some-model")
@patch("hermes_cli.runtime_provider.resolve_runtime_provider")
def test_provider_resolves_but_no_api_key_raises(self, mock_resolve):
@ -715,6 +733,7 @@ class TestDelegationCredentialResolution(unittest.TestCase):
with self.assertRaises(ValueError) as ctx:
_resolve_delegation_credentials(cfg, parent)
self.assertIn("no API key", str(ctx.exception))
mock_resolve.assert_called_once_with(requested="openrouter", target_model="some-model")
def test_missing_config_keys_inherit_parent(self):
"""When config dict has no model/provider keys at all, inherits parent."""

View file

@ -2164,7 +2164,7 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:
try:
from hermes_cli.runtime_provider import resolve_runtime_provider
runtime = resolve_runtime_provider(requested=configured_provider)
runtime = resolve_runtime_provider(requested=configured_provider, target_model=configured_model)
except Exception as exc:
raise ValueError(
f"Cannot resolve delegation provider '{configured_provider}': {exc}. "