refactor(cli)!: complete app-owned profile startup

This commit is contained in:
Turtle
2026-08-10 23:45:04 +08:00
parent 7e3a82eacc
commit d4ccfbd80f
97 changed files with 260 additions and 224 deletions
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write examples/headless-agent/README.md
README.md: f12a56920c79f3a7e257c4e56163f323e4312d11
README.zh.md: 9e409735f03afc62cd788fa2a5d1afdef0fa6c2a
README.md: 08b36e9c8e558db3b30175b20bd6e0af160ccef5
README.zh.md: 40d11ebeeb1631af1421b3c013a5e548fd3fd488
+2 -2
View File
@@ -10,10 +10,10 @@ This directory owns the replay and real-model test composition for a headless co
# repo root .env (gitignored) or exported env:
# DEEPSEEK_API_KEY=sk-…
# DEEPSEEK_BASE_URL=https://… # optional; defaults to the public API
pnpm run dsh run "fix the failing test in this workspace"
pnpm run dsh --profile headless "fix the failing test in this workspace"
```
The product command is [`dsh run`](../../apps/cli/README.md): it accepts one nonblank task, creates and persists a fresh session, prints the final assistant text, and exits. The root `demo:headless` script is only an alias of that command.
The product command is [`dsh --profile headless`](../../apps/cli/README.md): it accepts one nonblank task, creates and persists a fresh session, prints the final assistant text, and exits. The root `demo:headless` script is only an alias of that command.
Snapshot suites run this directory's configuration through [`tests/fixtures/headless-driver.ts`](tests/fixtures/headless-driver.ts), an unexported test-only process that emits canonical session events as JSONL before its result record. That stream is test infrastructure, not a supported CLI output format. Child sessions surface only through parent tool events and results.
+2 -2
View File
@@ -10,10 +10,10 @@
# repo root .env (gitignored) or exported env:
# DEEPSEEK_API_KEY=sk-…
# DEEPSEEK_BASE_URL=https://… # optional; defaults to the public API
pnpm run dsh run "fix the failing test in this workspace"
pnpm run dsh --profile headless "fix the failing test in this workspace"
```
产品命令是 [`dsh run`](../../apps/cli/README.md):它接受一项非空任务,创建并持久化新会话,打印最终 assistant 文本,然后退出。根目录的 `demo:headless` 脚本只是该命令的别名。
产品命令是 [`dsh --profile headless`](../../apps/cli/README.md):它接受一项非空任务,创建并持久化新会话,打印最终 assistant 文本,然后退出。根目录的 `demo:headless` 脚本只是该命令的别名。
快照套件通过 [`tests/fixtures/headless-driver.ts`](tests/fixtures/headless-driver.ts) 运行本目录的配置。这个未导出且仅供测试使用的进程会在结果记录之前,以 JSONL 发出规范会话事件。该事件流属于测试基础设施,不是受支持的 CLI(命令行界面)输出格式。子会话只通过父会话的工具事件和结果对外显示。
@@ -52,9 +52,9 @@ const dshBinScript = fileURLToPath(new URL('../../../apps/cli/src/bin.ts', impor
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const reasoningConfigPath = fileURLToPath(new URL('./fixtures/cli.cordis.yml', import.meta.url))
const deepseekDefaultsConfigPath = fileURLToPath(new URL('./fixtures/deepseek-defaults.cordis.yml', import.meta.url))
const dshRunOverlayPath = fileURLToPath(new URL('./fixtures/dsh-run.cordis.yml', import.meta.url))
const dshRunSessionExpected = join(snapshotsDir, 'dsh-run', 'session.expected.jsonl')
const dshRunFailureExpected = join(snapshotsDir, 'dsh-run', 'stderr.expected.txt')
const headlessOverlayPath = fileURLToPath(new URL('./fixtures/headless-profile.cordis.yml', import.meta.url))
const headlessSessionExpected = join(snapshotsDir, 'headless-profile', 'session.expected.jsonl')
const headlessFailureExpected = join(snapshotsDir, 'headless-profile', 'stderr.expected.txt')
const cliMockLlmPluginPath = fileURLToPath(new URL('./fixtures/cli-mock-llm.ts', import.meta.url))
const refreshing = process.env.DSH_SNAPSHOT === 'refresh'
@@ -217,14 +217,14 @@ async function prepareCliMockFixture(cwd: string): Promise<void> {
}
describe('headless stream-json snapshots', () => {
it('runs one task through the product dsh run command', async () => {
const task = 'Prove the product dsh run path with one real tool round trip.'
it('runs one task through the product headless profile command', async () => {
const task = 'Prove the product headless profile path with one real tool round trip.'
const result = await runLoaderSmoke({
label: 'product dsh run snapshot',
tempDirPrefix: 'headless-snapshot-dsh-run-',
label: 'product headless profile snapshot',
tempDirPrefix: 'headless-snapshot-profile-',
binScript: dshBinScript,
configPath: dshRunOverlayPath,
binArgs: ['run', '--patch', dshRunOverlayPath, task],
configPath: headlessOverlayPath,
binArgs: ['--profile', 'headless', '--patch', headlessOverlayPath, task],
tsconfigPath,
env: {
DSH_PERMISSION_MODE: 'danger-full-access',
@@ -236,11 +236,11 @@ describe('headless stream-json snapshots', () => {
const logs = await persistedLogs(cwd, join(cwd, '.dsh', 'sessions'))
expect(logs).toHaveLength(1)
const actual = logs[0]
if (actual === undefined) throw new Error('dsh run did not persist its session')
if (actual === undefined) throw new Error('the headless profile did not persist its session')
const context = contextFromLogs([actual.content])
const session = scrubRequestHeaders(normalizeSessionLog(actual.content, context))
if (refreshing) await writeFile(dshRunSessionExpected, session)
expect(session).toBe(await readFile(dshRunSessionExpected, 'utf8'))
if (refreshing) await writeFile(headlessSessionExpected, session)
expect(session).toBe(await readFile(headlessSessionExpected, 'utf8'))
expect(session).toContain(task)
expect(session).toContain('CLI tool round trip complete: CLI_TOOL_ROUND_TRIP')
},
@@ -250,13 +250,13 @@ describe('headless stream-json snapshots', () => {
expect(result.stderr).toBe('')
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
it('prints a terminal model failure through the product dsh run command', async () => {
it('prints a terminal model failure through the product headless profile command', async () => {
const result = await runLoaderSmoke({
label: 'product dsh run model failure snapshot',
tempDirPrefix: 'headless-snapshot-dsh-run-failure-',
label: 'product headless profile model failure snapshot',
tempDirPrefix: 'headless-snapshot-profile-failure-',
binScript: dshBinScript,
configPath: dshRunOverlayPath,
binArgs: ['run', '--patch', dshRunOverlayPath, 'Trigger the keyless model failure.'],
configPath: headlessOverlayPath,
binArgs: ['--profile', 'headless', '--patch', headlessOverlayPath, 'Trigger the keyless model failure.'],
tsconfigPath,
expectedExitCode: 1,
env: {
@@ -268,7 +268,7 @@ describe('headless stream-json snapshots', () => {
})
expect(result.stdout).toBe('\n')
await expect(result.stderr).toMatchFileSnapshot(dshRunFailureExpected)
await expect(result.stderr).toMatchFileSnapshot(headlessFailureExpected)
}, LOADER_SMOKE_TEST_TIMEOUT_MS)
it('prints the original Loader activation error through the assembled one-shot app', async () => {
@@ -2,16 +2,16 @@
{"type":"permission/preset","seq":0,"time":0,"data":{"preset":"danger-full-access"}}
{"type":"sandbox/mode","seq":1,"time":0,"data":{"mode":"danger-full-access"}}
{"type":"approval/policy","seq":2,"time":0,"data":{"policy":"never"}}
{"type":"agent/inbox/spliced","seq":3,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Prove the product dsh run path with one real tool round trip."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}
{"type":"agent/inbox/spliced","seq":3,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Prove the product headless profile path with one real tool round trip."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}
{"type":"turn/start","seq":4,"time":0,"data":{"turn":1}}
{"type":"agent/inbox/spliced","seq":5,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}
{"type":"user/message","seq":7,"time":0,"data":{"content":[{"type":"text","text":"Prove the product dsh run path with one real tool round trip."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"user/message","seq":7,"time":0,"data":{"content":[{"type":"text","text":"Prove the product headless profile path with one real tool round trip."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}
{"type":"session/title","seq":9,"time":0,"data":{"title":"Prove the product dsh run","messageSeqs":[7],"source":{"kind":"fallback"}}}
{"type":"session/title","seq":9,"time":0,"data":{"title":"Prove the product headless profile","messageSeqs":[7],"source":{"kind":"fallback"}}}
{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"cli-mock","model":"cli-mock","reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
{"type":"request/context","seq":11,"time":0,"data":{"provider":"cli-mock","model":"cli-mock"}}
{"type":"session/title-llm-request","seq":12,"time":0,"data":{"titleProvider":"session-title-first-message-llm","messageSeqs":[7],"route":{"provider":"cli-mock","model":"cli-mock"},"system":"Create a concise title for an AI coding-assistant session from the supplied human messages.\nReturn only the title on one line, **in plain text of natural language**, with no quotes, prefix, explanation, Markdown, XML, or terminal control codes. No code is allowed.\nUse the language of the messages.\nAim for about 5 words in non-CJK languages or 10 CJK characters.","messages":[{"content":[{"type":"text","text":"Generate the session title from this JSON array of human messages:\n[{\"seq\":7,\"text\":\"Prove the product dsh run path with one real tool round trip.\"}]"}],"source":{"kind":"plugin","plugin":"dsh-session-title-llm"},"role":"user","id":"{{sessionId}}"}],"maxTokens":64}}
{"type":"session/title-llm-request","seq":12,"time":0,"data":{"titleProvider":"session-title-first-message-llm","messageSeqs":[7],"route":{"provider":"cli-mock","model":"cli-mock"},"system":"Create a concise title for an AI coding-assistant session from the supplied human messages.\nReturn only the title on one line, **in plain text of natural language**, with no quotes, prefix, explanation, Markdown, XML, or terminal control codes. No code is allowed.\nUse the language of the messages.\nAim for about 5 words in non-CJK languages or 10 CJK characters.","messages":[{"content":[{"type":"text","text":"Generate the session title from this JSON array of human messages:\n[{\"seq\":7,\"text\":\"Prove the product headless profile path with one real tool round trip.\"}]"}],"source":{"kind":"plugin","plugin":"dsh-session-title-llm"},"role":"user","id":"{{sessionId}}"}],"maxTokens":64}}
{"type":"assistant/chunk","seq":13,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
{"type":"assistant/chunk","seq":14,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"cli-smoke-call","name":"bash","argumentsDelta":"{\"command\":\"printf CLI_TOOL_ROUND_TRIP\",\"description\":\"Prove the CLI tool round trip.\"}"}}}
{"type":"assistant/chunk","seq":15,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"cli-smoke-call","name":"bash","arguments":"{\"command\":\"printf CLI_TOOL_ROUND_TRIP\",\"description\":\"Prove the CLI tool round trip.\"}"}}}}