fix(test): address cli demo cleanup review feedback
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
/** Test driver: one delegation turn through a headless Loader composition. */
|
||||
|
||||
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import { runFixtureTurn } from '../../../../../headless-agent/tests/fixtures/one-shot.ts'
|
||||
import { runFixtureTurn } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
const configPath = process.argv[2]
|
||||
if (configPath === undefined) throw new Error('acp-subagent cwd driver requires a config path')
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
import type { Context } from 'cordis'
|
||||
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import { runFixtureTurn } from '@deepseek-ai/dsh-loader-smoke'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
import { runFixtureTurn } from './one-shot.ts'
|
||||
|
||||
const NAME = 'headless-test-driver'
|
||||
const [configPath, ...taskParts] = process.argv.slice(2)
|
||||
@@ -16,7 +16,7 @@ const uninstallFailLoud = installFailLoud(NAME)
|
||||
let ctx: Context | undefined
|
||||
try {
|
||||
loadEnv(NAME)
|
||||
ctx = await boot(NAME, resolveConfigPath(configPath, process.env.DSH_SNAPSHOT))
|
||||
ctx = await boot(NAME, resolveConfigPath(configPath, undefined))
|
||||
const result = await runFixtureTurn(ctx, {
|
||||
task: taskParts.join(' '),
|
||||
onEvent: (sessionId: string, event: SessionEvent) => {
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/** Test-only direct-agent turn driver shared by assembled Loader fixtures. */
|
||||
|
||||
import type { Context } from 'cordis'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import { createUserMessage, type TokenUsage } from '@deepseek-ai/dsh-llm'
|
||||
import type { SessionEvent } from '@deepseek-ai/dsh-session'
|
||||
|
||||
/** Result envelope consumed only by snapshot and composition tests. */
|
||||
export interface FixtureTurnResult {
|
||||
readonly type: 'result'
|
||||
readonly sessionId: string
|
||||
readonly output: string
|
||||
readonly usage?: TokenUsage
|
||||
}
|
||||
|
||||
/** Options for one fixture turn against exactly one configured root agent. */
|
||||
export interface FixtureTurnOptions {
|
||||
readonly task: string
|
||||
readonly onEvent?: (sessionId: string, event: SessionEvent) => void
|
||||
}
|
||||
|
||||
function addUsage(total: TokenUsage | undefined, step: TokenUsage): TokenUsage {
|
||||
const next: TokenUsage = {
|
||||
inputTokens: (total?.inputTokens ?? 0) + step.inputTokens,
|
||||
outputTokens: (total?.outputTokens ?? 0) + step.outputTokens,
|
||||
}
|
||||
for (const key of ['cacheReadTokens', 'cacheWriteTokens', 'reasoningTokens'] as const) {
|
||||
if (total?.[key] !== undefined || step[key] !== undefined) next[key] = (total?.[key] ?? 0) + (step[key] ?? 0)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
function assistantText(event: Extract<SessionEvent, { type: 'assistant/message' }>): string | undefined {
|
||||
const blocks = event.data.message.content.filter(block => block.type === 'text')
|
||||
return blocks.length === 0 ? undefined : blocks.map(block => block.text).join('')
|
||||
}
|
||||
|
||||
function onlyRootAgent(ctx: Context): Agent {
|
||||
const agents = ctx.get('agents')?.roots() ?? []
|
||||
const [agent] = agents
|
||||
if (agent === undefined || agents.length !== 1) {
|
||||
throw new Error(`headless fixture requires exactly one top-level agent, found ${agents.length}`)
|
||||
}
|
||||
return agent
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive one task from its durable inbox receipt through whole-agent idle.
|
||||
* @param ctx - settled Loader context with exactly one configured root agent.
|
||||
* @param options - task and optional canonical-event observer.
|
||||
* @returns the final assistant text and accumulated model usage.
|
||||
*/
|
||||
export async function runFixtureTurn(ctx: Context, options: FixtureTurnOptions): Promise<FixtureTurnResult> {
|
||||
const agent = onlyRootAgent(ctx)
|
||||
await agent.whenIdle()
|
||||
|
||||
const message = createUserMessage({
|
||||
content: [{ type: 'text', text: options.task }],
|
||||
source: { kind: 'user' },
|
||||
})
|
||||
let received = false
|
||||
let output = ''
|
||||
const usageByStep = new Map<string, TokenUsage>()
|
||||
const disposeListener = ctx.on('session/event', (session, event) => {
|
||||
if (session !== agent.session) return
|
||||
if (!received) {
|
||||
if (event.type !== 'agent/inbox/spliced'
|
||||
|| !event.data.inserted.some(inserted => inserted.id === message.id)) return
|
||||
received = true
|
||||
}
|
||||
options.onEvent?.(session.id, event)
|
||||
if (event.type === 'assistant/chunk' && event.data.chunk.type === 'usage') {
|
||||
usageByStep.set(`${event.data.turn}/${event.data.step}`, event.data.chunk.usage)
|
||||
}
|
||||
if (event.type === 'assistant/message') {
|
||||
output = assistantText(event) ?? output
|
||||
if (event.data.usage !== undefined) {
|
||||
usageByStep.set(`${event.data.turn}/${event.data.step}`, event.data.usage)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
agent.followup(message)
|
||||
await agent.whenIdle()
|
||||
} finally {
|
||||
disposeListener()
|
||||
}
|
||||
await ctx.sessions.flush(agent.session)
|
||||
const usage = [...usageByStep.values()].reduce<TokenUsage | undefined>(addUsage, undefined)
|
||||
return {
|
||||
type: 'result',
|
||||
sessionId: agent.session.id,
|
||||
output,
|
||||
...usage === undefined ? {} : { usage },
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { createServer } from 'node:http'
|
||||
import { once } from 'node:events'
|
||||
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import { recordFeedback } from '@deepseek-ai/dsh-command-feedback'
|
||||
import { runFixtureTurn } from './one-shot.ts'
|
||||
import { runFixtureTurn } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
const configPath = process.argv[2]
|
||||
if (configPath === undefined) throw new Error('telemetry-otel driver requires a config path')
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/** Test driver that sends two turns through one Headless Loader composition. */
|
||||
|
||||
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import { runFixtureTurn } from './one-shot.ts'
|
||||
import { runFixtureTurn } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
const configPath = process.argv[2]
|
||||
if (configPath === undefined) throw new Error('time-context driver requires a config path')
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/** Test driver: one delegation turn through a headless Loader composition. */
|
||||
|
||||
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
import { runFixtureTurn } from '../../../../../headless-agent/tests/fixtures/one-shot.ts'
|
||||
import { runFixtureTurn } from '@deepseek-ai/dsh-loader-smoke'
|
||||
|
||||
const configPath = process.argv[2]
|
||||
if (configPath === undefined) throw new Error('sdk-subagent cwd driver requires a config path')
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"@deepseek-ai/dsh-llm-deepseek": "workspace:*",
|
||||
"@deepseek-ai/dsh-llm-pi-ai": "workspace:*",
|
||||
"@deepseek-ai/dsh-llm-replay": "workspace:*",
|
||||
"@deepseek-ai/dsh-loader-smoke": "workspace:*",
|
||||
"@deepseek-ai/dsh-lsp": "workspace:*",
|
||||
"@deepseek-ai/dsh-lsp-local": "workspace:*",
|
||||
"@deepseek-ai/dsh-permission": "workspace:*",
|
||||
|
||||
Reference in New Issue
Block a user