From d25a56b431d98a6df3ff242df6386975acce05d4 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 15 Jul 2026 17:23:39 +0800 Subject: [PATCH] Restore CompactionResult diagnostics --- packages/compact/compact-basic/src/index.ts | 6 +++++- .../compact-basic/tests/compact-basic.spec.ts | 4 +++- packages/compact/compact/src/index.ts | 2 +- packages/compact/compact/src/types.ts | 8 ++++++++ packages/compact/compact/tests/compact.spec.ts | 16 ++++++++++++---- 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/compact/compact-basic/src/index.ts b/packages/compact/compact-basic/src/index.ts index 9449fc84f9..8bc21ddf5b 100644 --- a/packages/compact/compact-basic/src/index.ts +++ b/packages/compact/compact-basic/src/index.ts @@ -426,9 +426,13 @@ export class BasicCompactService extends CompactService { // compact/start and here leaves a detectable orphaned lock (a compact/start // with no matching compact/end) rather than a compact/end that falsely // claims compaction finished before the surface replacement landed. - session.append('compact/end', { turn: openTurn }) + const endEvent = session.append('compact/end', { turn: openTurn }) return { + startSeq: startEvent.seq, + summarySeq: summaryEvent.seq, + endSeq: endEvent.seq, + summary, shadowedRange: { start, end }, shadowedSeqs, shadowedTokenCount, diff --git a/packages/compact/compact-basic/tests/compact-basic.spec.ts b/packages/compact/compact-basic/tests/compact-basic.spec.ts index 7cb872f274..4b06b321b7 100644 --- a/packages/compact/compact-basic/tests/compact-basic.spec.ts +++ b/packages/compact/compact-basic/tests/compact-basic.spec.ts @@ -346,6 +346,7 @@ describe('BasicCompactService.compactRegion', () => { expect(result.shadowedSeqs).toEqual([firstSeq, secondSeq]) expect(result.shadowedRange.start).toBe(firstSeq) expect(result.shadowedRange.end).toBe(secondSeq) + expect(result.summary).toEqual(svc.mockSummary) expect(result.shadowedTokenCount).toBe(20) const events = session.events @@ -1057,7 +1058,8 @@ describe('BasicCompactService.summarize (real ctx.llm.stream)', () => { const session = multiTurnSession(2, 1) const nodes = session.surface.nodes - await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model') + const result = await compactRegion(svc, session, nodes[0]!, nodes[1]!, 'test-model') + expect(result.summary).toEqual([{ type: 'text', text: 'CONDENSED' }]) const summaryEvent = session.events.findLast(e => e.type === 'compact/summary')! expect(summaryEvent.data.summary).toEqual([{ type: 'text', text: 'CONDENSED' }]) // The raw summary is wrapped in the checkpoint framing on the surface. diff --git a/packages/compact/compact/src/index.ts b/packages/compact/compact/src/index.ts index e4baec6551..680f684ac6 100644 --- a/packages/compact/compact/src/index.ts +++ b/packages/compact/compact/src/index.ts @@ -73,7 +73,7 @@ export abstract class CompactService extends Service { * @param agent - context whose session is mutated and whose routing options guide summarization. * @param signal - optional cancellation; model-backed implementations must forward it. * @throws when compaction is active or the range is missing, reversed, or unbalanced. - * @returns the replaced range and token accounting; the durable event owns the summary. + * @returns the appended event seqs, summary, replaced range, and token accounting. */ abstract compactRegion( start: number, diff --git a/packages/compact/compact/src/types.ts b/packages/compact/compact/src/types.ts index 0d3d35ace8..10a5eabfcc 100644 --- a/packages/compact/compact/src/types.ts +++ b/packages/compact/compact/src/types.ts @@ -41,6 +41,14 @@ declare module '@deepseek-ai/dsh-session' { /** Result of a successful compaction operation. */ export interface CompactionResult { + /** The seq of the appended `compact/start` event. */ + startSeq: number + /** The seq of the appended `compact/summary` event. */ + summarySeq: number + /** The seq of the appended `compact/end` event. */ + endSeq: number + /** The summary content blocks produced by the backend. */ + summary: ContentBlock[] /** * The surface-boundary pair that was shadowed: the seqs of the first * (`start`) and last (`end`) surface nodes of the replaced range. A diff --git a/packages/compact/compact/tests/compact.spec.ts b/packages/compact/compact/tests/compact.spec.ts index e34c8420d9..3d95c12249 100644 --- a/packages/compact/compact/tests/compact.spec.ts +++ b/packages/compact/compact/tests/compact.spec.ts @@ -34,17 +34,22 @@ class StubCompactService extends CompactService { ): Promise { this.lastSignal = signal const session = agent.session + const summary = [{ type: 'text' as const, text: 'stub' }] // Minimal stub honoring the lock + log-only event contract. - session.append('compact/start', { turn: 0 }) - session.append('compact/summary', { - summary: [{ type: 'text', text: 'stub' }], + const startEvent = session.append('compact/start', { turn: 0 }) + const summaryEvent = session.append('compact/summary', { + summary, shadowedRange: { start, end }, shadowedSeqs: [], shadowedTokenCount: 0, model: 'stub', }) - session.append('compact/end', { turn: 0 }) + const endEvent = session.append('compact/end', { turn: 0 }) return { + startSeq: startEvent.seq, + summarySeq: summaryEvent.seq, + endSeq: endEvent.seq, + summary, shadowedRange: { start, end }, shadowedSeqs: [], shadowedTokenCount: 0, @@ -92,6 +97,9 @@ describe('CompactService seam', () => { // verify the runtime value is absent. const raw = startEvent as unknown as { surfaceOp?: unknown } expect(raw.surfaceOp).toBeUndefined() + expect(result.summary).toEqual([{ type: 'text', text: 'stub' }]) + expect(result.summarySeq).toBeGreaterThan(result.startSeq) + expect(result.endSeq).toBeGreaterThan(result.summarySeq) expect(result.shadowedRange).toEqual({ start: 0, end: 0 }) expect(session.events.filter(e => e.type.startsWith('compact/')).map(e => e.type)) .toEqual(['compact/start', 'compact/summary', 'compact/end'])