cleanup(cli): remove dsh-cli-demo

This commit is contained in:
Tianyi Cui
2026-08-08 03:08:37 +08:00
parent bdd2f49df7
commit dc57f7d854
90 changed files with 539 additions and 2238 deletions

View File

@@ -34,12 +34,22 @@
# budget, so the local numeric default cannot apply here.
maxDepth: 'provider-managed'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: mock
model: mock-delegate
agents:
- id: main
provider: mock
model: mock-delegate
cwd: !!js process.cwd()
persona: 'Test ACP subagent cwd inheritance.'
persistenceRoot: './.sessions'
persistenceCompression: 'none'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: 'none'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -2,14 +2,14 @@
/** Test driver: one delegation turn through a headless Loader composition. */
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts'
import { runFixtureTurn } from '../../../../../headless-agent/tests/fixtures/one-shot.ts'
const configPath = process.argv[2]
if (configPath === undefined) throw new Error('acp-subagent cwd driver requires a config path')
const ctx = await boot('acp-subagent-cwd-e2e', resolveConfigPath(configPath, undefined))
try {
await runOneShot(ctx, { task: 'delegate' })
await runFixtureTurn(ctx, { task: 'delegate' })
} finally {
await ctx.fiber.dispose()
}

View File

@@ -31,10 +31,21 @@
enableRunInBackground: false
maxDepth: 'provider-managed'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: mock
model: mock-delegate
agents:
- id: main
provider: mock
model: mock-delegate
cwd: !!js process.cwd()
persona: 'This composition test must not start a model turn.'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -20,10 +20,21 @@
enableRunInBackground: false
maxDepth: 'provider-managed'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: mock
model: mock-delegate
agents:
- id: main
provider: mock
model: mock-delegate
cwd: !!js process.cwd()
persona: 'This composition test must not start a model turn.'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

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: 670a91ab402cf98585f2ece70787beb3b4aaf4dc
README.zh.md: 6c8b3b5694403c5e09f2904f5c3ca18fe569163e
README.md: e00f3d2d4fd21a860239f3d3a3e5eb2d7520f14a
README.zh.md: 6cd845783b1c112ba73676474b176ec28a4d0b78

View File

