Description
Session.fork copies all messages and remaps messageID and parentID via an idMap, but does not remap tail_start_id inside CompactionPart parts.
Root cause
src/session/session.ts:596–602 — the part spread includes the raw (old) tail_start_id:
for (const part of msg.parts) {
yield* updatePart({
...part, // spread includes un-remapped tail_start_id
id: PartID.ascending(),
messageID: cloned.id,
sessionID: session.id,
})
}
filterCompacted (src/session/message-v2.ts:1072) relies on tail_start_id:
retain = part.tail_start_id // ← old message ID, never remapped
Forked session has new message IDs → msg.info.id === retain never matches → break never hit → all pre‑summary messages unfiltered.
Impact
Forked session context inflates massively (~300k → ~800k tokens observed per API-Usage response).
Fix
Remap tail_start_id in the fork loop via idMap, analogous to parentID (lines 588–593).
Plugins
no
OpenCode version
fresh clone
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Description
Session.fork copies all messages and remaps
messageIDandparentIDvia anidMap, but does not remaptail_start_idinside CompactionPart parts.Root cause
src/session/session.ts:596–602 — the part spread includes the raw (old)
tail_start_id:filterCompacted(src/session/message-v2.ts:1072) relies ontail_start_id:retain = part.tail_start_id // ← old message ID, never remappedForked session has new message IDs → msg.info.id === retain never matches → break never hit → all pre‑summary messages unfiltered.
Impact
Forked session context inflates massively (~300k → ~800k tokens observed per API-Usage response).
Fix
Remap
tail_start_idin the fork loop via idMap, analogous to parentID (lines 588–593).Plugins
no
OpenCode version
fresh clone
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response