| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- import { describe, expect, it } from 'vitest'
- import { join } from 'node:path'
- import type { Context } from 'cordis'
- import Loader from '@cordisjs/plugin-loader'
- import { TOOL_ORDER_REST } from '@deepseek-ai/dsh-system-prompt'
- import * as tuiAgent from '../src/index.ts'
- interface PluginCall {
- readonly name: string
- readonly config: unknown
- }
- function recordingContext(): { readonly ctx: Context; readonly calls: PluginCall[] } {
- const calls: PluginCall[] = []
- const ctx = {
- plugin(plugin: { name?: string }, config?: unknown) {
- calls.push({ name: plugin.name ?? '', config })
- },
- } as unknown as Context
- return { ctx, calls }
- }
- describe('dsh-tui-demo app', () => {
- it('composes the TUI cluster around one fresh exact session identity', () => {
- const { ctx, calls } = recordingContext()
- tuiAgent.composeTuiApp(ctx, {
- provider: 'mock',
- model: 'mock-model',
- maxParallelToolCalls: 3,
- persona: 'test persona',
- toolOrder: ['zulu', TOOL_ORDER_REST],
- tools: { mode: 'code' },
- dshHome: '/tmp/dsh-home',
- persistenceRoot: '/tmp/tui-sessions',
- persistenceCompression: 'none',
- sessionReferences: {
- maxReferences: 2,
- candidateLimit: 7,
- maxReferenceBytes: 1234,
- },
- welcome: 'TUI ready',
- resumeCommand: 'dsh --resume {session}',
- ui: { color: false, maxToolOutputLines: 3 },
- skills: { tool: { catalogDescriptionMaxLength: 8 } },
- toolBash: { enableRunInBackground: false },
- toolTasks: { waitTimeoutMs: 7, maxWaitTimeoutMs: 11 },
- workspaceContext: false,
- })
- expect(calls.map(call => call.name)).toEqual([
- 'CommandService',
- 'command-goal',
- 'SessionPersistenceJsonl',
- 'session-checkpoint-policy',
- 'SessionQuerySqlite',
- 'SessionReferenceService',
- 'UserInteractionService',
- 'ui-tui',
- 'agent-spine-demo',
- 'tool-ask-user',
- ])
- expect(calls[0]?.config).toBeUndefined()
- expect(calls[2]?.config).toEqual({ root: '/tmp/tui-sessions', compression: 'none' })
- expect(calls[4]?.config).toEqual({ path: join('/tmp/tui-sessions', 'session-query.db') })
- expect(calls[5]?.config).toEqual({
- maxReferences: 2,
- candidateLimit: 7,
- maxReferenceBytes: 1234,
- })
- const tuiConfig = calls[7]?.config as { sessionId: string }
- expect(tuiConfig).toMatchObject({
- welcome: 'TUI ready',
- resumeCommand: 'dsh --resume {session}',
- color: false,
- maxToolOutputLines: 3,
- })
- expect(tuiConfig.sessionId).toMatch(/^main-session-[0-9a-f-]{36}$/)
- const spineConfig = calls[8]?.config as {
- readonly agents: Array<Record<string, unknown>>
- readonly goals: Record<string, never>
- readonly maxParallelToolCalls: number
- readonly persona: string
- readonly toolOrder: string[]
- readonly tools: { mode: string }
- }
- expect(spineConfig).toMatchObject({
- maxParallelToolCalls: 3,
- persona: 'test persona',
- toolOrder: ['zulu', TOOL_ORDER_REST],
- tools: { mode: 'code' },
- goals: {},
- })
- expect(spineConfig.agents[0]).toMatchObject({
- id: 'main',
- provider: 'mock',
- model: 'mock-model',
- cwd: process.cwd(),
- sessionId: tuiConfig.sessionId,
- })
- })
- it('resumes the configured session and applies runtime defaults', () => {
- const { ctx, calls } = recordingContext()
- tuiAgent.composeTuiApp(ctx, {
- provider: 'mock',
- model: 'mock-model',
- resumeSessionId: 'persisted-session',
- workspaceContext: false,
- })
- expect(calls[2]?.config).toEqual({ root: './.sessions' })
- expect(calls[5]?.config).toEqual({})
- // No configured welcome forwards none: the TUI banner sweeps in without a subtitle.
- expect(calls[7]?.config).toEqual({ sessionId: 'persisted-session' })
- expect((calls[8]?.config as { agents: Array<Record<string, unknown>> }).agents[0]).toMatchObject({
- id: 'main',
- resumeSessionId: 'persisted-session',
- })
- })
- it('normalizes an empty resume id and routes apply through the same composition', () => {
- const { ctx, calls } = recordingContext()
- tuiAgent.apply(ctx, {
- provider: 'mock',
- model: 'mock-model',
- resumeSessionId: '',
- goals: false,
- workspaceContext: false,
- })
- const tuiConfig = calls[6]?.config as { sessionId: string }
- expect(tuiConfig.sessionId).toMatch(/^main-session-[0-9a-f-]{36}$/)
- expect((calls[7]?.config as { agents: Array<Record<string, unknown>> }).agents[0])
- .toMatchObject({ sessionId: tuiConfig.sessionId })
- expect(calls.map(call => call.name)).not.toContain('command-goal')
- expect(calls[7]?.config).toMatchObject({ goals: false })
- })
- it('has the namespace-plugin export shape so the Loader keeps its schema', () => {
- expect(tuiAgent.name).toBe('tui-demo')
- expect(tuiAgent.Config).toBeDefined()
- expect('default' in tuiAgent).toBe(false)
- expect(typeof tuiAgent.apply).toBe('function')
- const loader = Object.create(Loader.prototype) as Loader
- const unwrapped = loader.unwrapExports(tuiAgent) as Record<string, unknown>
- expect(unwrapped).toBe(tuiAgent)
- expect(unwrapped.name).toBe('tui-demo')
- expect(unwrapped.Config).toBeDefined()
- })
- })
|