@@ -2,7 +2,7 @@
English | [中文](README.zh.md)
Headless one-shot agent wiring: DeepSeek V4 + local bash and filesystem tools + subagent delegation + workflows and fresh-agent Ralph iteration + `todo_write` + JSONL persistence, with [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo) as the app front door.
This directory owns the replay and real-model test composition for a headless coding agent: DeepSeek V4 + local bash and filesystem tools + subagent delegation + workflows and fresh-agent Ralph iteration + `todo_write` + JSONL persistence. It explicitly mounts the shared agent spine, one root agent, persistence, and checkpoint policy; it is not a second product front door.
## Run it
@@ -10,17 +10,13 @@ Headless one-shot agent wiring: DeepSeek V4 + local bash and filesystem tools +
# repo root .env (gitignored) or exported env:
# DEEPSEEK_API_KEY=sk-…
# DEEPSEEK_BASE_URL=https://… # optional; defaults to the public API
pnpm run demo:headless "fix the failing test in this workspace"
pnpm run demo:headless --output-format json -- "summarize the implementation"
pnpm run demo:headless --output-format stream-json -- "run the focused tests"
pnpm run dsh run "fix the failing test in this workspace"
```
Exactly one nonblank positional task is required; quote tasks containing spaces. There is no `-p` flag. `text` prints the last text-bearing assistant message, `json` prints one DSH-native result record, and `stream-json` emits the top-level session's canonical task-turn events before that record. Child sessions surface only through parent tool events and results.
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.
Each invocation creates and persists a fresh session, runs all model and tool steps in one turn, flushes, disposes, and exits. This is non-interactive automation: there is no prompt, approval, resume, second turn, or stdin context. The configured tools can mutate the launch workspace, run commands, spawn child agents, and consume provider tokens.
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.
## Advanced configuration
[`advanced.cordis.yml`](advanced.cordis.yml) adds Code Mode and the Cordis tools to the shipped leaf.
The package-level [CLI contract](../../packages/examples/cli-demo/README.md) documents output records, exit status, cancellation, persistence, and model/token effects.
[`advanced.cordis.yml`](advanced.cordis.yml) adds Code Mode and the Cordis tools to the test composition.

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
无头单次 agent智能体接线DeepSeek V4 + 本地 bash 与文件系统工具 + subagent 委托 + 工作流与全新 agent Ralph 迭代 + `todo_write` + JSONL 持久化,并以 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo) 作为应用入口。
本目录负责 headless coding agent智能体的回放和真实模型测试组装DeepSeek V4 + 本地 bash 与文件系统工具 + subagent 委托 + 工作流与全新 agent Ralph 迭代 + `todo_write` + JSONL 持久化。本目录显式挂载共享 agent 主干、一个根 agent、持久化和检查点策略它不是第二个产品入口。
## 运行
@@ -10,17 +10,13 @@
# repo root .env (gitignored) or exported env:
# DEEPSEEK_API_KEY=sk-…
# DEEPSEEK_BASE_URL=https://… # optional; defaults to the public API
pnpm run demo:headless "fix the failing test in this workspace"
pnpm run demo:headless --output-format json -- "summarize the implementation"
pnpm run demo:headless --output-format stream-json -- "run the focused tests"
pnpm run dsh run "fix the failing test in this workspace"
```
必须提供一个且仅一个非空任务位置参数;含空格的任务需要加引号。没有 `-p` 标志。`text` 打印最后一条包含文本的 assistant 消息,`json` 打印一条 DSH 原生结果记录,`stream-json` 则在该记录之前发出顶层会话的规范任务轮次事件。子会话只通过父会话的工具事件和结果对外显示
产品命令是 [`dsh run`](../../apps/cli/README.md):它接受一项非空任务,创建并持久化新会话,打印最终 assistant 文本,然后退出。根目录的 `demo:headless` 脚本只是该命令的别名
每次调用都会创建并持久化新会话,在一个轮次中运行所有模型和工具步骤,然后刷写持久化数据、执行 dispose资源释放再退出。这是非交互式自动化没有提示符、批准、恢复、第二轮次或 stdin 上下文。已配置工具可以修改启动时所在的工作区、运行命令、spawn 子 agent并消耗提供方 token
快照套件通过 [`tests/fixtures/headless-driver.ts`](tests/fixtures/headless-driver.ts) 运行本目录的配置。这个未导出且仅供测试使用的进程会在结果记录之前,以 JSONL 发出规范会话事件。该事件流属于测试基础设施,不是受支持的 CLI命令行界面输出格式。子会话只通过父会话的工具事件和结果对外显示
## 高级配置
[`advanced.cordis.yml`](advanced.cordis.yml) 在已交付叶节点上添加 Code Mode 和 Cordis 工具。
这份包级 [CLI命令行界面契约](../../packages/examples/cli-demo/README.md) 说明输出记录、退出状态、取消、持久化以及模型token 影响。
[`advanced.cordis.yml`](advanced.cordis.yml) 在测试组装中添加 Code Mode 和 Cordis 工具。

View File

@@ -1,6 +1,6 @@
# Replay counterpart to advanced.cordis.yml. It includes the base `cordis.yml`
# directly — a config patch cannot target an entry behind a nested include — and
# restates advanced.cordis.yml's overlay (the cli-agent config plus the
# restates advanced.cordis.yml's overlay (the agent and persistence configs plus the
# code-runtime and tool-cordis inserts) so the whole app config lives in one patch.
# It re-pins `deepseek-v4-flash`: `cordis.yml` ships `deepseek-v4-pro`, but the
# recorded corpus (request headers, provenance) was captured on flash, so replay
@@ -15,15 +15,14 @@
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: deepseek-official
model: deepseek-v4-flash
persistenceRoot: './.sessions'
# Replay fixtures are raw JSONL; the whole-config patch must restate
# the compression choice or the default zstd frames hide the logs.
persistenceCompression: none
agents:
- id: main
provider: deepseek-official
model: deepseek-v4-flash
cwd: !!js process.cwd()
workspaceContext:
maxBytes: 65536
tools:
@@ -32,6 +31,13 @@
You are headless-agent, a coding assistant powered by the {{model}} model. Your working directory is {{cwd}}.
Verify your work by running the code or tests. Keep answers brief and factual.
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
# Replay fixtures are raw JSONL; the whole-config patch must restate
# the compression choice or the default zstd frames hide the logs.
compression: none
- insert:
- id: code-runtime
name: '@deepseek-ai/dsh-code-runtime-worker'

View File

