{"record":{"id":"ae59e62b678aebeb","repo":"can1357/oh-my-pi","slug":"v2-compaction-stream-closed-before-response-comple","errorCode":null,"errorMessage":"V2 compaction stream closed before response.completed","messagePattern":"V2 compaction stream closed before response\\.completed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/compaction/compaction-v2-streaming.ts","lineNumber":529,"sourceCode":"\t\t\t\tdataLines.push(buffer.slice(\"data:\".length).trimStart());\n\t\t\t} else if (buffer.startsWith(\"event:\")) {\n\t\t\t\teventName = buffer.slice(\"event:\".length).trim();\n\t\t\t}\n\t\t}\n\t\tdispatch();\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\n\treturn finishCompactionV2Collection(state, request);\n}\n\nfunction finishCompactionV2Collection(\n\tstate: CompactionV2CollectionState,\n\trequest: CompactionV2Request,\n): CompactionV2Response {\n\tif (!state.sawCompleted) {\n\t\tthrow new Error(\"V2 compaction stream closed before response.completed\");\n\t}\n\tif (state.compactionItems.length !== 1) {\n\t\tthrow new Error(\n\t\t\t`V2 compaction expected exactly one compaction output item, got ${state.compactionItems.length} from ${state.outputItemCount} output items`,\n\t\t);\n\t}\n\n\tconst compactionItem = state.compactionItems[0];\n\tconst { replacementHistory, retainedImageCount } = buildCompactionV2ReplacementHistory(\n\t\trequest.input,\n\t\tcompactionItem,\n\t\trequest.retainedMessageBudget,\n\t);\n\treturn {\n\t\tcompactionItem,\n\t\treplacementHistory,\n\t\tusedTokens: state.usage?.inputTokens ?? 0,\n\t\tusage: state.usage,","sourceCodeStart":511,"sourceCodeEnd":547,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/agent/src/compaction/compaction-v2-streaming.ts#L511-L547","documentation":"The SSE stream from the V2 compaction endpoint terminated without ever delivering a response.completed event (state.sawCompleted false), so the collected data cannot be trusted as a finished compaction. This guards against accepting partial results from a truncated or dropped connection.","triggerScenarios":"Connection drops mid-stream, server closes the SSE connection after an error without response.failed, a proxy/load-balancer times out the long-running stream, or [DONE] arrives before any response.completed event.","commonSituations":"Long compaction requests crossing proxy idle timeouts (e.g. 60s gateways); network interruptions on mobile/VPN; Azure OpenAI closing streams under load; misconfigured reverse proxy buffering/killing SSE.","solutions":["Retry the compaction — requestCompactionV2Streaming's retry logic (retryWait option) is designed for transient stream drops","Increase proxy/gateway idle timeouts for the compaction endpoint to exceed expected compaction duration","Disable response buffering on intermediaries (e.g. proxy_buffering off for nginx) so SSE events flow","Check server logs/status for early connection termination; if persistent, fall back to local compaction"],"exampleFix":"// before\nawait requestCompactionV2Streaming({ model, ... }); // stream drops behind 60s proxy timeout\n// after\nawait requestCompactionV2Streaming({ model, retryWait: (ms) => Bun.sleep(ms), ... });\n// plus: nginx: proxy_read_timeout 600s; proxy_buffering off;","handlingStrategy":"retry","validationCode":"// keep intermediary timeouts longer than worst-case compaction\n// e.g. nginx: proxy_read_timeout 600s; proxy_buffering off;","typeGuard":null,"tryCatchPattern":"try {\n  return await requestCompactionV2Streaming({ model, ... });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"closed before response.completed\")) {\n    await Bun.sleep(backoff);\n    return requestCompactionV2Streaming({ model, ... }); // transient drop: retry\n  }\n  throw err;\n}","preventionTips":["Configure proxies/LBs with idle timeouts exceeding compaction duration and SSE buffering disabled","Use requestCompactionV2Streaming's retryWait for automatic retries on stream drops","Fall back to local compaction after repeated truncations"],"tags":["streaming","sse","network","compaction","truncated-response"],"backgroundTag":"stream-truncated","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}