@@ -74,46 +74,65 @@ async def run_agent_session(
7474 await client .query (message )
7575
7676 # Collect response text and show tool use
77+ # Retry receive_response() on MessageParseError — the SDK raises this for
78+ # unknown CLI message types (e.g. "rate_limit_event") which kills the async
79+ # generator. The subprocess is still alive so we restart to read remaining
80+ # messages from the buffered channel.
7781 response_text = ""
78- async for msg in client .receive_response ():
79- msg_type = type (msg ).__name__
80-
81- # Handle AssistantMessage (text and tool use)
82- if msg_type == "AssistantMessage" and hasattr (msg , "content" ):
83- for block in msg .content :
84- block_type = type (block ).__name__
85-
86- if block_type == "TextBlock" and hasattr (block , "text" ):
87- response_text += block .text
88- print (block .text , end = "" , flush = True )
89- elif block_type == "ToolUseBlock" and hasattr (block , "name" ):
90- print (f"\n [Tool: { block .name } ]" , flush = True )
91- if hasattr (block , "input" ):
92- input_str = str (block .input )
93- if len (input_str ) > 200 :
94- print (f" Input: { input_str [:200 ]} ..." , flush = True )
95- else :
96- print (f" Input: { input_str } " , flush = True )
97-
98- # Handle UserMessage (tool results)
99- elif msg_type == "UserMessage" and hasattr (msg , "content" ):
100- for block in msg .content :
101- block_type = type (block ).__name__
102-
103- if block_type == "ToolResultBlock" :
104- result_content = getattr (block , "content" , "" )
105- is_error = getattr (block , "is_error" , False )
106-
107- # Check if command was blocked by security hook
108- if "blocked" in str (result_content ).lower ():
109- print (f" [BLOCKED] { result_content } " , flush = True )
110- elif is_error :
111- # Show errors (truncated)
112- error_str = str (result_content )[:500 ]
113- print (f" [Error] { error_str } " , flush = True )
114- else :
115- # Tool succeeded - just show brief confirmation
116- print (" [Done]" , flush = True )
82+ max_parse_retries = 50
83+ parse_retries = 0
84+ while True :
85+ try :
86+ async for msg in client .receive_response ():
87+ msg_type = type (msg ).__name__
88+
89+ # Handle AssistantMessage (text and tool use)
90+ if msg_type == "AssistantMessage" and hasattr (msg , "content" ):
91+ for block in msg .content :
92+ block_type = type (block ).__name__
93+
94+ if block_type == "TextBlock" and hasattr (block , "text" ):
95+ response_text += block .text
96+ print (block .text , end = "" , flush = True )
97+ elif block_type == "ToolUseBlock" and hasattr (block , "name" ):
98+ print (f"\n [Tool: { block .name } ]" , flush = True )
99+ if hasattr (block , "input" ):
100+ input_str = str (block .input )
101+ if len (input_str ) > 200 :
102+ print (f" Input: { input_str [:200 ]} ..." , flush = True )
103+ else :
104+ print (f" Input: { input_str } " , flush = True )
105+
106+ # Handle UserMessage (tool results)
107+ elif msg_type == "UserMessage" and hasattr (msg , "content" ):
108+ for block in msg .content :
109+ block_type = type (block ).__name__
110+
111+ if block_type == "ToolResultBlock" :
112+ result_content = getattr (block , "content" , "" )
113+ is_error = getattr (block , "is_error" , False )
114+
115+ # Check if command was blocked by security hook
116+ if "blocked" in str (result_content ).lower ():
117+ print (f" [BLOCKED] { result_content } " , flush = True )
118+ elif is_error :
119+ # Show errors (truncated)
120+ error_str = str (result_content )[:500 ]
121+ print (f" [Error] { error_str } " , flush = True )
122+ else :
123+ # Tool succeeded - just show brief confirmation
124+ print (" [Done]" , flush = True )
125+
126+ break # Normal completion
127+ except Exception as inner_exc :
128+ if type (inner_exc ).__name__ == "MessageParseError" :
129+ parse_retries += 1
130+ if parse_retries > max_parse_retries :
131+ print (f"Too many unrecognized CLI messages ({ parse_retries } ), stopping" )
132+ break
133+ print (f"Ignoring unrecognized message from Claude CLI: { inner_exc } " )
134+ continue
135+ raise # Re-raise to outer except
117136
118137 print ("\n " + "-" * 70 + "\n " )
119138 return "continue" , response_text
0 commit comments