From 34a1540c18a4985ebb79a728e8d806ebe4578a6d Mon Sep 17 00:00:00 2001 From: yatul Date: Tue, 25 Aug 2026 22:03:41 +0400 Subject: [PATCH] fix(teams): stream teammate runs so long generations keep the connection alive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handleTeammateMessage pinned Stream: false, so every team member run — coder, reviewer, researcher — made a non-streamed provider call. On a slow reasoning model that means a silent connection for the whole generation, and ResponseHeaderTimeout eventually kills it: iter 0 think: llm call: litellm: request failed: Post ".../v1/chat/completions": http2: timeout awaiting response headers Observed on a member asked to write a large single-file page: 15 minutes, zero output tokens, run failed. The same model over the same provider is fine on an ordinary channel run, which streams by default. Streaming here is for connection liveness, not delivery. A teammate run is never registered with the channel manager, so HandleAgentEvent returns on its first line and the chunks are dropped; nothing reaches a user incrementally. The task result is unchanged — it still comes from the final RunResult, since ChatStream returns the complete response once the stream ends. Co-Authored-By: Claude Opus 5 --- cmd/gateway_consumer_handlers.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/gateway_consumer_handlers.go b/cmd/gateway_consumer_handlers.go index cb80c848..b68a5f1d 100644 --- a/cmd/gateway_consumer_handlers.go +++ b/cmd/gateway_consumer_handlers.go @@ -276,7 +276,17 @@ func handleTeammateMessage( SenderID: teammateSenderID, // real user who triggered the teammate dispatch (#915) Role: teammateRole, // RBAC role for admin bypass during teammate turn (#915) RunID: fmt.Sprintf("teammate-%s-%s", msg.Metadata[tools.MetaFromAgent], msg.Metadata[tools.MetaToAgent]), - Stream: false, + // Streamed for connection liveness, not for delivery. A teammate run is + // never registered with the channel manager, so HandleAgentEvent drops its + // chunks on the first line and nothing is delivered incrementally; the task + // result still comes from the final RunResult. What streaming buys is the + // response headers arriving immediately: a non-streamed request to a slow + // reasoning model holds a silent connection for the whole generation, and + // ResponseHeaderTimeout kills it — observed as + // `http2: timeout awaiting response headers` on a member asked to produce a + // large file, while the same model over the same provider was fine on a + // streamed channel run. + Stream: true, TeamTaskID: msg.Metadata[tools.MetaTeamTaskID], TeamWorkspace: msg.Metadata[tools.MetaTeamWorkspace], LeaderAgentID: msg.Metadata[tools.MetaLeaderAgentID],