Merge master into worktree-windows-runtime

This commit is contained in:
Tianyi Cui
2026-07-21 23:39:14 +08:00
936 changed files with 36271 additions and 10361 deletions

View File

@@ -10,7 +10,7 @@ pnpm run demo:tui
The command needs `DEEPSEEK_API_KEY` in the environment or gitignored repository-root `.env`. Set `RESUME_SESSION_ID` to reopen a persisted conversation under `./.sessions`.
The TUI renders Markdown history, reasoning, tool-owned terminal/diff/generic cards, token totals, and the latest todo list. Enter submits or steers while the agent runs; Ctrl+O expands cards, Ctrl+R toggles reasoning, Escape cancels, and `/help` lists commands. `ask_user_question` opens a keyboard-driven overlay.
The TUI renders Markdown history, reasoning, tool-owned terminal/diff/generic cards, token totals, and the latest todo list. Long tool bodies keep a head/tail preview; Ctrl+O expands or collapses every card. Enter submits or steers while the agent runs, Ctrl+R toggles reasoning, Escape cancels, and `/help` lists commands. `/model` opens a keyboard selector for the current provider catalog; use Up/Down and Enter, or `/model <model>` and `/model <provider>/<model>` for direct selection. `ask_user_question` opens a wide bottom-left keyboard panel with batch progress and numbered options.
Run `pnpm run demo:code-mode tui` for the Code Mode overlay.

View File

@@ -19,7 +19,7 @@
welcome: 'TUI Code Mode ready. Give it a multi-tool task.'
ui:
showReasoning: true
maxToolOutputLines: 12
maxToolOutputLines: 6
persona: |
You are a coding agent powered by the {{model}} model.

View File

@@ -31,7 +31,7 @@
welcome: 'TUI agent ready. Give it a coding task.'
ui:
showReasoning: true
maxToolOutputLines: 12
maxToolOutputLines: 6
persona: |
You are a coding agent powered by the {{model}} model.

View File

