Skip to content

Commit d71b827

Browse files
fix(session): remap compaction tail_start_id when forking (#24898)
Co-authored-by: spark4862 <spark4862@users.noreply.github.com> Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
1 parent 504ca3d commit d71b827

2 files changed

Lines changed: 75 additions & 2 deletions

File tree

packages/opencode/src/session/session.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,12 +616,16 @@ export const layer: Layer.Layer<Service, never, Bus.Service | Storage.Service> =
616616
})
617617

618618
for (const part of msg.parts) {
619-
yield* updatePart({
619+
const p: MessageV2.Part = {
620620
...part,
621621
id: PartID.ascending(),
622622
messageID: cloned.id,
623623
sessionID: session.id,
624-
})
624+
}
625+
if (p.type === "compaction" && p.tail_start_id) {
626+
p.tail_start_id = idMap.get(p.tail_start_id)
627+
}
628+
yield* updatePart(p)
625629
}
626630
}
627631
return session

packages/opencode/test/session/messages-pagination.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ const svc = {
2929
updatePart<T extends MessageV2.Part>(part: T) {
3030
return run(SessionNs.Service.use((svc) => svc.updatePart(part)))
3131
},
32+
fork(input: { sessionID: SessionID; messageID?: MessageID }) {
33+
return run(SessionNs.Service.use((svc) => svc.fork(input)))
34+
},
3235
}
3336

3437
async function fill(sessionID: SessionID, count: number, time = (i: number) => Date.now() + i) {
@@ -837,6 +840,72 @@ describe("MessageV2.filterCompacted", () => {
837840
})
838841
})
839842

843+
test("fork remaps compaction tail_start_id for filterCompacted", async () => {
844+
await Instance.provide({
845+
directory: root,
846+
fn: async () => {
847+
const session = await svc.create({})
848+
849+
const u1 = await addUser(session.id, "first")
850+
const a1 = await addAssistant(session.id, u1, { finish: "end_turn" })
851+
await svc.updatePart({
852+
id: PartID.ascending(),
853+
sessionID: session.id,
854+
messageID: a1,
855+
type: "text",
856+
text: "first reply",
857+
})
858+
859+
const u2 = await addUser(session.id, "second")
860+
const a2 = await addAssistant(session.id, u2, { finish: "end_turn" })
861+
await svc.updatePart({
862+
id: PartID.ascending(),
863+
sessionID: session.id,
864+
messageID: a2,
865+
type: "text",
866+
text: "second reply",
867+
})
868+
869+
const c1 = await addUser(session.id)
870+
await addCompactionPart(session.id, c1, u2)
871+
const s1 = await addAssistant(session.id, c1, { summary: true, finish: "end_turn" })
872+
await svc.updatePart({
873+
id: PartID.ascending(),
874+
sessionID: session.id,
875+
messageID: s1,
876+
type: "text",
877+
text: "summary",
878+
})
879+
880+
const u3 = await addUser(session.id, "third")
881+
const a3 = await addAssistant(session.id, u3, { finish: "end_turn" })
882+
await svc.updatePart({
883+
id: PartID.ascending(),
884+
sessionID: session.id,
885+
messageID: a3,
886+
type: "text",
887+
text: "third reply",
888+
})
889+
890+
const parentFiltered = MessageV2.filterCompacted(MessageV2.stream(session.id))
891+
expect(parentFiltered.map((item) => item.info.id)).toEqual([u2, a2, c1, s1, u3, a3])
892+
893+
const forked = await svc.fork({ sessionID: session.id })
894+
const childFiltered = MessageV2.filterCompacted(MessageV2.stream(forked.id))
895+
expect(childFiltered).toHaveLength(parentFiltered.length)
896+
897+
const tailPart = childFiltered.flatMap((m) => m.parts).find((p) => p.type === "compaction")
898+
expect(tailPart?.type).toBe("compaction")
899+
if (!tailPart || tailPart.type !== "compaction") throw new Error("Expected forked compaction part")
900+
expect(tailPart.tail_start_id).toBeDefined()
901+
expect(childFiltered.some((m) => m.info.id === tailPart.tail_start_id)).toBe(true)
902+
903+
await svc.remove(forked.id)
904+
await svc.remove(session.id)
905+
},
906+
})
907+
})
908+
840909
test("retains an assistant tail when compaction starts inside a turn", async () => {
841910
await Instance.provide({
842911
directory: root,

0 commit comments

Comments
 (0)