2026-07-30 17:40:25 +08:00
import { describe , expect , it } from 'vitest'
2026-08-10 22:04:06 +08:00
import { Context } from '@deepseek-ai/cordis'
import Loader from '@deepseek-ai/cordis-plugin-loader'
2026-07-30 17:40:25 +08:00
import type { Agent } from '@deepseek-ai/dsh-agent'
2026-08-13 00:36:22 +08:00
import CommandRuntime , { type CommandResult } from '@deepseek-ai/dsh-commands'
2026-07-30 17:40:25 +08:00
import {
2026-08-09 15:48:56 +08:00
CompactionId ,
2026-08-13 00:36:22 +08:00
CompactionEngine ,
2026-07-30 17:40:25 +08:00
ManualCompactionError ,
2026-08-13 00:36:22 +08:00
type CompactionAgentContext ,
2026-07-30 17:40:25 +08:00
type CompactionResult ,
type CompactionTrigger ,
type ManualCompactAgentContext ,
2026-08-13 00:36:22 +08:00
} from '@deepseek-ai/dsh-compaction'
2026-07-30 17:40:25 +08:00
import { Session , SessionId } from '@deepseek-ai/dsh-session'
import * as commandCompact from '@deepseek-ai/dsh-command-compact'
2026-08-09 15:48:56 +08:00
const COMPACTION_ID = CompactionId ( 'command-compact-test' )
2026-07-30 17:40:25 +08:00
const RESULT : CompactionResult = {
2026-08-09 15:48:56 +08:00
compactionId : COMPACTION_ID ,
2026-08-08 14:11:17 +08:00
startSeq : 1 ,
summarySeq : 2 ,
endSeq : 3 ,
2026-07-30 17:40:25 +08:00
summary : [ { type : 'text' , text : 'summary' } ] ,
shadowedRange : { start : 1 , end : 7 } ,
shadowedSeqs : [ 1 , 3 , 7 ] ,
shadowedTokenCount : 42 ,
}
2026-08-13 00:36:22 +08:00
class StubCompactionEngine extends CompactionEngine {
2026-07-30 17:40:25 +08:00
result : CompactionResult | null = RESULT
failure : unknown
operation : ( ( ) = > Promise < CompactionResult | null > ) | undefined
calls : { agent : ManualCompactAgentContext ; signal : AbortSignal } [ ] = [ ]
override compactIfNeeded (
2026-08-13 00:36:22 +08:00
_agent : CompactionAgentContext ,
2026-07-30 17:40:25 +08:00
_trigger : CompactionTrigger ,
_signal : AbortSignal ,
) : Promise < CompactionResult | null > {
return Promise . resolve ( null )
}
override compactRegion ( ) : Promise < CompactionResult > {
return Promise . resolve ( RESULT )
}
override compactNow (
agent : ManualCompactAgentContext ,
signal : AbortSignal ,
2026-08-13 00:36:22 +08:00
sourceCommandId? : Parameters < CompactionEngine [ 'compactNow' ] > [ 2 ] ,
2026-07-30 17:40:25 +08:00
) : Promise < CompactionResult | null > {
this . calls . push ( { agent , signal } )
if ( this . operation !== undefined ) return this . operation ( )
return this . failure === undefined
2026-08-09 15:48:56 +08:00
? Promise . resolve ( this . result === null ? null : this . appendResult ( agent , this . result , sourceCommandId ) )
2026-07-30 17:40:25 +08:00
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercise arbitrary backend rejection values.
: Promise . reject ( this . failure )
}
2026-08-08 14:11:17 +08:00
2026-08-09 15:48:56 +08:00
private appendResult (
agent : ManualCompactAgentContext ,
result : CompactionResult ,
2026-08-13 00:36:22 +08:00
sourceCommandId : Parameters < CompactionEngine [ 'compactNow' ] > [ 2 ] ,
2026-08-09 15:48:56 +08:00
) : CompactionResult {
const provenance = {
compactionId : result.compactionId ,
. . . sourceCommandId === undefined ? { } : { sourceCommandId } ,
}
2026-08-13 00:36:22 +08:00
agent . session . append ( 'compaction/start' , { . . . provenance , turn : null } )
agent . session . append ( 'compaction/summary' , {
2026-08-09 15:48:56 +08:00
. . . provenance ,
2026-08-08 14:11:17 +08:00
summary : result.summary ,
shadowedRange : result.shadowedRange ,
shadowedSeqs : result.shadowedSeqs ,
shadowedTokenCount : result.shadowedTokenCount ,
provider : 'command-test' ,
model : 'command-test' ,
} )
2026-08-13 00:36:22 +08:00
agent . session . append ( 'compaction/end' , { . . . provenance , turn : null } )
2026-08-09 15:48:56 +08:00
return { . . . result , . . . provenance }
2026-08-08 14:11:17 +08:00
}
2026-07-30 17:40:25 +08:00
}
interface Harness {
readonly ctx : Context
2026-08-13 00:36:22 +08:00
readonly compact : StubCompactionEngine
2026-07-30 17:40:25 +08:00
readonly agent : Agent
readonly plugin : Awaited < ReturnType < Context [ 'plugin' ] > >
}
async function harness ( ) : Promise < Harness > {
const ctx = new Context ( )
2026-08-13 00:36:22 +08:00
await ctx . plugin ( CommandRuntime )
const compact = new StubCompactionEngine ( ctx )
2026-07-30 17:40:25 +08:00
const plugin = await ctx . plugin ( commandCompact )
2026-08-04 18:41:07 +08:00
const session = Session . create ( SessionId ( 'command-compact' ) )
2026-07-30 17:40:25 +08:00
const agent = {
session ,
status : 'idle' ,
options : { } ,
reserveTurnAdmission : ( ) = > ( ) = > undefined ,
} as unknown as Agent
return { ctx , compact , agent , plugin }
}
async function run (
test : Harness ,
suffix = '' ,
controller = new AbortController ( ) ,
2026-08-13 00:36:22 +08:00
) : Promise < NonNullable < Awaited < ReturnType < CommandRuntime [ 'execute' ] > > > > {
2026-07-30 17:40:25 +08:00
const execution = await test . ctx . commands . execute ( test . agent , ` /compact ${ suffix } ` , controller . signal )
if ( execution === undefined ) throw new Error ( 'compact command was not registered' )
return execution
}
/** Assert the executor-owned lifecycle pair and absence from model history. */
function expectLastLifecycle (
test : Harness ,
args : string ,
2026-08-08 14:11:17 +08:00
outcome : CommandResult ,
2026-07-30 17:40:25 +08:00
) : string {
2026-08-08 14:11:17 +08:00
const lifecycle = test . agent . session . events
. filter ( event = > event . type === 'command/run' || event . type === 'command/done' )
. slice ( - 2 )
2026-07-30 17:40:25 +08:00
const runEvent = lifecycle [ 0 ]
const doneEvent = lifecycle [ 1 ]
if ( runEvent ? . type !== 'command/run' || doneEvent ? . type !== 'command/done' ) {
throw new Error ( ` expected command lifecycle pair, got ${ lifecycle . map ( event = > event . type ) . join ( ',' ) } ` )
}
expect ( lifecycle . map ( event = > ( { type : event . type , data : event.data } ) ) ) . toEqual ( [
{
type : 'command/run' ,
data : {
commandId : runEvent.data.commandId ,
name : 'compact' ,
args ,
source : { kind : 'user' } ,
} ,
} ,
{
type : 'command/done' ,
data : {
commandId : runEvent.data.commandId ,
. . . outcome ,
} ,
} ,
] )
expect ( doneEvent . data . commandId ) . toBe ( runEvent . data . commandId )
expect ( test . agent . session . surface . nodes ) . toEqual ( [ ] )
expect ( test . agent . session . deriveMessages ( ) ) . toEqual ( [ ] )
return runEvent . data . commandId
}
describe ( '@deepseek-ai/dsh-command-compact registration' , ( ) = > {
it ( 'registers one argument-free command with Loader-safe exports and disposes it' , async ( ) = > {
const test = await harness ( )
expect ( commandCompact . name ) . toBe ( 'command-compact' )
2026-08-13 00:36:22 +08:00
expect ( commandCompact . inject ) . toEqual ( [ 'commands' , 'compaction' ] )
2026-07-30 17:40:25 +08:00
expect ( 'default' in commandCompact ) . toBe ( false )
const loader = Object . create ( Loader . prototype ) as Loader
expect ( loader . unwrapExports ( commandCompact ) ) . toBe ( commandCompact )
expect ( test . ctx . commands . list ( test . agent ) ) . toContainEqual ( {
name : 'compact' ,
description : 'Compact older conversation history' ,
} )
await test . plugin . dispose ( )
expect ( test . ctx . commands . find ( test . agent , 'compact' ) ) . toBeUndefined ( )
} )
} )
describe ( '/compact human command' , ( ) = > {
it ( 'reports success with useful accounting and forwards the exact target and signal' , async ( ) = > {
const test = await harness ( )
const controller = new AbortController ( )
const execution = await run ( test , '' , controller )
expect ( execution . result ) . toEqual ( {
kind : 'success' ,
text : 'Compacted 3 history items (~42 tokens).' ,
2026-08-08 14:11:17 +08:00
sourceEventSeq : RESULT.summarySeq ,
2026-07-30 17:40:25 +08:00
} )
expect ( execution . commandId ) . toBe ( expectLastLifecycle ( test , '' , execution . result ) )
expect ( test . compact . calls ) . toEqual ( [ { agent : test.agent , signal : controller.signal } ] )
} )
it ( 'returns direct no-history and argument-rejection results' , async ( ) = > {
const test = await harness ( )
test . compact . result = null
const empty = await run ( test )
expect ( empty . result ) . toEqual ( {
kind : 'success' ,
text : 'No compactable history yet.' ,
} )
expect ( empty . commandId ) . toBe ( expectLastLifecycle ( test , '' , empty . result ) )
const rejected = await run ( test , ' now' )
expect ( rejected . result ) . toEqual ( {
kind : 'error' ,
text : 'Usage: /compact (no arguments)' ,
} )
expect ( rejected . commandId ) . toBe ( expectLastLifecycle ( test , ' now' , rejected . result ) )
expect ( test . compact . calls ) . toHaveLength ( 1 )
} )
it . each ( [
[ 'busy' , 'Compaction is unavailable because this process has an active compaction, or the agent is not idle.' ] ,
2026-08-03 12:25:33 +08:00
[ 'cancelled' , 'Compaction cancelled.' ] ,
2026-07-30 17:40:25 +08:00
[ 'changed' , 'The history selected for compaction changed before it could be replaced. The conversation is unchanged; the attempt is recorded in the session log.' ] ,
[ 'summary' , 'Compaction could not produce a useful summary. The conversation is unchanged; the attempt is recorded in the session log.' ] ,
[ 'commit' , 'Compaction did not finish cleanly; some session history may have changed. Inspect the current session state before retrying.' ] ,
[ 'persistence' , 'Compaction finished, but the session could not be saved.' ] ,
] as const ) ( 'maps expected %s failures to direct errors' , async ( code , text ) = > {
const test = await harness ( )
test . compact . failure = new ManualCompactionError ( code , 'backend detail' )
const execution = await run ( test )
expect ( execution . result ) . toEqual ( { kind : 'error' , text } )
expect ( execution . commandId ) . toBe ( expectLastLifecycle ( test , '' , execution . result ) )
} )
it ( 'preserves cancellation and unexpected implementation failures' , async ( ) = > {
const cancelled = await harness ( )
const controller = new AbortController ( )
const abort = new Error ( 'operator cancelled' )
cancelled . compact . operation = ( ) = > {
controller . abort ( abort )
return Promise . reject ( new ManualCompactionError ( 'summary' , 'late failure' ) )
}
await expect ( run ( cancelled , '' , controller ) ) . rejects . toBe ( abort )
expectLastLifecycle ( cancelled , '' , { kind : 'error' , text : abort.message } )
const unexpected = await harness ( )
const bug = new Error ( 'unexpected backend bug' )
unexpected . compact . failure = bug
await expect ( run ( unexpected ) ) . rejects . toBe ( bug )
expectLastLifecycle ( unexpected , '' , { kind : 'error' , text : bug.message } )
} )
2026-07-30 22:00:34 +08:00
it ( 'drains an aborted handler through close and flush before plugin disposal settles' , async ( ) = > {
const test = await harness ( )
const controller = new AbortController ( )
const abort = new Error ( 'operator cancelled' )
const started = Promise . withResolvers < undefined > ( )
const allowClose = Promise . withResolvers < undefined > ( )
const closed = Promise . withResolvers < undefined > ( )
const allowFlush = Promise . withResolvers < undefined > ( )
const flushed = Promise . withResolvers < undefined > ( )
test . compact . operation = async ( ) = > {
started . resolve ( undefined )
await allowClose . promise
closed . resolve ( undefined )
await allowFlush . promise
flushed . resolve ( undefined )
throw abort
}
const execution = run ( test , '' , controller )
await started . promise
controller . abort ( abort )
await expect ( execution ) . rejects . toBe ( abort )
let disposed = false
const disposal = test . plugin . dispose ( )
void disposal . then ( ( ) = > { disposed = true } )
await new Promise ( resolve = > setTimeout ( resolve , 0 ) )
expect ( test . ctx . commands . find ( test . agent , 'compact' ) ) . toBeUndefined ( )
expect ( disposed ) . toBe ( false )
allowClose . resolve ( undefined )
await closed . promise
await new Promise ( resolve = > setTimeout ( resolve , 0 ) )
expect ( disposed ) . toBe ( false )
allowFlush . resolve ( undefined )
await flushed . promise
await disposal
expect ( disposed ) . toBe ( true )
} )
2026-07-30 17:40:25 +08:00
} )