@@ -4,13 +4,14 @@
config:
path: ./cordis.yml
patches:
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: deepseek-official
model: deepseek-v4-pro
persistenceRoot: './.sessions'
persistenceCompression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
agents:
- id: main
provider: deepseek-official
model: deepseek-v4-pro
cwd: !!js process.cwd()
workspaceContext:
maxBytes: 65536
tools:
@@ -19,6 +20,11 @@
You are headless-agent, a coding assistant powered by the {{model}} model. Your working directory is {{cwd}}.
Verify your work by running the code or tests. Keep answers brief and factual.
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
- insert:
- id: code-runtime
name: '@deepseek-ai/dsh-code-runtime-worker'

View File

@@ -1,9 +1,9 @@
<!-- Generated by scripts/gen-doc-graphs.ts - do not edit by hand.
Run `pnpm run gen-doc-graphs` to regenerate. -->
# Headless Agent App Composition
# Headless Agent Snapshot Composition
The headless demo combines the real DeepSeek adapter and coding capabilities with the one-shot app package, format-pure stdout, and one fresh persisted top-level session.
The headless snapshot composition combines the real DeepSeek adapter and coding capabilities with one explicitly configured persisted top-level agent; its JSONL driver is test-only.
```mermaid
flowchart LR
@@ -18,15 +18,12 @@ flowchart LR
cfg --> plugin_headless_subprocess
plugin_headless_bash["bash<br/>@deepseek-ai/dsh-bash-local"]
cfg --> plugin_headless_bash
plugin_headless_cli_agent["cli-agent<br/>@deepseek-ai/dsh-cli-demo"]
cfg --> plugin_headless_cli_agent
plugin_headless_cli_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
plugin_headless_cli_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
plugin_headless_cli_agent --> frontdoor_cli["one-shot driver<br/>format-pure stdout<br/>fresh top-level agent"]
bundle_agent_core --> spine_llm["ctx.llm"]
bundle_agent_core --> spine_sessions["ctx.sessions"]
bundle_agent_core --> spine_tools["ctx.tools + tool-bash"]
bundle_agent_core --> spine_loop["ctx.agents + ctx.agentLoop"]
plugin_headless_agent_spine["agent-spine<br/>@deepseek-ai/dsh-agent-spine-demo"]
cfg --> plugin_headless_agent_spine
plugin_headless_persistence["persistence<br/>@deepseek-ai/dsh-session-persistence-jsonl"]
cfg --> plugin_headless_persistence
plugin_headless_checkpoint_policy["checkpoint-policy<br/>@deepseek-ai/dsh-session-checkpoint-policy"]
cfg --> plugin_headless_checkpoint_policy
plugin_headless_token_meter["token-meter<br/>@deepseek-ai/dsh-token-meter"]
cfg --> plugin_headless_token_meter
plugin_headless_compact_basic["compact-basic<br/>@deepseek-ai/dsh-compact-basic"]
@@ -70,7 +67,9 @@ flowchart LR
| `llm-deepseek` | `@deepseek-ai/dsh-llm-deepseek` |
| `subprocess` | `@deepseek-ai/dsh-subprocess-local` |
| `bash` | `@deepseek-ai/dsh-bash-local` |
| `cli-agent` | `@deepseek-ai/dsh-cli-demo` |
| `agent-spine` | `@deepseek-ai/dsh-agent-spine-demo` |
| `persistence` | `@deepseek-ai/dsh-session-persistence-jsonl` |
| `checkpoint-policy` | `@deepseek-ai/dsh-session-checkpoint-policy` |
| `token-meter` | `@deepseek-ai/dsh-token-meter` |
| `compact-basic` | `@deepseek-ai/dsh-compact-basic` |
| `session-projection` | `@deepseek-ai/dsh-session-projection` |

View File

@@ -40,17 +40,18 @@
config:
timeoutMs: 60000
# The app bundle pre-creates one fresh `main` agent per invocation.
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
# The example composition pre-creates one fresh `main` agent for its test driver.
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: deepseek-official
# Stays on flash: the goal/ralph replay corpora were recorded on it, and
# their nested-include overlays cannot re-pin the app config (a config
# patch cannot target an entry behind a nested include).
model: deepseek-v4-flash
persistenceRoot: './.sessions'
persistenceCompression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
agents:
- id: main
provider: deepseek-official
# Stays on flash: the goal/ralph replay corpora were recorded on it, and
# their nested-include overlays cannot re-pin the app config (a config
# patch cannot target an entry behind a nested include).
model: deepseek-v4-flash
cwd: !!js process.cwd()
workspaceContext:
maxBytes: 65536
persona: |
@@ -59,6 +60,15 @@
Verify your work by running the code or tests. Keep answers brief and
factual.
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'
# Summarize an older range when derived history approaches the context window.
- id: token-meter
name: '@deepseek-ai/dsh-token-meter'

View File

@@ -12,15 +12,21 @@
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: cli-mock
model: cli-mock
persistenceRoot: './.sessions'
agents:
- id: main
provider: cli-mock
model: cli-mock
cwd: !!js process.cwd()
workspaceContext: false
dshHome: './.dsh-home'
skills:
local:
agentsHome: './.agents-home'
persona: 'Keyless headless-agent smoke.'
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'

View File

@@ -7,10 +7,15 @@
config:
baseURL: !!js process.env.DSH_SNAPSHOT_BASE_URL
thinking: disabled
- id: cli-agent
- id: agent-spine
config:
provider: deepseek-official
model: deepseek-v4-flash
persistenceRoot: './.sessions'
agents:
- id: main
provider: deepseek-official
model: deepseek-v4-flash
cwd: !!js process.cwd()
workspaceContext: false
persona: 'Keyless DeepSeek adapter defaults snapshot.'
- id: persistence
config:
root: './.sessions'

View File

@@ -17,12 +17,22 @@
- id: seed-goal
name: './seed-goal.ts'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: cli-mock
model: cli-mock
agents:
- id: main
provider: cli-mock
model: cli-mock
cwd: !!js process.cwd()
persona: 'Test the persisted goal domain.'
persistenceRoot: './.sessions'
persistenceCompression: none
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: none
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env node
/** Snapshot-only Loader driver: stream one fixture turn as canonical JSONL. */
import type { Context } from 'cordis'
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import type { SessionEvent } from '@deepseek-ai/dsh-session'
import { runFixtureTurn } from './one-shot.ts'
const NAME = 'headless-test-driver'
const [configPath, ...taskParts] = process.argv.slice(2)
if (configPath === undefined || taskParts.length === 0 || taskParts.every(part => part.trim() === '')) {
throw new Error(`${NAME}: expected <config-path> <task...>`)
}
const uninstallFailLoud = installFailLoud(NAME)
let ctx: Context | undefined
try {
loadEnv(NAME)
ctx = await boot(NAME, resolveConfigPath(configPath, process.env.DSH_SNAPSHOT))
const result = await runFixtureTurn(ctx, {
task: taskParts.join(' '),
onEvent: (sessionId: string, event: SessionEvent) => {
process.stdout.write(`${JSON.stringify({ type: 'session_event', sessionId, event })}\n`)
},
})
process.stdout.write(`${JSON.stringify(result)}\n`)
} catch (error: unknown) {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
process.exitCode = 1
} finally {
await ctx?.fiber.dispose()
uninstallFailLoud()
}

View File

@@ -0,0 +1,97 @@
/** Test-only direct-agent turn driver shared by assembled Loader fixtures. */
import type { Context } from 'cordis'
import type { Agent } from '@deepseek-ai/dsh-agent'
import { createUserMessage, type TokenUsage } from '@deepseek-ai/dsh-llm'
import type { SessionEvent } from '@deepseek-ai/dsh-session'
/** Result envelope consumed only by snapshot and composition tests. */
export interface FixtureTurnResult {
readonly type: 'result'
readonly sessionId: string
readonly output: string
readonly usage?: TokenUsage
}
/** Options for one fixture turn against exactly one configured root agent. */
export interface FixtureTurnOptions {
readonly task: string
readonly onEvent?: (sessionId: string, event: SessionEvent) => void
}
function addUsage(total: TokenUsage | undefined, step: TokenUsage): TokenUsage {
const next: TokenUsage = {
inputTokens: (total?.inputTokens ?? 0) + step.inputTokens,
outputTokens: (total?.outputTokens ?? 0) + step.outputTokens,
}
for (const key of ['cacheReadTokens', 'cacheWriteTokens', 'reasoningTokens'] as const) {
if (total?.[key] !== undefined || step[key] !== undefined) next[key] = (total?.[key] ?? 0) + (step[key] ?? 0)
}
return next
}
function assistantText(event: Extract<SessionEvent, { type: 'assistant/message' }>): string | undefined {
const blocks = event.data.message.content.filter(block => block.type === 'text')
return blocks.length === 0 ? undefined : blocks.map(block => block.text).join('')
}
function onlyRootAgent(ctx: Context): Agent {
const agents = ctx.get('agents')?.roots() ?? []
const [agent] = agents
if (agent === undefined || agents.length !== 1) {
throw new Error(`headless fixture requires exactly one top-level agent, found ${agents.length}`)
}
return agent
}
/**
* Drive one task from its durable inbox receipt through whole-agent idle.
* @param ctx - settled Loader context with exactly one configured root agent.
* @param options - task and optional canonical-event observer.
* @returns the final assistant text and accumulated model usage.
*/
export async function runFixtureTurn(ctx: Context, options: FixtureTurnOptions): Promise<FixtureTurnResult> {
const agent = onlyRootAgent(ctx)
await agent.whenIdle()
const message = createUserMessage({
content: [{ type: 'text', text: options.task }],
source: { kind: 'user' },
})
let received = false
let output = ''
const usageByStep = new Map<string, TokenUsage>()
const disposeListener = ctx.on('session/event', (session, event) => {
if (session !== agent.session) return
if (!received) {
if (event.type !== 'agent/inbox/spliced'
|| !event.data.inserted.some(inserted => inserted.id === message.id)) return
received = true
}
options.onEvent?.(session.id, event)
if (event.type === 'assistant/chunk' && event.data.chunk.type === 'usage') {
usageByStep.set(`${event.data.turn}/${event.data.step}`, event.data.chunk.usage)
}
if (event.type === 'assistant/message') {
output = assistantText(event) ?? output
if (event.data.usage !== undefined) {
usageByStep.set(`${event.data.turn}/${event.data.step}`, event.data.usage)
}
}
})
try {
agent.followup(message)
await agent.whenIdle()
} finally {
disposeListener()
}
await ctx.sessions.flush(agent.session)
const usage = [...usageByStep.values()].reduce<TokenUsage | undefined>(addUsage, undefined)
return {
type: 'result',
sessionId: agent.session.id,
output,
...usage === undefined ? {} : { usage },
}
}

View File

@@ -10,8 +10,8 @@ import { writeFile } from 'node:fs/promises'
import { createServer } from 'node:http'
import { once } from 'node:events'
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts'
import { recordFeedback } from '@deepseek-ai/dsh-command-feedback'
import { runFixtureTurn } from './one-shot.ts'
const configPath = process.argv[2]
if (configPath === undefined) throw new Error('telemetry-otel driver requires a config path')
@@ -35,14 +35,14 @@ const ctx = await boot('telemetry-otel-e2e', resolveConfigPath(configPath, undef
try {
// The fixture credential rides the model-visible user message; the exported
// copy must scrub it while the canonical log keeps the original bytes.
await runOneShot(ctx, { task: 'prove telemetry with key sk-e2efixture1234567890' })
await runFixtureTurn(ctx, { task: 'prove telemetry with key sk-e2efixture1234567890' })
const mode = process.env.DSH_TELEMETRY_E2E_MODE ?? 'FULL'
if (mode !== 'FULL') {
const [agent] = ctx.get('agents')?.roots() ?? []
if (agent === undefined) throw new Error('telemetry-otel driver requires one root agent')
recordFeedback(agent.session, 'fixture feedback')
if (mode === 'FEEDBACK_ONLY') {
await runOneShot(ctx, { task: 'post-feedback private suffix' })
await runFixtureTurn(ctx, { task: 'post-feedback private suffix' })
}
}
} finally {

View File

@@ -30,12 +30,22 @@
exporter:
url: !!js process.env.DSH_TELEMETRY_E2E_URL
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: cli-mock
model: cli-mock
agents:
- id: main
provider: cli-mock
model: cli-mock
cwd: !!js process.cwd()
persona: 'Test the session-telemetry-otel plugin.'
persistenceRoot: './.sessions'
persistenceCompression: 'none'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: 'none'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -2,15 +2,15 @@
/** Test driver that sends two turns through one Headless Loader composition. */
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts'
import { runFixtureTurn } from './one-shot.ts'
const configPath = process.argv[2]
if (configPath === undefined) throw new Error('time-context driver requires a config path')
const ctx = await boot('time-context-e2e', resolveConfigPath(configPath, undefined))
try {
await runOneShot(ctx, { task: 'first' })
await runOneShot(ctx, { task: 'second' })
await runFixtureTurn(ctx, { task: 'first' })
await runFixtureTurn(ctx, { task: 'second' })
} finally {
await ctx.fiber.dispose()
}

View File

@@ -12,12 +12,22 @@
- id: time-context
name: '@deepseek-ai/dsh-time-context'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: time-context-mock
model: time-context-mock
agents:
- id: main
provider: time-context-mock
model: time-context-mock
cwd: !!js process.cwd()
persona: 'Test the time-context plugin.'
persistenceRoot: './.sessions'
persistenceCompression: 'none'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: 'none'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -47,7 +47,7 @@ const ralphScenarioDir = join(snapshotsDir, 'ralph-loop')
const ralphConfigPath = fileURLToPath(new URL('../ralph.cordis.snapshot.yml', import.meta.url))
const startupFailureConfigPath = fileURLToPath(new URL('./fixtures/startup-activation-error/cordis.yml', import.meta.url))
const startupFailureExpected = join(snapshotsDir, 'startup-activation-error', 'stderr.expected.txt')
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const dshBinScript = fileURLToPath(new URL('../../../apps/cli/src/bin.ts', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const reasoningConfigPath = fileURLToPath(new URL('./fixtures/cli.cordis.yml', import.meta.url))
@@ -242,8 +242,9 @@ describe('headless stream-json snapshots', () => {
label: 'headless startup activation error snapshot',
tempDirPrefix: 'headless-snapshot-startup-error-',
binScript,
libBinScript: binScript,
configPath: startupFailureConfigPath,
binArgs: ['--config', startupFailureConfigPath, '--output-format', 'stream-json', 'unreachable task'],
binArgs: [startupFailureConfigPath, 'unreachable task'],
tsconfigPath,
expectedExitCode: 1,
})
@@ -259,8 +260,9 @@ describe('headless stream-json snapshots', () => {
label: 'provider retry headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-provider-retry-',
binScript,
libBinScript: binScript,
configPath: retryConfigPath,
binArgs: ['--config', retryConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [retryConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',
@@ -299,8 +301,9 @@ describe('headless stream-json snapshots', () => {
label: 'compaction recovery headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-compaction-recovery-',
binScript,
libBinScript: binScript,
configPath: compactionConfigPath,
binArgs: ['--config', compactionConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [compactionConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',
@@ -367,8 +370,9 @@ describe('headless stream-json snapshots', () => {
label: 'missing-credential headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-missing-credential-',
binScript,
libBinScript: binScript,
configPath: credentialsConfigPath,
binArgs: ['--config', credentialsConfigPath, '--output-format', 'stream-json', 'say pong'],
binArgs: [credentialsConfigPath, 'say pong'],
tsconfigPath,
env: {
// First-run posture: no key in the environment, none under ./.dsh.
@@ -404,8 +408,9 @@ describe('headless stream-json snapshots', () => {
label: 'invalid-credential headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-invalid-credential-',
binScript,
libBinScript: binScript,
configPath: credentialsConfigPath,
binArgs: ['--config', credentialsConfigPath, '--output-format', 'stream-json', 'say pong'],
binArgs: [credentialsConfigPath, 'say pong'],
tsconfigPath,
env: {
// A key that exists but no HTTP header can carry — the paste this
@@ -438,8 +443,9 @@ describe('headless stream-json snapshots', () => {
label: 'reasoning effort headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-reasoning-effort-',
binScript,
libBinScript: binScript,
configPath: reasoningConfigPath,
binArgs: ['--config', reasoningConfigPath, '--output-format', 'stream-json', 'prove dynamic reasoning effort'],
binArgs: [reasoningConfigPath, 'prove dynamic reasoning effort'],
tsconfigPath,
})
@@ -480,12 +486,10 @@ describe('headless stream-json snapshots', () => {
label: 'DeepSeek adapter defaults headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-deepseek-defaults-',
binScript,
libBinScript: binScript,
configPath: deepseekDefaultsConfigPath,
binArgs: [
'--config',
deepseekDefaultsConfigPath,
'--output-format',
'stream-json',
'return the deterministic response',
],
tsconfigPath,
@@ -540,8 +544,9 @@ describe('headless stream-json snapshots', () => {
label: 'advanced headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-advanced-',
binScript,
libBinScript: binScript,
configPath: advancedConfigPath,
binArgs: ['--config', advancedConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [advancedConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',
@@ -611,8 +616,9 @@ describe('headless stream-json snapshots', () => {
label: 'goal tools headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-goal-tools-',
binScript,
libBinScript: binScript,
configPath: goalConfigPath,
binArgs: ['--config', goalConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [goalConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',
@@ -667,8 +673,9 @@ describe('headless stream-json snapshots', () => {
label: 'Ralph loop headless stream-json snapshot',
tempDirPrefix: 'headless-snapshot-ralph-loop-',
binScript,
libBinScript: binScript,
configPath: ralphConfigPath,
binArgs: ['--config', ralphConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [ralphConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',
@@ -748,8 +755,9 @@ describe('headless stream-json snapshots', () => {
label: 'headless persistent PTY snapshot',
tempDirPrefix: 'headless-snapshot-pty-',
binScript,
libBinScript: binScript,
configPath: ptyConfigPath,
binArgs: ['--config', ptyConfigPath, '--output-format', 'stream-json', prompt],
binArgs: [ptyConfigPath, prompt],
tsconfigPath,
env: {
DSH_SNAPSHOT: 'replay',

View File

@@ -9,7 +9,7 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
import { PREPARED_ENTRY_FILENAME, prepareDshPlugin } from '@deepseek-ai/dsh-repository-plugin'
import type { SessionEvent } from '@deepseek-ai/dsh-session'
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const configPath = fileURLToPath(new URL('./fixtures/cli.cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const decompress = promisify(zstdDecompress)
@@ -21,8 +21,9 @@ describe('headless-agent keyless smoke', () => {
label: 'headless-agent',
tempDirPrefix: 'headless-agent-smoke-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', 'prove the tool path'],
binArgs: [configPath, 'prove the tool path'],
tsconfigPath,
inspect: async (cwd) => {
const files = await readdir(cwd, { recursive: true })

View File

@@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
import { runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke'
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const hasKey = Boolean(process.env.DEEPSEEK_API_KEY)
@@ -16,9 +16,9 @@ describe.skipIf(!hasKey)('headless-agent with real model', () => {
label: 'headless-agent real model',
tempDirPrefix: 'headless-agent-real-',
binScript,
libBinScript: binScript,
configPath,
binArgs: [
'--config',
configPath,
'Read task.txt, replace its complete contents with exactly "value=after" followed by a newline, read it again, and report briefly.',
],

View File

@@ -14,7 +14,7 @@ const replayFixture = join(fixtureDir, 'replay.jsonl')
const replayOverride = join(fixtureDir, 'replay.override.json')
const sessionExpected = join(fixtureDir, 'session.expected.jsonl')
const configPath = fileURLToPath(new URL('../semantic-checkpoint.cordis.snapshot.yml', import.meta.url))
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const sessionId = SessionId('semantic-checkpoint-unknown-outcome')
const refreshing = process.env.DSH_SNAPSHOT === 'refresh'
@@ -87,8 +87,9 @@ describe('semantic checkpoint recovery snapshot', () => {
label: 'semantic checkpoint headless stream-json snapshot',
tempDirPrefix: 'dsh-semantic-snapshot-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', task],
binArgs: [configPath, task],
tsconfigPath,
env: {
DSH_SNAPSHOT_FILE: replayFixture,

View File

@@ -1,3 +1,3 @@
dsh-cli-demo: dsh-cli-demo: plugin tree failed to load: failed to apply loader entry include (cordis:include): failed to apply loader entry activation-error (./activation-error.mjs): startup activation snapshot failure
headless-test-driver: plugin tree failed to load: failed to apply loader entry include (cordis:include): failed to apply loader entry activation-error (./activation-error.mjs): startup activation snapshot failure
Error: startup activation snapshot failure
at activation-error-fixture

View File

@@ -19,7 +19,7 @@ const fixtureDir = fileURLToPath(new URL('./subagent-diagnostic-snapshots/descri
const replayOverride = join(fixtureDir, 'replay.override.json')
const parentExpected = join(fixtureDir, 'parent.expected.jsonl')
const configPath = fileURLToPath(new URL('../subagent-diagnostic.cordis.snapshot.yml', import.meta.url))
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const parentId = SessionId('subagent-diagnostic-parent')
const childId = SessionId('subagent-diagnostic-child')
@@ -77,8 +77,9 @@ describe('descriptor-less cold child diagnostic snapshot', () => {
label: 'subagent diagnostic headless stream-json snapshot',
tempDirPrefix: 'dsh-subagent-diag-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', task],
binArgs: [configPath, task],
tsconfigPath,
env: {
DSH_SNAPSHOT_FILE: replayOverride,

View File

@@ -20,7 +20,7 @@ const childReplay = join(fixtureDir, 'child.replay.jsonl')
const parentExpected = join(fixtureDir, 'parent.expected.jsonl')
const childExpected = join(fixtureDir, 'child.expected.jsonl')
const configPath = fileURLToPath(new URL('../subagent-inheritance.cordis.snapshot.yml', import.meta.url))
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const sessionId = SessionId('subagent-inheritance-parent')
const refreshing = process.env.DSH_SNAPSHOT === 'refresh'
@@ -59,8 +59,9 @@ describe('parent-only override inheritance snapshot', () => {
label: 'subagent inheritance headless stream-json snapshot',
tempDirPrefix: 'dsh-subagent-inherit-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', task],
binArgs: [configPath, task],
tsconfigPath,
env: {
// The primary fixture path must exist for llm-replay's config guard;

View File

@@ -28,7 +28,7 @@ const replayOverride = join(fixtureDir, 'replay.override.json')
const sessionExpected = join(fixtureDir, 'session.expected.jsonl')
const precedenceExpected = join(dirname(fixtureDir), 'precedence-change/session.expected.jsonl')
const configPath = fileURLToPath(new URL('../workspace-context-resume.cordis.snapshot.yml', import.meta.url))
const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url))
const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
const sessionId = SessionId('workspace-context-resume')
const refreshing = process.env.DSH_SNAPSHOT === 'refresh'
@@ -119,8 +119,9 @@ describe('workspace-context resume snapshot', () => {
label: 'workspace-context resume headless stream-json snapshot',
tempDirPrefix: 'dsh-workspace-context-resume-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', 'Acknowledge the current workspace instruction.'],
binArgs: [configPath, 'Acknowledge the current workspace instruction.'],
tsconfigPath,
env: {
DSH_SNAPSHOT_FILE: replayFixture,
@@ -175,8 +176,9 @@ describe('workspace-context resume snapshot', () => {
label: 'workspace-context precedence-change resume snapshot',
tempDirPrefix: 'dsh-workspace-context-precedence-',
binScript,
libBinScript: binScript,
configPath,
binArgs: ['--config', configPath, '--output-format', 'stream-json', 'Acknowledge the current workspace instruction.'],
binArgs: [configPath, 'Acknowledge the current workspace instruction.'],
tsconfigPath,
env: {
DSH_SNAPSHOT_FILE: replayFixture,

View File

@@ -32,12 +32,22 @@
# recursion budget, so the local numeric default cannot apply here.
maxDepth: 'provider-managed'
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: mock
model: mock-delegate
agents:
- id: main
provider: mock
model: mock-delegate
cwd: !!js process.cwd()
persona: 'Test SDK subagent cwd inheritance.'
persistenceRoot: './.sessions'
persistenceCompression: 'none'
workspaceContext: false
- id: persistence
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: './.sessions'
compression: 'none'
- id: checkpoint-policy
name: '@deepseek-ai/dsh-session-checkpoint-policy'

View File

@@ -2,14 +2,14 @@
/** Test driver: one delegation turn through a headless Loader composition. */
import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts'
import { runFixtureTurn } from '../../../../../headless-agent/tests/fixtures/one-shot.ts'
const configPath = process.argv[2]
if (configPath === undefined) throw new Error('sdk-subagent cwd driver requires a config path')
const ctx = await boot('sdk-subagent-cwd-e2e', resolveConfigPath(configPath, undefined))
try {
await runOneShot(ctx, { task: 'delegate' })
await runFixtureTurn(ctx, { task: 'delegate' })
} finally {
await ctx.fiber.dispose()
}

View File

@@ -18,7 +18,6 @@
"@deepseek-ai/dsh-bash-env": "workspace:*",
"@deepseek-ai/dsh-bash-local": "workspace:*",
"@deepseek-ai/dsh-bash-sandbox": "workspace:*",
"@deepseek-ai/dsh-cli-demo": "workspace:*",
"@deepseek-ai/dsh-code-runtime-worker": "workspace:*",
"@deepseek-ai/dsh-command-feedback": "workspace:*",
"@deepseek-ai/dsh-command-goal": "workspace:*",