From 20ade400ab9013fc013dc28fb84c2c03a9e3e099 Mon Sep 17 00:00:00 2001 From: fangliquan Date: Wed, 16 Sep 2026 16:04:25 +0800 Subject: [PATCH] fix(auxiliary): propagate OpenCode session header --- agent/auxiliary_client.py | 18 ++++++---- run_agent.py | 5 ++- tests/agent/test_opencode_session_affinity.py | 35 +++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index f70c12312d..7ef6f88ba9 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -2921,7 +2921,9 @@ def _try_anthropic(explicit_api_key: str = None) -> Tuple[Optional[Any], Optiona _MAIN_RUNTIME_FIELDS = ("provider", "model", "base_url", "api_key", "api_mode", "auth_mode") -_MAIN_RUNTIME_CONTEXT_FIELDS = _MAIN_RUNTIME_FIELDS + ("requested_provider",) +_MAIN_RUNTIME_CONTEXT_FIELDS = _MAIN_RUNTIME_FIELDS + ( + "requested_provider", "session_id", "cache_scope", +) def _normalize_main_runtime(main_runtime: Optional[Dict[str, Any]]) -> Dict[str, Any]: @@ -7408,6 +7410,7 @@ def call_llm( prior_progress_hook = getattr(_aux_progress, "hook", None) try: with ( + scoped_runtime_main(main_runtime), aux_progress_hook( prior_progress_hook if callable(prior_progress_hook) @@ -7697,12 +7700,13 @@ async def async_call_llm( if semaphore is not None: await semaphore.acquire() try: - return await _async_call_llm_impl( - task=task, provider=provider, model=model, base_url=base_url, api_key=api_key, - main_runtime=main_runtime, messages=messages, temperature=temperature, - max_tokens=max_tokens, tools=tools, timeout=timeout, extra_body=extra_body, - reasoning_config=reasoning_config, route_info=route_info, - ) + with scoped_runtime_main(main_runtime): + return await _async_call_llm_impl( + task=task, provider=provider, model=model, base_url=base_url, api_key=api_key, + main_runtime=main_runtime, messages=messages, temperature=temperature, + max_tokens=max_tokens, tools=tools, timeout=timeout, extra_body=extra_body, + reasoning_config=reasoning_config, route_info=route_info, + ) finally: if semaphore is not None: semaphore.release() diff --git a/run_agent.py b/run_agent.py index 67eac17cf7..2bfbf3e2e2 100644 --- a/run_agent.py +++ b/run_agent.py @@ -505,7 +505,10 @@ class AIAgent( def _current_main_runtime(self) -> Dict[str, str]: """Return the live main runtime for session-scoped auxiliary routing.""" - return {key: getattr(self, key, "") or "" for key in ("model", "provider", "base_url", "api_key", "api_mode", "auth_mode")} + return { + key: getattr(self, key, "") or "" + for key in ("model", "provider", "base_url", "api_key", "api_mode", "auth_mode", "session_id") + } _check_compression_model_feasibility = _forward("agent.conversation_compression", "check_compression_model_feasibility") _replay_compression_warning = _forward("agent.conversation_compression", "replay_compression_warning") diff --git a/tests/agent/test_opencode_session_affinity.py b/tests/agent/test_opencode_session_affinity.py index 51c3f3139c..24569d2a85 100644 --- a/tests/agent/test_opencode_session_affinity.py +++ b/tests/agent/test_opencode_session_affinity.py @@ -2,6 +2,8 @@ from __future__ import annotations +from types import SimpleNamespace + import pytest from agent import auxiliary_client as aux @@ -60,3 +62,36 @@ def test_auxiliary_calls_share_the_main_turn_session_key(): assert "x-opencode-session" not in (other.get("extra_headers") or {}) finally: aux._RUNTIME_MAIN_CONTEXT.reset(token) + + +def test_auxiliary_call_uses_explicit_main_runtime_session(monkeypatch): + captured = {} + + class Completions: + def create(self, **kwargs): + captured.update(kwargs) + return SimpleNamespace( + choices=[SimpleNamespace(message=SimpleNamespace(content="ok"))], + model="glm-5", + ) + + client = SimpleNamespace( + chat=SimpleNamespace(completions=Completions()), + base_url="https://opencode.ai/zen/v1", + ) + monkeypatch.setattr( + aux, + "_resolve_task_provider_model", + lambda *_args, **_kwargs: ( + "opencode-zen", "glm-5", "https://opencode.ai/zen/v1", "test-key", None, + ), + ) + monkeypatch.setattr(aux, "_get_cached_client", lambda *_args, **_kwargs: (client, "glm-5")) + + aux.call_llm( + task="title_generation", + messages=_MSGS, + main_runtime={"session_id": "sess-explicit-2"}, + ) + + assert captured["extra_headers"]["x-opencode-session"] == "sess-explicit-2"