Merge refreshed canonical outputs into typed Code Mode results
# Conflicts: # docs/module-graph.md # 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/session.jsonl # examples/acp-agent/tests/snapshots/code-mode-workspace-context/system-prompt.expected.md # packages/core/tools/src/ts-types.ts
This commit is contained in:
@@ -5,6 +5,14 @@ import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm'
|
||||
const CONTROL_PROBE = '\u001b]2;MODEL_CONTROLLED\u0007\u001b[999CMODEL_CURSOR\u009b31mMODEL_C1'
|
||||
const INITIAL_TEXT = `I need one decision before I continue. ${CONTROL_PROBE}`
|
||||
const FINAL_TEXT = 'Decision received. Scripted TUI run complete.'
|
||||
// The `skill` scenario types `/skill:scripted-skill`; the manual-invocation front
|
||||
// door delivers the loaded skill as a user turn wrapped in `<skill name="…">`. The
|
||||
// body marker below lives in the fixture skill, so echoing it back proves the whole
|
||||
// block (name attribute plus body) reached the model, not just the command text.
|
||||
const SKILL_BLOCK_OPEN = '<skill name="scripted-skill">'
|
||||
const SKILL_BODY_MARKER = 'SCRIPTED SKILL BODY MARKER'
|
||||
const SKILL_RECEIVED_TEXT = 'Scripted skill body received.'
|
||||
const TITLE_TEXT = 'scripted session title'
|
||||
|
||||
function textChunks(text: string): StreamChunk[] {
|
||||
return [
|
||||
@@ -16,7 +24,7 @@ function textChunks(text: string): StreamChunk[] {
|
||||
]
|
||||
}
|
||||
|
||||
/** Keyless two-step adapter for the real-PTY TUI conversation test. */
|
||||
/** Keyless adapter for the real-PTY TUI tests: the two-step conversation and the `/skill:` round-trip. */
|
||||
class ScriptedTuiAdapter extends LlmAdapter {
|
||||
override listModels(provider: string): Promise<readonly LlmModelInfo[]> {
|
||||
return Promise.resolve([
|
||||
@@ -30,10 +38,30 @@ class ScriptedTuiAdapter extends LlmAdapter {
|
||||
}
|
||||
|
||||
override async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
|
||||
// The session-title provider's auxiliary request carries no tool schemas,
|
||||
// unlike every agent turn; answer it with a fixed title so the PTY test can
|
||||
// assert the logged title reaches the terminal window title.
|
||||
if ((options.tools?.length ?? 0) === 0) {
|
||||
for (const chunk of textChunks(TITLE_TEXT)) yield chunk
|
||||
return
|
||||
}
|
||||
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
|
||||
const lastMessage = options.messages.at(-1)
|
||||
const lastText = (lastMessage?.content ?? [])
|
||||
.filter(block => block.type === 'text')
|
||||
.map(block => block.text)
|
||||
.join('\n')
|
||||
if (lastText.includes(SKILL_BLOCK_OPEN)) {
|
||||
const ack = lastText.includes(SKILL_BODY_MARKER)
|
||||
? SKILL_RECEIVED_TEXT
|
||||
: 'Scripted skill block arrived without its body.'
|
||||
for (const chunk of textChunks(ack)) yield chunk
|
||||
return
|
||||
}
|
||||
|
||||
const hasToolResult = lastMessage?.content.some(block => block.type === 'tool-result') ?? false
|
||||
if (hasToolResult) {
|
||||
for (const chunk of textChunks(FINAL_TEXT)) yield chunk
|
||||
return
|
||||
|
||||
@@ -15,15 +15,35 @@
|
||||
- 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:
|
||||
provider: tui-scripted
|
||||
model: tui-scripted-model
|
||||
persistenceRoot: './.sessions'
|
||||
# The smoke's log inspection reads plain `.jsonl`; keep the scripted
|
||||
# fixture uncompressed like the other snapshot-facing configs.
|
||||
persistenceCompression: none
|
||||
workspaceContext:
|
||||
maxBytes: 65536
|
||||
welcome: 'scripted TUI ready.'
|
||||
persona: 'Scripted model {{model}}.'
|
||||
ui:
|
||||
showReasoning: true
|
||||
|
||||
# Model-made session titles, as in the shipped cordis.yml: the scripted adapter
|
||||
# answers the tool-less title request with a fixed string so the PTY test can
|
||||
# assert the logged title reaches the terminal window title.
|
||||
- id: session-title-llm
|
||||
name: '@deepseek-ai/dsh-session-title-first-message-llm'
|
||||
config:
|
||||
targetWords: 5
|
||||
targetCjkCharacters: 10
|
||||
maxInputBytes: 4096
|
||||
maxOutputTokens: 64
|
||||
timeoutMs: 10000
|
||||
|
||||
@@ -10,6 +10,10 @@ node, launch_args_json, launch_env_json, cwd, actions_json, expected_exit, timeo
|
||||
env = os.environ.copy()
|
||||
env.update(json.loads(launch_env_json))
|
||||
env.update({"COLUMNS": "100", "LINES": "30"})
|
||||
# Deterministic banner: a developer shell's COLORTERM=truecolor would switch the
|
||||
# banner to the per-letter gradient (one SGR per letter), breaking literal
|
||||
# DEEPSEEK assertions. The gradient path has its own unit and snapshot coverage.
|
||||
env.pop("COLORTERM", None)
|
||||
actions = json.loads(actions_json)
|
||||
pid, fd = pty.fork()
|
||||
if pid == 0:
|
||||
@@ -63,12 +67,19 @@ export interface TuiPtySmokeOptions {
|
||||
readonly label: string
|
||||
readonly tempDirPrefix: string
|
||||
readonly binScript: string
|
||||
readonly configPath: string
|
||||
/** Config argument; ignored when {@link configArgs} is set. */
|
||||
readonly configPath?: string
|
||||
/** Full argument vector for the bin (e.g. `[]` for a bin with a built-in default config). */
|
||||
readonly configArgs?: readonly string[]
|
||||
readonly tsconfigPath: string
|
||||
readonly actions?: readonly TuiPtyAction[]
|
||||
readonly env?: Readonly<NodeJS.ProcessEnv>
|
||||
readonly expectedExitCode?: number
|
||||
readonly timeoutMs?: number
|
||||
/** Seed the isolated workspace (`cwd`, with `$DSH_HOME` at `.dsh` and the agents home at `.agents`) before launch. */
|
||||
readonly prepare?: (cwd: string) => Promise<void>
|
||||
/** Inspect the workspace after a passing run, before the temp dir is removed. */
|
||||
readonly inspect?: (cwd: string) => Promise<void>
|
||||
}
|
||||
|
||||
function definedEnv(env: NodeJS.ProcessEnv): Record<string, string> {
|
||||
@@ -135,6 +146,9 @@ async function runWindowsPtySmoke(
|
||||
env: definedEnv({
|
||||
...process.env,
|
||||
...launch.env,
|
||||
// Match the POSIX driver: no COLORTERM, so the banner never takes the
|
||||
// truecolor gradient path under a developer's shell.
|
||||
COLORTERM: undefined,
|
||||
COLUMNS: '100',
|
||||
LINES: '30',
|
||||
}),
|
||||
@@ -175,9 +189,13 @@ export async function runTuiPtySmoke(options: TuiPtySmokeOptions): Promise<strin
|
||||
const cwd = await mkdtemp(join(tmpdir(), options.tempDirPrefix))
|
||||
const timeoutMs = options.timeoutMs ?? 25_000
|
||||
try {
|
||||
await options.prepare?.(cwd)
|
||||
const launch = resolveExampleLaunch({
|
||||
srcBin: options.binScript,
|
||||
configArgs: [options.configPath],
|
||||
configArgs: options.configArgs !== undefined
|
||||
? [...options.configArgs]
|
||||
/* v8 ignore next -- every caller passes configPath or configArgs; the fallback keeps the type total */
|
||||
: [options.configPath ?? './cordis.yml'],
|
||||
tsconfigPath: options.tsconfigPath,
|
||||
exposeInternals: true,
|
||||
env: {
|
||||
@@ -186,10 +204,12 @@ export async function runTuiPtySmoke(options: TuiPtySmokeOptions): Promise<strin
|
||||
...options.env,
|
||||
},
|
||||
})
|
||||
if (process.platform === 'win32') {
|
||||
return await runWindowsPtySmoke(launch, cwd, options, timeoutMs)
|
||||
}
|
||||
return await runPosixPtySmoke(launch, cwd, options, timeoutMs)
|
||||
const output = process.platform === 'win32'
|
||||
? await runWindowsPtySmoke(launch, cwd, options, timeoutMs)
|
||||
: await runPosixPtySmoke(launch, cwd, options, timeoutMs)
|
||||
// Inspect the workspace before `finally` removes it (e.g. the session log).
|
||||
await options.inspect?.(cwd)
|
||||
return output
|
||||
} finally {
|
||||
await rm(cwd, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
@@ -1,73 +1,63 @@
|
||||
terminal 100x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Use the bash tool to — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=27 bufferRow=27
|
||||
cursor hidden column=1 viewportRow=25 bufferRow=25
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Use the bash tool to"
|
||||
style 1-20 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Use the bash tool to │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-21 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Use the bash tool to run exactly: echo TERMINAL_OK. Then reply with the single word DONE and stop."
|
||||
6| "▌ Use the bash tool to run exactly: echo TERMINAL_OK. Then reply with the single word DONE and stop."
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ "
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
8| <blank>
|
||||
9| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
12| " The user wants me to run a simple bash command and then reply with \"DONE\". "
|
||||
10| " The user wants me to run a simple bash command and then reply with \"DONE\". "
|
||||
style 1-74 fg=bright-black italic
|
||||
13| <blank>
|
||||
14| "▌ "
|
||||
11| <blank>
|
||||
12| "▌ "
|
||||
style 0-0 fg=green
|
||||
15| "▌ ✓ echo TERMINAL_OK "
|
||||
13| "▌ ✓ echo TERMINAL_OK "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-19 bold
|
||||
16| "▌ Echo TERMINAL_OK to verify terminal access "
|
||||
14| "▌ Echo TERMINAL_OK to verify terminal access "
|
||||
style 0-0 fg=green
|
||||
style 2-43 fg=bright-black
|
||||
17| "▌ TERMINAL_OK "
|
||||
15| "▌ TERMINAL_OK "
|
||||
style 0-0 fg=green
|
||||
18| "▌ [exit 0] "
|
||||
16| "▌ [exit 0] "
|
||||
style 0-0 fg=green
|
||||
style 2-9 dim
|
||||
19| "▌ "
|
||||
17| "▌ "
|
||||
style 0-0 fg=green
|
||||
20| <blank>
|
||||
21| " Reasoning "
|
||||
18| <blank>
|
||||
19| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
22| " The command ran successfully and output \"TERMINAL_OK\". I should now reply with just \"DONE\". "
|
||||
20| " The command ran successfully and output \"TERMINAL_OK\". I should now reply with just \"DONE\". "
|
||||
style 1-91 fg=bright-black italic
|
||||
23| <blank>
|
||||
24| " Assistant "
|
||||
21| <blank>
|
||||
22| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
25| " DONE "
|
||||
23| " DONE "
|
||||
24| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
25| " "
|
||||
style 1-1 inverse
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
27| " "
|
||||
style 1-1 inverse
|
||||
28| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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>
|
||||
27| "deepseek-v4-flash /workspace/project ↑3.0k ↓115 cache 48% 3% contex"
|
||||
style 0-88 dim
|
||||
style 91-99 dim
|
||||
28-35| <blank>
|
||||
|
||||
@@ -1,79 +1,69 @@
|
||||
terminal 100x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Using ONE run_code program: call — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=29 bufferRow=29
|
||||
cursor hidden column=1 viewportRow=27 bufferRow=27
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Using ONE run_code program: call"
|
||||
style 1-32 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Using ONE run_code program: call │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-33 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Using ONE run_code program: call the bash tool twice — exactly echo CODE_ONE then exactly echo "
|
||||
6| "▌ Using ONE run_code program: call the bash tool twice — exactly echo CODE_ONE then exactly echo "
|
||||
style 0-0 fg=bright-blue
|
||||
style 65-77 fg=cyan
|
||||
style 92-99 fg=cyan
|
||||
9| "▌ CODE_TWO — and return the two outputs joined with a plus sign. Then reply with that joined string "
|
||||
7| "▌ CODE_TWO — and return the two outputs joined with a plus sign. Then reply with that joined string "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=cyan
|
||||
10| "▌ only and stop. "
|
||||
8| "▌ only and stop. "
|
||||
style 0-0 fg=bright-blue
|
||||
11| "▌ "
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
12| <blank>
|
||||
13| " Reasoning "
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
14| " The user wants a single run_code program that calls bash twice, then returns the two outputs "
|
||||
12| " The user wants a single run_code program that calls bash twice, then returns the two outputs "
|
||||
style 1-99 fg=bright-black italic
|
||||
15| " joined with a plus sign. Let me write this. "
|
||||
13| " joined with a plus sign. Let me write this. "
|
||||
style 1-43 fg=bright-black italic
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
14| <blank>
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ ✓ const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" }); "
|
||||
16| "▌ ✓ const out1 = await tools.bash({ command: \"echo CODE_ONE\", description: \"First echo\" }); "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-99 bold
|
||||
19| "▌ const o "
|
||||
17| "▌ const o "
|
||||
style 0-0 fg=green
|
||||
style 2-8 bold
|
||||
20| "▌ CODE_ONE+CODE_TWO "
|
||||
18| "▌ CODE_ONE+CODE_TWO "
|
||||
style 0-0 fg=green
|
||||
21| "▌ "
|
||||
19| "▌ "
|
||||
style 0-0 fg=green
|
||||
22| <blank>
|
||||
23| " Reasoning "
|
||||
20| <blank>
|
||||
21| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
24| " The output is exactly what the user asked for: CODE_ONE+CODE_TWO "
|
||||
22| " The output is exactly what the user asked for: CODE_ONE+CODE_TWO "
|
||||
style 1-64 fg=bright-black italic
|
||||
25| <blank>
|
||||
26| " Assistant "
|
||||
23| <blank>
|
||||
24| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
27| " CODE_ONE+CODE_TWO "
|
||||
25| " CODE_ONE+CODE_TWO "
|
||||
26| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
27| " "
|
||||
style 1-1 inverse
|
||||
28| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
29| " "
|
||||
style 1-1 inverse
|
||||
30| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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>
|
||||
29| "deepseek-v4-flash /workspace/project ↑3.1k ↓158 cache 50% 3% context tools:"
|
||||
style 0-79 dim
|
||||
style 82-99 dim
|
||||
30-35| <blank>
|
||||
|
||||
@@ -1,116 +1,106 @@
|
||||
terminal 100x36 buffer=normal length=50 base=14 viewport=14
|
||||
terminal 100x36 buffer=normal length=48 base=12 viewport=12
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Run this advanced flow exactly — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=47
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=45
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Run this advanced flow exactly"
|
||||
style 1-30 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Run this advanced flow exactly │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-31 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Run this advanced flow exactly once: mount a no-op Cordis plugin named snapshot-marker; use "
|
||||
6| "▌ Run this advanced flow exactly once: mount a no-op Cordis plugin named snapshot-marker; use "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ run_code to inspect the live dynamic mounts through tools.cordis_inspect; delegate once to a "
|
||||
7| "▌ run_code to inspect the live dynamic mounts through tools.cordis_inspect; delegate once to a "
|
||||
style 0-0 fg=bright-blue
|
||||
10| "▌ direct spawn child; run one workflow that delegates to another spawn child; unmount dyn-1; then "
|
||||
8| "▌ direct spawn child; run one workflow that delegates to another spawn child; unmount dyn-1; then "
|
||||
style 0-0 fg=bright-blue
|
||||
11| "▌ reply with exactly ADVANCED_ACP_OK. "
|
||||
9| "▌ reply with exactly ADVANCED_ACP_OK. "
|
||||
style 0-0 fg=bright-blue
|
||||
10| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
11| <blank>
|
||||
12| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
13| <blank>
|
||||
14| "▌ "
|
||||
style 0-0 fg=green
|
||||
15| "▌ ✓ Mount plugin into live cordis runtime "
|
||||
13| "▌ ✓ Mount plugin into live cordis runtime "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-40 bold
|
||||
16| "▌ mounted dyn-1 (plugin \"snapshot-marker\", state: active) "
|
||||
14| "▌ mounted dyn-1 (plugin \"snapshot-marker\", state: active) "
|
||||
style 0-0 fg=green
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| <blank>
|
||||
19| "▌ "
|
||||
style 0-0 fg=green
|
||||
20| "▌ ✓ return await tools.cordis_inspect({ what: 'dynamic' }) "
|
||||
18| "▌ ✓ return await tools.cordis_inspect({ what: 'dynamic' }) "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-57 bold
|
||||
21| "▌ ## dynamic "
|
||||
19| "▌ ## dynamic "
|
||||
style 0-0 fg=green
|
||||
22| "▌ - dyn-1: snapshot-marker [active] "
|
||||
20| "▌ - dyn-1: snapshot-marker [active] "
|
||||
style 0-0 fg=green
|
||||
21| "▌ "
|
||||
style 0-0 fg=green
|
||||
22| <blank>
|
||||
23| "▌ "
|
||||
style 0-0 fg=green
|
||||
24| <blank>
|
||||
25| "▌ "
|
||||
style 0-0 fg=green
|
||||
26| "▌ ✓ subagent "
|
||||
24| "▌ ✓ subagent "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-11 bold
|
||||
27| "▌ DIRECT_CHILD_OK "
|
||||
25| "▌ DIRECT_CHILD_OK "
|
||||
style 0-0 fg=green
|
||||
26| "▌ "
|
||||
style 0-0 fg=green
|
||||
27| <blank>
|
||||
28| "▌ "
|
||||
style 0-0 fg=green
|
||||
29| <blank>
|
||||
30| "▌ "
|
||||
style 0-0 fg=green
|
||||
31| "▌ ✓ workflow: advanced-acp-snapshot "
|
||||
29| "▌ ✓ workflow: advanced-acp-snapshot "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-34 bold
|
||||
32| "▌ workflow \"advanced-acp-snapshot\" completed (1 agent). "
|
||||
30| "▌ workflow \"advanced-acp-snapshot\" completed (1 agent). "
|
||||
style 0-0 fg=green
|
||||
33| "▌ Return value: "
|
||||
31| "▌ Return value: "
|
||||
style 0-0 fg=green
|
||||
34| "▌ { "
|
||||
32| "▌ { "
|
||||
style 0-0 fg=green
|
||||
35| "▌ \"reply\": \"WORKFLOW_CHILD_OK\" "
|
||||
33| "▌ \"reply\": \"WORKFLOW_CHILD_OK\" "
|
||||
style 0-0 fg=green
|
||||
36| "▌ } "
|
||||
34| "▌ } "
|
||||
style 0-0 fg=green
|
||||
35| "▌ "
|
||||
style 0-0 fg=green
|
||||
36| <blank>
|
||||
37| "▌ "
|
||||
style 0-0 fg=green
|
||||
38| <blank>
|
||||
39| "▌ "
|
||||
style 0-0 fg=green
|
||||
40| "▌ ✓ Unmount dyn-1 "
|
||||
38| "▌ ✓ Unmount dyn-1 "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-16 bold
|
||||
41| "▌ unmounted dyn-1 (plugin \"snapshot-marker\") "
|
||||
39| "▌ unmounted dyn-1 (plugin \"snapshot-marker\") "
|
||||
style 0-0 fg=green
|
||||
42| "▌ "
|
||||
40| "▌ "
|
||||
style 0-0 fg=green
|
||||
43| <blank>
|
||||
44| " Assistant "
|
||||
41| <blank>
|
||||
42| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
45| " ADVANCED_ACP_OK "
|
||||
43| " ADVANCED_ACP_OK "
|
||||
44| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
45| " "
|
||||
style 1-1 inverse
|
||||
46| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
47| " "
|
||||
style 1-1 inverse
|
||||
48| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
49| "/tmp/dsh-tui-snapshot-cordis-dyn ↑18 ↓18 8% context tools:compact deepseek-v4-flash(reasoning:on)"
|
||||
style 0-31 dim
|
||||
style 42-99 dim
|
||||
47| "deepseek-v4-flash /workspace/project ↑18 ↓18 cache 0% 8% cont"
|
||||
style 0-90 dim
|
||||
style 93-99 dim
|
||||
|
||||
@@ -1,106 +1,96 @@
|
||||
terminal 100x36 buffer=normal length=47 base=11 viewport=11
|
||||
terminal 100x36 buffer=normal length=45 base=9 viewport=9
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Use the workflow tool exactly — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=44
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=42
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Use the workflow tool exactly"
|
||||
style 1-29 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Use the workflow tool exactly │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-30 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Use the workflow tool exactly once, with args omitted, meta set to { \"name\": \"snapshot-flow\", "
|
||||
6| "▌ Use the workflow tool exactly once, with args omitted, meta set to { \"name\": \"snapshot-flow\", "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ \"description\": \"one child for the snapshot\" }, and this EXACT script body (copy it verbatim): "
|
||||
7| "▌ \"description\": \"one child for the snapshot\" }, and this EXACT script body (copy it verbatim): "
|
||||
style 0-0 fg=bright-blue
|
||||
10| "▌ phase('Run') "
|
||||
8| "▌ phase('Run') "
|
||||
style 0-0 fg=bright-blue
|
||||
11| "▌ const reply = await agent('Reply with exactly the word WF_CHILD_OK and nothing else.') "
|
||||
9| "▌ const reply = await agent('Reply with exactly the word WF_CHILD_OK and nothing else.') "
|
||||
style 0-0 fg=bright-blue
|
||||
12| "▌ return { reply } "
|
||||
10| "▌ return { reply } "
|
||||
style 0-0 fg=bright-blue
|
||||
13| "▌ After the workflow returns, reply with the single word WORKFLOW_DONE and stop. Do not use any "
|
||||
11| "▌ After the workflow returns, reply with the single word WORKFLOW_DONE and stop. Do not use any "
|
||||
style 0-0 fg=bright-blue
|
||||
14| "▌ other tool. "
|
||||
12| "▌ other tool. "
|
||||
style 0-0 fg=bright-blue
|
||||
15| "▌ "
|
||||
13| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
16| <blank>
|
||||
17| " Reasoning "
|
||||
14| <blank>
|
||||
15| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
18| " The user wants me to use the workflow tool exactly once with specific parameters. Let me carefully "
|
||||
16| " The user wants me to use the workflow tool exactly once with specific parameters. Let me carefully "
|
||||
style 1-99 fg=bright-black italic
|
||||
19| " follow the instructions: "
|
||||
17| " follow the instructions: "
|
||||
style 1-24 fg=bright-black italic
|
||||
20| " "
|
||||
21| " 1. args omitted (so I don't include it) "
|
||||
18| " "
|
||||
19| " 1. args omitted (so I don't include it) "
|
||||
style 1-3 fg=bright-blue
|
||||
style 4-39 fg=bright-black italic
|
||||
22| " 2. meta = { \"name\": \"snapshot-flow\", \"description\": \"one child for the snapshot\" } "
|
||||
20| " 2. meta = { \"name\": \"snapshot-flow\", \"description\": \"one child for the snapshot\" } "
|
||||
style 1-3 fg=bright-blue
|
||||
style 4-82 fg=bright-black italic
|
||||
23| " 3. script = as given verbatim "
|
||||
21| " 3. script = as given verbatim "
|
||||
style 1-3 fg=bright-blue
|
||||
style 4-29 fg=bright-black italic
|
||||
24| " 4. After it returns, reply with \"WORKFLOW_DONE\" "
|
||||
22| " 4. After it returns, reply with \"WORKFLOW_DONE\" "
|
||||
style 1-3 fg=bright-blue
|
||||
style 4-47 fg=bright-black italic
|
||||
25| " "
|
||||
26| " Let me do exactly that. "
|
||||
23| " "
|
||||
24| " Let me do exactly that. "
|
||||
style 1-23 fg=bright-black italic
|
||||
27| <blank>
|
||||
28| "▌ "
|
||||
25| <blank>
|
||||
26| "▌ "
|
||||
style 0-0 fg=green
|
||||
29| "▌ ✓ workflow: snapshot-flow "
|
||||
27| "▌ ✓ workflow: snapshot-flow "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-26 bold
|
||||
30| "▌ workflow \"snapshot-flow\" completed (1 agent). "
|
||||
28| "▌ workflow \"snapshot-flow\" completed (1 agent). "
|
||||
style 0-0 fg=green
|
||||
31| "▌ Return value: "
|
||||
29| "▌ Return value: "
|
||||
style 0-0 fg=green
|
||||
32| "▌ { "
|
||||
30| "▌ { "
|
||||
style 0-0 fg=green
|
||||
33| "▌ \"reply\": \"WF_CHILD_OK\" "
|
||||
31| "▌ \"reply\": \"WF_CHILD_OK\" "
|
||||
style 0-0 fg=green
|
||||
34| "▌ } "
|
||||
32| "▌ } "
|
||||
style 0-0 fg=green
|
||||
35| "▌ "
|
||||
33| "▌ "
|
||||
style 0-0 fg=green
|
||||
36| <blank>
|
||||
37| " Reasoning "
|
||||
34| <blank>
|
||||
35| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
38| " The workflow returned successfully with the reply \"WF_CHILD_OK\". Now I need to reply with exactly "
|
||||
36| " The workflow returned successfully with the reply \"WF_CHILD_OK\". Now I need to reply with exactly "
|
||||
style 1-99 fg=bright-black italic
|
||||
39| " \"WORKFLOW_DONE\" and stop. "
|
||||
37| " \"WORKFLOW_DONE\" and stop. "
|
||||
style 1-25 fg=bright-black italic
|
||||
40| <blank>
|
||||
41| " Assistant "
|
||||
38| <blank>
|
||||
39| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
42| " WORKFLOW_DONE "
|
||||
40| " WORKFLOW_DONE "
|
||||
41| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
42| " "
|
||||
style 1-1 inverse
|
||||
43| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
44| " "
|
||||
style 1-1 inverse
|
||||
45| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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
|
||||
44| "deepseek-v4-flash /workspace/project ↑3.5k ↓227 cache 47% 3% context "
|
||||
style 0-86 dim
|
||||
style 89-99 dim
|
||||
|
||||
@@ -3,23 +3,16 @@ lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Reply with exactly the word: — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=28 bufferRow=28
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Reply with exactly the word: │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-29 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Reply with exactly the word:"
|
||||
style 1-28 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| " Entering plan mode (applies from the next step). "
|
||||
style 1-48 fg=bright-black
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
@@ -64,7 +57,7 @@ buffer
|
||||
style 1-1 inverse
|
||||
29| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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
|
||||
30| "deepseek-v4-flash /workspace/project ↑2.9k ↓41 cache 49% 3% co"
|
||||
style 0-92 dim
|
||||
style 95-99 dim
|
||||
31-35| <blank>
|
||||
|
||||
@@ -1,91 +1,81 @@
|
||||
terminal 100x36 buffer=normal length=39 base=3 viewport=3
|
||||
terminal 100x36 buffer=normal length=37 base=1 viewport=1
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Use the read tool twice — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=36
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=34
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Use the read tool twice"
|
||||
style 1-23 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
2| "│ Use the read tool twice │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-24 fg=bright-black
|
||||
style 99-99 fg=bright-blue
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Use the read tool twice in the same assistant message: read a.txt and b.txt. Then reply DONE. "
|
||||
6| "▌ Use the read tool twice in the same assistant message: read a.txt and b.txt. Then reply DONE. "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
8| <blank>
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
10| <blank>
|
||||
11| "▌ "
|
||||
style 0-0 fg=green
|
||||
12| "▌ ✓ Read a.txt "
|
||||
10| "▌ ✓ Read a.txt "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-13 bold
|
||||
13| "▌ <path>/workspace/project/a.txt</path> "
|
||||
11| "▌ <path>/workspace/project/a.txt</path> "
|
||||
style 0-0 fg=green
|
||||
14| "▌ <type>file</type> "
|
||||
12| "▌ <type>file</type> "
|
||||
style 0-0 fg=green
|
||||
15| "▌ <content> "
|
||||
13| "▌ <content> "
|
||||
style 0-0 fg=green
|
||||
16| "▌ 1: alpha "
|
||||
14| "▌ 1: alpha "
|
||||
style 0-0 fg=green
|
||||
17| "▌ "
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ (End of file - total 1 lines) "
|
||||
16| "▌ (End of file - total 1 lines) "
|
||||
style 0-0 fg=green
|
||||
19| "▌ </content> "
|
||||
17| "▌ </content> "
|
||||
style 0-0 fg=green
|
||||
18| "▌ "
|
||||
style 0-0 fg=green
|
||||
19| <blank>
|
||||
20| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| <blank>
|
||||
22| "▌ "
|
||||
style 0-0 fg=green
|
||||
23| "▌ ✓ Read b.txt "
|
||||
21| "▌ ✓ Read b.txt "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-13 bold
|
||||
24| "▌ <path>/workspace/project/b.txt</path> "
|
||||
22| "▌ <path>/workspace/project/b.txt</path> "
|
||||
style 0-0 fg=green
|
||||
25| "▌ <type>file</type> "
|
||||
23| "▌ <type>file</type> "
|
||||
style 0-0 fg=green
|
||||
26| "▌ <content> "
|
||||
24| "▌ <content> "
|
||||
style 0-0 fg=green
|
||||
27| "▌ 1: beta "
|
||||
25| "▌ 1: beta "
|
||||
style 0-0 fg=green
|
||||
28| "▌ "
|
||||
26| "▌ "
|
||||
style 0-0 fg=green
|
||||
29| "▌ (End of file - total 1 lines) "
|
||||
27| "▌ (End of file - total 1 lines) "
|
||||
style 0-0 fg=green
|
||||
30| "▌ </content> "
|
||||
28| "▌ </content> "
|
||||
style 0-0 fg=green
|
||||
31| "▌ "
|
||||
29| "▌ "
|
||||
style 0-0 fg=green
|
||||
32| <blank>
|
||||
33| " Assistant "
|
||||
30| <blank>
|
||||
31| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
34| " DONE "
|
||||
32| " DONE "
|
||||
33| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
34| " "
|
||||
style 1-1 inverse
|
||||
35| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
36| " "
|
||||
style 1-1 inverse
|
||||
37| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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
|
||||
36| "deepseek-v4-flash /workspace/project ↑20 ↓6 cache 0% 3% context t"
|
||||
style 0-84 dim
|
||||
style 87-99 dim
|
||||
|
||||
@@ -1,81 +1,72 @@
|
||||
terminal 100x36 buffer=normal length=36 base=0 viewport=0
|
||||
lifecycle started=1 stopped=0 progress=inactive
|
||||
title "Use the todo_write tool to — DSH TUI snapshot"
|
||||
cursor hidden column=1 viewportRow=33 bufferRow=33
|
||||
cursor hidden column=1 viewportRow=31 bufferRow=31
|
||||
buffer
|
||||
0| "╭──────────────────────────────────────────────────────────────────────────────────────────────────╮"
|
||||
style 0-99 fg=bright-blue
|
||||
1| "│ DEEPSEEK HARNESS │"
|
||||
0| " DEEPSEEK HARNESS"
|
||||
style 1-8 fg=bright-blue bold
|
||||
style 10-16 bold
|
||||
1| " Use the todo_write tool to"
|
||||
style 1-26 fg=bright-black
|
||||
2| " deepseek-v4-flash • main-session"
|
||||
style 1-34 dim
|
||||
3| <blank>
|
||||
4| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-9 fg=bright-blue bold
|
||||
style 11-17 bold
|
||||
style 99-99 fg=bright-blue
|
||||
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
|
||||
3| "│ deepseek-v4-flash • main-session │"
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-35 dim
|
||||
style 99-99 fg=bright-blue
|
||||
4| "╰──────────────────────────────────────────────────────────────────────────────────────────────────╯"
|
||||
style 0-99 fg=bright-blue
|
||||
5| <blank>
|
||||
6| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
7| "▌ You "
|
||||
5| "▌ You "
|
||||
style 0-0 fg=bright-blue
|
||||
style 2-4 fg=bright-blue bold
|
||||
8| "▌ Use the todo_write tool to record a plan with exactly three todos: \"read the code\" (in_progress), "
|
||||
6| "▌ Use the todo_write tool to record a plan with exactly three todos: \"read the code\" (in_progress), "
|
||||
style 0-0 fg=bright-blue
|
||||
9| "▌ \"write the fix\" (pending), \"run the tests\" (pending). Send all three in one todo_write call. Then "
|
||||
7| "▌ \"write the fix\" (pending), \"run the tests\" (pending). Send all three in one todo_write call. Then "
|
||||
style 0-0 fg=bright-blue
|
||||
10| "▌ reply with the single word DONE and stop. "
|
||||
8| "▌ reply with the single word DONE and stop. "
|
||||
style 0-0 fg=bright-blue
|
||||
11| "▌ "
|
||||
9| "▌ "
|
||||
style 0-0 fg=bright-blue
|
||||
12| <blank>
|
||||
13| " Reasoning "
|
||||
10| <blank>
|
||||
11| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
14| " The user wants me to use the todo_write tool to record a plan with exactly three todos in the "
|
||||
12| " The user wants me to use the todo_write tool to record a plan with exactly three todos in the "
|
||||
style 1-99 fg=bright-black italic
|
||||
15| " specified statuses, then reply with \"DONE\". "
|
||||
13| " specified statuses, then reply with \"DONE\". "
|
||||
style 1-43 fg=bright-black italic
|
||||
16| <blank>
|
||||
17| "▌ "
|
||||
14| <blank>
|
||||
15| "▌ "
|
||||
style 0-0 fg=green
|
||||
18| "▌ ✓ Update todo list "
|
||||
16| "▌ ✓ Update todo list "
|
||||
style 0-0 fg=green
|
||||
style 2-2 fg=green bold
|
||||
style 3-19 bold
|
||||
19| "▌ Updated todo list: 2 pending, 1 in progress, 0 completed. "
|
||||
17| "▌ Updated todo list: 2 pending, 1 in progress, 0 completed. "
|
||||
style 0-0 fg=green
|
||||
20| "▌ "
|
||||
18| "▌ "
|
||||
style 0-0 fg=green
|
||||
21| <blank>
|
||||
22| " Reasoning "
|
||||
19| <blank>
|
||||
20| " Reasoning "
|
||||
style 1-9 fg=bright-black italic
|
||||
23| " The todos have been written successfully. Now I just need to reply with the single word \"DONE\". "
|
||||
21| " The todos have been written successfully. Now I just need to reply with the single word \"DONE\". "
|
||||
style 1-95 fg=bright-black italic
|
||||
24| <blank>
|
||||
25| " Assistant "
|
||||
22| <blank>
|
||||
23| " Assistant "
|
||||
style 1-9 fg=bright-magenta bold
|
||||
26| " DONE "
|
||||
27| <blank>
|
||||
28| "Plan"
|
||||
24| " DONE "
|
||||
25| <blank>
|
||||
26| "Plan"
|
||||
style 0-3 fg=bright-blue bold
|
||||
29| " ● read the code"
|
||||
27| " ● read the code"
|
||||
style 2-2 fg=yellow
|
||||
30| " ○ write the fix"
|
||||
28| " ○ write the fix"
|
||||
style 2-2 dim
|
||||
31| " ○ run the tests"
|
||||
29| " ○ run the tests"
|
||||
style 2-2 dim
|
||||
30| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
31| " "
|
||||
style 1-1 inverse
|
||||
32| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-99 dim
|
||||
33| " "
|
||||
style 1-1 inverse
|
||||
34| "────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
style 0-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
|
||||
33| "deepseek-v4-flash /workspace/project ↑3.1k ↓145 cache 47% 3% context tools:"
|
||||
style 0-79 dim
|
||||
style 82-99 dim
|
||||
34-35| <blank>
|
||||
|
||||
@@ -1,45 +1,118 @@
|
||||
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { LOADER_SMOKE_TEST_TIMEOUT_MS } from '@deepseek-ai/dsh-loader-smoke'
|
||||
import { runTuiPtySmoke } from './pty-harness.ts'
|
||||
import { runTuiPtySmoke, type TuiPtySmokeOptions } from './pty-harness.ts'
|
||||
|
||||
const binScript = fileURLToPath(new URL('../../../packages/examples/tui-demo/src/bin.ts', import.meta.url))
|
||||
const dshBinScript = fileURLToPath(new URL('../../../apps/cli/src/bin.ts', import.meta.url))
|
||||
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
||||
const codeModeConfigPath = fileURLToPath(new URL('../code-mode.cordis.yml', import.meta.url))
|
||||
const scriptedConfigPath = fileURLToPath(new URL('./fixtures/tui-scripted.cordis.yml', import.meta.url))
|
||||
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
|
||||
|
||||
/**
|
||||
* Seed the harness workspace: personal files land in the isolated Harness home
|
||||
* (`.dsh`), skill bundles under the agents home's `skills/` root — the same
|
||||
* trees `$DSH_HOME` / `$DSH_AGENTS_HOME` point the child at.
|
||||
*/
|
||||
function seedWorkspace(
|
||||
files: { personal?: Record<string, string>; skills?: Record<string, string> },
|
||||
): (cwd: string) => Promise<void> {
|
||||
return async (cwd) => {
|
||||
for (const [name, content] of Object.entries(files.personal ?? {})) {
|
||||
const file = join(cwd, '.dsh', name)
|
||||
await mkdir(dirname(file), { recursive: true })
|
||||
await writeFile(file, content)
|
||||
}
|
||||
for (const [name, content] of Object.entries(files.skills ?? {})) {
|
||||
const file = join(cwd, '.agents', 'skills', name)
|
||||
await mkdir(dirname(file), { recursive: true })
|
||||
await writeFile(file, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The rendered system prompt from the first `request/header` in the workspace's persisted session log. */
|
||||
async function readLoggedSystemPrompt(cwd: string): Promise<string> {
|
||||
const sessionsDir = join(cwd, '.sessions')
|
||||
const entries = await readdir(sessionsDir, { recursive: true })
|
||||
// A single keyless run writes one session log; the source section is global, so any log carries it.
|
||||
const logRelPath = entries.find(name => name.endsWith('.jsonl'))
|
||||
if (logRelPath === undefined) throw new Error(`no session log written under ${sessionsDir}`)
|
||||
const lines = (await readFile(join(sessionsDir, logRelPath), 'utf8')).split('\n').filter(Boolean)
|
||||
for (const line of lines) {
|
||||
const event = JSON.parse(line) as { type: string; data: { header?: { system?: string } } }
|
||||
if (event.type === 'request/header') return event.data.header?.system ?? ''
|
||||
}
|
||||
throw new Error(`session log ${logRelPath} has no request/header event`)
|
||||
}
|
||||
|
||||
/** Shared defaults: the keyless key, the tui-demo bin, and the live cordis.yml. */
|
||||
function smoke(overrides: Partial<TuiPtySmokeOptions> & { label: string }): Promise<string> {
|
||||
return runTuiPtySmoke({
|
||||
tempDirPrefix: 'tui-agent-smoke-',
|
||||
binScript,
|
||||
configPath,
|
||||
tsconfigPath,
|
||||
env: { DEEPSEEK_API_KEY: 'keyless-tui-no-call' },
|
||||
...overrides,
|
||||
})
|
||||
}
|
||||
|
||||
// The scripted conversation switches to the pro model first: the scripted
|
||||
// adapter proves routing + prompt variables by rejecting tool-ful calls on any
|
||||
// other route (see fixtures/tui-scripted-llm.ts).
|
||||
const SELECT_PRO_MODEL = [
|
||||
{ waitFor: 'scripted TUI ready.', send: '/model\r' },
|
||||
{ waitFor: 'Select model', send: '\x1b[B\r' },
|
||||
] as const
|
||||
|
||||
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 () => {
|
||||
const output = await runTuiPtySmoke({
|
||||
it('boots pi-tui, sweeps the borderless banner in, enters plan mode, and restores the terminal', async () => {
|
||||
// With no configured welcome the borderless banner sweeps in left-to-right;
|
||||
// the detail line's session id (`main-session-<uuid>`) renders only once
|
||||
// the sweep reaches it, so it marks a settled banner.
|
||||
const output = await smoke({
|
||||
label: 'tui-agent boot',
|
||||
tempDirPrefix: 'tui-agent-smoke-',
|
||||
binScript,
|
||||
configPath,
|
||||
tsconfigPath,
|
||||
env: { DEEPSEEK_API_KEY: 'keyless-tui-no-call' },
|
||||
actions: [{ waitFor: 'TUI agent ready.', send: '/exit\r' }],
|
||||
actions: [
|
||||
{ waitFor: 'main-session-', 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('HARNESS')
|
||||
expect(output).toContain('main-session-')
|
||||
expect(output).toContain('Entering plan mode (applies from the next step).')
|
||||
// Borderless: no box-drawing frame around the banner.
|
||||
expect(output).not.toContain('╭')
|
||||
expect(output).not.toContain('╮')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('switches models, streams a response, answers a user-question dialog, and exits cleanly', async () => {
|
||||
const output = await runTuiPtySmoke({
|
||||
const output = await smoke({
|
||||
label: 'tui-agent conversation',
|
||||
tempDirPrefix: 'tui-agent-conversation-',
|
||||
binScript,
|
||||
configPath: scriptedConfigPath,
|
||||
tsconfigPath,
|
||||
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' },
|
||||
...SELECT_PRO_MODEL,
|
||||
{ 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' },
|
||||
{ waitFor: 'Decision received. Scripted TUI run complete.', send: '' },
|
||||
// Session title: the first user message drives the first-message-llm
|
||||
// provider's tool-less title call; the scripted adapter answers it, the
|
||||
// accepted title lands in the log, and the TUI renders the terminal
|
||||
// window title as `<session title> — <configured title>` via OSC 0.
|
||||
// Gating /status on it keeps the assertion race-free; the diagnostics
|
||||
// card is then exercised through the same real Loader/PTY composition.
|
||||
{ waitFor: 'scripted session title — DeepSeek Harness', send: '/status\r' },
|
||||
{ waitFor: 'Session status', 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`)
|
||||
@@ -47,16 +120,68 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
||||
expect(output).not.toContain('\u001B[999CMODEL_CURSOR')
|
||||
expect(output).not.toContain('\u009B31mMODEL_C1')
|
||||
expect(output).toContain('Safe')
|
||||
expect(output).toContain('\u001B]0;scripted session title — DeepSeek Harness\u0007')
|
||||
expect(output).toContain('Session status')
|
||||
expect(output).toContain('Title')
|
||||
expect(output).toContain('scripted session title')
|
||||
expect(output).toContain('Model')
|
||||
expect(output).toContain('tui-scripted/tui-scripted-model-pro')
|
||||
expect(output).toContain('KV cache')
|
||||
expect(output).toContain('Context')
|
||||
expect(output).toContain('128,000')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('loads a local skill via /skill: and delivers its body to the model as a user turn', async () => {
|
||||
// The whole manual-invocation path in one keyless boot: `ctx.get('skills')`
|
||||
// resolves in the shipped tree, the client-side `/skill:` command parses,
|
||||
// the local provider loads `scripted-skill` from the agents home, and the
|
||||
// rendered `<skill name="…">` block reaches the model — proven by the
|
||||
// scripted adapter echoing the fixture's body marker only when it arrives.
|
||||
const output = await smoke({
|
||||
label: 'tui-agent skill',
|
||||
tempDirPrefix: 'tui-agent-skill-',
|
||||
configPath: scriptedConfigPath,
|
||||
prepare: seedWorkspace({
|
||||
skills: {
|
||||
'scripted-skill/SKILL.md': [
|
||||
'---',
|
||||
'name: scripted-skill',
|
||||
'description: Keyless PTY proof that the skill command loads a local skill into the conversation.',
|
||||
'---',
|
||||
'',
|
||||
'SCRIPTED SKILL BODY MARKER',
|
||||
'',
|
||||
].join('\n'),
|
||||
},
|
||||
}),
|
||||
actions: [
|
||||
...SELECT_PRO_MODEL,
|
||||
{ waitFor: 'Model selected: tui-scripted/tui-scripted-model-pro.', send: '/skill:scripted-skill\r' },
|
||||
{ waitFor: 'Scripted skill body received.', send: '/exit\r' },
|
||||
],
|
||||
})
|
||||
expect(output).toContain('Scripted skill body received.')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('boots the Code Mode overlay tree, renders its banner, and exits cleanly', async () => {
|
||||
// The overlay's only keyless composition proof: the include+patch tree,
|
||||
// worker code runtime, and one-tool registry all mount before the banner.
|
||||
const output = await smoke({
|
||||
label: 'tui-agent code mode',
|
||||
tempDirPrefix: 'tui-agent-code-mode-',
|
||||
configPath: codeModeConfigPath,
|
||||
actions: [{ waitFor: 'TUI Code Mode ready.', send: '/exit\r' }],
|
||||
})
|
||||
expect(output).toContain('TUI Code Mode ready.')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('prints a config-resume failure and exits instead of leaving a blank terminal', async () => {
|
||||
const output = await runTuiPtySmoke({
|
||||
const output = await smoke({
|
||||
label: 'tui-agent resume failure',
|
||||
tempDirPrefix: 'tui-agent-resume-',
|
||||
binScript,
|
||||
configPath,
|
||||
tsconfigPath,
|
||||
env: {
|
||||
DEEPSEEK_API_KEY: 'keyless-tui-no-call',
|
||||
RESUME_SESSION_ID: 'missing-session',
|
||||
@@ -66,3 +191,98 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
||||
expect(output).toContain('ui-tui: session "missing-session" failed to start:')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
})
|
||||
|
||||
describe('dsh CLI keyless smoke (apps/cli through the same PTY)', () => {
|
||||
it('boots the shipped default config with no arguments and no personal overlay', async () => {
|
||||
const output = await smoke({
|
||||
label: 'dsh default boot',
|
||||
tempDirPrefix: 'dsh-default-boot-',
|
||||
binScript: dshBinScript,
|
||||
configArgs: [],
|
||||
actions: [{ waitFor: 'main-session-', send: '/exit\r' }],
|
||||
})
|
||||
expect(output).toContain('DEEPSEEK')
|
||||
expect(output).toContain('main-session-')
|
||||
expect(output).not.toContain('╭')
|
||||
expect(output).not.toContain('╮')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('applies the personal overlay: config.yaml patches the tree and .env feeds its !!js', async () => {
|
||||
// The whole personal-config chain in one boot: the personal .env supplies
|
||||
// the variable, config.yaml patches the tui-agent entry with a `!!js`
|
||||
// reference to it, and the banner renders the patched welcome verbatim.
|
||||
const output = await smoke({
|
||||
label: 'dsh personal overlay',
|
||||
tempDirPrefix: 'dsh-personal-overlay-',
|
||||
binScript: dshBinScript,
|
||||
configArgs: [],
|
||||
prepare: seedWorkspace({
|
||||
personal: {
|
||||
'.env': 'DSH_PERSONAL_WELCOME=PERSONAL OVERLAY READY.\n',
|
||||
'config.yaml': [
|
||||
'- id: tui-agent',
|
||||
" name: '@deepseek-ai/dsh-tui-demo'",
|
||||
' config:',
|
||||
' provider: deepseek',
|
||||
' model: deepseek-v4-flash',
|
||||
' workspaceContext: false',
|
||||
' welcome: !!js process.env.DSH_PERSONAL_WELCOME',
|
||||
'',
|
||||
].join('\n'),
|
||||
},
|
||||
}),
|
||||
actions: [{ waitFor: 'PERSONAL OVERLAY READY.', send: '/exit\r' }],
|
||||
})
|
||||
expect(output).toContain('PERSONAL OVERLAY READY.')
|
||||
expect(output).toContain('\u001B[?2004l')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('fails loud instead of booting when the personal config.yaml is invalid', async () => {
|
||||
const output = await smoke({
|
||||
label: 'dsh invalid personal config',
|
||||
tempDirPrefix: 'dsh-invalid-personal-',
|
||||
binScript: dshBinScript,
|
||||
configArgs: [],
|
||||
prepare: seedWorkspace({ personal: { 'config.yaml': 'id: not-a-list\n' } }),
|
||||
expectedExitCode: 1,
|
||||
})
|
||||
expect(output).toContain('must be a top-level YAML array of loader patch entries')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('routes the --resume flag into the config resume intake, failing loud on a missing id', async () => {
|
||||
// The flag path end to end: apps/cli parses `--resume missing-session` and
|
||||
// sets RESUME_SESSION_ID, the shipped config's `!!js` reads it, and the
|
||||
// resume fails loud — proving the printed `dsh --resume <id>` hint reaches
|
||||
// the same intake as the env var.
|
||||
const output = await smoke({
|
||||
label: 'dsh resume flag failure',
|
||||
tempDirPrefix: 'dsh-resume-flag-',
|
||||
binScript: dshBinScript,
|
||||
configArgs: ['--resume', 'missing-session'],
|
||||
expectedExitCode: 1,
|
||||
})
|
||||
expect(output).toContain('ui-tui: session "missing-session" failed to start:')
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
|
||||
it('tells the model where its own source lives, in the system prompt it sends', async () => {
|
||||
// The launcher resolves the checkout root three hops up from apps/cli/{src,lib};
|
||||
// this test file sits an equal depth under the same root, so the same hop applies.
|
||||
const sourceRoot = fileURLToPath(new URL('../../..', import.meta.url))
|
||||
let loggedSystem = ''
|
||||
await smoke({
|
||||
label: 'dsh source-path prompt',
|
||||
tempDirPrefix: 'dsh-source-path-',
|
||||
binScript: dshBinScript,
|
||||
configArgs: [scriptedConfigPath],
|
||||
actions: [
|
||||
...SELECT_PRO_MODEL,
|
||||
{ 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' },
|
||||
],
|
||||
inspect: async (cwd) => { loggedSystem = await readLoggedSystemPrompt(cwd) },
|
||||
})
|
||||
expect(loggedSystem).toContain(`Your own source code is the checkout at ${sourceRoot}; you can read it there to learn how dsh works and how to extend it.`)
|
||||
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
|
||||
})
|
||||
|
||||
@@ -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,8 +46,15 @@ interface Scenario {
|
||||
expectedTools: string[]
|
||||
expectedEventCounts?: Record<string, number>
|
||||
childSessions?: number
|
||||
enterPlanMode?: boolean
|
||||
recorded: boolean
|
||||
seedWorkspace?: boolean
|
||||
/**
|
||||
* Load the opt-in `todo_write` tool for this scenario. The shipped tui-agent
|
||||
* config omits it, so only the todo-plan scenario (the enabled-path proof)
|
||||
* mounts it; the rest cover the default, todo-free composition.
|
||||
*/
|
||||
enableTodo?: boolean
|
||||
}
|
||||
|
||||
const SCENARIOS: Scenario[] = [
|
||||
@@ -54,6 +62,8 @@ const SCENARIOS: Scenario[] = [
|
||||
name: 'multi-turn-conversation',
|
||||
composition: 'native',
|
||||
expectedTools: [],
|
||||
expectedEventCounts: { 'plan/mode': 1 },
|
||||
enterPlanMode: true,
|
||||
recorded: true,
|
||||
},
|
||||
{
|
||||
@@ -62,6 +72,7 @@ const SCENARIOS: Scenario[] = [
|
||||
expectedTools: ['todo_write'],
|
||||
expectedEventCounts: { 'todo/write': 1 },
|
||||
recorded: true,
|
||||
enableTodo: true,
|
||||
},
|
||||
{
|
||||
name: 'bash-terminal-card',
|
||||
@@ -196,7 +207,9 @@ async function mountScenarioContext(
|
||||
await ctx.plugin(FsPolicy)
|
||||
await ctx.plugin(ToolFs)
|
||||
await ctx.plugin(UserInteractionService)
|
||||
await ctx.plugin(ToolTodo)
|
||||
// todo_write is opt-in: only the todo-plan scenario mounts it, matching the shipped
|
||||
// config that omits it. The other scenarios prove the default todo-free composition.
|
||||
if (scenario.enableTodo === true) await ctx.plugin(ToolTodo)
|
||||
await ctx.plugin(SubagentService)
|
||||
await ctx.plugin(SubagentSpawn, { providerName: 'spawn' })
|
||||
await ctx.plugin(ToolSubagent, { provider: 'spawn', toolName: 'subagent', enableRunInBackground: false })
|
||||
@@ -204,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, {})
|
||||
}
|
||||
@@ -268,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()
|
||||
@@ -280,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') {
|
||||
|
||||
Reference in New Issue
Block a user