Merge latest master into tool JSON schema DSL

# Conflicts:
#	examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md
This commit is contained in:
Tianyi Cui
2026-07-22 20:58:17 +08:00
186 files changed
+8053 -582

No files matched your search

@@ -15,6 +15,11 @@
- id: token-meter
name: '@deepseek-ai/dsh-token-meter'
- id: plan-mode
name: '@deepseek-ai/dsh-plan-mode'
config:
section: 'Stay in plan mode for this scripted TUI test.'
- id: tui-agent
name: '@deepseek-ai/dsh-tui-demo'
config:
@@ -1,7 +1,7 @@
terminal 100x36 buffer=normal length=36 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "Reply with exactly the word: — DSH TUI snapshot"
cursor hidden column=1 viewportRow=28 bufferRow=28
cursor hidden column=1 viewportRow=30 bufferRow=30
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
style 0-99 fg=bright-blue
@@ -21,50 +21,53 @@ buffer
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
style 0-99 fg=bright-blue
5| <blank>
6| " "
6| " Entering plan mode (applies from the next step). "
style 1-48 fg=bright-black
7| <blank>
8| "▌ "
style 0-0 fg=bright-blue
7| "▌ You "
9| "▌ You "
style 0-0 fg=bright-blue
style 2-4 fg=bright-blue bold
8| "▌ Reply with exactly the word: ONE. No tools. "
10| "▌ Reply with exactly the word: ONE. No tools. "
style 0-0 fg=bright-blue
9| "▌ "
11| "▌ "
style 0-0 fg=bright-blue
10| <blank>
11| " Reasoning "
12| <blank>
13| " Reasoning "
style 1-9 fg=bright-black italic
12| " The user wants me to reply with exactly the word \"ONE\" and use no tools. "
14| " The user wants me to reply with exactly the word \"ONE\" and use no tools. "
style 1-72 fg=bright-black italic
13| <blank>
14| " Assistant "
15| <blank>
16| " Assistant "
style 1-9 fg=bright-magenta bold
15| " ONE "
16| <blank>
17| "▌ "
17| " ONE "
18| <blank>
19| "▌ "
style 0-0 fg=bright-blue
18| "▌ You "
20| "▌ You "
style 0-0 fg=bright-blue
style 2-4 fg=bright-blue bold
19| "▌ Reply with exactly the word: TWO. No tools. "
21| "▌ Reply with exactly the word: TWO. No tools. "
style 0-0 fg=bright-blue
20| "▌ "
22| "▌ "
style 0-0 fg=bright-blue
21| <blank>
22| " Reasoning "
23| <blank>
24| " Reasoning "
style 1-9 fg=bright-black italic
23| " The user wants me to reply with exactly the word \"TWO\" and no tools. "
25| " The user wants me to reply with exactly the word \"TWO\" and no tools. "
style 1-68 fg=bright-black italic
24| <blank>
25| " Assistant "
26| <blank>
27| " Assistant "
style 1-9 fg=bright-magenta bold
26| " TWO "
27| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
28| " "
style 1-1 inverse
28| " TWO "
29| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
30| "/tmp/dsh-tui-snapshot-multi-tu ↑2.9k ↓41 3% context tools:compact deepseek-v4-flash(reasoning:on)"
30| " "
style 1-1 inverse
31| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
32| "/tmp/dsh-tui-snapshot-multi-tu ↑2.9k ↓41 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-29 dim
style 42-99 dim
31-35| <blank>
33-35| <blank>
@@ -9,7 +9,7 @@ const scriptedConfigPath = fileURLToPath(new URL('./fixtures/tui-scripted.cordis
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
it('boots pi-tui, renders the configured banner, accepts /exit, and restores the terminal', async () => {
it('boots pi-tui, enters plan mode through /plan, accepts /exit, and restores the terminal', async () => {
const output = await runTuiPtySmoke({
label: 'tui-agent boot',
tempDirPrefix: 'tui-agent-smoke-',
@@ -17,10 +17,14 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
configPath,
tsconfigPath,
env: { DEEPSEEK_API_KEY: 'keyless-tui-no-call' },
actions: [{ waitFor: 'TUI agent ready.', send: '/exit\r' }],
actions: [
{ waitFor: 'TUI agent ready.', send: '/plan\r' },
{ waitFor: 'Entering plan mode (applies from the next step).', send: '/exit\r' },
],
})
expect(output).toContain('DEEPSEEK')
expect(output).toContain('TUI agent ready.')
expect(output).toContain('Entering plan mode (applies from the next step).')
expect(output).toContain('\u001B[?2004l')
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
@@ -34,12 +38,13 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
actions: [
{ waitFor: 'scripted TUI ready.', send: '/model\r' },
{ waitFor: 'Select model', send: '\x1b[B\r' },
{ waitFor: 'Model selected: tui-scripted/tui-scripted-model-pro.', send: 'exercise the TUI\r' },
{ waitFor: 'Model selected: tui-scripted/tui-scripted-model-pro.', send: '/plan exercise the TUI\r' },
{ waitFor: 'How should the scripted run proceed?', send: '\r' },
{ waitFor: 'Decision received. Scripted TUI run complete.', send: '/exit\r' },
],
})
expect(output).toContain('I need one decision before I continue.')
expect(output).toContain('Entering plan mode (applies from the next step).')
expect(output).toContain(String.raw`\x1b]2;MODEL_CONTROLLED\x07`)
expect(output).toContain(String.raw`\x1b[999CMODEL_CURSOR`)
expect(output).toContain(String.raw`\x9b31mMODEL_C1`)
+30 -1
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
}
@@ -54,6 +56,8 @@ const SCENARIOS: Scenario[] = [
name: 'multi-turn-conversation',
composition: 'native',
expectedTools: [],
expectedEventCounts: { 'plan/mode': 1 },
enterPlanMode: true,
recorded: true,
},
{
@@ -204,6 +208,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, {})
}
@@ -268,7 +275,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()
@@ -280,6 +297,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') {