88 from .result import RunResult , RunResultStreaming
99
1010# Ephemeral maps linking tool call objects to nested agent results within the same run.
11- # Store by object identity to avoid collisions when call IDs repeat across tool calls .
11+ # Store by object identity, and index by a stable signature to avoid call ID collisions .
1212_agent_tool_run_results_by_obj : dict [int , RunResult | RunResultStreaming ] = {}
13- _agent_tool_run_results_by_call_id : dict [str , set [int ]] = {}
13+ _agent_tool_run_results_by_signature : dict [
14+ tuple [str , str , str , str , str | None , str | None ],
15+ set [int ],
16+ ] = {}
17+ _agent_tool_run_result_signature_by_obj : dict [
18+ int ,
19+ tuple [str , str , str , str , str | None , str | None ],
20+ ] = {}
1421
1522
16- def _index_agent_tool_run_result (tool_call_id : str , tool_call_obj_id : int ) -> None :
17- """Track tool call objects by call ID for fallback lookup."""
18- _agent_tool_run_results_by_call_id .setdefault (tool_call_id , set ()).add (tool_call_obj_id )
23+ def _tool_call_signature (
24+ tool_call : ResponseFunctionToolCall ,
25+ ) -> tuple [str , str , str , str , str | None , str | None ]:
26+ """Build a stable signature for fallback lookup across tool call instances."""
27+ return (
28+ tool_call .call_id ,
29+ tool_call .name ,
30+ tool_call .arguments ,
31+ tool_call .type ,
32+ tool_call .id ,
33+ tool_call .status ,
34+ )
35+
36+
37+ def _index_agent_tool_run_result (
38+ tool_call : ResponseFunctionToolCall , tool_call_obj_id : int
39+ ) -> None :
40+ """Track tool call objects by signature for fallback lookup."""
41+ signature = _tool_call_signature (tool_call )
42+ _agent_tool_run_result_signature_by_obj [tool_call_obj_id ] = signature
43+ _agent_tool_run_results_by_signature .setdefault (signature , set ()).add (tool_call_obj_id )
1944
2045
21- def _drop_agent_tool_run_result (tool_call_id : str | None , tool_call_obj_id : int ) -> None :
46+ def _drop_agent_tool_run_result (tool_call_obj_id : int ) -> None :
2247 """Remove a tool call object from the fallback index."""
23- if tool_call_id is None :
48+ signature = _agent_tool_run_result_signature_by_obj .pop (tool_call_obj_id , None )
49+ if signature is None :
2450 return
25- call_ids = _agent_tool_run_results_by_call_id .get (tool_call_id )
26- if not call_ids :
51+ candidate_ids = _agent_tool_run_results_by_signature .get (signature )
52+ if not candidate_ids :
2753 return
28- call_ids .discard (tool_call_obj_id )
29- if not call_ids :
30- _agent_tool_run_results_by_call_id .pop (tool_call_id , None )
54+ candidate_ids .discard (tool_call_obj_id )
55+ if not candidate_ids :
56+ _agent_tool_run_results_by_signature .pop (signature , None )
3157
3258
3359def record_agent_tool_run_result (
@@ -36,32 +62,29 @@ def record_agent_tool_run_result(
3662 """Store the nested agent run result by tool call identity."""
3763 tool_call_obj_id = id (tool_call )
3864 _agent_tool_run_results_by_obj [tool_call_obj_id ] = run_result
39- if isinstance (tool_call .call_id , str ):
40- _index_agent_tool_run_result (tool_call .call_id , tool_call_obj_id )
65+ _index_agent_tool_run_result (tool_call , tool_call_obj_id )
4166
4267
4368def consume_agent_tool_run_result (
4469 tool_call : ResponseFunctionToolCall ,
4570) -> RunResult | RunResultStreaming | None :
46- """Return and drop the stored nested agent run result for the given tool call ID ."""
71+ """Return and drop the stored nested agent run result for the given tool call."""
4772 obj_id = id (tool_call )
4873 run_result = _agent_tool_run_results_by_obj .pop (obj_id , None )
4974 if run_result is not None :
50- _drop_agent_tool_run_result (tool_call . call_id , obj_id )
75+ _drop_agent_tool_run_result (obj_id )
5176 return run_result
5277
53- call_id = tool_call .call_id
54- if not call_id :
55- return None
56-
57- candidate_ids = _agent_tool_run_results_by_call_id .get (call_id )
78+ signature = _tool_call_signature (tool_call )
79+ candidate_ids = _agent_tool_run_results_by_signature .get (signature )
5880 if not candidate_ids :
5981 return None
6082 if len (candidate_ids ) != 1 :
6183 return None
6284
6385 candidate_id = next (iter (candidate_ids ))
64- _agent_tool_run_results_by_call_id .pop (call_id , None )
86+ _agent_tool_run_results_by_signature .pop (signature , None )
87+ _agent_tool_run_result_signature_by_obj .pop (candidate_id , None )
6588 return _agent_tool_run_results_by_obj .pop (candidate_id , None )
6689
6790
@@ -74,11 +97,8 @@ def peek_agent_tool_run_result(
7497 if run_result is not None :
7598 return run_result
7699
77- call_id = tool_call .call_id
78- if not call_id :
79- return None
80-
81- candidate_ids = _agent_tool_run_results_by_call_id .get (call_id )
100+ signature = _tool_call_signature (tool_call )
101+ candidate_ids = _agent_tool_run_results_by_signature .get (signature )
82102 if not candidate_ids :
83103 return None
84104 if len (candidate_ids ) != 1 :
@@ -93,18 +113,17 @@ def drop_agent_tool_run_result(tool_call: ResponseFunctionToolCall) -> None:
93113 obj_id = id (tool_call )
94114 run_result = _agent_tool_run_results_by_obj .pop (obj_id , None )
95115 if run_result is not None :
96- _drop_agent_tool_run_result (tool_call . call_id , obj_id )
116+ _drop_agent_tool_run_result (obj_id )
97117 return
98118
99- call_id = tool_call .call_id
100- if not call_id :
101- return
102- candidate_ids = _agent_tool_run_results_by_call_id .get (call_id )
119+ signature = _tool_call_signature (tool_call )
120+ candidate_ids = _agent_tool_run_results_by_signature .get (signature )
103121 if not candidate_ids :
104122 return
105123 if len (candidate_ids ) != 1 :
106124 return
107125
108126 candidate_id = next (iter (candidate_ids ))
109- _agent_tool_run_results_by_call_id .pop (call_id , None )
127+ _agent_tool_run_results_by_signature .pop (signature , None )
128+ _agent_tool_run_result_signature_by_obj .pop (candidate_id , None )
110129 _agent_tool_run_results_by_obj .pop (candidate_id , None )
0 commit comments