This commit is contained in:
João Salavisa
2026-02-05 22:37:29 +00:00
committed by GitHub
parent 93e3759c5f
commit b0fe1a8a59
2 changed files with 57 additions and 5 deletions
@@ -1351,11 +1351,17 @@ func (m *Manager) handleAgentEvent(execution *AgentExecution, event agentctl.Age
zap.Bool("is_error", isError))
// Flush the message buffer to publish any remaining content as a streaming message.
// All adapters now handle duplicate prevention at the adapter layer:
// - They send text via message_chunk events (which accumulate in the buffer)
// - They send complete events WITHOUT text
// So we just flush the buffer here - no need to track streamingUsedThisTurn.
m.flushMessageBuffer(execution)
// If the buffer never triggered streaming (no newlines), we emit the text on the
// complete event so the orchestrator can persist the final message.
flushedText := m.flushMessageBuffer(execution)
if flushedText != "" {
event.Text = flushedText
if m.historyManager != nil && execution.SessionID != "" {
if err := m.historyManager.AppendAgentMessage(execution.SessionID, flushedText); err != nil {
m.logger.Warn("failed to store final agent message to history", zap.Error(err))
}
}
}
m.logger.Info("complete event processed",
zap.String("execution_id", execution.ID),
@@ -839,6 +839,52 @@ func TestHandleAgentEvent_CompleteWithoutStreaming(t *testing.T) {
}
}
// TestHandleAgentEvent_CompleteWithBufferedText verifies that buffered text
// without streaming is emitted on complete for persistence.
func TestHandleAgentEvent_CompleteWithBufferedText(t *testing.T) {
mgr, eventBus := createTestManagerWithTracking()
execution := createTestExecution("exec-1", "task-1", "session-1")
mgr.executionStore.Add(execution)
// Buffer text without newlines (no streaming event should be emitted)
mgr.handleAgentEvent(execution, agentctl.AgentEvent{
Type: "message_chunk",
Text: "Final message without newline",
})
// Complete event should flush buffer into complete text
mgr.handleAgentEvent(execution, agentctl.AgentEvent{
Type: "complete",
})
events := eventBus.getStreamEvents()
var completeEvents []AgentStreamEventPayload
var streamingEvents []AgentStreamEventPayload
for _, e := range events {
if e.Data != nil {
switch e.Data.Type {
case "complete":
completeEvents = append(completeEvents, e)
case "message_streaming":
streamingEvents = append(streamingEvents, e)
}
}
}
if len(completeEvents) != 1 {
t.Errorf("expected 1 complete event, got %d", len(completeEvents))
}
if len(completeEvents) > 0 && completeEvents[0].Data.Text != "Final message without newline" {
t.Errorf("expected complete event to carry buffered text, got %q", completeEvents[0].Data.Text)
}
if len(streamingEvents) != 0 {
t.Errorf("expected 0 message_streaming events when no newlines, got %d", len(streamingEvents))
}
}
// TestHandleAgentEvent_CompleteThenMessageChunk tests the scenario where
// message_chunk arrives after complete. This documents the behavior when
// an adapter incorrectly sends text after the turn has completed.