@@ -865,17 +865,45 @@ async def async_messages_transform(self,
865865 tool_calls_map = {}
866866 last_tool_calls = []
867867 matched_tool_call_ids = set ()
868+
869+ def _is_tool_history (history ) -> bool :
870+ if isinstance (history , MemoryMessage ):
871+ return isinstance (history , MemoryToolMessage )
872+ return history .metadata .get ('role' ) == 'tool'
873+
874+ def _drop_incomplete_tool_call_turn (reason : str ):
875+ nonlocal tool_calls_map , last_tool_calls
876+ if not last_tool_calls :
877+ return
878+ dropped_message = None
879+ if messages and messages [- 1 ].get ("role" ) == "assistant" and messages [- 1 ].get ("tool_calls" ):
880+ dropped_message = messages .pop ()
881+ logger .warning (
882+ "Skip incomplete tool-call turn in memory replay: "
883+ f"reason={ reason } , missing_tool_call_ids={ last_tool_calls } , "
884+ f"matched_tool_result_ids={ list (tool_calls_map .keys ())} , "
885+ f"dropped_assistant_message={ bool (dropped_message )} , agent={ self .id ()} "
886+ )
887+ tool_calls_map = {}
888+ last_tool_calls = []
889+
890+ def _append_complete_tool_results ():
891+ nonlocal tool_calls_map , last_tool_calls
892+ for tool_call_id in last_tool_calls :
893+ if tool_call_id not in tool_calls_map :
894+ _drop_incomplete_tool_call_turn (f"missing tool result for { tool_call_id } " )
895+ return
896+ messages .append (tool_calls_map .get (tool_call_id ))
897+ matched_tool_call_ids .add (tool_call_id )
898+ tool_calls_map = {}
899+ last_tool_calls = []
900+
868901 for history in histories :
869902 if len (last_tool_calls ) > 0 and len (tool_calls_map ) == len (last_tool_calls ):
870903 # Maintain the order of tool calls
871- for tool_call_id in last_tool_calls :
872- if tool_call_id not in tool_calls_map :
873- raise AWorldRuntimeException (
874- f"tool_calls mismatch! { tool_call_id } not found in { tool_calls_map } , last_tool_calls: { last_tool_calls } , messages: { messages } , histories: { histories } " )
875- messages .append (tool_calls_map .get (tool_call_id ))
876- matched_tool_call_ids .add (tool_call_id )
877- tool_calls_map = {}
878- last_tool_calls = []
904+ _append_complete_tool_results ()
905+ elif last_tool_calls and not _is_tool_history (history ):
906+ _drop_incomplete_tool_call_turn ("next non-tool message encountered" )
879907
880908 if isinstance (history , MemoryMessage ):
881909 if isinstance (history , MemoryToolMessage ):
@@ -887,9 +915,10 @@ async def async_messages_transform(self,
887915 f"tool_call_id={ history .tool_call_id } , agent={ self .id ()} "
888916 )
889917 else :
890- raise AWorldRuntimeException (
891- f"tool_calls mismatch! { history .tool_call_id } not found in { last_tool_calls } , "
892- f"messages: { messages } , histories: { histories } " )
918+ logger .warning (
919+ "Skip orphan tool result in memory replay: "
920+ f"tool_call_id={ history .tool_call_id } , agent={ self .id ()} "
921+ )
893922 else :
894923 messages .append (history .to_openai_message ())
895924 if isinstance (history , MemoryAIMessage ) and history .tool_calls :
@@ -908,9 +937,10 @@ async def async_messages_transform(self,
908937 f"tool_call_id={ tool_call_id } , agent={ self .id ()} "
909938 )
910939 else :
911- raise AWorldRuntimeException (
912- f"tool_calls mismatch! { tool_call_id } not found in { last_tool_calls } , "
913- f"messages: { messages } , histories: { histories } " )
940+ logger .warning (
941+ "Skip orphan tool result in memory replay: "
942+ f"tool_call_id={ tool_call_id } , agent={ self .id ()} "
943+ )
914944 else :
915945 if not self .use_tools_in_prompt and history .metadata .get ('tool_calls' ):
916946 messages .append ({'role' : history .metadata ['role' ], 'content' : history .content ,
@@ -922,31 +952,13 @@ async def async_messages_transform(self,
922952 "tool_call_id" : history .metadata .get ("tool_call_id" )})
923953 if len (last_tool_calls ) > 0 and len (tool_calls_map ) == len (last_tool_calls ):
924954 # Maintain the order of tool calls
925- for tool_call_id in last_tool_calls :
926- if tool_call_id not in tool_calls_map :
927- raise AWorldRuntimeException (
928- f"tool_calls mismatch! { tool_call_id } not found in { tool_calls_map } , last_tool_calls: { last_tool_calls } , messages: { messages } , histories: { histories } " )
929- messages .append (tool_calls_map .get (tool_call_id ))
930- matched_tool_call_ids .add (tool_call_id )
931- tool_calls_map = {}
932- last_tool_calls = []
955+ _append_complete_tool_results ()
933956 elif len (tool_calls_map ) > len (last_tool_calls ):
934- raise AWorldRuntimeException (
935- f"tool_calls mismatch! { len (tool_calls_map )} tool messages > { len (last_tool_calls )} tool calls: "
936- f"tool_calls_map={ tool_calls_map } , last_tool_calls={ last_tool_calls } , messages={ messages } , histories={ histories } " )
937- if len (tool_calls_map ) == len (last_tool_calls ):
938- for tool_call_id in last_tool_calls :
939- if tool_call_id not in tool_calls_map :
940- raise AWorldRuntimeException (
941- f"tool_calls mismatch! { tool_call_id } not found in { tool_calls_map } , last_tool_calls: { last_tool_calls } , messages: { messages } , histories: { histories } " )
942- messages .append (tool_calls_map .get (tool_call_id ))
943- matched_tool_call_ids .add (tool_call_id )
944- tool_calls_map = {}
945- last_tool_calls = []
957+ _drop_incomplete_tool_call_turn ("more tool results than tool calls" )
958+ if last_tool_calls and len (tool_calls_map ) == len (last_tool_calls ):
959+ _append_complete_tool_results ()
946960 else :
947- raise AWorldRuntimeException (
948- f"tool_calls mismatch! { len (tool_calls_map )} tool messages != { len (last_tool_calls )} tool calls: "
949- f"tool_calls_map={ tool_calls_map } , last_tool_calls={ last_tool_calls } , messages={ messages } , histories={ histories } " )
961+ _drop_incomplete_tool_call_turn ("end of history reached" )
950962
951963 return messages
952964
0 commit comments