fix(agent): defer run-loop publish to after all steering continuations

Before this fix the Run loop published the initial response immediately,
before draining queued steering messages. This caused two outbound
messages when a late steering message arrived (initial + continued),
whereas upstream only ever emits one final message.

Additionally, the handleReasoning goroutine was launched with turnCtx,
which is canceled by defer turnCancel() as soon as runTurn returns.
Removal of the eager-save block at the end of runTurn made it return
faster, exposing a pre-existing race where the goroutine checked
ctx.Err() and returned without publishing. Fixed by using the
longer-lived parent ctx.

Both issues were caught by the two new tests added in the previous
commit (TestOnDelivered_* and TestContinueResponse_*).
This commit is contained in:
Dmitrii Balabanov 2026-03-31 17:12:57 +03:00
parent 6ea3ce6aa0
commit 9880cb343b

View file

@ -574,11 +574,12 @@ func (al *AgentLoop) Run(ctx context.Context) error {
return
}
if response.Content != "" {
al.publishAgentResponseIfNeeded(ctx, response, target.Channel, target.ChatID)
}
// Accumulate the final response before publishing so that a
// steering continuation can supersede the initial reply.
// We publish exactly once at the end (matching upstream behavior).
finalResponse := response
prevContent := response.Content
for al.pendingSteeringCountForScope(target.SessionKey) > 0 {
logger.InfoCF("agent", "Continuing queued steering after turn end",
map[string]any{
@ -607,7 +608,7 @@ func (al *AgentLoop) Run(ctx context.Context) error {
if continued.Content == "" {
return
}
al.publishAgentResponseIfNeeded(ctx, continued, target.Channel, target.ChatID)
finalResponse = continued
prevContent = continued.Content
}
@ -641,9 +642,13 @@ func (al *AgentLoop) Run(ctx context.Context) error {
if continued.Content == "" {
break
}
al.publishAgentResponseIfNeeded(ctx, continued, target.Channel, target.ChatID)
finalResponse = continued
prevContent = continued.Content
}
if finalResponse.Content != "" {
al.publishAgentResponseIfNeeded(ctx, finalResponse, target.Channel, target.ChatID)
}
}()
}
}