Avoid bun memory leak bug from TransformStream#4255
Avoid bun memory leak bug from TransformStream#4255TheodoreSpeaks wants to merge 4 commits intostagingfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@BugBot review |
PR SummaryMedium Risk Overview Adds a new Reviewed by Cursor Bugbot for commit c6272d9. Bugbot is set up for automated code reviews on this repo. Configure here. |
Previously, if the onStream consumer caught an internal error without re-throwing, the block-executor would treat the shortened accumulator as the complete response, persist a truncated string to memory via appendToMemory, and set it as executionOutput.content. Track whether the source ReadableStream actually closed (done=true) in the pull handler. If onStream returns before the source drains, skip content persistence and log a warning — the old tee()-based flow was immune to this because the executor branch drained independently of the client branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@BugBot review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit bf2f9af. Configure here.
Greptile SummaryThis PR fixes a Bun runtime memory leak (oven-sh/bun#28035) caused by Confidence Score: 5/5Safe to merge; the fix correctly avoids the Bun TransformStream memory leak and all remaining findings are P2 style suggestions. The core logic is sound: the pull-based approach eliminates the TransformStream, backpressure is correctly propagated, and edge cases (stream error, early consumer exit, empty content) are all guarded. The only finding is a minor inconsistency where onFullContent is called even when fullContent is empty, which is handled defensively by the agent handler today. apps/sim/executor/execution/block-executor.ts — minor onFullContent guard inconsistency at line 718. Important Files Changed
Sequence DiagramsequenceDiagram
participant AH as AgentHandler
participant BE as BlockExecutor
participant CS as clientSource (ReadableStream)
participant PC as processedClientStream
participant OS as onStream consumer
AH->>BE: StreamingExecution { stream, execution, onFullContent }
BE->>CS: Create pull-based ReadableStream (reads from sourceReader, accumulates chunks)
BE->>PC: streamingResponseFormatProcessor.processStream(clientSource)
BE->>OS: ctx.onStream({ stream: processedClientStream, execution })
loop For each chunk
OS->>PC: read chunk
PC->>CS: pull
CS->>CS: sourceReader.read() → decode → accumulated.push()
CS-->>PC: enqueue(value)
PC-->>OS: chunk
end
OS-->>BE: stream fully drained (sourceFullyDrained = true)
BE->>BE: executionOutput.content = accumulated.join('')
BE->>AH: onFullContent(fullContent)
AH->>AH: memoryService.appendToMemory(ctx, inputs, { role: 'assistant', content })
Reviews (1): Last reviewed commit: "fix lint" | Re-trigger Greptile |
| if (streamingExec.onFullContent) { | ||
| try { | ||
| await streamingExec.onFullContent(fullContent) | ||
| } catch (error) { | ||
| this.execLogger.error('onFullContent callback failed', { blockId, error }) | ||
| } | ||
| } |
There was a problem hiding this comment.
onFullContent called unconditionally with empty string
onFullContent is invoked regardless of whether fullContent is empty, while the preceding block that sets executionOutput.content is guarded by if (fullContent). The current agent handler defensively checks !content.trim(), but any future onFullContent implementor might not, leading to spurious empty-content persistence calls.
| if (streamingExec.onFullContent) { | |
| try { | |
| await streamingExec.onFullContent(fullContent) | |
| } catch (error) { | |
| this.execLogger.error('onFullContent callback failed', { blockId, error }) | |
| } | |
| } | |
| if (streamingExec.onFullContent && fullContent) { | |
| try { | |
| await streamingExec.onFullContent(fullContent) | |
| } catch (error) { | |
| this.execLogger.error('onFullContent callback failed', { blockId, error }) | |
| } | |
| } |
…ntent symmetric Previously, executionOutput.content was guarded by `if (fullContent)` but `onFullContent` fired regardless. The agent-handler implementor defensively bails on empty/whitespace content, but that's a callee contract, not enforced at the call site — future implementors could spuriously persist empty assistant turns to memory. Hoist the `!fullContent` check to a single early return, so both the output write and the callback share the same precondition. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Bun has a bug in TransformStream: oven-sh/bun#28035 causing high memory consumption due to no backpressure signal. We use this in
Type of Change
Testing
Checklist
Screenshots/Videos