agent: drain FIFO after interrupted/failed turns

Fix holes where queued prompts were orphaned:
- After turn loop exits (interrupt, toolsrv unavailable), drain remaining FIFO items
- On panic recovery, pop next FIFO item and re-submit in a new goroutine
- fifo file write triggers Submit when agent is idle
This commit is contained in:
Levi Neely 2026-08-13 11:59:11 +02:00
parent e662d32c61
commit 1ac50d97e1
2 changed files with 25 additions and 0 deletions

View File

@ -30,6 +30,11 @@ func (ag *Agent) Submit(ctx context.Context, input string) {
}
ag.SetState("idle")
ag.emit(Event{Role: "error", Content: fmt.Sprintf("%v", r)})
// Re-submit next FIFO item in a new goroutine so queued
// prompts aren't orphaned by the panic.
if next, ok := ag.fifo.Pop(); ok {
go ag.Submit(ctx, next)
}
}
}()
ag.log.Debug("Agent.Submit() input_len=%d running=%v", len(input), ag.IsRunning())
@ -63,6 +68,17 @@ func (ag *Agent) Submit(ctx context.Context, input string) {
for input != "" && ctx.Err() == nil {
input = ag.executeTurn(ctx, input)
}
// Drain any remaining FIFO items (covers cases where executeTurn
// returned "" early: interrupt, toolsrv unavailable, etc.).
for ctx.Err() == nil {
next, ok := ag.fifo.Pop()
if !ok {
break
}
for next != "" && ctx.Err() == nil {
next = ag.executeTurn(ctx, next)
}
}
}
// executeTurn runs a single agent turn and returns the next prompt to execute,

View File

@ -373,6 +373,15 @@ func buildAgentChildren(a *agent.Agent, s *session.Session) []virtfs.FsNodeDecl
return nil
}
a.Queue(input)
// If the agent is idle, trigger processing.
if !a.IsRunning() {
go func() {
if next, ok := a.PopQueue(); ok {
a.Submit(s.Ctx, next)
a.EnsureTrailingNewline()
}
}()
}
return nil
}),
virtfs.Read(func() ([]byte, error) {