feat(preset): add image reading and compaction to sdk-minimal

Reuse read_image and automatic compaction in the standalone profile without
adding SDK slash-command handling. Update profile guidance, upgrade steps,
and startup and recorded-session coverage.
This commit is contained in:
LogosVeritas committed 2026-10-12 12:11:18 +08:00
1 parent 110ef57123
commit 444692d1ca
36 files changed
+466 -86

No files matched your search

@@ -202,10 +202,13 @@ describe('Python SDK dsh profile keyless smoke', () => {
}, 40_000)
it.each([
{ label: 'boots the standalone minimal profile through its generated manifest', editorEnabled: false },
{ label: 'executes the documented editor opt-in patch with sdk-minimal', editorEnabled: true },
])('$label', async ({ editorEnabled }) => {
{ label: 'boots the standalone minimal profile through its generated manifest', editorEnabled: false, imageEnabled: false, optOut: false },
{ label: 'executes the documented editor opt-in patch with sdk-minimal', editorEnabled: true, imageEnabled: false, optOut: false },
{ label: 'sends a read_image result to the model with sdk-minimal', editorEnabled: false, imageEnabled: true, optOut: false },
{ label: 'retains the previous tools through the documented opt-out patch', editorEnabled: false, imageEnabled: false, optOut: true },
])('$label', async ({ editorEnabled, imageEnabled, optOut }) => {
const root = await mkdtemp(join(tmpdir(), 'dsh-python-sdk-minimal-'))
onTestFinished(() => rm(root, { recursive: true, force: true }))
const editorPatch = join(root, 'editor.patch.yml')
if (editorEnabled) {
const guide = await readFile(join(repoRoot, 'docs/user/guide/python-sdk.md'), 'utf8')
@@ -214,7 +217,16 @@ describe('Python SDK dsh profile keyless smoke', () => {
expect(yaml).toBeDefined()
await writeFile(editorPatch, yaml!)
}
if (optOut) {
const guide = await readFile(join(repoRoot, 'docs/upgrade-guide/v0.2.1-alpha.2/sdk-minimal-image-compaction/guide.md'), 'utf8')
const yaml = guide.match(/```yaml\n([\s\S]*?)```/)?.[1]
expect(yaml).toBeDefined()
await writeFile(editorPatch, yaml!)
}
const editorFile = join(root, 'editor.txt')
if (imageEnabled) await writeFile(join(root, 'red.png'), Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR4nGP4z8AAAAMBAQDJ/pLvAAAAAElFTkSuQmCC', 'base64',
))
const editorContent = 'sdk-minimal editor opt-in\n'
const editorCalls = editorEnabled ? [
{ command: 'create', path: editorFile, file_text: editorContent },
@@ -222,17 +234,29 @@ describe('Python SDK dsh profile keyless smoke', () => {
] : []
const modelRequests: Record<string, unknown>[] = []
const modelServer = createServer((request, response) => {
if (imageEnabled && request.url?.endsWith('/files')) {
request.resume()
response.writeHead(200, { 'content-type': 'application/json' })
response.end(JSON.stringify({
id: 'file-minimal-image', type: 'file', size_bytes: 69,
created_at: new Date().toISOString(),
filename: 'red.png', mime_type: 'image/png',
}))
return
}
let body = ''
request.setEncoding('utf8')
request.on('data', (chunk: string) => { body += chunk })
request.on('end', () => {
modelRequests.push(JSON.parse(body) as Record<string, unknown>)
response.writeHead(200, { 'content-type': 'text/event-stream' })
const toolCall = editorCalls[modelRequests.length - 1]
const toolCall = imageEnabled && modelRequests.length === 1
? { file_path: 'red.png' }
: editorCalls[modelRequests.length - 1]
response.end(messagesResponse(toolCall ? {
type: 'tool_use',
id: `editor-${toolCall.command}`,
name: 'str_replace_editor',
id: imageEnabled ? 'minimal-image-read' : `editor-${editorCalls[modelRequests.length - 1]?.command}`,
name: imageEnabled ? 'read_image' : 'str_replace_editor',
input: toolCall,
} : { type: 'text', text: 'done' }, toolCall ? 'tool_use' : 'end_turn'))
})
@@ -244,7 +268,7 @@ describe('Python SDK dsh profile keyless smoke', () => {
...launch.args,
'--profile',
'sdk-minimal',
...(editorEnabled ? ['--patch', editorPatch] : []),
...(editorEnabled || optOut ? ['--patch', editorPatch] : []),
], {
cwd: repoRoot,
env: {
@@ -274,7 +298,7 @@ describe('Python SDK dsh profile keyless smoke', () => {
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: { cwd: root, provider: 'deepseek-official', model: 'deepseek-v4-pro' },
params: { cwd: root, provider: 'deepseek-official', model: imageEnabled ? 'deepseek-flash' : 'deepseek-v4-pro' },
})}\n`)
await waitForLine(lines, value => value.id === 1, () => stderr)
child.stdin.write(`${JSON.stringify({
@@ -302,10 +326,23 @@ describe('Python SDK dsh profile keyless smoke', () => {
const tools = modelRequests[0]?.tools as { name?: string }[]
expect(tools.map(tool => tool.name)).toEqual([
process.platform === 'win32' ? 'pwsh' : 'bash',
...(optOut ? [] : ['read_image']),
...(editorEnabled ? ['str_replace_editor'] : []),
'working_directory',
])
expect(modelRequests).toHaveLength(editorEnabled ? 3 : 1)
expect(modelRequests).toHaveLength(editorEnabled ? 3 : imageEnabled ? 2 : 1)
if (imageEnabled) {
const messages = modelRequests[1]?.messages as {
content: { type: string; tool_use_id?: string; content?: { type: string; source?: { type: string; file_id: string } }[] }[]
}[]
const imageResult = messages.flatMap(message => message.content)
.find(block => block.type === 'tool_result' && block.tool_use_id === 'minimal-image-read')
expect(imageResult?.content).toEqual(expect.arrayContaining([
{ type: 'image', source: { type: 'file', file_id: 'file-minimal-image' } },
]))
const stored = await readdir(join(root, '.dsh', 'attachments', 'v1', 'objects'), { recursive: true })
expect(stored.some(file => /[a-f0-9]{64}$/u.test(file))).toBe(true)
}
if (editorEnabled) {
expect(await readFile(editorFile, 'utf8')).toBe(editorContent)
expect(modelRequests[2]?.messages).toEqual(expect.arrayContaining([
@@ -334,7 +371,6 @@ describe('Python SDK dsh profile keyless smoke', () => {
child.kill('SIGKILL')
await child
await new Promise<void>(resolve => modelServer.close(() => { resolve() }))
await rm(root, { recursive: true, force: true })
}
}, 40_000)
@@ -1,5 +1,5 @@
- menu:
- menuitem "Standard mode Work with code, files, and information. Suitable for most tasks, with search, editing, terminal commands, and other tools available as needed."
- menuitem "PTC mode Includes all Standard mode capabilities. Better suited to tasks that call tools in batches and then filter, organize, deduplicate, count, or summarize the results."
- menuitem "Minimal mode The agent works using only a terminal tool. Useful for testing and comparing its basic performance."
- menuitem "Minimal mode The agent uses a terminal and image reading, with context compaction. Useful for testing and comparing its basic performance."
- menuitem "Creator mode Customize DSH through conversation. Let the agent write plugins that add features or UI, or combine tools and prompts to create your own mode."
@@ -0,0 +1,16 @@
# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-alpha.2/sdk-minimal-image-compaction/guide.md
/:
en: 5fc67054b45f1734
zh: 0cb92b2e036dfb67
/sdk-minimal-image-reading-and-automatic-compaction:
en: 1b0161d44c885284
zh: 5babee2ad7dc2571
/sdk-minimal-image-reading-and-automatic-compaction/change:
en: b71b37ed705e0387
zh: 9cabd8cb8cf59882
/sdk-minimal-image-reading-and-automatic-compaction/migration:
en: e944f28ce8c2ef8d
zh: 3bd5fd84a02e5866
@@ -0,0 +1,28 @@
---
kind: upgrade-guide
description: "The sdk-minimal default tool roster adds read_image and automatically summarizes older context."
---
# SDK-minimal image reading and automatic compaction
English | [中文](guide.zh.md)
## Change
`sdk-minimal` advertises `read_image` alongside its persistent shell and `working_directory`. Automatic compaction sends an additional model request to summarize older history when context pressure reaches the configured threshold. The complete Session log remains stored as uncompressed JSONL. SDK prompt text does not execute `/compact`.
Clients that pin tool names, benchmark prompt size, or count model requests must account for these defaults. Image reading requires an adapter route that declares image input. See the [bundle reference](../../../../packages/bundle/sdk-minimal/README.md) for configuration and model effects.
## Migration
1. Accept the new defaults, or place this patch in `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml` to retain the previous default tools and disable automatic compaction:
```yaml
- id: tool-fs
disabled: true
- id: compaction-basic
config:
auto: false
```
2. Launch a fresh SDK runtime. Without additional user plugins, its model requests contain the persistent `bash` or `pwsh` tool and `working_directory`; it sends no automatic summarization requests.
@@ -0,0 +1,28 @@
---
kind: upgrade-guide
description: "sdk-minimal 默认工具清单新增 read_image,并自动生成较早上下文的摘要。"
---
# SDK-minimal 图片读取与自动压缩
[English](guide.md) | 中文
## 变更
`sdk-minimal` 在持久 shell 和 `working_directory` 之外公布 `read_image`。上下文压力达到配置阈值时,自动压缩会额外发起模型请求,生成较早历史的摘要。完整 Session 日志仍存储为未压缩 JSONL。SDK 提示词文本不会执行 `/compact`。
固定工具名称、基准提示词大小或统计模型请求数的客户端必须考虑这些默认行为。图片读取需要适配器路由声明支持图片输入。配置与模型影响见[组合包参考](../../../../packages/bundle/sdk-minimal/README.zh.md)。
## 迁移
1. 接受新增默认能力,或将以下 patch 写入 `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml`,保留原有默认工具并关闭自动压缩:
```yaml
- id: tool-fs
disabled: true
- id: compaction-basic
config:
auto: false
```
2. 启动新的 SDK 运行时。未额外配置用户插件时,模型请求包含持久 `bash` 或 `pwsh` 工具及 `working_directory`;不会发起自动摘要请求。
+4 -4
View File
@@ -21,8 +21,8 @@
en: 592dd306b920cd83
zh: 8c22110621c12ba5
/get-started-with-the-python-sdk/install-or-define-plugins/opt-in-to-str-replace-editor:
en: c63ca1e3a99e6fe1
zh: 2ceddea3f30d92d3
en: 450d54b6e9e38469
zh: f0dc06a08c073571
/get-started-with-the-python-sdk/understand-the-minimal-profile:
en: 5eaacc1bc52853c4
zh: 5b94bfc79aac04d8
en: 8ed0bfd3cc9cc967
zh: a52dab4cb3dd09ea
+8 -9
View File
@@ -152,19 +152,15 @@ Another `profile` is valid when it includes `@deepseek-ai/dsh-sdk-app` or anothe
<a id="opt-in-to-str_replace_editor"></a>
### Opt in to `str_replace_editor`
The bundled runtime includes `str_replace_editor`, but `sdk-minimal` omits it from the default Cordis tree. To use it, save this configuration as `editor.patch.yml`; `insert` adds both the editor and the filesystem provider that the minimal profile lacks:
The bundled runtime includes `str_replace_editor`, but `sdk-minimal` omits it from the default Cordis tree. To use it, save this configuration as `editor.patch.yml`; `insert` adds the editor using the existing filesystem provider:
```yaml
- insert:
- id: fs-local
name: '@deepseek-ai/dsh-fs-local'
config:
cwd: !!js process.cwd()
- id: tool-str-replace-editor
name: '@deepseek-ai/dsh-tool-str-replace-editor'
```
Pass `patches=("/absolute/path/to/editor.patch.yml",)` when constructing `DeepSeekHarness(profile="sdk-minimal", ...)`, or put the patch in `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml` for persistent configuration. On the next runtime launch, model requests include `str_replace_editor` beside the persistent shell. The local filesystem provider uses the runtime working directory for relative paths; like the minimal shell, it does not confine access to that directory. For the standard `sdk` profile, insert only the editor row so it uses the existing filesystem provider and policies.
Pass `patches=("/absolute/path/to/editor.patch.yml",)` when constructing `DeepSeekHarness(profile="sdk-minimal", ...)`, or put the patch in `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml` for persistent configuration. On the next runtime launch, model requests include `str_replace_editor` beside the default tools. The local filesystem provider uses the runtime working directory for relative paths; like the minimal shell, it does not confine access to that directory. The same patch works with the standard `sdk` profile.
## Understand the minimal profile
@@ -172,12 +168,15 @@ Pass `patches=("/absolute/path/to/editor.patch.yml",)` when constructing `DeepSe
|---|---|
| System prompt | `DSH_SYSTEM_PROMPT`, falling back to `You are a helpful software engineer assistant.` |
| Model in `minimal.py` | `--model`, then `DSH_MODEL`, then `deepseek-v4-flash` |
| Model-facing tool | Persistent `bash` on Linux/macOS or `pwsh` on Windows |
| Model-facing tools | Persistent `bash` on Linux/macOS or `pwsh` on Windows, `read_image`, and `working_directory` |
| Shell timeout | 300 seconds |
| Runtime context and compaction | Absent |
| Optional runtime context | Absent |
| Context compaction | Automatic; summarizes older history through an additional model request |
| Session persistence | Uncompressed JSONL under `<dsh_home>/sessions` |
The profile's sole bundle inserts the complete tree over an empty root and does not include `dsh-base`; later base-profile tools therefore cannot appear implicitly. It contains the SDK protocol, one environment-configured DeepSeek adapter, local execution, and persistence, while filesystem tools, settings, managed credentials, OTel telemetry, Web tools, subagents, local instruction discovery, and compaction are absent. The [DeepSeek session-log contributor](../../../packages/session/session-log-deepseek/README.md) uploads unaccepted log events with DeepSeek requests by default, at most `maxBytes` (8 MiB) per request; set `session-log-deepseek.enabled: false` in a profile patch to disable it. It pins `danger-full-access`, so the platform-selected persistent shell can modify any path visible to the runtime; use a disposable checkout or container.
The profile's sole bundle inserts the complete tree over an empty root and does not include `dsh-base`; later base-profile tools therefore cannot appear implicitly. It contains the SDK protocol, one environment-configured DeepSeek adapter, local execution, and persistence, while text file tools, settings, managed credentials, OTel telemetry, Web tools, subagents, and local instruction discovery are absent. The [DeepSeek session-log contributor](../../../packages/session/session-log-deepseek/README.md) uploads unaccepted log events with DeepSeek requests by default, at most `maxBytes` (8 MiB) per request; set `session-log-deepseek.enabled: false` in a profile patch to disable it. It pins `danger-full-access`, so the platform-selected persistent shell can modify any path visible to the runtime; use a disposable checkout or container.
Image reading requires an image-capable route. Automatic compaction preserves the complete Session log; see the [bundle reference](../../../packages/bundle/sdk-minimal/README.md) for model and storage effects. SDK prompt text does not execute `/compact` or other slash commands.
The installed wheel still packages the full `web` profile and frontend assets. Run `dsh web` against an explicit `DSH_HOME` when a Python SDK deployment also needs the browser application; `web` is a separate CLI application and cannot serve a Python SDK client.
+8 -9
View File
@@ -152,19 +152,15 @@ dsh plugin --profile sdk-minimal add file:C:/work/my-plugin-bundle
<a id="opt-in-to-str_replace_editor"></a>
### 显式启用 `str_replace_editor`
随附运行时包含 `str_replace_editor`,但 `sdk-minimal` 的默认 Cordis tree 不挂载它。要使用该工具,请将以下配置保存为 `editor.patch.yml`;`insert` 会添加 editor,以及极简 profile 缺少的文件系统后端:
随附运行时包含 `str_replace_editor`,但 `sdk-minimal` 的默认 Cordis tree 不挂载它。要使用该工具,请将以下配置保存为 `editor.patch.yml`;`insert` 会添加 editor,并使用已有的文件系统后端:
```yaml
- insert:
- id: fs-local
name: '@deepseek-ai/dsh-fs-local'
config:
cwd: !!js process.cwd()
- id: tool-str-replace-editor
name: '@deepseek-ai/dsh-tool-str-replace-editor'
```
构造 `DeepSeekHarness(profile="sdk-minimal", ...)` 时传入 `patches=("/absolute/path/to/editor.patch.yml",)`,或将 patch 写入 `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml` 以持久保存配置。下次运行时启动后,模型请求会在持久 shell 之外包含 `str_replace_editor`。本地文件系统后端以运行时工作目录解析相对路径;与极简 shell 一样,它不会将访问限制在该目录内。对于标准 `sdk` profile,只插入 editor 配置项,让它使用已有的文件系统后端与策略。
构造 `DeepSeekHarness(profile="sdk-minimal", ...)` 时传入 `patches=("/absolute/path/to/editor.patch.yml",)`,或将 patch 写入 `$DSH_HOME/profiles/sdk-minimal/cordis.patch.yml` 以持久保存配置。下次运行时启动后,模型请求会在默认工具之外包含 `str_replace_editor`。本地文件系统后端以运行时工作目录解析相对路径;与极简 shell 一样,它不会将访问限制在该目录内。该 patch 也适用于标准 `sdk` profile。
## 理解极简 profile
@@ -172,12 +168,15 @@ dsh plugin --profile sdk-minimal add file:C:/work/my-plugin-bundle
|---|---|
| 系统提示词 | `DSH_SYSTEM_PROMPT`,未设置时为 `You are a helpful software engineer assistant.` |
| `minimal.py` 的模型 | `--model`,然后是 `DSH_MODEL`,最后是 `deepseek-v4-flash` |
| 面向模型的工具 | Linux/macOS 上的持久 `bash` 或 Windows 上的 `pwsh` |
| 面向模型的工具 | Linux/macOS 上的持久 `bash` 或 Windows 上的 `pwsh`、`read_image` 和 `working_directory` |
| Shell 超时 | 300 秒 |
| 运行时上下文与 compaction | 不存在 |
| 可选运行时上下文 | 不存在 |
| 上下文压缩 | 自动执行;通过额外模型请求生成较早历史的摘要 |
| 会话持久化 | `<dsh_home>/sessions` 下的未压缩 JSONL |
该 profile 的唯一组合包会在空根之上插入完整配置树,且不包含 `dsh-base`,因此基础 profile 以后新增的工具不会隐式出现。它包含 SDK 协议、一个由环境配置的 DeepSeek 适配器、本地执行与持久化;文件系统工具、settings、托管凭据、OTel 遥测、Web 工具、subagent、本地指令发现和 compaction 均不存在。[DeepSeek 会话日志贡献器](../../../packages/session/session-log-deepseek/README.zh.md)默认随 DeepSeek 请求上传未接受的日志事件,每次请求最多 `maxBytes`(8 MiB);在 profile patch 中设置 `session-log-deepseek.enabled: false` 可将其关闭。它固定使用 `danger-full-access`,因此按平台选择的持久 shell 可以修改运行时可见的任何路径;应使用一次性 checkout 或容器。
该 profile 的唯一组合包会在空根之上插入完整配置树,且不包含 `dsh-base`,因此基础 profile 以后新增的工具不会隐式出现。它包含 SDK 协议、一个由环境配置的 DeepSeek 适配器、本地执行与持久化;文本文件工具、settings、托管凭据、OTel 遥测、Web 工具、subagent、本地指令发现均不存在。[DeepSeek 会话日志贡献器](../../../packages/session/session-log-deepseek/README.zh.md)默认随 DeepSeek 请求上传未接受的日志事件,每次请求最多 `maxBytes`(8 MiB);在 profile patch 中设置 `session-log-deepseek.enabled: false` 可将其关闭。它固定使用 `danger-full-access`,因此按平台选择的持久 shell 可以修改运行时可见的任何路径;应使用一次性 checkout 或容器。
图片读取需要支持图片输入的路由。自动压缩保留完整 Session 日志;模型与存储影响见[组合包参考](../../../packages/bundle/sdk-minimal/README.zh.md)。SDK 提示词文本不会执行 `/compact` 或其他斜杠命令。
已安装 wheel 仍会打包完整 `web` profile 与前端产物。如果 Python SDK 部署还需要浏览器应用,请针对显式 `DSH_HOME` 运行 `dsh web`;`web` 是独立 CLI 应用,不能为 Python SDK client 提供服务。
+16 -16
View File
@@ -3,23 +3,23 @@
# After editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bundle/sdk-minimal/README.md
/:
en: 7cbc0e332890851f
zh: 07c71026d8e1bb15
en: b2fce08b0fa865da
zh: 97e214d87ded4b54
/deepseek-ai-dsh-sdk-minimal:
en: 807c43eedba7d53e
zh: 9f1efe5d6ac393f7
/deepseek-ai-dsh-sdk-minimal/summary:
en: c0a98b4bcbb3e719
zh: 92895dd5ce381cd1
en: 31b83af058b212f9
zh: 289678ac3738ee5e
/deepseek-ai-dsh-sdk-minimal/table-of-contents:
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
/deepseek-ai-dsh-sdk-minimal/use-this-package:
en: f920307c0cf12118
zh: edf9051846fecd5c
en: 39483eef4a61f212
zh: 62d82f46a04e07fe
/deepseek-ai-dsh-sdk-minimal/understand-the-implementation:
en: 91f4a78ab7a688d3
zh: 7bb8bf33c0d8b429
en: 5db5d8f041867958
zh: bff5ef3a2e140712
/deepseek-ai-dsh-sdk-minimal/understand-the-implementation/source-map:
en: 3784c554e96ab004
zh: 0a05d4fe1e26b3b1
@@ -33,17 +33,17 @@
en: bd87e16b0c6e0506
zh: c8ee5e3b4578754e
/deepseek-ai-dsh-sdk-minimal/model-experience/minimal-coding-agent-composition/what-the-model-sees:
en: 724e1f4075df9293
zh: 35955569ded10b56
en: df40d9529b566cfa
zh: 4678769b4f85120b
/deepseek-ai-dsh-sdk-minimal/model-experience/minimal-coding-agent-composition/token-effect:
en: 5df298b2c9f95d27
zh: def93cd59b5ca843
en: d84b54486d1c66b0
zh: 01a22b8947cb9a49
/deepseek-ai-dsh-sdk-minimal/model-experience/minimal-coding-agent-composition/kv-cache-effect:
en: 904ae09b5fdb87c1
zh: de6fcaaa12bd9733
en: e4ed99b28a68b765
zh: fa39a06a5a3a5156
/deepseek-ai-dsh-sdk-minimal/known-limitations-and-deferred-work:
en: 8f74b1b4f39eda83
zh: af96ec4cb42810c5
en: 00c4192d6af9f621
zh: 460451ab6dc07c3a
/deepseek-ai-dsh-sdk-minimal/known-limitations-and-deferred-work/dev-note:
en: e67f633dc6fe7773
zh: e88aeb617ffb74ea
+9 -7
View File
@@ -1,5 +1,5 @@
---
description: "Standalone SDK profile with a persistent shell and Session working-directory tool for a minimal cross-platform coding agent without the shared base bundle."
description: "Standalone SDK profile with a persistent shell, image reading, automatic context compaction, and a Session working-directory tool for a minimal cross-platform coding agent without the shared base bundle."
kind: "package-bundle"
---
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
Use `dsh --profile sdk-minimal` when an SDK client needs a small, explicit coding-agent runtime. By default, the profile advertises a platform-selected persistent shell and `working_directory`, persists sessions as uncompressed JSONL, and selects the model from the SDK initialization request. It supplies a complete Cordis tree and excludes `dsh-base`, Web, settings, managed credentials, telemetry, compaction, filesystem tools, workspace instructions, skills, jobs, and subagents. Its danger-full-access policy lets the shell modify any path available to the process, so use it only with an isolated workspace.
Use `dsh --profile sdk-minimal` when an SDK client needs a small, explicit coding-agent runtime. By default, the profile advertises a platform-selected persistent shell, `read_image`, and `working_directory`, persists sessions as uncompressed JSONL, and selects the model from the SDK initialization request. It supplies a complete Cordis tree and excludes `dsh-base`, Web, settings, managed credentials, telemetry, text file tools, workspace instructions, skills, jobs, and subagents. Its danger-full-access policy lets the shell modify any path available to the process, so use it only with an isolated workspace.
## Table of Contents
@@ -38,7 +38,7 @@ Use `dsh plugin --profile sdk-minimal` to manage persistent external dependencie
The profile mounts exactly one persistent shell stack: Bash on Linux and macOS, or PowerShell on Windows. Both stacks use a 300-second timeout and one owner-scoped terminal; the other platform's rows remain disabled.
Like every shipped profile, it mounts [MCP resources](../../mcp/mcp-resources/README.md) once. Configure only [MCP client entries](../../mcp/mcp-client/README.md) to add servers. Clients mounted by another provider also count as configured. With no server configured in the caller's scope, MCP contributes no prompt text or tools and the default remains the shell and `working_directory` tools.
Like every shipped profile, it mounts [MCP resources](../../mcp/mcp-resources/README.md) once. Configure only [MCP client entries](../../mcp/mcp-client/README.md) to add servers. Clients mounted by another provider also count as configured. With no server configured in the caller's scope, MCP contributes no prompt text or tools and the default remains the shell, `read_image`, and `working_directory` tools.
-----
@@ -48,7 +48,7 @@ Like every shipped profile, it mounts [MCP resources](../../mcp/mcp-resources/RE
<details>
<summary>Implementation internals — click to expand</summary>
The bundle's single insert is the complete application tree: SDK stdio startup and JSON-RPC serving, one environment-configured DeepSeek adapter, the explicit agent core, conditional MCP resource tools, local filesystem and subprocess services, Session working-directory state and its tool, a platform-selected persistent shell PTY, and uncompressed JSONL persistence under `$DSH_HOME/sessions`. It does not inherit another bundle, so every extra row is an explicit profile change.
The bundle's single insert is the complete application tree: SDK stdio startup and JSON-RPC serving, one environment-configured DeepSeek adapter, the explicit agent core, conditional MCP resource tools, local filesystem, image attachments, automatic context compaction, and subprocess services, Session working-directory state and its tool, a platform-selected persistent shell PTY, and uncompressed JSONL persistence under `$DSH_HOME/sessions`. It does not inherit another bundle, so every extra row is an explicit profile change.
### Source map
@@ -78,21 +78,23 @@ The bundle's single insert is the complete application tree: SDK stdio startup a
#### What the model sees
The system prompt is `DSH_SYSTEM_PROMPT` or `You are a helpful software engineer assistant.`. With no MCP server configured, the advertised tools are `working_directory` and owner-scoped persistent `bash` on Linux/macOS or `pwsh` on Windows. Required user context supplies the current directory. Optional runtime context, filesystem tools, workspace instructions, skills, jobs controls, compaction, and Harness identity are absent.
The system prompt is `DSH_SYSTEM_PROMPT` or `You are a helpful software engineer assistant.`. With no MCP server configured, the advertised tools are `read_image`, `working_directory`, and owner-scoped persistent `bash` on Linux/macOS or `pwsh` on Windows. Required user context supplies the current directory. Optional runtime context, text file tools, workspace instructions, skills, jobs controls, and Harness identity are absent.
#### Token effect
By default, one stable persona, two tool schemas, and user context for the initial directory and subsequent changes. Configured MCP servers add their tools, shared resource tools, and available server instructions. Tool results and ordinary conversation history grow with the session.
By default, one stable persona, three tool schemas, and user context for the initial directory and subsequent changes. Configured MCP servers add their tools, shared resource tools, and available server instructions. Images consume model input tokens. Automatic compaction sends an additional summarization request when context pressure reaches the configured threshold and replaces older model-visible history with its summary; the durable JSONL log retains those events.
#### KV Cache effect
Stable for a fixed persona, platform, provider, model, and bundle patch stack. Profile changes take effect on the next process.
Stable for a fixed persona, platform, provider, model, and bundle patch stack. Compaction replaces part of the request history and can reduce cache reuse. Profile changes take effect on the next process.
## Known Limitations and Deferred Work
<a id="known-limitations-and-deferred-work"></a>
- **The composition intentionally omits shared product services** — select `dsh --profile sdk` when settings, managed credentials, policy presets, telemetry, Web tools, or the full default tool roster are required.
- **Image reading requires an image-capable model** — select a route whose adapter declares image input; text-only routes return a tool error. Images are stored under `$DSH_HOME/attachments/v1`.
- **Compaction is automatic** — configure [compaction-basic](../../compaction/compaction-basic/README.md) through profile patches. SDK prompt text does not execute `/compact` or other slash commands.
- **User patches can expand the tree and corrupt stdout** — profile customization is trusted application composition; a plugin that writes ordinary text to stdout can break JSON-RPC framing.
<a id="dev-note"></a>
+9 -7
View File
@@ -1,5 +1,5 @@
---
description: "独立 SDK profile,提供持久 shell 和 Session 工作目录工具,用于不含共享 base bundle 的极简跨平台 coding agent(编程智能体)。"
description: "独立 SDK profile,提供持久 shell、图片读取、自动上下文压缩和 Session 工作目录工具,用于不含共享 base bundle 的极简跨平台 coding agent(编程智能体)。"
kind: "package-bundle"
---
@@ -9,7 +9,7 @@ kind: "package-bundle"
## 概述
当 SDK 客户端需要小型、显式的 coding agent 运行时时,请使用 `dsh --profile sdk-minimal`。该 profile 默认公布按平台选择的持久 shell 和 `working_directory`,把会话持久化为未压缩 JSONL,并从 SDK 初始化请求选择模型。它提供完整 Cordis 配置树,并排除 `dsh-base`、Web、settings、托管凭据、遥测、压缩(compaction)、文件系统工具、workspace 指令、skill(技能)、jobs 与 subagent。其 danger-full-access 策略允许 shell 修改进程可访问的任何路径,因此只能配合隔离 workspace 使用。
当 SDK 客户端需要小型、显式的 coding agent 运行时时,请使用 `dsh --profile sdk-minimal`。该 profile 默认公布按平台选择的持久 shell、`read_image` 和 `working_directory`,把会话持久化为未压缩 JSONL,并从 SDK 初始化请求选择模型。它提供完整 Cordis 配置树,并排除 `dsh-base`、Web、settings、托管凭据、遥测、文本文件工具、workspace 指令、skill(技能)、jobs 与 subagent。其 danger-full-access 策略允许 shell 修改进程可访问的任何路径,因此只能配合隔离 workspace 使用。
## 目录
@@ -38,7 +38,7 @@ dsh --profile sdk-minimal
该 profile 只挂载一套持久 shell:Linux 和 macOS 使用 Bash,Windows 使用 PowerShell。两套配置都使用 300 秒超时与一个 agent 自有终端;另一平台的配置项保持禁用。
与其他随附 profile 一样,它统一挂载 [MCP 资源](../../mcp/mcp-resources/README.zh.md)一次。只需配置 [MCP 客户端条目](../../mcp/mcp-client/README.zh.md)即可添加服务器。其他提供方挂载的客户端也属于已配置状态。调用方作用域中未配置服务器时,MCP 不贡献提示词文本或工具,默认仍为 shell 与 `working_directory` 两个工具。
与其他随附 profile 一样,它统一挂载 [MCP 资源](../../mcp/mcp-resources/README.zh.md)一次。只需配置 [MCP 客户端条目](../../mcp/mcp-client/README.zh.md)即可添加服务器。其他提供方挂载的客户端也属于已配置状态。调用方作用域中未配置服务器时,MCP 不贡献提示词文本或工具,默认仍为 shell、`read_image` 与 `working_directory` 三个工具。
-----
@@ -48,7 +48,7 @@ dsh --profile sdk-minimal
<details>
<summary>实现细节——点击展开</summary>
该 bundle 的单个 insert 就是完整应用配置树:SDK stdio 启动与 JSON-RPC 服务、一个由环境配置的 DeepSeek 适配器、显式 agent 核心、按配置启用的 MCP 资源工具、本地文件系统与子进程服务、Session 工作目录状态及其工具、按平台选择的持久 shell PTY,以及位于 `$DSH_HOME/sessions` 的未压缩 JSONL 持久化。它不继承其他 bundle,因此每个额外配置项都是显式 profile 变更。
该 bundle 的单个 insert 就是完整应用配置树:SDK stdio 启动与 JSON-RPC 服务、一个由环境配置的 DeepSeek 适配器、显式 agent 核心、按配置启用的 MCP 资源工具、本地文件系统、图片附件、自动上下文压缩与子进程服务、Session 工作目录状态及其工具、按平台选择的持久 shell PTY,以及位于 `$DSH_HOME/sessions` 的未压缩 JSONL 持久化。它不继承其他 bundle,因此每个额外配置项都是显式 profile 变更。
### 源码地图
@@ -78,21 +78,23 @@ dsh --profile sdk-minimal
#### 模型看到的内容
系统提示词取 `DSH_SYSTEM_PROMPT`,未设置时使用 `You are a helpful software engineer assistant.`。未配置 MCP 服务器时,对外公布的工具为 `working_directory`,以及 Linux/macOS 上 agent 所有的持久 `bash` 或 Windows 上的 `pwsh`。必需的用户上下文提供当前目录。可选运行时上下文、文件系统工具、workspace 指令、skill、jobs 控制、压缩与 Harness 身份均不存在。
系统提示词取 `DSH_SYSTEM_PROMPT`,未设置时使用 `You are a helpful software engineer assistant.`。未配置 MCP 服务器时,对外公布的工具为 `read_image`、`working_directory`,以及 Linux/macOS 上 agent 所有的持久 `bash` 或 Windows 上的 `pwsh`。必需的用户上下文提供当前目录。可选运行时上下文、文本文件工具、workspace 指令、skill、jobs 控制与 Harness 身份均不存在。
#### Token 影响
默认是一个稳定 persona、两个工具 schema,以及初始目录与后续变更的用户上下文。已配置 MCP 服务器会添加自己的工具、共享资源工具及可用的服务器指令。工具结果与普通对话历史随会话增长。
默认是一个稳定 persona、三个工具 schema,以及初始目录与后续变更的用户上下文。已配置 MCP 服务器会添加自己的工具、共享资源工具及可用的服务器指令。图片消耗模型输入 token。上下文压力达到配置阈值时,自动压缩会额外发起摘要请求,并用摘要替换较早的模型可见历史;持久 JSONL 日志保留这些事件。
#### KV Cache 影响
当 persona、平台、提供方、模型与 bundle patch 栈固定时保持稳定。Profile 变更在下一个进程生效。
当 persona、平台、提供方、模型与 bundle patch 栈固定时保持稳定。压缩会替换部分请求历史,可能降低缓存复用率。Profile 变更在下一个进程生效。
## 已知限制与延期工作
<a id="known-limitations-and-deferred-work"></a>
- **该组合刻意省略共享产品服务** — 需要 settings、托管凭据、策略预设、遥测、Web 工具或完整默认工具清单时,请选择 `dsh --profile sdk`。
- **图片读取需要支持图片输入的模型** — 选择适配器声明支持图片输入的路由;纯文本路由会返回工具错误。图片存储在 `$DSH_HOME/attachments/v1` 下。
- **压缩由系统自动执行** — 通过 profile patch 配置 [compaction-basic](../../compaction/compaction-basic/README.zh.md)。SDK 提示词文本不会执行 `/compact` 或其他斜杠命令。
- **用户 patch 可以扩展配置树并破坏 stdout** — profile 自定义属于受信任的应用组合;向 stdout 写入普通文本的插件会破坏 JSON-RPC 分帧。
<a id="dev-note"></a>
@@ -38,6 +38,15 @@
- id: filesystem
name: '@deepseek-ai/dsh-fs-local'
- id: attachment-local
name: '@deepseek-ai/dsh-attachment-local'
- id: tool-fs
name: '@deepseek-ai/dsh-tool-fs'
config:
tools:
- read_image
- id: working-directory
name: '@deepseek-ai/dsh-working-directory'
@@ -47,6 +56,14 @@
- id: session-projection
name: '@deepseek-ai/dsh-session-projection'
- id: token-meter
name: '@deepseek-ai/dsh-token-meter'
- id: compaction-basic
name: '@deepseek-ai/dsh-compaction-basic'
config:
auto: true
- id: sandbox-policy
name: '@deepseek-ai/dsh-sandbox-policy'
config:
+4
View File
@@ -37,6 +37,8 @@
"@deepseek-ai/cordis-plugin-timer": "workspace:~",
"@deepseek-ai/dsh-agent": "workspace:*",
"@deepseek-ai/dsh-agent-loop": "workspace:*",
"@deepseek-ai/dsh-attachment-local": "workspace:*",
"@deepseek-ai/dsh-compaction-basic": "workspace:*",
"@deepseek-ai/dsh-deepseek-llm-api-extensions": "workspace:*",
"@deepseek-ai/dsh-jobs-local": "workspace:*",
"@deepseek-ai/dsh-llm": "workspace:*",
@@ -57,7 +59,9 @@
"@deepseek-ai/dsh-system-prompt": "workspace:*",
"@deepseek-ai/dsh-terminal": "workspace:*",
"@deepseek-ai/dsh-terminal-bash": "workspace:*",
"@deepseek-ai/dsh-token-meter": "workspace:*",
"@deepseek-ai/dsh-tool-bash-persistent": "workspace:*",
"@deepseek-ai/dsh-tool-fs": "workspace:*",
"@deepseek-ai/dsh-tool-pwsh-persistent": "workspace:*",
"@deepseek-ai/dsh-tools": "workspace:*",
"@deepseek-ai/dsh-working-directory": "workspace:*",
@@ -34,9 +34,13 @@ describe('dsh-sdk-minimal bundle', () => {
['llm-deepseek', '@deepseek-ai/dsh-llm-deepseek-api-key'],
['sandbox', '@deepseek-ai/dsh-sandbox-local'],
['filesystem', '@deepseek-ai/dsh-fs-local'],
['attachment-local', '@deepseek-ai/dsh-attachment-local'],
['tool-fs', '@deepseek-ai/dsh-tool-fs'],
['working-directory', '@deepseek-ai/dsh-working-directory'],
['tool-working-directory', '@deepseek-ai/dsh-tool-working-directory'],
['session-projection', '@deepseek-ai/dsh-session-projection'],
['token-meter', '@deepseek-ai/dsh-token-meter'],
['compaction-basic', '@deepseek-ai/dsh-compaction-basic'],
['sandbox-policy', '@deepseek-ai/dsh-sandbox-policy'],
['subprocess', '@deepseek-ai/dsh-subprocess-local'],
['pty', '@deepseek-ai/dsh-terminal'],
@@ -73,6 +77,8 @@ describe('dsh-sdk-minimal bundle', () => {
personaPrefix: { __jsExpr: "process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'" },
})
expect(rows.find(row => row.id === 'agent-loop')?.config).toEqual({ agents: [] })
expect(rows.find(row => row.id === 'tool-fs')?.config).toEqual({ tools: ['read_image'] })
expect(rows.find(row => row.id === 'compaction-basic')?.config).toEqual({ auto: true })
expect(rows.find(row => row.id === 'terminal-bash')).toMatchObject({
disabled: { __jsExpr: "process.platform === 'win32'" },
})
@@ -55,7 +55,7 @@ export const en: Record<AgentPresetSettingsKey, string> = {
'Includes all Standard mode capabilities. Better suited to tasks that call tools in batches and then filter, organize, deduplicate, count, or summarize the results.',
presetMinimalName: 'Minimal mode',
presetMinimalDescription:
'The agent works using only a terminal tool. Useful for testing and comparing its basic performance.',
'The agent uses a terminal and image reading, with context compaction. Useful for testing and comparing its basic performance.',
presetCordisName: 'Creator mode',
presetCordisDescription:
'Customize DSH through conversation. Let the agent write plugins that add features or UI, or combine tools and prompts to create your own mode.',
@@ -97,7 +97,7 @@ export const zh: Record<AgentPresetSettingsKey, string> = {
presetPtcName: 'PTC 模式',
presetPtcDescription: '包含标准模式的所有能力,更适合批量调用工具,并对结果进行筛选、整理、去重、统计或汇总的任务。',
presetMinimalName: '极简模式',
presetMinimalDescription: 'Agent 仅使用终端工具完成任务,适合测试和对比其基础表现。',
presetMinimalDescription: 'Agent 使用终端和图片读取工具,并支持上下文压缩,适合测试和对比其基础表现。',
presetCordisName: '创造模式',
presetCordisDescription: '用对话定制 DSH:让 Agent 编写插件,添加新功能或界面;也能组合工具和提示词,创建自己的模式。',
@@ -9,8 +9,8 @@
en: b184b97e2d1e1fa7
zh: 7d4b4cc8d73446af
/deepseek-ai-dsh-session-snapshot/summary:
en: 71cd3441e7189ac4
zh: 874ae7ac5fd231c9
en: 5d11e1dbbf5dd1cf
zh: 7a54089ed26ddd8f
/deepseek-ai-dsh-session-snapshot/table-of-contents:
en: d152484eb41ac6b4
zh: 09388d293f9be9cb
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
## Summary
`dsh-session-snapshot` provides the shared support behind keyless recorded-session tests (`pnpm run test:snapshot`): closed manifests, typed identity redaction, normalization, workspace comparison, fixture guards, and protocol adapters for headless, SDK, ACP, and Web owners. The ACP adapter launches the tested profile as a real subprocess, drives a deterministic input script, and registers the complete record, replay, and refresh suite. Every scenario owns enough committed evidence to prove model-visible output and filesystem effects without trusting the agent's report. The package entry imports vitest and is therefore available only inside a vitest run.
`dsh-session-snapshot` provides the shared support behind keyless recorded-session tests (`pnpm run test:snapshot`): closed manifests, typed identity redaction, normalization, workspace comparison, fixture guards, and protocol adapters for headless, SDK (`sdk` and `sdk-minimal`), ACP, and Web owners. The ACP adapter launches the tested profile as a real subprocess, drives a deterministic input script, and registers the complete record, replay, and refresh suite. Every scenario owns enough committed evidence to prove model-visible output and filesystem effects without trusting the agent's report. The package entry imports vitest and is therefore available only inside a vitest run.
## Table of Contents
@@ -9,7 +9,7 @@ kind: "package-library"
## 概述
`dsh-session-snapshot` 提供无密钥已记录会话测试(`pnpm run test:snapshot`)背后的共享支持:封闭 manifest、类型化身份脱敏、规范化、workspace 比较、fixture(测试前置数据)保护,以及 headless、SDK、ACP(Agent Client Protocol)与 Web owner 使用的协议适配器。ACP 适配器以真实子进程启动被测 profile,驱动确定性输入脚本,并注册完整的录制、回放与刷新套件。每个场景都提交足够证据来证明模型可见输出与文件系统效果,不依赖 agent(智能体)自述。包入口会导入 vitest,因此只能在 vitest 运行中使用。
`dsh-session-snapshot` 提供无密钥已记录会话测试(`pnpm run test:snapshot`)背后的共享支持:封闭 manifest、类型化身份脱敏、规范化、workspace 比较、fixture(测试前置数据)保护,以及 headless、SDK(`sdk` 与 `sdk-minimal`)、ACP(Agent Client Protocol)与 Web owner 使用的协议适配器。ACP 适配器以真实子进程启动被测 profile,驱动确定性输入脚本,并注册完整的录制、回放与刷新套件。每个场景都提交足够证据来证明模型可见输出与文件系统效果,不依赖 agent(智能体)自述。包入口会导入 vitest,因此只能在 vitest 运行中使用。
## 目录
@@ -4,7 +4,7 @@ import { isAbsolute } from 'node:path'
import * as yaml from 'js-yaml'
/** Public `dsh` profile used to control a recorded-session scenario. */
export type SnapshotProfile = 'headless' | 'sdk' | 'acp' | 'web'
export type SnapshotProfile = 'headless' | 'sdk' | 'sdk-minimal' | 'acp' | 'web'
/** How a canonical session may be regenerated. */
export type SnapshotRecording = 'live' | 'authored'
@@ -143,7 +143,7 @@ export function writesCurrentSessionFixtures(
return mode !== 'replay' && manifest.session === undefined && manifest.sessionFormat === undefined
}
const PROFILES = new Set<SnapshotProfile>(['headless', 'sdk', 'acp', 'web'])
const PROFILES = new Set<SnapshotProfile>(['headless', 'sdk', 'sdk-minimal', 'acp', 'web'])
const RECORDINGS = new Set<SnapshotRecording>(['live', 'authored'])
const PLATFORMS = new Set<SnapshotPlatform>(['posix', 'pwsh'])
const PERMISSIONS = new Set<SnapshotPermission>(['read-only', 'workspace-write', 'danger-full-access'])
@@ -227,7 +227,7 @@ export function parseSnapshotManifest(source: string, path = 'snapshot.yml'): Sn
if (root.version !== 1) throw new Error('manifest.version must equal 1')
const scenario = root.scenario === undefined ? undefined : name(root.scenario, 'manifest.scenario')
if (typeof root.profile !== 'string' || !PROFILES.has(root.profile as SnapshotProfile)) {
throw new Error('manifest.profile must be headless, sdk, acp, or web')
throw new Error('manifest.profile must be headless, sdk, sdk-minimal, acp, or web')
}
const composition = root.composition === undefined
@@ -9,6 +9,13 @@ describe('snapshot manifest', () => {
})
})
it('accepts the standalone SDK-minimal profile', () => {
expect(parseSnapshotManifest('version: 1\nprofile: sdk-minimal\n')).toEqual({
version: 1,
profile: 'sdk-minimal',
})
})
it('parses an explicitly retained Session generation and its migration coverage', () => {
expect(parseSnapshotManifest([
'version: 1',
@@ -161,7 +168,7 @@ describe('snapshot manifest', () => {
it.each([
['', 'manifest must be a mapping'],
['version: 2\nprofile: acp\n', 'manifest.version must equal 1'],
['version: 1\nprofile: private\n', 'manifest.profile must be headless, sdk, acp, or web'],
['version: 1\nprofile: private\n', 'manifest.profile must be headless, sdk, sdk-minimal, acp, or web'],
['version: 1\nprofile: acp\nextra: true\n', 'manifest has unknown field(s): extra'],
['version: 1\nprofile: acp\ncomposition: Not_Safe\n', 'manifest.composition must be a lower-kebab-case name'],
['version: 1\nprofile: acp\nrecording: maybe\n', 'manifest.recording must be live or authored'],
+12
View File
@@ -2410,6 +2410,12 @@ importers:
'@deepseek-ai/dsh-agent-loop':
specifier: workspace:*
version: link:../../core/agent-loop
'@deepseek-ai/dsh-attachment-local':
specifier: workspace:*
version: link:../../attachment/attachment-local
'@deepseek-ai/dsh-compaction-basic':
specifier: workspace:*
version: link:../../compaction/compaction-basic
'@deepseek-ai/dsh-deepseek-llm-api-extensions':
specifier: workspace:*
version: link:../../llm/deepseek-llm-api-extensions
@@ -2473,9 +2479,15 @@ importers:
'@deepseek-ai/dsh-terminal-bash':
specifier: workspace:*
version: link:../../terminal/terminal-bash
'@deepseek-ai/dsh-token-meter':
specifier: workspace:*
version: link:../../llm/token-meter
'@deepseek-ai/dsh-tool-bash-persistent':
specifier: workspace:*
version: link:../../shell/tool-bash-persistent
'@deepseek-ai/dsh-tool-fs':
specifier: workspace:*
version: link:../../fs/tool-fs
'@deepseek-ai/dsh-tool-pwsh-persistent':
specifier: workspace:*
version: link:../../shell/tool-pwsh-persistent
+2 -2
View File
@@ -6,8 +6,8 @@
en: d9dfc996ea2ace40
zh: 33de241bad6c4ee1
/python-sdk-example/run-the-minimal-agent:
en: 0a23802ca759a16c
zh: 9a68ff9642f90efb
en: f0d785582fe72a91
zh: ee563fb17c775ed3
/python-sdk-example/add-plugins:
en: 5e1e30dac13f6c9e
zh: 0af98ebb75c88f43
+3 -1
View File
@@ -22,8 +22,10 @@ Set `DEEPSEEK_BASE_URL` for a compatible proxy, `DSH_MODEL` for the script's def
The shipped [`@deepseek-ai/dsh-sdk-minimal` bundle](../../../packages/bundle/sdk-minimal/README.md) is the complete explicit Cordis tree for this mode. It exposes exactly:
- owner-scoped persistent `bash` on Linux/macOS or `pwsh` on Windows
- `read_image` for PNG/JPEG/WebP/GIF files, with an image-capable model
- `working_directory` to inspect or change the Session directory
The bundle does not include `dsh-base`, so every additional row is an explicit profile change. Runtime context, filesystem tools, local instruction discovery, compaction, settings, managed credentials, telemetry, Web tools, subagents, and the full default tool roster are absent. The tree retains SDK startup and JSON-RPC serving, one environment-configured DeepSeek adapter, local execution, and JSONL persistence.
The bundle does not include `dsh-base`, so every additional row is an explicit profile change. Runtime context, text file tools, local instruction discovery, settings, managed credentials, telemetry, Web tools, subagents, and the full default tool roster are absent. The tree retains SDK startup and JSON-RPC serving, one environment-configured DeepSeek adapter, local execution, and JSONL persistence. [Automatic context compaction](../../../packages/bundle/sdk-minimal/README.md#model-experience) summarizes older history through an additional model request while preserving the complete log. SDK prompt text does not execute slash commands.
The persistent PTY can modify any path available to the runtime process, so use a disposable checkout or container.
+3 -1
View File
@@ -22,8 +22,10 @@ python python/sdk/examples/minimal.py \
随附的 [`@deepseek-ai/dsh-sdk-minimal` 组合包](../../../packages/bundle/sdk-minimal/README.zh.md) 是该模式完整且显式的 Cordis 配置树。它只暴露:
- Linux/macOS 上所有者作用域内的持久 `bash`,或 Windows 上的 `pwsh`
- 配合支持图片输入的模型读取 PNG/JPEG/WebP/GIF 文件的 `read_image`
- 查询或修改 Session 目录的 `working_directory`
该组合包不包含 `dsh-base`,因此每一个新增配置项都是显式 profile 变更。运行时上下文、文件系统工具、本地指令发现、压缩(compaction)、设置、托管凭据、遥测、Web 工具、subagent 与完整默认工具清单均不存在。配置树保留 SDK 启动与 JSON-RPC 服务、一个由环境配置的 DeepSeek 适配器、本地执行和 JSONL 持久化。
该组合包不包含 `dsh-base`,因此每一个新增配置项都是显式 profile 变更。运行时上下文、文本文件工具、本地指令发现、设置、托管凭据、遥测、Web 工具、subagent 与完整默认工具清单均不存在。配置树保留 SDK 启动与 JSON-RPC 服务、一个由环境配置的 DeepSeek 适配器、本地执行和 JSONL 持久化。[自动上下文压缩](../../../packages/bundle/sdk-minimal/README.zh.md#model-experience)通过额外模型请求生成较早历史的摘要,同时保留完整日志。SDK 提示词文本不会执行斜杠命令。
持久 PTY 可以修改运行时进程可访问的任何路径,因此只应在一次性 checkout 或容器中使用。
+5 -1
View File
@@ -55,7 +55,11 @@ async function scenarios(): Promise<Scenario[]> {
expect(existsSync(path), `${profile}/${entry.name}/snapshot.yml`).toBe(true)
const manifest = parseSnapshotManifest(await readFile(path, 'utf8'), path)
expect(manifest.scenario, `${profile}/${entry.name}: scenario`).toBe(entry.name)
expect(manifest.profile, `${profile}/${entry.name}: profile`).toBe(profile === 'session' ? 'headless' : profile)
if (profile === 'sdk') {
expect(['sdk', 'sdk-minimal'], `${profile}/${entry.name}: profile`).toContain(manifest.profile)
} else {
expect(manifest.profile, `${profile}/${entry.name}: profile`).toBe(profile === 'session' ? 'headless' : profile)
}
expect(manifest.composition, `${profile}/${entry.name}: composition`).toBeTypeOf('string')
expect(manifest.recording, `${profile}/${entry.name}: recording`).toMatch(/^(live|authored)$/)
expect(manifest.header, `${profile}/${entry.name}: header`).toBeDefined()
@@ -0,0 +1,22 @@
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek-api-key'
disabled: true
- insert:
- id: llm-replay
name: '@deepseek-ai/dsh-llm-replay'
config:
providers:
- id: deepseek-official
name: DeepSeek
models:
- id: deepseek-flash
inputModalities: [text, image]
contextWindow: 1000000
- id: compaction-basic
config:
thresholdRatio: 0.001
headroomTokens: 256
retainTokens: 64
maxTokens: 256
@@ -0,0 +1,4 @@
# Disable the external Session uploader in this local fixture.
- id: session-log-deepseek
config:
enabled: false
@@ -0,0 +1,26 @@
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":0,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Read red.png with read_image, then reply exactly MINIMAL_IMAGE_OK. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. ReLine truncated
{"method":"session.status","params":{"sessionId":"{{sessionId}}","status":"running"}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/start","seq":1,"time":0,"data":{"turn":1}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":2,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":3,"time":0,"data":{"turn":1,"step":1}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"system/message","seq":4,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":5,"time":0,"data":{"content":[{"type":"text","text":"Read red.png with read_image, then reply exactly MINIMAL_IMAGE_OK. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tooLine truncated
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":6,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/header","seq":7,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-flash"},"tools":"{{tools}}"},"reason":"initial"}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/context","seq":8,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-flash","contextWindow":1000000}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"session/title","seq":9,"time":0,"data":{"title":"Read red.png with read_image, then","messageSeqs":[5],"source":{"kind":"fallback"}}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":10,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":4},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"minimal-image-read","name":"read_image","args":["{\"file_path\":\"red.png\"}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":4}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":11,"time":0,"data":{"turn":1,"step":1,"callId":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":12,"time":0,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"minimal-image-read"},"toolCallId":"minimal-image-read","content":[{"type":"text","text":"<path>{{cwd}}/red.png</path>\n<type>image</type>\n<content>\nimage/png image, 1x1 px, 69 bytes\n</content>"},{"type":"image","attachment":{"attachmentId":"sha256:b1ff9c8ea3a780bad09b346c423d2d0e46815926879b18e841d928376a946640","mediaType":"image/png","bytes":69,"width":1,"height":1,"name":"red.png"}}],"isError":false,"id":"{{sessionId}}"},"meta":{"path":"{{cwd}}/red.png"}},"sourceEventSeqs":[11],"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":13,"time":0,"data":{"turn":1,"step":1}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"compaction/start","seq":14,"time":0,"data":{"compactionId":"{{sessionId}}","turn":1}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"compaction/summary","seq":15,"time":0,"data":{"compactionId":"{{sessionId}}","summary":[{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."}],"rawOutput":[{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."}],"llmStreamCall":true,"shadowedRange":{"start":5,"end":6},"shadowedSeqs":[5,6],"shadowedTokenCount":2923,"provider":"deepseek-official","model":"deepseek-flash","maxTokens":256}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":16,"time":0,"data":{"content":[{"type":"text","text":"This is an automatically generated checkpoint condensing an earlier span of the conversation to free up context. Treat the captured context as established background and build on it without restating it. Continue the task directly from the messages that follow, without acknowledging this checkpoint.\n\n<compacted-summary>"},{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."},{"type":"text","text":"</compacted-summary>"}],"source":{"kind":"compact-checkpoint","compactionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"sourceEventSeqs":[14,15,5,6],"surfaceOp":{"op":"replace","startSeq":5,"endSeq":6}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"compaction/end","seq":17,"time":0,"data":{"compactionId":"{{sessionId}}","turn":1}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":18,"time":0,"data":{"turn":1,"step":2}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":19,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/header","seq":20,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-flash"},"tools":"{{tools}}"},"reason":"series"}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":21,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"MINIMAL_IMAGE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":4},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["MINIMAL_IMAGE_OK"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"MINIMAL_IMAGE_OK"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":4}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":22,"time":0,"data":{"turn":1,"step":2}}}}
{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":23,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}}
{"method":"session.status","params":{"sessionId":"{{sessionId}}","status":"idle"}}
@@ -0,0 +1 @@
{"sessionId":"{{sessionId}}","finalResponse":"MINIMAL_IMAGE_OK"}
@@ -0,0 +1,25 @@
{"type":"session","version":4,"id":"{{session:1}}","createdAt":1788240634286,"cwd":"{{cwd}}","isSeeded":false,"delegationDepth":0}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Read red.png with read_image, then reply exactly MINIMAL_IMAGE_OK. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and Line truncated
{"type":"turn/start","data":{"turn":1}}
{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
{"type":"step/start","data":{"turn":1,"step":1}}
{"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{message:2}}"}},"surfaceOp":"append"}
{"type":"user/message","data":{"content":[{"type":"text","text":"Read red.png with read_image, then reply exactly MINIMAL_IMAGE_OK. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the image task and preserve the selected tool roster. Remember the imaLine truncated
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."}]},"role":"user","id":"{{message:3}}"},"surfaceOp":"append"}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-flash"},"tools":"{{tools}}"},"reason":"initial"}}
{"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-flash","contextWindow":1000000}}
{"type":"session/title","data":{"title":"Read red.png with read_image, then","messageSeqs":[5],"source":{"kind":"fallback"}}}
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-flash"},"id":"{{message:4}}"},"usage":{"inputTokens":10,"outputTokens":4},"stream":[{"type":"chunk","time":1791776019937,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791776019937,"index":0,"dt":[],"id":"minimal-image-read","name":"read_image","args":["{\"file_path\":\"red.png\"}"]},{"type":"chunk","time":1791776019937,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}}},{"type":"chunk","time":1791776019937,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":4}}},{"type":"chunk","time":1791776019937,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"minimal-image-read","name":"read_image","arguments":"{\"file_path\":\"red.png\"}"}}
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"minimal-image-read"},"toolCallId":"minimal-image-read","content":[{"type":"text","text":"<path>{{cwd}}/red.png</path>\n<type>image</type>\n<content>\nimage/png image, 1x1 px, 69 bytes\n</content>"},{"type":"image","attachment":{"attachmentId":"sha256:b1ff9c8ea3a780bad09b346c423d2d0e46815926879b18e841d928376a946640","mediaType":"image/png","bytes":69,"width":1,"height":1,"name":"red.png"}}],"isError":false,"id":"{{message:5}}"},"meta":{"path":"{{cwd}}/red.png"}},"sourceEventSeqs":[11],"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":1}}
{"type":"compaction/start","data":{"compactionId":"{{id:1}}","turn":1}}
{"type":"compaction/summary","data":{"compactionId":"{{id:1}}","summary":[{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."}],"rawOutput":[{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."}],"llmStreamCall":true,"shadowedRange":{"start":5,"end":6},"shadowedSeqs":[5,6],"shadowedTokenCount":2923,"provider":"deepseek-official","model":"deepseek-flash","maxTokens":256}}
{"type":"user/message","data":{"content":[{"type":"text","text":"This is an automatically generated checkpoint condensing an earlier span of the conversation to free up context. Treat the captured context as established background and build on it without restating it. Continue the task directly from the messages that follow, without acknowledging this checkpoint.\n\n<compacted-summary>"},{"type":"text","text":"Read red.png and report MINIMAL_IMAGE_OK."},{"type":"text","text":"</compacted-summary>"}],"source":{"kind":"compact-checkpoint","compactionId":"{{id:1}}"},"role":"user","id":"{{message:6}}"},"sourceEventSeqs":[14,15,5,6],"surfaceOp":{"op":"replace","startSeq":5,"endSeq":6}}
{"type":"compaction/end","data":{"compactionId":"{{id:1}}","turn":1}}
{"type":"step/start","data":{"turn":1,"step":2}}
{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\"."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."}]},"role":"user","id":"{{message:7}}"},"surfaceOp":"append"}
{"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-flash"},"tools":"{{tools}}"},"reason":"series"}}
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"MINIMAL_IMAGE_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-flash"},"id":"{{message:8}}"},"usage":{"inputTokens":10,"outputTokens":4},"stream":[{"type":"chunk","time":1791776020002,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":1791776020002,"index":0,"dt":[],"texts":["MINIMAL_IMAGE_OK"]},{"type":"chunk","time":1791776020002,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"MINIMAL_IMAGE_OK"}}},{"type":"chunk","time":1791776020002,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":4}}},{"type":"chunk","time":1791776020002,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
{"type":"step/end","data":{"turn":1,"step":2}}
{"type":"turn/end","data":{"turn":1,"reason":{"kind":"completed"}}}
@@ -0,0 +1,8 @@
version: 1
scenario: minimal-image-compaction
profile: sdk-minimal
composition: sdk-minimal-image-compaction
recording: authored
header:
class: sdk-minimal-image-compaction
pin: true
@@ -0,0 +1 @@
You are a helpful software engineer assistant.
@@ -0,0 +1,98 @@
{
"initial": [
{
"name": "bash",
"description": "Run commands in a bash shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* Network access depends on the task environment. Prefer configured mirrors/proxies when they are available.\n* State is persistent across command calls and discussions with the user.\n* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
},
{
"name": "read_image",
"description": "Read a PNG/JPEG/WebP/GIF file and return the image itself. Large images are downscaled automatically; do not install image libraries or create thumbnails to inspect an image.",
"parameters": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to the image file, resolved by the filesystem backend."
}
},
"required": [
"file_path"
]
}
},
{
"name": "working_directory",
"description": "Read the current working directory, or change it with cd. Relative paths use the current directory. Existing shells and running processes keep their own directories.",
"parameters": {
"type": "object",
"properties": {
"cd": {
"type": "string",
"description": "Existing directory to enter. Omit to read the current directory."
}
}
}
}
],
"changes": [
[
{
"name": "bash",
"description": "Run commands in a bash shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* Network access depends on the task environment. Prefer configured mirrors/proxies when they are available.\n* State is persistent across command calls and discussions with the user.\n* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}
},
{
"name": "read_image",
"description": "Read a PNG/JPEG/WebP/GIF file and return the image itself. Large images are downscaled automatically; do not install image libraries or create thumbnails to inspect an image.",
"parameters": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to the image file, resolved by the filesystem backend."
}
},
"required": [
"file_path"
]
}
},
{
"name": "working_directory",
"description": "Read the current working directory, or change it with cd. Relative paths use the current directory. Existing shells and running processes keep their own directories.",
"parameters": {
"type": "object",
"properties": {
"cd": {
"type": "string",
"description": "Existing directory to enter. Omit to read the current directory."
}
}
}
}
]
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

+38 -6
View File
@@ -1,6 +1,6 @@
/**
* Keyless snapshot coverage for the TypeScript SDK path: each scenario spawns
* the real `dsh --profile sdk` runtime through
* the real `dsh --profile sdk` or `sdk-minimal` runtime through
* `@deepseek-ai/dsh-sdk-client`, drives one turn over stdio JSON-RPC,
* and pins the SDK `RunResult`, the complete notification stream, and the
* persisted session logs. Replay serves recorded model
@@ -127,6 +127,10 @@ interface SdkAssertions {
}
const SDK_ASSERTIONS: Readonly<Record<string, SdkAssertions>> = {
'minimal-image-compaction': {
expectedFinalResponse: 'MINIMAL_IMAGE_OK',
expectedTools: { bash: ['command'], read_image: ['file_path'], working_directory: [] },
},
'session-title-stability': { waitForProviderTitle: true },
'dynamic-tool-updates': {
expectedFinalResponse: 'DONE',
@@ -222,7 +226,7 @@ async function collectCorpus(): Promise<CorpusScenario[]> {
const corpus = await collectCorpus()
const scenarioByKey = new Map(corpus.map(scenario => [scenario.key, scenario]))
const sdkScenarios = corpus
.filter(scenario => scenario.manifest.profile === 'sdk')
.filter(scenario => scenario.manifest.profile === 'sdk' || scenario.manifest.profile === 'sdk-minimal')
.sort((left, right) => left.name.localeCompare(right.name))
const compositionOwners = new Map<string, CorpusScenario>()
const headerPins = new Map<string, CorpusScenario>()
@@ -554,7 +558,7 @@ function authoredPatches(scenario: CorpusScenario, replaying: boolean): string[]
]
}
/** One SDK-controlled recorded scenario against a fresh `dsh --profile sdk` subprocess. */
/** One SDK-controlled recorded scenario against a fresh SDK-profile subprocess. */
async function runScenario(scenario: CorpusScenario): Promise<{
results: RunResult[]
notifications: HarnessNotification[]
@@ -576,7 +580,7 @@ async function runScenario(scenario: CorpusScenario): Promise<{
await mkdir(patchRoot, { recursive: true })
const assertions = SDK_ASSERTIONS[scenario.name] ?? {}
const patches = [...authoredPatches(scenario, !recording), ...assertions.patches ?? []]
.map((patch, index) => materializeProfilePatch(patch, cwd, 'sdk', patchRoot, index))
.map((patch, index) => materializeProfilePatch(patch, cwd, scenario.manifest.profile, patchRoot, index))
let childSessionsRoot: string | undefined
let childEnvironment: Record<string, string> = {}
if (assertions.dshSdkChild !== undefined) {
@@ -631,7 +635,7 @@ async function runScenario(scenario: CorpusScenario): Promise<{
}
const createHarness = (): DeepSeekHarness => new DeepSeekHarness({
profile: 'sdk',
profile: scenario.manifest.profile,
patches,
dshHome,
processCwd: cwd,
@@ -910,7 +914,7 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
&& (scenario.manifest.recording === 'authored' || scenario.manifest.sessionFormat !== undefined)
? it.skip
: it
scenarioTest(`${mode}s ${scenario.name} through dsh --profile sdk`, async () => {
scenarioTest(`${mode}s ${scenario.name} through dsh --profile ${scenario.manifest.profile}`, async () => {
const scenarioDir = scenario.dir
const retained = scenario.manifest.sessionFormat !== undefined
const notificationsExpectedPath = join(scenarioDir, retained ? 'notifications.current.expected.jsonl' : 'notifications.expected.jsonl')
@@ -934,6 +938,34 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
)
reconcileCatalogCreationTimes(ordered.map(log => log.content), 'validate')
const actualContext = contextOf(ordered, cwd)
if (scenario.name === 'minimal-image-compaction') {
const events = results.flatMap(result => result.events)
const image = events.find(event => event.type === 'tool/result')
expect(image).toMatchObject({ data: { message: {
toolCallId: 'minimal-image-read',
isError: false,
content: expect.arrayContaining([expect.objectContaining({ type: 'image', attachment: {
attachmentId: expect.stringMatching(/^sha256:/u),
mediaType: 'image/png', bytes: 69, width: 1, height: 1, name: 'red.png',
} })]),
} } })
const summaries = events.filter(event => event.type === 'compaction/summary')
expect(summaries).toHaveLength(1)
expect(summaries[0]).toMatchObject({ data: {
llmStreamCall: true,
rawOutput: [{ type: 'text', text: 'Read red.png and report MINIMAL_IMAGE_OK.' }],
} })
expect(summaries[0]?.data).not.toHaveProperty('sourceCommandId')
expect(events.filter(event => event.type === 'compaction/end')).toHaveLength(1)
expect(events.filter(event => event.type === 'compaction/error')).toHaveLength(0)
const subscribed = notifications.flatMap(notification => {
const event = notificationEvent(notification)
return event?.type === 'compaction/summary' ? [event] : []
})
expect(subscribed).toEqual(summaries)
expect(events.findLastIndex(event => event.type === 'assistant/message'))
.toBeGreaterThan(events.findIndex(event => event.type === 'compaction/summary'))
}
expect(logs.some(log => log.content.includes('llm-replay: script exhausted')), `${scenario.name}: replay script covers every model request`).toBe(false)
if (scenario.name === 'subagent-dsh-sdk-diagnostic' || scenario.name === 'subagent-dsh-sdk-dynamic-route') {
const parentEvents = records(ordered[0]!.content)
@@ -14,10 +14,9 @@
- button "Read image red.png" [expanded]:
- text: Read image
- button "red.png"
- text: red.png
- button "red.png, click to view original":
- img "red.png"
- text: <path>{{cwd}}/red.png</path> <type>image</type> <content> image/png image, 1x1 px, 69 bytes </content>
- text: {{cwd}}/red.png 1x1px, 69 bytes
- button "Inspect"
- paragraph: MINIMAL_IMAGE_OK
- button "Copy"