@@ -70,6 +70,30 @@ def format_elapsed(start_time):
7070 return f"{ seconds } s"
7171
7272
73+ def format_tool_status (tool_counts , start_time ):
74+ """Format spinner status text showing tool activity summary."""
75+ if not tool_counts :
76+ return "[cyan]Working...[/cyan]"
77+ parts = []
78+ for name , count in tool_counts .items ():
79+ if count > 1 :
80+ parts .append (f"{ name } x{ count } " )
81+ else :
82+ parts .append (name )
83+ return f"[cyan]{ ', ' .join (parts )} [/cyan] [dim][{ format_elapsed (start_time )} ][/dim]"
84+
85+
86+ def format_tool_summary (tool_counts ):
87+ """Format a final one-line summary of all tools used."""
88+ parts = []
89+ for name , count in tool_counts .items ():
90+ if count > 1 :
91+ parts .append (f"{ name } x{ count } " )
92+ else :
93+ parts .append (name )
94+ return ", " .join (parts )
95+
96+
7397def flush_text_buffer (text_buffer ):
7498 """Render accumulated text as rich markdown and clear the buffer."""
7599 if not text_buffer :
@@ -80,7 +104,7 @@ def flush_text_buffer(text_buffer):
80104 console .print (Markdown (combined ))
81105
82106
83- def handle_assistant_event (message , start_time , text_buffer ):
107+ def handle_assistant_event (message , start_time , text_buffer , tool_counts , status ):
84108 """Display content blocks from an assistant message event."""
85109 for block in message .get ("content" , []):
86110 block_type = block .get ("type" , "" )
@@ -93,33 +117,31 @@ def handle_assistant_event(message, start_time, text_buffer):
93117 elif block_type == "tool_use" :
94118 flush_text_buffer (text_buffer )
95119 tool_name = block .get ("name" , "unknown" )
96- console .print (
97- f"\n [dim]tool:[/dim] [bold]{ tool_name } [/bold] "
98- f"[dim][{ format_elapsed (start_time )} ][/dim]"
99- )
120+ tool_counts [tool_name ] = tool_counts .get (tool_name , 0 ) + 1
121+ status .update (format_tool_status (tool_counts , start_time ))
100122
101123
102- def handle_event (event , start_time , text_buffer ):
124+ def handle_event (event , start_time , text_buffer , tool_counts , status ):
103125 """Handle a single stream-json event. Returns session_id if found, else None."""
104126 session_id = event .get ("session_id" ) or None
105127 event_type = event .get ("type" , "" )
106128
107129 if event_type == "assistant" :
108130 message = event .get ("message" , {})
109- handle_assistant_event (message , start_time , text_buffer )
131+ handle_assistant_event (message , start_time , text_buffer , tool_counts , status )
110132
111133 elif event_type == "tool_result" :
112134 flush_text_buffer (text_buffer )
113- console .print (
114- f" [dim]done[/dim] [{ format_elapsed (start_time )} ]"
115- )
135+ status .update (format_tool_status (tool_counts , start_time ))
116136
117137 return session_id
118138
119139
120- def print_session_summary (session_id , start_time ):
140+ def print_session_summary (session_id , start_time , tool_counts ):
121141 """Print the final session summary after stream ends."""
122142 elapsed = format_elapsed (start_time )
143+ if tool_counts :
144+ console .print (f" [dim]Tools: { format_tool_summary (tool_counts )} [/dim]" )
123145 if session_id :
124146 console .print (
125147 f"\n [green]Session saved ({ session_id } ). "
@@ -145,28 +167,28 @@ def main():
145167 phase = "fixing"
146168 start_time = time .time ()
147169 text_buffer = []
170+ tool_counts = {}
148171
149172 try :
150- console .print ("[cyan] Working...[/cyan]" )
151-
152- with open (EVENT_DEBUG_LOG , "w" , encoding = "utf-8" ) as debug_log :
153- for line in sys .stdin :
154- line = line .strip ()
155- if not line :
156- continue
157-
158- debug_log .write (line + "\n " )
159- debug_log .flush ()
160-
161- try :
162- event = json .loads (line )
163- except json .JSONDecodeError :
164- sys .stderr .write (f" { line } \n " )
165- continue
166-
167- event_session_id = handle_event (event , start_time , text_buffer )
168- if event_session_id :
169- session_id = event_session_id
173+ with console .status ("[cyan]Working...[/cyan]" , spinner = "dots" ) as status :
174+ with open (EVENT_DEBUG_LOG , "w" , encoding = "utf-8" ) as debug_log :
175+ for line in sys .stdin :
176+ line = line .strip ()
177+ if not line :
178+ continue
179+
180+ debug_log .write (line + "\n " )
181+ debug_log .flush ()
182+
183+ try :
184+ event = json .loads (line )
185+ except json .JSONDecodeError :
186+ sys .stderr .write (f" { line } \n " )
187+ continue
188+
189+ event_session_id = handle_event (event , start_time , text_buffer , tool_counts , status )
190+ if event_session_id :
191+ session_id = event_session_id
170192
171193 flush_text_buffer (text_buffer )
172194 phase = "completed"
@@ -180,7 +202,7 @@ def main():
180202 phase = "stuck"
181203
182204 write_state (session_id , phase , attempt_count )
183- print_session_summary (session_id , start_time )
205+ print_session_summary (session_id , start_time , tool_counts )
184206
185207
186208if __name__ == "__main__" :
0 commit comments