1111- Thread-safe with bounded workers
1212"""
1313
14- import asyncio
1514import concurrent .futures
1615import logging
17- from typing import Any , Callable , Dict , List , Optional , Protocol , Union
16+ from typing import Any , Callable , Dict , List , Optional , Protocol
1817from dataclasses import dataclass
19- from threading import BoundedSemaphore
18+ from .. trace . context_events import copy_context_to_callable
2019
2120logger = logging .getLogger (__name__ )
2221
@@ -34,6 +33,7 @@ class ToolCall:
3433class ToolResult :
3534 """Result of executing a single tool call."""
3635 function_name : str
36+ arguments : Dict [str , Any ]
3737 result : Any
3838 tool_call_id : str
3939 is_ollama : bool
@@ -85,6 +85,7 @@ def execute_batch(
8585 )
8686 results .append (ToolResult (
8787 function_name = tool_call .function_name ,
88+ arguments = tool_call .arguments ,
8889 result = result ,
8990 tool_call_id = tool_call .tool_call_id ,
9091 is_ollama = tool_call .is_ollama
@@ -93,6 +94,7 @@ def execute_batch(
9394 logger .error (f"Tool execution error for { tool_call .function_name } : { e } " )
9495 results .append (ToolResult (
9596 function_name = tool_call .function_name ,
97+ arguments = tool_call .arguments ,
9698 result = f"Error executing tool: { e } " ,
9799 tool_call_id = tool_call .tool_call_id ,
98100 is_ollama = tool_call .is_ollama ,
@@ -120,7 +122,6 @@ def __init__(self, max_workers: int = 5):
120122 max_workers: Maximum concurrent tool executions (default 5)
121123 """
122124 self .max_workers = max_workers
123- self ._semaphore = BoundedSemaphore (max_workers )
124125
125126 def execute_batch (
126127 self ,
@@ -138,34 +139,35 @@ def execute_batch(
138139
139140 def _execute_single_tool (tool_call : ToolCall ) -> ToolResult :
140141 """Execute a single tool call with error handling."""
141- with self ._semaphore : # Respect max_workers bound
142- try :
143- result = execute_tool_fn (
144- tool_call .function_name ,
145- tool_call .arguments ,
146- tool_call .tool_call_id
147- )
148- return ToolResult (
149- function_name = tool_call .function_name ,
150- result = result ,
151- tool_call_id = tool_call .tool_call_id ,
152- is_ollama = tool_call .is_ollama
153- )
154- except Exception as e :
155- logger .error (f"Tool execution error for { tool_call .function_name } : { e } " )
156- return ToolResult (
157- function_name = tool_call .function_name ,
158- result = f"Error executing tool: { e } " ,
159- tool_call_id = tool_call .tool_call_id ,
160- is_ollama = tool_call .is_ollama ,
161- error = e
162- )
142+ try :
143+ result = execute_tool_fn (
144+ tool_call .function_name ,
145+ tool_call .arguments ,
146+ tool_call .tool_call_id
147+ )
148+ return ToolResult (
149+ function_name = tool_call .function_name ,
150+ arguments = tool_call .arguments ,
151+ result = result ,
152+ tool_call_id = tool_call .tool_call_id ,
153+ is_ollama = tool_call .is_ollama
154+ )
155+ except Exception as e :
156+ logger .error (f"Tool execution error for { tool_call .function_name } : { e } " )
157+ return ToolResult (
158+ function_name = tool_call .function_name ,
159+ arguments = tool_call .arguments ,
160+ result = f"Error executing tool: { e } " ,
161+ tool_call_id = tool_call .tool_call_id ,
162+ is_ollama = tool_call .is_ollama ,
163+ error = e
164+ )
163165
164166 # Use ThreadPoolExecutor for sync tools
165167 with concurrent .futures .ThreadPoolExecutor (max_workers = self .max_workers ) as executor :
166168 # Submit all tool calls
167169 future_to_index = {
168- executor .submit (_execute_single_tool , tool_call ): i
170+ executor .submit (copy_context_to_callable ( _execute_single_tool ) , tool_call ): i
169171 for i , tool_call in enumerate (tool_calls )
170172 }
171173
@@ -192,4 +194,4 @@ def create_tool_call_executor(parallel: bool = False, max_workers: int = 5) -> T
192194 if parallel :
193195 return ParallelToolCallExecutor (max_workers = max_workers )
194196 else :
195- return SequentialToolCallExecutor ()
197+ return SequentialToolCallExecutor ()
0 commit comments