From d861e41d31e4cf5c7b44b8be11a9109bf2709ae7 Mon Sep 17 00:00:00 2001 From: Ollie Agent Date: Sun, 9 Aug 2026 11:48:29 +0200 Subject: [PATCH] fix: chat stream closes when stripMarkers produces empty output When a streaming chunk contains only markers/fences, stripMarkers returns empty bytes. The 9P server interprets a zero-length Rread as EOF, closing the client's FD. Fix: loop in streamAgentChatText, advancing the offset past marker-only chunks until real content arrives. --- fs/handlers_agent.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/handlers_agent.go b/fs/handlers_agent.go index 2bbcfbd..17377b8 100644 --- a/fs/handlers_agent.go +++ b/fs/handlers_agent.go @@ -125,11 +125,18 @@ func streamAgentChat(ctx HandlerCtx, cctx context.Context, base string) ([]byte, func streamAgentChatText(ctx HandlerCtx, cctx context.Context, base string) ([]byte, string, error) { merged, cancel := mergeCtx(ctx, cctx) defer cancel() - data, nextBase, err := streamChat(ctx.AgentLog, merged, base) - if err != nil || len(data) == 0 { - return data, nextBase, err + for { + data, nextBase, err := streamChat(ctx.AgentLog, merged, base) + if err != nil || len(data) == 0 { + return data, nextBase, err + } + stripped := stripMarkers(data) + if len(stripped) > 0 { + return stripped, nextBase, nil + } + // All data was markers/fences — advance base and wait for more. + base = nextBase } - return stripMarkers(data), nextBase, nil } // stripMarkers removes [[[...]]] marker lines and source fence lines from raw