| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
Sorry, something went wrong.
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate Found:
This PR appears to address the same issue—avoiding full history hydration after compaction. Both PRs focus on optimizing memory usage by limiting what gets hydrated from prompt history during session compaction iterations. You should verify whether PR #31638 is already merged or if it needs to be reconciled with the current PR #39930. |
Sorry, something went wrong.
|
Addressed the follow-up comments:
|
Sorry, something went wrong.
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Sorry, something went wrong.
|
Validated this fix against two real production sessions (Windows, opencode 1.18.13). The two-phase walk works exactly as proposed — here's the measured impact and one edge case worth deciding on: Measured impact (replicated the walk against the live DBs)
Both sessions currently hydrate all parts on every prompt (stream() → filterCompactedEffect), which is the observed multi-second block + RSS spike. The row-walk + boundary-stop cuts that to <1,300 parts per prompt. One edge case to decide: empty compaction marker behaviorBoth sessions carry a compaction part with tail_start_id: null (empty marker, 0-char text — they're compaction-managed by a plugin, not opencode's native compaction). In the new walk: if (!compaction.tail_start_id) break pages // ← stops the walk HEREThis is a behavior change from the old path: filterCompacted(stream(...)) with a null tail_start_id returned the full history (tailIndex = -1 → return result), whereas the new walk breaks at the marker and truncates the hydrated set to messages newer than it. For the two sessions above that means ~7,800 / ~7,900 older messages become unavailable to the model even though they previously fit (up to the context window). The PR description states "incomplete compactions … unchanged" — this path changes them. Options:
Also worth noting: the null-marker case in old code already skipped compaction reordering (returned everything), so either choice is defensible — but the "incomplete compactions unchanged" claim in the description only holds with the continue variant. Otherwise the implementation is clean: messageRows shares the pagination core with page(), the boundary detection correctly keys on completed user messages, and the batched hydrate (rows.slice(index, index + size)) keeps the fix's memory bounded. LGTM. |
Sorry, something went wrong.
|
@Qiiks Addressed in commit 4ff112ab19.
Verification:
The package-wide bun test run was also attempted but could not complete because of unrelated environment failures: missing zod resolution in plugin tests and a v2 PTY test timeout. |
Sorry, something went wrong.
|
Corrected the follow-up in 69d3227b52 after re-checking native compaction semantics. tail_start_id is intentionally absent when a completed compaction summarizes the full history (SessionCompaction.select returns no tail when keep.start === 0). Treating every missing tail as incomplete made the row walk hydrate history older than a valid completed compaction, defeating the bounded-hydration change and potentially reintroducing context overflow. The update now:
Verification: 162 passed, 2 skipped across the targeted session tests; bun typecheck passed; repository pre-push typecheck passed. Known persisted-data limitation: a plugin marker paired with a completed-looking summary but no tail is indistinguishable from a valid native full-summary compaction, so it follows native completed-compaction semantics. |
Sorry, something went wrong.
…malyco#39930) Compaction previously materialized every message of a session through the full stream; now only the newest messages are hydrated. Reduces a 609-message session from 11.4MB to 0.8MB of allocations on compaction.
- pin note, seam-lookup range, and deferred-port re-verification now reference v1.18.23 (post-split packages/ai|util tree still absent, anomalyco#43769 stays blocked) - watch-list gains the 2026-08-26 sweep candidates (anomalyco#39930, anomalyco#38939, anomalyco#41950, anomalyco#33713, anomalyco#44631) - fork-build.sh BASE lookup now excludes *-lowmem.* tags: after a fresh upstream merge the previous fork tag ties the new base tag on commit distance with a newer date and git describe stamps the OLD base
Upstream PR anomalyco#39930 by @brauliobo, ported onto current dev. Finds the compaction boundary from lightweight message rows first, then hydrates only the retained messages, so oversized parts on the boundary page are never hydrated. Supersedes upstream PR anomalyco#31638 by @ualtinok, which this branch previously carried. The two are competing rewrites of the same function and conflict. Verified 2026-08-28: anomalyco#31638's full pagination test file passes against this implementation, while this PR's boundary-hydration test fails against anomalyco#31638's. Co-authored-by: Braulio Oliveira <brauliobo@gmail.com>
Carries five third-party upstream PRs, one commit each, with original authorship and Co-authored-by trailers preserved: anomalyco#32203 @ualtinok stabilize duplicate skill discovery anomalyco#31859 @ualtinok reject bootstrap client reentry anomalyco#19961 @ualtinok fire system transform before messages transform anomalyco#39930 @brauliobo bound compacted history hydration anomalyco#31867 @ChangedenCZD improve deepseek prompt cache reuse Reconciles anomalyco#19961's hook reordering with the fork's sparse-context and instruction-audience handling: sparse still branches before skills/MCP are built, and modelMsgs is computed after messages.transform so plugin mutations are picked up.
Freshly persisted messages now read Date.now() once, mint the ascending message ID from that value, and persist the same value as time.created. The captured inversion was msg_04b012001003... at time_created 1787964760065 appearing after msg_04b012001001... at 1787964760066 despite the later ID. The divergence predates upstream PR anomalyco#39930; that PR's test merely observes it. Deriving time.created from the ID was rejected because legacy rows already contain independently stored timestamps, so new derived timestamps regress ordering against those rows. Fixed fresh sites in session/prompt.ts, session/compaction.ts, tool/message.ts, session/interrupt.ts, tool/plan.ts, cli/cmd/debug/agent.handler.ts, and the fresh prompt calls in tool/task.ts and cli/cmd/github.handler.ts. Runtime queue IDs are local UI identities and are marked so the transport does not persist them. session/session.ts fork cloning remains copied history, session/message-v2.ts and cli/cmd/run/runtime.ts remain ephemeral, and project-copy.ts was considered and excluded because its LLM request message is ephemeral and never persisted.
| Back | FazBrowse Home | New Git URL |
Issue for this PR
Closes #35570
Type of change
What does this PR do?
filterCompactedEffect currently hydrates every message part before discarding history older than the latest completed compaction. This change finds that boundary from lightweight message rows first, then hydrates only the retained messages in batches. Retained tails, incomplete compactions, forks, and the existing stream behavior are unchanged.
On one compacted session this reduced the hydrated window from 609 messages / 11.4 MB of parts to 51 messages / 0.81 MB.
Related to #31638. That PR scans already-hydrated pages; this implementation avoids hydrating oversized parts on the boundary page by separating row discovery from part hydration, as proposed in #35570.
How did you verify your code works?
Screenshots / recordings
N/A - backend memory fix.
Checklist