(ctx context.Context, tcID string, isSafe bool)
| 376 | e.mu.Lock() |
| 377 | slot := e.slots[tcID] |
| 378 | if slot == nil || slot.State != ToolStateQueued { |
| 379 | e.mu.Unlock() |
| 380 | return |
| 381 | } |
| 382 | isSafe := e.isSafeLocked(slot.TC) |
| 383 | slot.State = ToolStateExecuting |
| 384 | ctx, cancel := context.WithCancel(e.cancelCtx) |
| 385 | slot.cancel = cancel |
| 386 | if !isSafe { |
| 387 | e.nonSafeRunning++ |
| 388 | } |
| 389 | e.mu.Unlock() |
| 390 | go e.executeOne(ctx, tcID, isSafe) |
| 391 | } |
| 392 | |
| 393 | func (e *StreamingToolExecutor) executeOne(ctx context.Context, tcID string, isSafe bool) { |
| 394 | defer func() { |
| 395 | if recovered := recover(); recovered != nil { |
| 396 | e.finishResult( |
| 397 | tcID, |
| 398 | fmt.Sprintf("<tool_use_error>\nTool execution panic: %v\n</tool_use_error>", recovered), |
| 399 | fmt.Sprintf("<tool_use_error>\nTool execution panic: %v\n%s\n</tool_use_error>", recovered, string(debug.Stack())), |
| 400 | true, |
| 401 | ) |
| 402 | } |
| 403 | e.mu.Lock() |
| 404 | slot := e.slots[tcID] |
| 405 | if slot != nil { |
| 406 | if slot.State != ToolStateAborted { |
| 407 | slot.State = ToolStateCompleted |
| 408 | } |
| 409 | close(slot.done) |
| 410 | } |
| 411 | if !isSafe { |
| 412 | e.nonSafeRunning-- |
| 413 | } |
| 414 | e.mu.Unlock() |
| 415 | e.maybeDrain() |
| 416 | e.signalActivity() |
| 417 | }() |
| 418 | |
| 419 | e.mu.Lock() |
| 420 | slot := e.slots[tcID] |
| 421 | if slot == nil { |
| 422 | e.mu.Unlock() |
| 423 | return |
| 424 | } |
| 425 | tc := slot.TC |
| 426 | abort := slot.abort |
| 427 | e.mu.Unlock() |
| 428 | |
| 429 | if e.Cancelled() || abortSignalled(abort) { |
| 430 | e.finishCancelled(tcID, "Execution cancelled — a prior write tool failed.") |
| 431 | return |
| 432 | } |
| 433 | execCtx := e.executionContextForSlot(abort) |
| 434 | |
| 435 | if e.State != nil { |
no test coverage detected