Merge remote-tracking branch 'origin/master' into worktree/pr504-retarget-latest-master

# Conflicts:
#	docs/event-producer-consumer.md
#	examples/tui-agent/README.md
#	examples/tui-agent/composition.md
#	examples/tui-agent/cordis.yml
#	examples/tui-agent/tests/snapshots/multi-turn-conversation/terminal.expected.txt
#	examples/tui-agent/tests/tui-keyless-smoke.e2e.ts
#	packages/ui/tui/README.md
#	vitest.config.ts
This commit is contained in:
Tianyi Cui
2026-07-22 20:55:12 +08:00
182 changed files with 8016 additions and 576 deletions

View File

@@ -15,6 +15,7 @@ import * as FsPolicy from '@deepseek-ai/dsh-fs-policy'
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
import * as LlmDeepSeek from '@deepseek-ai/dsh-llm-deepseek'
import { installLlmReplay, parseSessionLog } from '@deepseek-ai/dsh-llm-replay'
import PlanModeService from '@deepseek-ai/dsh-plan-mode'
import TokenMeterService from '@deepseek-ai/dsh-token-meter'
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'
import { SessionId } from '@deepseek-ai/dsh-session'
@@ -45,6 +46,7 @@ interface Scenario {
expectedTools: string[]
expectedEventCounts?: Record<string, number>
childSessions?: number
enterPlanMode?: boolean
recorded: boolean
seedWorkspace?: boolean
/**
@@ -60,6 +62,8 @@ const SCENARIOS: Scenario[] = [
name: 'multi-turn-conversation',
composition: 'native',
expectedTools: [],
expectedEventCounts: { 'plan/mode': 1 },
enterPlanMode: true,
recorded: true,
},
{
@@ -213,6 +217,9 @@ async function mountScenarioContext(
await ctx.plugin(ToolWorkflow)
await ctx.plugin(ToolRalph)
await ctx.plugin(CommandService)
if (scenario.enterPlanMode === true) {
await ctx.plugin(PlanModeService, { section: 'Snapshot plan mode instructions.' })
}
if (scenario.composition === 'code' || scenario.composition === 'advanced') {
await ctx.plugin(WorkerCodeRuntime, {})
}
@@ -277,7 +284,17 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
})
await settleTerminal(terminal)
for (const prompt of prompts) {
let remainingPrompts = prompts
if (scenario.enterPlanMode === true) {
const firstPrompt = prompts[0]!
terminal.send(`/plan ${firstPrompt}`)
terminal.send('\r')
await agent.whenIdle()
await settleTerminal(terminal)
remainingPrompts = prompts.slice(1)
}
for (const prompt of remainingPrompts) {
terminal.send(prompt)
terminal.send('\r')
await agent.whenIdle()
@@ -289,6 +306,18 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
for (const [type, count] of Object.entries(scenario.expectedEventCounts ?? {})) {
expect(events.filter(event => event.type === type), `${scenario.name} must emit ${type}`).toHaveLength(count)
}
if (scenario.enterPlanMode === true) {
expect(ctx.planMode.get(agent)).toEqual({ active: true })
const planMode = events.find(event => event.type === 'plan/mode')
const firstHeader = events.find(event => event.type === 'request/header')
if (planMode === undefined || firstHeader === undefined) {
throw new Error('plan-mode command snapshot needs plan/mode before its first request/header')
}
expect(planMode.seq).toBeLessThan(firstHeader.seq)
expect(firstHeader.data.header.system).toContain('Snapshot plan mode instructions.')
const firstMessage = events.find(event => event.type === 'user/message')
expect(firstMessage?.data.content).toEqual([{ type: 'text', text: prompts[0] }])
}
expect(events.filter(event => event.type === 'tool/result').every(event => !event.data.isError)).toBe(true)
expect(events.filter(event => event.type === 'turn/end').every(event => event.data.reason.kind !== 'error')).toBe(true)
if (scenario.name === 'dynamic-workflow' || scenario.name === 'cordis-dynamic-toolchain') {