diff --git a/tests/tools/test_delegate.py b/tests/tools/test_delegate.py index 5ee253d7e6d..0fe6e0028eb 100644 --- a/tests/tools/test_delegate.py +++ b/tests/tools/test_delegate.py @@ -1265,6 +1265,24 @@ class TestDelegationCredentialResolution(unittest.TestCase): requested="crof.ai", target_model="deepseek-v4-pro-CEER" ) + @patch("hermes_cli.runtime_provider.resolve_runtime_provider") + def test_provider_forwards_runtime_request_overrides_and_output_cap(self, mock_resolve): + mock_resolve.return_value = { + "provider": "custom", + "model": "real-model", + "base_url": "https://gateway.example/v1", + "api_key": "gateway-key", + "api_mode": "chat_completions", + "request_overrides": {"extra_body": {"store": False}}, + "max_output_tokens": 3072, + } + creds = _resolve_delegation_credentials( + {"model": "real-model", "provider": "gateway"}, + _make_mock_parent(depth=0), + ) + self.assertEqual(creds["request_overrides"], {"extra_body": {"store": False}}) + self.assertEqual(creds["max_output_tokens"], 3072) + @patch("hermes_cli.runtime_provider.resolve_runtime_provider") def test_standard_provider_not_overwritten_by_configured_name(self, mock_resolve): """Standard (non-custom) providers must still return runtime identity, diff --git a/tools/delegate_tool.py b/tools/delegate_tool.py index 7a9854148b9..24c2cd3325d 100644 --- a/tools/delegate_tool.py +++ b/tools/delegate_tool.py @@ -1055,6 +1055,8 @@ def _build_child_agent( override_base_url: Optional[str] = None, override_api_key: Optional[str] = None, override_api_mode: Optional[str] = None, + override_request_overrides: Optional[Dict[str, Any]] = None, + override_max_tokens: Optional[int] = None, # ACP transport overrides from trusted delegation config. override_acp_command: Optional[str] = None, override_acp_args: Optional[List[str]] = None, @@ -1306,6 +1308,15 @@ def _build_child_agent( # openrouter/pareto-code), so we keep it inherited even when the # provider is overridden — it's a no-op on any other model. + child_max_tokens = ( + override_max_tokens + if override_max_tokens is not None + else getattr(parent_agent, "max_tokens", None) + ) + child_optional_kwargs: Dict[str, Any] = {} + if isinstance(child_max_tokens, int): + child_optional_kwargs["max_tokens"] = child_max_tokens + child = AIAgent( base_url=effective_base_url, api_key=effective_api_key, @@ -1315,7 +1326,7 @@ def _build_child_agent( acp_command=effective_acp_command, acp_args=effective_acp_args, max_iterations=max_iterations, - max_tokens=getattr(parent_agent, "max_tokens", None), + reasoning_config=child_reasoning, prefill_messages=getattr(parent_agent, "prefill_messages", None), fallback_model=parent_fallback, @@ -1336,9 +1347,15 @@ def _build_child_agent( provider_sort=child_provider_sort, provider_require_parameters=child_provider_require_parameters, provider_data_collection=child_provider_data_collection, + request_overrides=( + dict(override_request_overrides or {}) + if override_provider + else dict(getattr(parent_agent, "request_overrides", {}) or {}) + ), openrouter_min_coding_score=child_openrouter_min_coding_score, tool_progress_callback=child_progress_cb, iteration_budget=None, # fresh budget per subagent + **child_optional_kwargs, ) child._print_fn = getattr(parent_agent, "_print_fn", None) # Now the child exists, its session id can ride on every relayed event @@ -2510,6 +2527,8 @@ def delegate_task( override_base_url=creds["base_url"], override_api_key=creds["api_key"], override_api_mode=creds["api_mode"], + override_request_overrides=creds.get("request_overrides"), + override_max_tokens=creds.get("max_output_tokens"), override_acp_command=creds.get("command"), override_acp_args=creds.get("args"), role=effective_role, @@ -3096,6 +3115,8 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict: "base_url": None, "api_key": None, "api_mode": None, + "request_overrides": None, + "max_output_tokens": None, } # Provider is configured — resolve full credentials @@ -3124,6 +3145,8 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict: "base_url": runtime.get("base_url"), "api_key": api_key, "api_mode": runtime.get("api_mode"), + "request_overrides": dict(runtime.get("request_overrides") or {}), + "max_output_tokens": runtime.get("max_output_tokens"), "command": runtime.get("command"), "args": list(runtime.get("args") or []), }