@@ -1,5 +1,5 @@
import type { Context } from 'cordis'
import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'
import type { GenerateOptions, LlmModelContext, LlmModelInfo, StreamChunk } from '@deepseek-ai/dsh-llm'
import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm'
const CONTROL_PROBE = '\u001b]2;MODEL_CONTROLLED\u0007\u001b[999CMODEL_CURSOR\u009b31mMODEL_C1'
@@ -18,7 +18,21 @@ function textChunks(text: string): StreamChunk[] {
/** Keyless two-step adapter for the real-PTY TUI conversation test. */
class ScriptedTuiAdapter extends LlmAdapter {
async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
override listModels(provider: string): Promise<readonly LlmModelInfo[]> {
return Promise.resolve([
{ provider, id: 'tui-scripted-model', name: 'Scripted Base' },
{ provider, id: 'tui-scripted-model-pro', name: 'Scripted Pro' },
])
}
override resolveModelContext(_provider: string, _model: string): Promise<LlmModelContext> {
return Promise.resolve({ contextWindow: 128_000 })
}
override async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
if (options.model !== 'tui-scripted-model-pro' || !options.system?.includes('tui-scripted-model-pro')) {
throw new Error('the scripted TUI request did not apply the selected model to routing and prompt variables')
}
const hasToolResult = options.messages.at(-1)?.content.some(block => block.type === 'tool-result') ?? false
if (hasToolResult) {
for (const chunk of textChunks(FINAL_TEXT)) yield chunk

View File

@@ -12,6 +12,9 @@
config:
cwd: !!js process.cwd()
- id: token-meter
name: '@deepseek-ai/dsh-token-meter'
- id: tui-agent
name: '@deepseek-ai/dsh-tui-demo'
config:
@@ -21,5 +24,6 @@
workspaceContext:
maxBytes: 65536
welcome: 'scripted TUI ready.'
persona: 'Scripted model {{model}}.'
ui:
showReasoning: true

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=36 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Use the bash tool to — DSH TUI snapshot"
cursor hidden column=1 viewportRow=27 bufferRow=27
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: bash-terminal-card │"
2| "│ Use the bash tool to │"
style 0-0 fg=bright-blue
style 2-36 fg=bright-black
style 2-21 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -67,7 +67,7 @@ buffer
style 1-1 inverse
28| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
29| "/workspace/project ↑3.0k ↓115 idle reasoning:on tools:compact"
style 0-58 dim
style 67-99 dim
29| "/tmp/dsh-tui-snapshot-bash-te ↑3.0k ↓115 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-28 dim
style 42-99 dim
30-35| <blank>

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=36 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Using ONE run_code program: call — DSH TUI snapshot"
cursor hidden column=1 viewportRow=29 bufferRow=29
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: code-mode │"
2| "│ Using ONE run_code program: call │"
style 0-0 fg=bright-blue
style 2-27 fg=bright-black
style 2-33 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -73,7 +73,7 @@ buffer
style 1-1 inverse
30| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
31| "/workspace/project ↑3.1k ↓158 idle reasoning:on tools:compact"
style 0-49 dim
style 67-99 dim
31| "/tmp/dsh-tui-snapshot-code-mo ↑3.1k ↓158 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-28 dim
style 42-99 dim
32-35| <blank>

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=50 base=14 viewport=14
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Run this advanced flow exactly — DSH TUI snapshot"
cursor hidden column=1 viewportRow=33 bufferRow=47
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: cordis-dynamic-toolchain │"
2| "│ Run this advanced flow exactly │"
style 0-0 fg=bright-blue
style 2-42 fg=bright-black
style 2-31 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -111,6 +111,6 @@ buffer
style 1-1 inverse
48| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
49| "/workspace/project ↑18 ↓18 idle reasoning:on tools:compact"
style 0-61 dim
style 67-99 dim
49| "/tmp/dsh-tui-snapshot-cordis-dyn ↑18 ↓18 7% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-31 dim
style 42-99 dim

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=47 base=11 viewport=11
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Use the workflow tool exactly — DSH TUI snapshot"
cursor hidden column=1 viewportRow=33 bufferRow=44
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: dynamic-workflow │"
2| "│ Use the workflow tool exactly │"
style 0-0 fg=bright-blue
style 2-34 fg=bright-black
style 2-30 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -101,6 +101,6 @@ buffer
style 1-1 inverse
45| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
46| "/workspace/project ↑3.5k ↓227 idle reasoning:on tools:compact"
style 0-56 dim
style 67-99 dim
46| "/tmp/dsh-tui-snapshot-dynamic ↑3.5k ↓227 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-28 dim
style 42-99 dim

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=36 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Reply with exactly the word: — DSH TUI snapshot"
cursor hidden column=1 viewportRow=28 bufferRow=28
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: multi-turn-conversation │"
2| "│ Reply with exactly the word: │"
style 0-0 fg=bright-blue
style 2-41 fg=bright-black
style 2-29 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -64,7 +64,7 @@ buffer
style 1-1 inverse
29| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
30| "/workspace/project ↑2.9k ↓41 idle reasoning:on tools:compact"
style 0-62 dim
style 67-99 dim
30| "/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>

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=39 base=3 viewport=3
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Use the read tool twice — DSH TUI snapshot"
cursor hidden column=1 viewportRow=33 bufferRow=36
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,9 +10,9 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: parallel-file-reads │"
2| "│ Use the read tool twice │"
style 0-0 fg=bright-blue
style 2-37 fg=bright-black
style 2-24 fg=bright-black
style 99-99 fg=bright-blue
3| "│ deepseek-v4-flash • main-session │"
style 0-0 fg=bright-blue
@@ -86,6 +86,6 @@ buffer
style 1-1 inverse
37| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
38| "/workspace/project ↑20 ↓6 idle reasoning:on tools:compact"
style 0-55 dim
style 67-99 dim
38| "/tmp/dsh-tui-snapshot-parallel-fi ↑20 ↓6 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-32 dim
style 42-99 dim

View File

@@ -1,6 +1,6 @@
terminal 100x36 buffer=normal length=36 base=0 viewport=0
lifecycle started=1 stopped=0 progress=inactive
title "DSH TUI snapshot"
title "Use the todo_write tool to — DSH TUI snapshot"
cursor hidden column=1 viewportRow=33 bufferRow=33
buffer
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
@@ -10,7 +10,7 @@ buffer
style 2-9 fg=bright-blue bold
style 11-17 bold
style 99-99 fg=bright-blue
2| "│ Recorded replay: todo-plan │"
2| "│ Use the todo_write tool to │"
style 0-0 fg=bright-blue
style 2-27 fg=bright-black
style 99-99 fg=bright-blue
@@ -76,6 +76,6 @@ buffer
style 1-1 inverse
34| "────────────────────────────────────────────────────────────────────────────────────────────────────"
style 0-99 dim
35| "/workspace/project ↑3.1k ↓145 idle reasoning:on tools:compact"
style 0-49 dim
style 67-99 dim
35| "/tmp/dsh-tui-snapshot-todo-pl ↑3.1k ↓145 3% context tools:compact deepseek-v4-flash(reasoning:on)"
style 0-28 dim
style 42-99 dim

View File

@@ -24,7 +24,7 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
expect(output).toContain('\u001B[?2004l')
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
it('streams a response, answers a user-question dialog, completes the tool round-trip, and exits cleanly', async () => {
it('switches models, streams a response, answers a user-question dialog, and exits cleanly', async () => {
const output = await runTuiPtySmoke({
label: 'tui-agent conversation',
tempDirPrefix: 'tui-agent-conversation-',
@@ -32,7 +32,9 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
configPath: scriptedConfigPath,
tsconfigPath,
actions: [
{ waitFor: 'scripted TUI ready.', send: 'exercise the TUI\r' },
{ 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: 'How should the scripted run proceed?', send: '\r' },
{ waitFor: 'Decision received. Scripted TUI run complete.', send: '/exit\r' },
],

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 TokenMeterService from '@deepseek-ai/dsh-token-meter'
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session'
import { SessionId } from '@deepseek-ai/dsh-session'
import SubagentService from '@deepseek-ai/dsh-subagent'
@@ -32,7 +33,7 @@ import { HeadlessTerminal } from '../../../packages/ui/tui/tests/headless-termin
const SNAPSHOTS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'snapshots')
// Keep pre-normalization layout widths identical across macOS and Linux.
const SNAPSHOT_TMP_ROOT = process.platform === 'win32' ? tmpdir() : '/tmp'
const PROVIDERS = [{ id: 'deepseek', models: [{ id: 'deepseek-v4-flash' }] }]
const PROVIDERS = [{ id: 'deepseek', models: [{ id: 'deepseek-v4-flash', contextWindow: 128_000 }] }]
const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi
type SnapshotMode = 'replay' | 'record' | 'refresh'
@@ -189,6 +190,7 @@ async function mountScenarioContext(
tools: { mode: scenario.composition === 'code' ? 'code' : scenario.composition === 'advanced' ? 'both' : 'native' },
skills: { local: { agentsHome: join(cwd, '.agents') } },
})
await ctx.plugin(TokenMeterService)
await ctx.plugin(LocalBashExecutor, { cwd, timeoutMs: 30_000 })
await ctx.plugin(SnapshotLocalFileSystem, { cwd: '/' })
await ctx.plugin(FsPolicy)