@@ -1310,55 +1310,62 @@ def flush_pending_msg():
13101310 # Emit MESSAGES_SNAPSHOT with input messages + new messages from this run.
13111311 # Enrich tool result messages with tool names so the frontend can
13121312 # reconstruct parent-child hierarchy with proper display names.
1313- if run_messages :
1314- enriched : list [Any ] = []
1315- for msg in run_messages :
1316- # Check if this is a tool result message that needs a name
1317- msg_role = getattr (msg , "role" , None )
1318- msg_tcid = getattr (msg , "tool_call_id" , None )
1319- if msg_role == "tool" and msg_tcid and msg_tcid in tool_name_by_id :
1320- # Convert to dict so we can add the name field
1321- if hasattr (msg , "model_dump" ):
1322- d = msg .model_dump (exclude_none = True )
1323- elif hasattr (msg , "dict" ):
1324- d = msg .dict (exclude_none = True )
1325- else :
1326- d = {
1327- "id" : getattr (msg , "id" , "" ),
1328- "role" : msg_role ,
1329- "content" : getattr (msg , "content" , "" ),
1330- "tool_call_id" : msg_tcid ,
1331- }
1332- d ["name" ] = tool_name_by_id [msg_tcid ]
1333- enriched .append (d )
1334- else :
1335- enriched .append (msg )
1336-
1337- # Stamp input messages with the run-start timestamp so they
1338- # survive a page refresh (the frontend's local timestamp is
1339- # lost when reconnecting to the SSE stream).
1340- run_start_iso = (
1341- datetime .fromtimestamp (run_start_ts / 1000 , tz = timezone .utc ).isoformat ()
1342- if run_start_ts
1343- else None
1344- )
1345- stamped_inputs : list [Any ] = []
1346- for msg in (input_data .messages if input_data else None ) or []:
1313+ #
1314+ # Always emit MESSAGES_SNAPSHOT regardless of whether run_messages is
1315+ # populated — compactFinishedRun requires it to succeed. Runs that
1316+ # produce no assistant output (interrupted, state-tool-only, halted)
1317+ # still need a snapshot so the JSONL can be compacted and prior
1318+ # history is not lost. When run_messages is empty the snapshot is
1319+ # just the stamped input history.
1320+ enriched : list [Any ] = []
1321+ for msg in run_messages :
1322+ # Check if this is a tool result message that needs a name
1323+ msg_role = getattr (msg , "role" , None )
1324+ msg_tcid = getattr (msg , "tool_call_id" , None )
1325+ if msg_role == "tool" and msg_tcid and msg_tcid in tool_name_by_id :
1326+ # Convert to dict so we can add the name field
13471327 if hasattr (msg , "model_dump" ):
13481328 d = msg .model_dump (exclude_none = True )
1349- elif isinstance (msg , dict ):
1350- d = dict (msg )
1329+ elif hasattr (msg , " dict" ):
1330+ d = msg . dict (exclude_none = True )
13511331 else :
13521332 d = {
13531333 "id" : getattr (msg , "id" , "" ),
1354- "role" : getattr ( msg , "role" , "" ) ,
1334+ "role" : msg_role ,
13551335 "content" : getattr (msg , "content" , "" ),
1336+ "tool_call_id" : msg_tcid ,
13561337 }
1357- if "timestamp" not in d and run_start_iso :
1358- d ["timestamp" ] = run_start_iso
1359- stamped_inputs .append (d )
1338+ d ["name" ] = tool_name_by_id [msg_tcid ]
1339+ enriched .append (d )
1340+ else :
1341+ enriched .append (msg )
1342+
1343+ # Stamp input messages with the run-start timestamp so they
1344+ # survive a page refresh (the frontend's local timestamp is
1345+ # lost when reconnecting to the SSE stream).
1346+ run_start_iso = (
1347+ datetime .fromtimestamp (run_start_ts / 1000 , tz = timezone .utc ).isoformat ()
1348+ if run_start_ts
1349+ else None
1350+ )
1351+ stamped_inputs : list [Any ] = []
1352+ for msg in (input_data .messages if input_data else None ) or []:
1353+ if hasattr (msg , "model_dump" ):
1354+ d = msg .model_dump (exclude_none = True )
1355+ elif isinstance (msg , dict ):
1356+ d = dict (msg )
1357+ else :
1358+ d = {
1359+ "id" : getattr (msg , "id" , "" ),
1360+ "role" : getattr (msg , "role" , "" ),
1361+ "content" : getattr (msg , "content" , "" ),
1362+ }
1363+ if "timestamp" not in d and run_start_iso :
1364+ d ["timestamp" ] = run_start_iso
1365+ stamped_inputs .append (d )
13601366
1361- all_messages = stamped_inputs + enriched
1367+ all_messages = stamped_inputs + enriched
1368+ if all_messages :
13621369 logger .debug (
13631370 f"MESSAGES_SNAPSHOT: { len (all_messages )} msgs ({ message_count } SDK messages processed)"
13641371 )
0 commit comments