diff --git a/internal/channels/events.go b/internal/channels/events.go index b261423f..f791ee1c 100644 --- a/internal/channels/events.go +++ b/internal/channels/events.go @@ -35,8 +35,11 @@ func (m *Manager) HandleAgentEvent(eventType, runID string, payload any) { ctx = store.WithTenantID(ctx, ta.TenantID()) } - // Forward to StreamingChannel - if sc, ok := ch.(StreamingChannel); ok { + // Forward to StreamingChannel (only when streaming is enabled for this run). + // Without this gate, channels that implement StreamingChannel but have streaming + // disabled (e.g. group_stream=false) would create stream messages AND emit + // block.reply outbound messages, causing duplicate delivery. + if sc, ok := ch.(StreamingChannel); ok && rc.Streaming { switch eventType { case protocol.AgentEventRunStarted: stream, err := sc.CreateStream(ctx, rc.ChatID, true)