mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(agent): resolve race conditions and resource leaks in SubTurn
Critical fixes (5): - Fix turnState hierarchy corruption in nested SubTurns by checking context before creating new root turnState in runAgentLoop - Fix deadlock risk in deliverSubTurnResult by separating lock and channel ops - Fix session rollback race in HardAbort by calling Finish() before rollback - Fix resource leak by closing pendingResults channel in Finish() with recovery - Add thread-safety docs for childTurnIDs and isFinished fields Medium priority fixes (5): - Move globalTurnCounter to AgentLoop.subTurnCounter to prevent ID conflicts - Improve semaphore acquisition to ensure release even on early validation failures - Document design choice: ephemeral sessions start empty for complete isolation - Add final poll before Finish() to capture late-arriving SubTurn results - Remove duplicate channel registration in spawnSubTurn to fix timing issues Testing: - Add 6 new tests covering hierarchy, deadlock, ordering, channel lifecycle, final poll, and semaphore behavior - All 12 SubTurn tests passing with race detector This resolves 10 critical and medium issues (5 race conditions, 2 resource leaks, 3 timing issues) identified in code review, bringing SubTurn to production-ready state.
This commit is contained in:
@@ -1043,6 +1043,20 @@ func (al *AgentLoop) runAgentLoop(
|
||||
return "", err
|
||||
}
|
||||
|
||||
// IMPORTANT: Before finishing the turn, do a final poll for any pending SubTurn results.
|
||||
// This ensures we don't lose results that arrived after the last iteration poll.
|
||||
if isRootTurn {
|
||||
finalResults := al.dequeuePendingSubTurnResults(opts.SessionKey)
|
||||
if len(finalResults) > 0 {
|
||||
// Inject late-arriving results into the final response
|
||||
for _, result := range finalResults {
|
||||
if result != nil && result.ForLLM != "" {
|
||||
finalContent += fmt.Sprintf("\n\n[SubTurn Result] %s", result.ForLLM)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal completion to rootTS so it knows it is finished, terminating any active sub-turns.
|
||||
// Only call Finish() if this is a root turn (not a SubTurn recursively calling runAgentLoop).
|
||||
if isRootTurn {
|
||||
|
||||
Reference in New Issue
Block a user