@@ -25,18 +25,6 @@ type toolExecResult struct {
2525 isErr bool
2626}
2727
28- // classifyToolCalls splits tool calls into concurrent (read-only) and sequential (write) batches.
29- func classifyToolCalls (calls []types.ToolCall ) (concurrent , sequential []types.ToolCall ) {
30- for _ , tc := range calls {
31- if tool .IsReadOnly (tc .Name ) {
32- concurrent = append (concurrent , tc )
33- } else {
34- sequential = append (sequential , tc )
35- }
36- }
37- return
38- }
39-
4028// filePathArgKeys is the list of argument names that are conventionally
4129// file paths. Tools with non-standard names silently fall through and
4230// extractTargets returns an empty list. For a more robust extraction, see
@@ -203,6 +191,7 @@ func (s *Session) executeToolCalls(ctx context.Context, toolCalls []types.ToolCa
203191 readOnlySem := make (chan struct {}, maxConcurrentReadOnlyToolCalls )
204192 networkSem := make (chan struct {}, maxConcurrentNetworkReadOnlyToolCalls )
205193 var wg sync.WaitGroup
194+ var mu sync.Mutex
206195
207196 for _ , item := range concurrentCalls {
208197 wg .Add (1 )
@@ -214,13 +203,17 @@ func (s *Session) executeToolCalls(ctx context.Context, toolCalls []types.ToolCa
214203 networkSem <- struct {}{}
215204 defer func () { <- networkSem }()
216205 }
206+ mu .Lock ()
217207 results [item .index ] = s .executeSingleTool (ctx , item .tc , ch , turnCount , intentText )
208+ mu .Unlock ()
218209 }(item )
219210 }
220211 wg .Wait ()
221212
222213 for _ , item := range sequentialCalls {
214+ mu .Lock ()
223215 results [item .index ] = s .executeSingleTool (ctx , item .tc , ch , turnCount , intentText )
216+ mu .Unlock ()
224217 }
225218
226219 return results
0 commit comments