Restore CompactionResult diagnostics

This commit is contained in:
Tianyi Cui
2026-07-15 17:23:39 +08:00
parent c2081d8abf
commit d25a56b431
5 changed files with 29 additions and 7 deletions

View File

@@ -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,

View File

@@ -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.

View File

@@ -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,

View File

@@ -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

View File

@@ -34,17 +34,22 @@ class StubCompactService extends CompactService {
): Promise<CompactionResult> {
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'])