refactor: simplify session log representation
This commit is contained in:
@@ -259,8 +259,8 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
const svc = createTestService()
|
||||
const session = toolTurnSession(1)
|
||||
const nodes = session.surface.nodes // [user, asst(tool-call), result]
|
||||
const userSeq = nodes[0]!.seq
|
||||
const resultSeq = nodes[2]!.seq
|
||||
const userSeq = nodes[0]!
|
||||
const resultSeq = nodes[2]!
|
||||
// start = the tool/result: its issuing assistant precedes it IN THE SAME STEP,
|
||||
// so starting here would orphan that assistant's tool-call. end is fine (user).
|
||||
await expect(compactRegion(svc, session, resultSeq, resultSeq, 'm'))
|
||||
@@ -272,8 +272,8 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
const svc = createTestService()
|
||||
const session = toolTurnSession(1)
|
||||
const nodes = session.surface.nodes
|
||||
const userSeq = nodes[0]!.seq
|
||||
const asstSeq = nodes[1]!.seq
|
||||
const userSeq = nodes[0]!
|
||||
const asstSeq = nodes[1]!
|
||||
// end = the assistant/message: its tool/result follows IN THE SAME STEP, so
|
||||
// ending here would strand that result. start is fine (the pre-step user).
|
||||
await expect(compactRegion(svc, session, userSeq, asstSeq, 'm'))
|
||||
@@ -291,8 +291,8 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
content: [{ type: 'tool-call', id: CallId('c1'), name: 'bash', arguments: '{}' }],
|
||||
}, { surfaceOp: 'append' })
|
||||
const nodes = s.surface.nodes // [user, asst]
|
||||
const userSeq = nodes[0]!.seq
|
||||
const asstSeq = nodes[1]!.seq
|
||||
const userSeq = nodes[0]!
|
||||
const asstSeq = nodes[1]!
|
||||
await expect(compactRegion(svc, s, userSeq, asstSeq, 'm'))
|
||||
.rejects.toThrow(/end seq .* is not a balanced boundary/)
|
||||
})
|
||||
@@ -301,8 +301,8 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
const svc = createTestService()
|
||||
const session = toolTurnSession(2)
|
||||
const nodes = session.surface.nodes // [user1, asst1, res1, user2, asst2, res2]
|
||||
const startSeq = nodes[0]!.seq // pre-step user1 (free boundary)
|
||||
const endSeq = nodes[2]!.seq // res1 = last node of turn 1's closed step
|
||||
const startSeq = nodes[0]! // pre-step user1 (free boundary)
|
||||
const endSeq = nodes[2]! // res1 = last node of turn 1's closed step
|
||||
const result = await compactRegion(svc, session, startSeq, endSeq, 'm')
|
||||
expect(result.shadowedRange).toEqual({ start: startSeq, end: endSeq })
|
||||
expectNoOrphanToolResults(session.deriveMessages())
|
||||
@@ -312,7 +312,7 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
const svc = createTestService()
|
||||
const session = toolTurnSession(1)
|
||||
const nodes = session.surface.nodes
|
||||
const userSeq = nodes[0]!.seq // pre-step user: free boundary both ways
|
||||
const userSeq = nodes[0]! // pre-step user: free boundary both ways
|
||||
const result = await compactRegion(svc, session, userSeq, userSeq, 'm')
|
||||
expect(result.shadowedRange).toEqual({ start: userSeq, end: userSeq })
|
||||
})
|
||||
@@ -327,7 +327,7 @@ describe('BasicCompactService step-alignment (never split a tool-call/result pai
|
||||
s.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
const nodes = s.surface.nodes
|
||||
const ctxSeq = nodes[0]!.seq
|
||||
const ctxSeq = nodes[0]!
|
||||
const result = await compactRegion(svc, s, ctxSeq, ctxSeq, 'm')
|
||||
expect(result.shadowedRange).toEqual({ start: ctxSeq, end: ctxSeq })
|
||||
})
|
||||
@@ -386,8 +386,8 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const nodes = session.surface.nodes
|
||||
expect(nodes.length).toBe(6)
|
||||
|
||||
const firstSeq = nodes[0]!.seq
|
||||
const secondSeq = nodes[1]!.seq
|
||||
const firstSeq = nodes[0]!
|
||||
const secondSeq = nodes[1]!
|
||||
const result = await compactRegion(svc, session, firstSeq, secondSeq, 'test-model')
|
||||
|
||||
expect(result.shadowedSeqs).toEqual([firstSeq, secondSeq])
|
||||
@@ -427,7 +427,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
// Surface now has: summary user/message + retained 4 nodes = 5 nodes.
|
||||
const newNodes = session.surface.nodes
|
||||
expect(newNodes.length).toBe(5)
|
||||
expect(newNodes[0]!.seq).toBe(userMsg.seq)
|
||||
expect(newNodes[0]!).toBe(userMsg.seq)
|
||||
|
||||
// deriveMessages() produces the framed summary as a user-role message:
|
||||
// a checkpoint preamble + tag-wrapped summary blocks.
|
||||
@@ -452,7 +452,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const svc = createTestService()
|
||||
const session = multiTurnSession(2, 1)
|
||||
const nodes = session.surface.nodes
|
||||
await expect(compactRegion(svc, session, nodes[1]!.seq, nodes[0]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[1]!, nodes[0]!, 'm'))
|
||||
.rejects.toThrow(/is after end seq .* on the surface/)
|
||||
})
|
||||
|
||||
@@ -461,7 +461,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const session = multiTurnSession(2, 1)
|
||||
const nodes = session.surface.nodes
|
||||
session.append('compact/start', { turn: 2 })
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow(/compaction already in progress/)
|
||||
})
|
||||
|
||||
@@ -471,7 +471,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const session = multiTurnSession(2, 1)
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow('model unavailable')
|
||||
|
||||
const endEvent = session.events.findLast(e => e.type === 'compact/end')
|
||||
@@ -494,7 +494,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const session = multiTurnSession(1, 2)
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
await compactRegion(svc, session, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, session, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
|
||||
expect(svc.summarizeCalls.length).toBe(1)
|
||||
const { text, model } = svc.summarizeCalls[0]!
|
||||
@@ -509,7 +509,7 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const session = multiTurnSession(3, 1)
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
const result = await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm')
|
||||
const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm')
|
||||
|
||||
// Provenance (compact/summary) carries the RAW, unframed summary.
|
||||
expect(result.summary).toEqual([{ type: 'text', text: 'STRUCTURED SUMMARY' }])
|
||||
@@ -529,8 +529,8 @@ describe('BasicCompactService.compactRegion', () => {
|
||||
const session = sessionWithTools()
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
const firstSeq = nodes[0]!.seq
|
||||
const lastSeq = nodes[nodes.length - 1]!.seq
|
||||
const firstSeq = nodes[0]!
|
||||
const lastSeq = nodes[nodes.length - 1]!
|
||||
await compactRegion(svc, session, firstSeq, lastSeq, 'm')
|
||||
|
||||
expect(svc.summarizeCalls.length).toBe(1)
|
||||
@@ -601,7 +601,7 @@ describe('BasicCompactService.compactIfNeeded', () => {
|
||||
expect(result).not.toBeNull()
|
||||
const nodes = session.surface.nodes
|
||||
expect(result!.shadowedSeqs.length).toBeGreaterThan(0)
|
||||
expect(result!.shadowedSeqs).not.toContain(nodes[nodes.length - 1]!.seq)
|
||||
expect(result!.shadowedSeqs).not.toContain(nodes[nodes.length - 1]!)
|
||||
})
|
||||
|
||||
it('returns null when the whole surface fits the retain budget (over threshold by role/system overhead)', async () => {
|
||||
@@ -653,7 +653,7 @@ describe('BasicCompactService.compactIfNeeded', () => {
|
||||
// The most-recent step's tool result is retained verbatim (still on surface).
|
||||
const lastResultSeq = s.events.findLast(e => e.type === 'tool/result')!.seq
|
||||
expect(result!.shadowedSeqs).not.toContain(lastResultSeq)
|
||||
expect(s.surface.nodes.some(n => n.seq === lastResultSeq)).toBe(true)
|
||||
expect(s.surface.nodes).toContain(lastResultSeq)
|
||||
// No orphaned tool-result survives (whole-step boundaries respected).
|
||||
expectNoOrphanToolResults(s.deriveMessages())
|
||||
})
|
||||
@@ -677,7 +677,7 @@ describe('BasicCompactService.compactIfNeeded', () => {
|
||||
const first = await compactIfNeeded(svc, s, '', 'm', SIGNAL)
|
||||
expect(first).not.toBeNull()
|
||||
// The summary node now heads the surface with a fresh high seq.
|
||||
const summaryHeadSeq = s.surface.nodes[0]!.seq
|
||||
const summaryHeadSeq = s.surface.nodes[0]!
|
||||
const turn5StartSeq = s.events.filter(e => e.type === 'turn/start').at(-1)!.seq
|
||||
expect(summaryHeadSeq).toBeGreaterThan(turn5StartSeq)
|
||||
|
||||
@@ -745,7 +745,7 @@ describe('BasicCompactService replay equivalence', () => {
|
||||
const session = multiTurnSession(3, 1)
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm')
|
||||
await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm')
|
||||
const derived = session.deriveMessages()
|
||||
|
||||
const replayed = new Session(SessionId('replay'), [...session.events])
|
||||
@@ -761,7 +761,7 @@ describe('BasicCompactService blocking (compaction in progress)', () => {
|
||||
const nodes = session.surface.nodes
|
||||
// Whole step (user → assistant) is a step-aligned region, so the call reaches
|
||||
// the in-progress check rather than being rejected for splitting a step.
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow(/compaction already in progress/)
|
||||
})
|
||||
|
||||
@@ -771,7 +771,7 @@ describe('BasicCompactService blocking (compaction in progress)', () => {
|
||||
const nodes = session.surface.nodes
|
||||
session.append('compact/start', { turn: 1 })
|
||||
session.append('compact/end', { turn: 1 })
|
||||
const result = await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm')
|
||||
const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm')
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
|
||||
@@ -794,7 +794,7 @@ describe('BasicCompactService blocking (compaction in progress)', () => {
|
||||
const nodes = s.surface.nodes
|
||||
|
||||
// The stale start is before the turn/end, so it is NOT seen as in-progress.
|
||||
const result = await compactRegion(svc, s, nodes[0]!.seq, nodes[1]!.seq, 'm')
|
||||
const result = await compactRegion(svc, s, nodes[0]!, nodes[1]!, 'm')
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
})
|
||||
@@ -1112,7 +1112,7 @@ describe('BasicCompactService.summarize (real ctx.llm.stream)', () => {
|
||||
const before = [...session.surface.nodes]
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'test-model'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model'))
|
||||
.rejects.toMatchObject({ code: 'MAX_TOKENS' })
|
||||
|
||||
// No replacement landed — the surface is byte-identical, and the lock was
|
||||
@@ -1129,7 +1129,7 @@ describe('BasicCompactService.summarize (real ctx.llm.stream)', () => {
|
||||
const session = multiTurnSession(2, 1)
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
const result = await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'test-model')
|
||||
const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model')
|
||||
expect(result.summary).toEqual([{ type: 'text', text: 'CONDENSED' }])
|
||||
// The raw summary is wrapped in the checkpoint framing on the surface.
|
||||
expect(session.deriveMessages()[0]!.content).toContainEqual({ type: 'text', text: 'CONDENSED' })
|
||||
@@ -1141,7 +1141,7 @@ describe('BasicCompactService.summarize (real ctx.llm.stream)', () => {
|
||||
const nodes = session.surface.nodes
|
||||
svc.mockSummary = Array.from({ length: 20 }, (_, index) => ({ type: 'text', text: `large ${index}` }))
|
||||
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow(/summary is not smaller than the shadowed content/)
|
||||
expect(session.events.some(e => e.type === 'compact/summary')).toBe(false)
|
||||
})
|
||||
@@ -1160,7 +1160,7 @@ describe('BasicCompactService.summarize (real ctx.llm.stream)', () => {
|
||||
const before = [...session.surface.nodes]
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow(/summary is not smaller than the shadowed content/)
|
||||
expect(session.events.some(e => e.type === 'compact/summary')).toBe(false)
|
||||
expect(session.surface.nodes).toEqual(before)
|
||||
@@ -1321,7 +1321,7 @@ describe('BasicCompactService transcript rendering (delegated to dsh-compact)',
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const nodes = s.surface.nodes
|
||||
await compactRegion(svc, s, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, s, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
|
||||
const { text } = svc.summarizeCalls[0]!
|
||||
expect(text).toContain('[Context: project context here]')
|
||||
@@ -1350,7 +1350,7 @@ describe('BasicCompactService transcript rendering (delegated to dsh-compact)',
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const nodes = s.surface.nodes
|
||||
await compactRegion(svc, s, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, s, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
expect(svc.summarizeCalls[0]!.text).toContain('Tool error (call c9): boom failure')
|
||||
})
|
||||
})
|
||||
@@ -1384,7 +1384,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const nodes = s.surface.nodes
|
||||
await compactRegion(svc, s, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, s, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
const { text } = svc.summarizeCalls[0]!
|
||||
expect(text).toContain('[tool-result: [chart]]') // nested tool-result with content
|
||||
expect(text).toContain('[custom-widget]') // unknown block placeholder
|
||||
@@ -1432,7 +1432,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
s.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
|
||||
const nodes = s.surface.nodes
|
||||
|
||||
await expect(compactRegion(svc, s, nodes[0]!.seq, nodes[1]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, s, nodes[0]!, nodes[1]!, 'm'))
|
||||
.rejects.toThrow(/no open turn/)
|
||||
// The lock was never acquired — no compact/start landed.
|
||||
expect(s.events.some(e => e.type === 'compact/start')).toBe(false)
|
||||
@@ -1447,7 +1447,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
s.append('user/message', { content: [{ type: 'text', text: 'orphan' }], source: { kind: 'user' } }, { surfaceOp: 'append' })
|
||||
const nodes = s.surface.nodes
|
||||
|
||||
await expect(compactRegion(svc, s, nodes[0]!.seq, nodes[0]!.seq, 'm'))
|
||||
await expect(compactRegion(svc, s, nodes[0]!, nodes[0]!, 'm'))
|
||||
.rejects.toThrow(/no open turn/)
|
||||
expect(s.events.some(e => e.type === 'compact/start')).toBe(false)
|
||||
})
|
||||
@@ -1464,7 +1464,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
const svc = createTestService()
|
||||
const session = multiTurnSession(1, 1)
|
||||
const nodes = session.surface.nodes
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, 9999, 'm'))
|
||||
await expect(compactRegion(svc, session, nodes[0]!, 9999, 'm'))
|
||||
.rejects.toThrow(/end seq 9999 not found in surface/)
|
||||
})
|
||||
|
||||
@@ -1476,7 +1476,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
const nodes = session.surface.nodes
|
||||
|
||||
// Whole step (user → assistant): a step-aligned region that reaches summarize.
|
||||
await expect(compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'm')).rejects.toBe('plain string failure')
|
||||
await expect(compactRegion(svc, session, nodes[0]!, nodes[1]!, 'm')).rejects.toBe('plain string failure')
|
||||
const endEvent = session.events.findLast(e => e.type === 'compact/end')!
|
||||
expect(endEvent.data).toMatchObject({ error: 'plain string failure' })
|
||||
})
|
||||
@@ -1542,7 +1542,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const nodes = s.surface.nodes
|
||||
await compactRegion(svc, s, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, s, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
// Every empty-content message (user text, empty reasoning, empty-content
|
||||
// tool/result, empty context, empty steering) extracted to nothing and was
|
||||
// skipped — the only surviving line is the assistant's tool-call (which a
|
||||
@@ -1580,7 +1580,7 @@ describe('BasicCompactService edge cases', () => {
|
||||
s.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const nodes = s.surface.nodes
|
||||
await compactRegion(svc, s, nodes[0]!.seq, nodes[nodes.length - 1]!.seq, 'm')
|
||||
await compactRegion(svc, s, nodes[0]!, nodes[nodes.length - 1]!, 'm')
|
||||
const { text } = svc.summarizeCalls[0]!
|
||||
// Every non-text block surfaces as a placeholder rather than being dropped.
|
||||
expect(text).toContain('User: [chart]')
|
||||
@@ -1604,32 +1604,32 @@ describe('BasicCompactService positional range (surface seqs are not monotonic a
|
||||
|
||||
// First compaction: shadow the two oldest surface nodes.
|
||||
const nodes0 = session.surface.nodes
|
||||
const first = await compactRegion(svc, session, nodes0[0]!.seq, nodes0[1]!.seq, 'm')
|
||||
const first = await compactRegion(svc, session, nodes0[0]!, nodes0[1]!, 'm')
|
||||
|
||||
// The summary node now sits at the head with a seq HIGHER than the
|
||||
// retained older nodes that follow it — the non-monotonic surface. (The
|
||||
// head is the user/message replace node, appended after the compact/summary
|
||||
// provenance event, so its seq is at least first.summarySeq.)
|
||||
const nodes1 = session.surface.nodes
|
||||
expect(nodes1[0]!.seq).toBeGreaterThanOrEqual(first.summarySeq)
|
||||
expect(nodes1[0]!.seq).toBeGreaterThan(nodes1[1]!.seq)
|
||||
expect(nodes1[0]!).toBeGreaterThanOrEqual(first.summarySeq)
|
||||
expect(nodes1[0]!).toBeGreaterThan(nodes1[1]!)
|
||||
|
||||
// Second compaction: shadow [summary(head) … turn-2's step end]. The start
|
||||
// seq (the head summary node) is GREATER than the end seq (an older retained
|
||||
// node), so the range is a SURFACE-POSITION span, not a numeric seq interval.
|
||||
// The end must land on a step boundary (turn-2's assistant message closes
|
||||
// its step).
|
||||
const startSeq = nodes1[0]!.seq
|
||||
const endSeq = nodes1[2]!.seq
|
||||
const startSeq = nodes1[0]!
|
||||
const endSeq = nodes1[2]!
|
||||
expect(startSeq).toBeGreaterThan(endSeq)
|
||||
const second = await compactRegion(svc, session, startSeq, endSeq, 'm')
|
||||
|
||||
// Exactly the three nodes at surface positions [0..2] are shadowed, in
|
||||
// surface order — the positional slice, regardless of their seq values.
|
||||
expect(second.shadowedSeqs).toEqual([nodes1[0]!.seq, nodes1[1]!.seq, nodes1[2]!.seq])
|
||||
expect(second.shadowedSeqs).toEqual([nodes1[0]!, nodes1[1]!, nodes1[2]!])
|
||||
// The surface still derives cleanly: a new head replace node + the rest.
|
||||
const finalNodes = session.surface.nodes
|
||||
expect(finalNodes[0]!.seq).toBeGreaterThanOrEqual(second.summarySeq)
|
||||
expect(finalNodes[0]!).toBeGreaterThanOrEqual(second.summarySeq)
|
||||
expect(session.deriveMessages().length).toBe(finalNodes.length)
|
||||
})
|
||||
|
||||
@@ -1640,14 +1640,14 @@ describe('BasicCompactService positional range (surface seqs are not monotonic a
|
||||
// First compaction shadows the oldest two surface nodes, landing a high-seq
|
||||
// summary node at the head.
|
||||
const n0 = session.surface.nodes
|
||||
await compactRegion(svc, session, n0[0]!.seq, n0[1]!.seq, 'm')
|
||||
await compactRegion(svc, session, n0[0]!, n0[1]!, 'm')
|
||||
|
||||
// Second compaction spans [head summary … turn-2's step end]. The head's seq
|
||||
// is higher than the older retained nodes' seqs, so a log-seq-order walk
|
||||
// would emit the older messages BEFORE the checkpoint.
|
||||
const n1 = session.surface.nodes
|
||||
svc.summarizeCalls = []
|
||||
await compactRegion(svc, session, n1[0]!.seq, n1[2]!.seq, 'm')
|
||||
await compactRegion(svc, session, n1[0]!, n1[2]!, 'm')
|
||||
|
||||
// The extracted transcript follows surface order: the checkpoint (head)
|
||||
// first, then the older retained messages — matching deriveMessages().
|
||||
@@ -1679,7 +1679,7 @@ describe('BasicCompactService llm inject (real plugin-load path)', () => {
|
||||
const svc = ctx.compact as BasicCompactService
|
||||
const session = multiTurnSession(2, 1)
|
||||
const nodes = session.surface.nodes
|
||||
const result = await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'test-model')
|
||||
const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model')
|
||||
expect(result.summary).toEqual([{ type: 'text', text: 'CONDENSED' }])
|
||||
|
||||
// Tear the fiber down so this test owns no leaked registration; the
|
||||
@@ -1727,9 +1727,9 @@ describe('BasicCompactService under the real invariants plugin', () => {
|
||||
|
||||
const nodes = session.surface.nodes
|
||||
// No invariant throws here: compact/* + the replacement are all in turn 3.
|
||||
const result = await compactRegion(svc, session, nodes[0]!.seq, nodes[1]!.seq, 'test-model')
|
||||
const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model')
|
||||
expect(result.shadowedSeqs.length).toBe(2)
|
||||
expect(session.surface.nodes[0]!.seq).toBeGreaterThan(session.surface.nodes[1]!.seq)
|
||||
expect(session.surface.nodes[0]!).toBeGreaterThan(session.surface.nodes[1]!)
|
||||
})
|
||||
|
||||
it('accepts a second compaction over the non-monotonic surface left by the first', async () => {
|
||||
@@ -1740,14 +1740,14 @@ describe('BasicCompactService under the real invariants plugin', () => {
|
||||
session.append('turn/start', { turn: 4, trigger: { kind: 'message', source: { kind: 'user' } } })
|
||||
|
||||
const n0 = session.surface.nodes
|
||||
await compactRegion(svc, session, n0[0]!.seq, n0[1]!.seq, 'test-model')
|
||||
await compactRegion(svc, session, n0[0]!, n0[1]!, 'test-model')
|
||||
|
||||
// Surface head now carries a higher seq than the older retained nodes. A
|
||||
// second compaction spanning [head … a later closed-step end] must pass the
|
||||
// invariants' positional replace check even though startSeq > endSeq.
|
||||
const n1 = session.surface.nodes
|
||||
expect(n1[0]!.seq).toBeGreaterThan(n1[2]!.seq)
|
||||
const second = await compactRegion(svc, session, n1[0]!.seq, n1[2]!.seq, 'test-model')
|
||||
expect(second.shadowedSeqs).toEqual([n1[0]!.seq, n1[1]!.seq, n1[2]!.seq])
|
||||
expect(n1[0]!).toBeGreaterThan(n1[2]!)
|
||||
const second = await compactRegion(svc, session, n1[0]!, n1[2]!, 'test-model')
|
||||
expect(second.shadowedSeqs).toEqual([n1[0]!, n1[1]!, n1[2]!])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user