11import asyncio
2- from typing import Callable , Awaitable , Any
2+ from typing import Any , TYPE_CHECKING
33from dataclasses import dataclass
44
55from claude_agent_sdk import (
2626from agent_chat_cli .system .mcp_inference import infer_mcp_servers
2727from agent_chat_cli .utils .logger import log_json
2828
29+ if TYPE_CHECKING :
30+ from agent_chat_cli .app import AgentChatCLIApp
31+
2932
3033@dataclass
3134class AgentMessage :
@@ -36,17 +39,17 @@ class AgentMessage:
3639class AgentLoop :
3740 def __init__ (
3841 self ,
39- on_message : Callable [[ AgentMessage ], Awaitable [ None ]] ,
42+ app : "AgentChatCLIApp" ,
4043 session_id : str | None = None ,
4144 ) -> None :
45+ self .app = app
4246 self .config = load_config ()
4347 self .session_id = session_id
4448 self .available_servers = get_available_servers ()
4549 self .inferred_servers : set [str ] = set ()
4650
4751 self .client : ClaudeSDKClient
4852
49- self .on_message = on_message
5053 self .query_queue : asyncio .Queue [str | ControlCommand ] = asyncio .Queue ()
5154 self .permission_response_queue : asyncio .Queue [str ] = asyncio .Queue ()
5255 self .permission_lock = asyncio .Lock ()
@@ -104,11 +107,8 @@ async def start(self) -> None:
104107 if inference_result ["new_servers" ]:
105108 server_list = ", " .join (inference_result ["new_servers" ])
106109
107- await self .on_message (
108- AgentMessage (
109- type = AgentMessageType .SYSTEM ,
110- data = f"Connecting to { server_list } ..." ,
111- )
110+ self .app .actions .post_system_message (
111+ f"Connecting to { server_list } ..."
112112 )
113113
114114 await asyncio .sleep (0.1 )
@@ -136,7 +136,9 @@ async def start(self) -> None:
136136
137137 await self ._handle_message (message )
138138
139- await self .on_message (AgentMessage (type = AgentMessageType .RESULT , data = None ))
139+ await self .app .actions .handle_agent_message (
140+ AgentMessage (type = AgentMessageType .RESULT , data = None )
141+ )
140142
141143 async def _initialize_client (self , mcp_servers : dict ) -> None :
142144 sdk_config = get_sdk_config (self .config )
@@ -174,7 +176,7 @@ async def _handle_message(self, message: Any) -> None:
174176 text_chunk = delta .get ("text" , "" )
175177
176178 if text_chunk :
177- await self .on_message (
179+ await self .app . actions . handle_agent_message (
178180 AgentMessage (
179181 type = AgentMessageType .STREAM_EVENT ,
180182 data = {"text" : text_chunk },
@@ -202,7 +204,7 @@ async def _handle_message(self, message: Any) -> None:
202204 )
203205
204206 # Finally, post the agent assistant response
205- await self .on_message (
207+ await self .app . actions . handle_agent_message (
206208 AgentMessage (
207209 type = AgentMessageType .ASSISTANT ,
208210 data = {"content" : content },
@@ -219,7 +221,7 @@ async def _can_use_tool(
219221
220222 # Handle permission request queue
221223 async with self .permission_lock :
222- await self .on_message (
224+ await self .app . actions . handle_agent_message (
223225 AgentMessage (
224226 type = AgentMessageType .TOOL_PERMISSION_REQUEST ,
225227 data = {
@@ -252,11 +254,8 @@ async def _can_use_tool(
252254 )
253255
254256 if DENY :
255- await self .on_message (
256- AgentMessage (
257- type = AgentMessageType .SYSTEM ,
258- data = f"Permission denied for { tool_name } " ,
259- )
257+ self .app .actions .post_system_message (
258+ f"Permission denied for { tool_name } "
260259 )
261260
262261 return PermissionResultDeny (
@@ -266,14 +265,7 @@ async def _can_use_tool(
266265 )
267266
268267 # If a user instead typed in a message (instead of confirming or denying)
269- # post it to chat. actions.respond_to_tool_permission will handle querying.
270- await self .on_message (
271- AgentMessage (
272- type = AgentMessageType .USER ,
273- data = user_response ,
274- )
275- )
276-
268+ # actions.respond_to_tool_permission will handle posting and querying.
277269 return PermissionResultDeny (
278270 behavior = "deny" ,
279271 message = user_response ,
0 commit comments