|
14 | 14 | import threading |
15 | 15 | import time |
16 | 16 | from collections.abc import Callable |
17 | | -from typing import Any |
| 17 | +from typing import TYPE_CHECKING, Any |
18 | 18 |
|
19 | 19 | from . import config |
20 | | -from .client import Client |
| 20 | +from .client import Client, LLMClient |
21 | 21 | from .mcp.config import MCPConfig |
22 | 22 | from .mcp.manager import MCPManager |
23 | 23 | from .models import AgentMode |
|
31 | 31 | from .tools.filesystem import cleanup_spooled_files |
32 | 32 | from .tools.mcp import mcp_tools_from_manager |
33 | 33 |
|
| 34 | +if TYPE_CHECKING: |
| 35 | + from .tools.base import ToolRuntime |
| 36 | + |
34 | 37 |
|
35 | 38 | def _tool_excluded(pattern: str, name: str) -> bool: |
36 | 39 | """True when *pattern* excludes tool *name*. |
@@ -85,15 +88,15 @@ class Session: |
85 | 88 | def __init__( |
86 | 89 | self, |
87 | 90 | project_dir: str, |
88 | | - client: Client, |
| 91 | + client: LLMClient, |
89 | 92 | model: str, |
90 | 93 | system_prompt: str | None = None, |
91 | 94 | subagent_system_prompt: str | None = None, |
92 | 95 | temperature: float = config.TEMPERATURE, |
93 | 96 | max_tokens: int | None = config.MAX_TOKENS, |
94 | 97 | reasoning_effort: str | None = None, |
95 | 98 | stream: bool = True, |
96 | | - subagent_client: Client | None = None, |
| 99 | + subagent_client: LLMClient | None = None, |
97 | 100 | subagent_temperature: float | None = None, |
98 | 101 | subagent_max_tokens: int | None = None, |
99 | 102 | subagent_reasoning_effort: str | None = None, |
@@ -172,7 +175,7 @@ def __init__( |
172 | 175 | # down a sibling's in-flight request on a shared client. The |
173 | 176 | # active clones are tracked so cancel()/close() can reach them. |
174 | 177 | self._subagent_clients_lock = threading.Lock() |
175 | | - self._active_subagent_clients: list[Client] = [] |
| 178 | + self._active_subagent_clients: list[LLMClient] = [] |
176 | 179 | # guards _skill_index_cache: parallel readonly tool threads |
177 | 180 | # (e.g. multiple Skill calls in one round) can hit the lazy |
178 | 181 | # cache build simultaneously — double-checked locking prevents |
@@ -880,3 +883,13 @@ def summarize_conversation(self) -> str: |
880 | 883 | self.last_messages.append(Msg(role="assistant", content=summary)) |
881 | 884 | self.auto_save(self.last_messages, self.system_prompt) |
882 | 885 | return "Summary appended." |
| 886 | + |
| 887 | + |
| 888 | +if TYPE_CHECKING: |
| 889 | + # static conformance: Session must satisfy the ToolRuntime interface |
| 890 | + # that ToolContext proxies to (it is passed as ``ToolContext(self)``). |
| 891 | + # pyright fails here if Session ever drifts from that surface — e.g. |
| 892 | + # a renamed run_subagent — instead of the mismatch surfacing only as |
| 893 | + # a runtime AttributeError inside a tool. |
| 894 | + def _assert_session_is_tool_runtime(s: Session) -> ToolRuntime: |
| 895 | + return s |
0 commit comments