Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.md
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.zh.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.i18n.yaml
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.zh.md
#	docs/architecture.i18n.yaml
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/core.md
#	docs/core-data-structures/core.zh.md
#	docs/defensive-patterns.i18n.yaml
#	packages/client/runtime/src/client/sessions/session.ts
#	packages/client/runtime/tests/queue-store.spec.ts
#	packages/context/time-context/tests/time-context.spec.ts
#	packages/context/workspace-context/tests/workspace-context.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-loop/README.i18n.yaml
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/README.zh.md
#	packages/core/agent-loop/src/agent.ts
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/README.md
#	packages/core/agent/README.zh.md
#	packages/core/agent/src/types.ts
#	packages/core/agent/tests/agent.spec.ts
#	packages/core/scope/src/scoped-events.generated.ts
#	packages/goal/command-goal/tests/command-goal.spec.ts
#	packages/goal/goal-session/src/index.ts
#	packages/goal/goal-session/tests/goal-session.spec.ts
#	packages/goal/goal/tests/goal.spec.ts
#	packages/goal/goal/tests/projection.spec.ts
#	packages/goal/tool-goal/tests/tool-goal.spec.ts
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/events.schema.ts
#	packages/host/apiproxy/src/api/events.ts
#	packages/host/apiproxy/tests/api-proxy-workspace.spec.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/llm/llm/README.zh.md
#	packages/llm/llm/src/index.ts
#	packages/pty/pty-local/tests/index.spec.ts
#	packages/pty/pty-local/tests/local.spec.ts
#	packages/pty/pty/tests/service.spec.ts
#	packages/pty/tool-pty/tests/loader-composition.spec.ts
#	packages/pty/tool-pty/tests/tools.spec.ts
#	packages/skill/tool-skill/tests/tool-skill.spec.ts
#	packages/tasks/tasks-local/tests/tasks.spec.ts
#	packages/ui/tui/src/index.ts
#	packages/ui/tui/tests/harness.ts
#	packages/ui/tui/tests/tui.spec.ts
#	scripts/gen-cordis-catalog.ts
#	scripts/type-equiv.manifest.json
This commit is contained in:
_Kerman
2026-07-30 14:04:53 +08:00
1175 changed files with 49683 additions and 8452 deletions

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# 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
# pnpm run verify-translation-pairing --write packages/examples/README.md
README.md: c229cef22087ac290bf862d6b3e31fdb533858c4
README.zh.md: 5472fe7be76b015a2f3b06b2738b728a927acdd4
README.zh.md: 208b9a138506785ea1dd2d83ddfbba29e4b7968e

View File

@@ -2,17 +2,17 @@
[English](README.md) | 中文
预先组合的插件 bundle组合包供轻量叶节点 `cordis.yml` 加载,无需手工组装主干和前端入口。这些是 **演示/参考**npm 名称的 `-demo` 后缀把每个包标为非产品表层,直接查看包名即可辨认。仓库根目录 [`examples/`](../../examples/AGENTS.md) 下的可运行叶节点与 [Python SDK runtime](../../python/sdk-runtime/README.md) 是消费方;每个叶节点都只包含可替换后端和一个组合包入口。
预先组合的插件 bundle组合包供轻量叶节点 `cordis.yml` 加载,无需手工组装主干和前端入口。这些是 **演示/参考**packagenpm 名称的 `-demo` 后缀把每个包标为非产品表层,直接查看包名即可辨认。仓库根目录 [`examples/`](../../examples/AGENTS.md) 下的可运行叶节点与 [Python SDK 运行时](../../python/sdk-runtime/README.md) 是消费方;每个消费方都只包含可替换后端和一个组合包入口。
| 包 | npm 名称 | 角色 |
|---|---|---|
| `agent-spine-demo/` | `@deepseek-ai/dsh-agent-spine-demo` | 不含执行器和 UI 的 agent 主干,打包为一个组合包插件,带后备会话标题和用的持久目标栈 |
| `tui-demo/` | `@deepseek-ai/dsh-tui-demo` | 全屏终端应用组合包:主干 + 持久目标 + `/goal` 命令 + JSONL 持久化 + `dsh-tui` + 预创建的 `main` agent没有 bin由 [`dsh`](../../apps/cli/README.md) CLI 启动 |
| `agent-spine-demo/` | `@deepseek-ai/dsh-agent-spine-demo` | 不含执行器和 UI 的 agent(智能体)主干,打包为一个组合包插件,带后备会话标题和可选择启用的持久目标栈 |
| `tui-demo/` | `@deepseek-ai/dsh-tui-demo` | 全屏终端应用组合包:主干 + 持久目标 + `/goal` 命令 + JSONL 持久化 + `dsh-tui` + 预创建的 `main` agent没有 bin由 [`dsh`](../../apps/cli/README.md) CLI(命令行界面)启动 |
| `cli-demo/` | `@deepseek-ai/dsh-cli-demo` | 无头单次应用:主干 + JSONL 持久化 + 预创建的 `main` agent提供文本和 DSH 原生 JSON 输出 |
| `acp-demo/` | `@deepseek-ai/dsh-acp-demo` | ACP 自动化服务器应用:主干 + 持久目标 + JSONL 持久化 + [`acp`](../acp/acp/README.md) 桥接层(无 stdout logger带启动 `bin` |
| `jsonrpc-demo/` | `@deepseek-ai/dsh-jsonrpc-demo` | 只有 bin 的 runtime,用于启动外部 `cordis.yml`,供 stdio JSON-RPC SDK 客户端使用 |
| `acp-demo/` | `@deepseek-ai/dsh-acp-demo` | ACPAgent Client Protocol自动化服务器应用:主干 + 持久目标 + JSONL 持久化 + [`acp`](../acp/acp/README.md) 桥接层(无 stdout logger带启动 `bin` |
| `jsonrpc-demo/` | `@deepseek-ai/dsh-jsonrpc-demo` | 只有 bin 的运行时,用于启动外部 `cordis.yml`,供 stdio JSON-RPC SDK 客户端使用 |
`agent-spine-demo` 是共享组合包;`tui-demo``cli-demo``acp-demo` 分别将它与全屏终端、无头单次和 ACP 自动化前端入口组合。`cli-demo``acp-demo` 拥有各自的启动 bin`tui-demo` 只交付组合包插件,产品 [`dsh`](../../apps/cli/README.md) CLI 是它的终端前端入口。`jsonrpc-demo` 自身不挂载任何组合,而是启动部署的 `cordis.yml` 所指名的任意插件树Python SDK runtime 会启动它。
`agent-spine-demo` 是共享组合包;`tui-demo``cli-demo``acp-demo` 分别将它与全屏终端、无头单次和 ACP 自动化前端入口组合。`cli-demo``acp-demo` 拥有各自的启动 bin`tui-demo` 只交付组合包插件,产品 [`dsh`](../../apps/cli/README.md) CLI 是它的终端前端入口。`jsonrpc-demo` 自身不挂载任何组合,而是启动部署的 `cordis.yml` 所指名的任意插件树Python SDK 运行时会启动它。
这些 **不是** 产品 API。它们打包的主干组件位于 [`core/`](../core/README.md)人类SDK 通道和启动粘合代码位于 [`ui/`](../ui/README.md),自动化传输位于 [`acp/`](../acp/README.md),可替换后端位于各自能力组;演示组合包只选定其中一种具体组合。可以自由替换或 fork。
@@ -20,4 +20,4 @@
## jsonrpc binexe 名称是历史遗留
`jsonrpc-demo` 已像同级包一样重命名,但其 bin 仍为 `dsh-jsonrpc-agent`,单文件可执行程序仍为 `dsh-jsonrpc-agent-pkg`(在 [Python 分发](../../python/sdk-runtime/README.md)各处被引用)。这些名称属于 SDK 的 runtime 启动表层;只有 SDK 统一该启动流程时才会协调它们,而不会在此次移动中处理。
`jsonrpc-demo` 已像同级包一样重命名,但其 bin 仍为 `dsh-jsonrpc-agent`,单文件可执行程序仍为 `dsh-jsonrpc-agent-pkg`(在 [Python 分发](../../python/sdk-runtime/README.md)各处被引用)。这些名称属于 SDK 的运行时启动表层;只有 SDK 统一该启动流程时才会协调它们,而不会在此次移动中处理。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/examples/acp-demo/README.md
README.md: 395ab230146568989c4e6d1361218efb72d857e7
README.zh.md: 1dfd2d99f4ab80953df77feba19649b934775d68
README.zh.md: bfba1f83e506e60ab117f11f85851b3d3a7ea16a

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
ACP 自动化服务器应用:默认 agent 主干、客户端通过 [`@deepseek-ai/dsh-acp`](../../acp/acp/README.md) 创建的 agent、JSONL 持久化,以及由一个 JSON-RPC stdio bin 提供的语义检查点。程序化客户端创建新会话;此包不挂载人 UI。
ACPAgent Client Protocol自动化服务器应用:默认 agent(智能体)主干、客户端通过 [`@deepseek-ai/dsh-acp`](../../acp/acp/README.md) 创建的 agent、JSONL 持久化,以及由一个 JSON-RPC stdio bin 提供的语义检查点。程序化客户端创建新会话;此包package不挂载人工交互 UI。
## 组合
@@ -14,7 +14,7 @@ ACP 自动化服务器应用:默认 agent 主干、客户端通过 [`@deepseek
| `@deepseek-ai/dsh-session-query-sqlite` | 派生的精确FTS 会话查询服务;先于 ACP 传输打开,使叶节点消费方在首次模型请求前就绪。 |
| `@deepseek-ai/dsh-acp` | 通过 stdinstdout 提供的纯自动化 ACP 传输。 |
应用不安装命令、用户交互、会话导航、配置选择器或 stdout logger。它通过一个有序 effect 拥有这些插件,因此查询服务会在 ACP 接受工作前就绪,而 ACP 会话会在检查点与持久化分离前静默。叶节点配置负责提供 LLM、执行器、沙箱、批、文件系统和面向模型的工具插件。
应用不安装命令、用户交互、会话导航、配置选择器或 stdout logger。它通过一个有序 effect 拥有这些插件,因此查询服务会在 ACP 接受工作前就绪,而 ACP 会话会在检查点与持久化插件卸载前完全停稳。叶节点配置负责提供 LLM(大语言模型)、执行器、沙箱、批、文件系统和面向模型的工具插件。
## 配置
@@ -22,26 +22,26 @@ ACP 自动化服务器应用:默认 agent 主干、客户端通过 [`@deepseek
|---|---|---|
| `provider` | 必填 | 每个由 ACP 创建的 agent 所用的提供方路由。 |
| `model` | 必填 | 每个由 ACP 创建的 agent 所用的模型。 |
| `maxParallelToolCalls` | agent-loop 默认值 | 正整数工具调用并发上限;`1` 表示串行。 |
| `maxParallelToolCalls` | agent loop 默认值 | 正整数工具调用并发上限;`1` 表示串行。 |
| `persona` | 无 | 供 `dsh-system-prompt` 使用的部署 persona 模板。 |
| `toolOrder` | 字典序 | 供 `dsh-system-prompt` 使用的显式面向模型工具顺序。 |
| `tools` | `{ mode: 'native' }` | Native、Code Mode 或组合式模型工具传输。 |
| `dshHome` | `$DSH_HOME``~/.dsh` | bash 与本地 skill 发现共享的 harness 主目录。 |
| `dshHome` | `$DSH_HOME``~/.dsh` | bash 与本地 skill(技能)发现共享的 harness 主目录。 |
| `sessionTitle` | 主干示例限制 | 持久后备标题限制;标题仍不会进入 ACP wire。 |
| `persistenceRoot` | `./.sessions` | JSONL 后端根目录,以及派生 `session-query.db` 索引的父目录。 |
| `packChunks` | `true` | 在存储中打包连续的增量 chunk 事件。 |
| `packChunks` | `true` | 在存储中打包连续的增量分片事件。 |
| `persistenceCompression` | `zstd` | 带校验和的 Zstandard 帧,或原始 `none`。 |
| `workspaceContext` | 必填 | Workspace 指令字节预算/配置,或 `false`。 |
| `skills` | 拥有者默认值 | Skill 注册表、本地提供方和面向模型的 skill 工具。 |
| `workspaceContext` | 必填 | 工作区指令字节预算/配置,或 `false`。 |
| `skills` | 拥有者默认值 | skill 注册表、本地提供方和面向模型的 skill 工具。 |
| `toolBash` | 拥有者默认值 | 面向模型的 bash 工具配置。 |
| `toolTasks` | 拥有者默认值 | 通用后台任务控制配置,或 `false`。 |
| `goals` | 拥有者默认值 | 持久的同会话目标领域与模型工具,或 `false`。 |
| `goals` | 拥有者默认值 | 持久的同会话目标领域与模型工具,或 `false`。 |
已交付的 [`examples/acp-agent/cordis.yml`](../../../examples/acp-agent/cordis.yml) 添加 DeepSeek 适配器、沙箱化 bash 与文件系统提供方、一次性批策略、压缩、subagent、工作流、钩子以及面向模型的工具。应用提供派生会话查询索引而面向模型的查询消费方仍由叶节点显式选用。快照 overlay 只替换非确定性提供方或策略值。
已交付的 [`examples/acp-agent/cordis.yml`](../../../examples/acp-agent/cordis.yml) 添加 DeepSeek 适配器、沙箱化 bash 与文件系统提供方、一次性批策略、压缩compaction、subagent、工作流、钩子以及面向模型的工具。应用提供派生会话查询索引而面向模型的查询消费方仍由叶节点显式选用。快照 overlay 只替换非确定性提供方或策略值。
## Bin
`dsh-acp-demo [--config path-to-cordis.yml]`(短形式 `-c`;默认为 `./cordis.yml`)会加载 gitignore 排除的 `.env`,回放 mode 除外;`DSH_SNAPSHOT=replay` 选择同级 `cordis.snapshot.yml`stdin EOF 会在退出前释放上下文并刷新会话。Loader 已安装的可选 peer `node-addon-require-builtin` 使纯 Node 下构建后的 bin 可以解析裸插件说明符。诊断使用 stderr因为 stdout 是 ACP wire。
`dsh-acp-demo [--config path-to-cordis.yml]`(短形式 `-c`;默认为 `./cordis.yml`)会加载 gitignore 排除的 `.env`,回放模式除外;`DSH_SNAPSHOT=replay` 选择同级 `cordis.snapshot.yml`stdin EOF 会在退出前释放上下文并刷新会话。loader 已安装的可选对等依赖peer dependency`node-addon-require-builtin` 使纯 Node 下构建后的 bin 可以解析裸插件说明符。诊断使用 stderr因为 stdout 是 ACP wire。
## 模型体验
@@ -49,10 +49,10 @@ ACP 自动化服务器应用:默认 agent 主干、客户端通过 [`@deepseek
#### KV Cache 影响
每个会话追加;应用本身不添加请求前缀内容。
每个会话追加;应用本身不添加请求前缀内容。
## 已知限制与延后工作
## 已知限制与暂缓事项
- **JSONL 持久化固定不变**:使用其他后端需要另一种组合。
- **同级插件可能破坏 stdout**:应用无法阻止另一个条目写入非协议字节。
- **只支持新建自动化会话**:恢复和人交互属于其他前端入口。
- **只支持新建自动化会话**:恢复和人交互属于其他前端入口。

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/examples/agent-spine-demo/README.md
README.md: 359e7153be2f480ba3fea4b06782acdc9f89ebb9
README.zh.md: 57fec3f32f5bbc8f3d82ff8971d36d376d722753
README.zh.md: acd8c06940b03e90e368314cd725846a2b92b656

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
**默认的不含执行器、不含 UI 的 agent 主干** 作为一个 Cordis 组合包插件。它加载每个 harness agent 所需的固定服务集合,包括本地 skill 提供方,并将循环的 `agents` 列表作为自身配置转发。因此,应用包只需添加前端入口和可替换后端,就能组合出可工作的 agent。
**默认的不含执行器、不含 UI 的 agent(智能体)主干** 作为一个 Cordis 组合包插件。它加载每个 harness agent 所需的固定服务集合,包括本地 skill(技能)提供方,并将循环的 `agents` 列表作为自身配置转发。因此,应用包package只需添加前端入口和可替换后端,就能组合出可工作的 agent。
阅读此包可了解完整插件树及其组合顺序。
@@ -43,11 +43,11 @@
主干包含每个前端入口都共有的全部组件。可替换组件和与前端入口耦合的组件留在外部,由加载组合包的一方选择:
- **LLM 适配器**:组合包交付抽象 `llm` 服务;叶节点在 `ctx.llm` 上注册具体适配器(`llm-deepseek``llm-pi-ai``llm-replay`)。
- **模型支持的会话标题提供方**组合包挂载带可覆盖示例限制的后备服务5 个词、40 个后备字节、80 个可接受标题字节);叶节点可以恰好选用一个首消息或全消息 LLM 提供方。
- **LLM(大语言模型)适配器**:组合包交付抽象 `llm` 服务;叶节点在 `ctx.llm` 上注册具体适配器(`llm-deepseek``llm-pi-ai``llm-replay`)。
- **基于模型的会话标题提供方**组合包挂载带可覆盖示例限制的后备服务5 个词、40 个后备字节、80 个可接受标题字节);叶节点可以恰好选用一个首消息或全消息 LLM 提供方。
- **bash 执行器**:组合包交付 `tool-bash`(消费方 schema叶节点提供 `ctx.bash``bash-local` 或沙箱化实现)。
- **非本地 skill 提供方**:组合包交付 skill 注册表、本地文件系统提供方和 `skill` 工具;部署可以把嵌入式目录或远程目录等其他提供方作为同级插件添加。
- **前端入口与各应用基础设施**:终端 TUI 或 ACP 自动化传输,以及 `hmr`。应用包([`dsh-tui-demo`](../tui-demo/README.md)、[`dsh-acp-demo`](../acp-demo/README.md))拥有这些选择。`timer` 位于主干中,因为它是共有组件且不写 stdout前端入口拥有 stdout因此留在组合包外。
- **前端入口与各应用基础设施**:终端 TUI 或 ACPAgent Client Protocol自动化传输,以及 `hmr`。应用包([`dsh-tui-demo`](../tui-demo/README.md)、[`dsh-acp-demo`](../acp-demo/README.md))拥有这些选择。`timer` 位于主干中,因为它是共有组件且不写 stdout前端入口拥有 stdout因此留在组合包外。
这把[接口/实现/消费方 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md) 提升到组合层:组合包拥有共享主干,叶节点拥有后端,应用包拥有前端入口。
@@ -59,25 +59,25 @@ import type { Config } from '@deepseek-ai/dsh-agent-spine-demo'
// workspaceContext requires { maxBytes } or false; the other owner schemas supply defaults.
```
组合包将每个字段转发给拥有它的子节点:`agents``maxParallelToolCalls` 交给 `agent-loop``agents` 默认为 `[]`,上限在该处默认),因此每个应用提供自己的预创建 agentTUI 和无头应用预创建 `main`ACP 应用则在 `session/new` 按需创建 agent`persona``toolOrder` 交给 `dsh-system-prompt``tools` 交给工具注册表以配置呈现 mode`sessionTitle` 交给后备标题服务;`skills.registry``skills.local``skills.tool` 分别交给 skill 注册表、本地提供方和面向模型的消费方;必填的 `workspaceContext` 选择交给 `dsh-workspace-context``{ maxBytes }` 启用加载,`false` 禁用);`invariants` 交给不变式服务;`toolBash`/`toolTasks` 交给组合包拥有的两个面向模型工具插件。组合包始终挂载 `dsh-llm-retry`,而每个叶节点适配器拥有自己的嵌套 `retryPolicy`。省略 `sessionTitle` 时采用显式示例策略5 个词、40 个后备字节、80 个可接受标题字节。`goals` 对象会选用持久领域、模型工具和同会话驱动器,并将 `goals.domain``goals.tool` 转发给各自拥有者;省略或设为 `false` 会让整个栈缺席,使无头调用方继续以一轮结算。设置 `skills.enabled: false` 会同时省略本地提供方和面向模型的 skill 工具;设置 `toolTasks: false` 会保留供前台生产方使用的任务服务,但不公开 `task_output`/`task_list`/`task_kill`。它对 `dshHome` 只解析一次,解析通过 [`@deepseek-ai/dsh-paths`](../../util/paths/README.md) 完成,并将所得绝对值转发给 tool-bash 的托管环境和已启用的本地 skill 发现。顶层 `dshHome` 缺席时采用 `skills.local.dshHome`;两者同时提供但解析后的路径不同会明确失败。`toolBash.enableRunInBackground` 只控制 bash 生产方;独立加载的生产方保留各自配置。Workspace 指令先于 skill 目录注册,因此其会话前缀消息先渲染。应用包使用 `pickSpineConfig()`,只复制这些由组合包拥有的字段。
组合包将每个字段转发给拥有它的子节点:`agents``maxParallelToolCalls` 交给 `agent-loop``agents` 默认为 `[]`,上限在该处默认),因此每个应用提供自己的预创建 agentTUI 和无头应用预创建 `main`ACP 应用则在 `session/new` 按需创建 agent`persona``toolOrder` 交给 `dsh-system-prompt``tools` 交给工具注册表以配置呈现模式`sessionTitle` 交给后备标题服务;`skills.registry``skills.local``skills.tool` 分别交给 skill 注册表、本地提供方和面向模型的消费方;必填的 `workspaceContext` 选择交给 `dsh-workspace-context``{ maxBytes }` 启用加载,`false` 禁用);`invariants` 交给不变式服务;`toolBash`/`toolTasks` 交给组合包拥有的两个面向模型工具插件。组合包始终挂载 `dsh-llm-retry`,而每个叶节点适配器拥有自己的嵌套 `retryPolicy`。省略 `sessionTitle` 时采用显式示例策略5 个词、40 个后备字节、80 个可接受标题字节。`goals` 对象会选用持久领域、模型工具和同会话 Goal Round 驱动器,并将 `goals.domain``goals.tool` 转发给各自拥有者;省略或设为 `false` 会让整个栈缺席,使无头调用方继续以单轮次结算。设置 `skills.enabled: false` 会同时省略本地提供方和面向模型的 skill 工具;设置 `toolTasks: false` 会保留供前台生产方使用的任务服务,但不公开 `task_output`/`task_list`/`task_kill`。它对 `dshHome` 只解析一次,解析通过 [`@deepseek-ai/dsh-paths`](../../util/paths/README.md) 完成,并将所得绝对值转发给 tool-bash 的托管环境和已启用的本地 skill 发现。顶层 `dshHome` 缺席时采用 `skills.local.dshHome`;两者同时提供但解析后的路径不同会明确失败。`toolBash.enableRunInBackground` 只控制 bash 生产方;独立加载的生产方保留各自配置。工作区指令先于 skill 目录注册,因此其会话前缀消息先渲染。应用包使用 `pickSpineConfig()`,只复制这些由组合包拥有的字段。
例如,`{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` 会让包拥有的配套插件保持挂载但抑制被阻止的拥有者。Blocklist 匹配优先于 allowlist 匹配;正则表达式与生命周期规则见 [`dsh-invariants`](../../support/invariants/README.md)。
## 为何使用代码组合包,而非共享 YAML include
YAML include 可以去重配置,却无法拥有 bin 或提供前端入口默认值。ACP 应用包默认接出协议纯净的 stdout但叶节点仍可添加不安全的 logger。组合包子节点把服务注册到根 isolate-keyed store因此注入这些服务的叶节点同级插件无需依赖加载顺序即可看到它们。
YAML include 可以去重配置,却无法拥有 bin 或提供前端入口默认值。ACP 应用包默认接出协议纯净的 stdout但叶节点仍可添加不安全的 logger。组合包子节点把服务注册到根 isolate-keyed store因此叶节点同级插件无需依赖加载顺序即可通过注入看到它们。
重试策略可能在新的编号步骤中重复失败的请求。重试状态、提供方错误和失败的部分 chunk 不进入模型历史每次提供方尝试仍可能产生计费always mode 没有尝试次数上限;前端入口从所有已记录步骤推导用量;重建的请求保留先前前缀,以便复用提供方 cache
重试策略可能在新的编号步骤中重复失败的请求。重试状态、提供方错误和失败的部分分片不进入模型历史每次提供方尝试仍可能产生计费always 模式没有尝试次数上限;前端入口从所有已记录步骤推导用量;重建的请求保留先前前缀,以便复用提供方缓存
## 模型体验
模型通过 `dsh-system-prompt``dsh-tool-skill``dsh-tool-bash``dsh-tools``dsh-llm-retry` 间接获得体验;还会通过 `dsh-tool-goal`目标轮次提示词获得体验,前提是启用 `goals`。组合包自身不添加面向模型的包装内容。
模型通过 `dsh-system-prompt``dsh-tool-skill``dsh-tool-bash``dsh-tools``dsh-llm-retry` 间接获得体验;还会通过 `dsh-tool-goal` Goal Round 提示词获得体验,前提是启用 `goals`。组合包自身不添加面向模型的包装内容。
#### KV Cache 影响
不会直接失效;具名消费方拥有请求前缀的任何变更。
不会直接失效;上述消费方负责请求前缀的任何变更。
## 已知限制与延后工作
## 已知限制与暂缓事项
- **大部分主干集合固定在代码中**`apply()` 始终挂载核心服务与 `tool-bash`配置可以省略组合包内的目标、skill 与任务控制工具,但要替换循环或删除其他主干成员,就必须组合另一个 bundle
- **大部分主干集合固定在代码中**`apply()` 始终挂载核心服务与 `tool-bash`配置可以省略组合包内的目标、skill 与任务控制工具,但要替换循环或删除其他主干成员,就必须组合另一个组合包
- **不变式 seam 与配套插件仍是固定成员**`invariants.enabled: false` 或包筛选器会抑制检查但不会移除服务或配套插件注册Session 始终启用的校验与冻结是另一套机制。

View File

@@ -55,6 +55,7 @@
"@cordisjs/plugin-timer": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-bash-local": "workspace:^",
"@deepseek-ai/dsh-bash-sandbox": "workspace:^",
"@deepseek-ai/dsh-fs-local": "workspace:^",
"@deepseek-ai/dsh-fs-policy": "workspace:^",

View File

@@ -8,9 +8,12 @@ import { TOOL_ORDER_REST } from '@deepseek-ai/dsh-system-prompt'
import * as agentCore from '../src/index.ts'
import { agentEvents, type Agent } from '@deepseek-ai/dsh-agent'
import { SessionId } from '@deepseek-ai/dsh-session'
import LocalBashExecutor from '@deepseek-ai/dsh-bash-local'
import LocalFileSystem from '@deepseek-ai/dsh-fs-local'
import { MockAdapter, textResponse } from '../../../core/agent-loop/tests/mock-adapter.ts'
import { createUserMessage,
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
import { MockAdapter, textResponse, toolCallResponse } from '../../../core/agent-loop/tests/mock-adapter.ts'
import {
createUserMessage,
CallId,
LlmAdapter,
LlmError,
@@ -403,6 +406,142 @@ describe('dsh-agent-spine-demo bundle', () => {
await ctx.fiber.dispose()
})
it('snapshots a created project skill through catalog refresh and progressive loading', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-skill-refresh-'))
const home = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-skill-refresh-home-'))
try {
await mkdir(join(root, '.git'), { recursive: true })
const skillPath = '.agents/skills/hot-skill/SKILL.md'
const skillSource = '---\nname: hot-skill\ndescription: Hot-added skill\n---\n\nUse the freshly loaded body.\n'
const adapter = new MockAdapter([
toolCallResponse('mkdir-skill', 'bash', {
command: 'mkdir -p .agents/skills/hot-skill',
description: 'Create the project skill directory',
}),
toolCallResponse('write-skill', 'write', {
file_path: skillPath,
content: skillSource,
}),
toolCallResponse('load-skill', 'skill', { name: 'hot-skill' }),
textResponse('SKILL_REFRESH_OK'),
])
const ctx = await mount({
workspaceContext: false,
skills: {
local: {
dshHome: join(home, '.dsh'),
agentsHome: join(home, '.agents'),
watchStabilityThresholdMs: 20,
watchPollIntervalMs: 10,
},
},
})
await ctx.plugin(LocalBashExecutor, {})
await ctx.plugin(LocalFileSystem, { cwd: root })
await ctx.plugin(ToolFs)
ctx.llm.registerAdapter(['mock'], adapter)
const handle = await ctx.agents.create({
sessionId: SessionId('skill-refresh-session'),
meta: { cwd: root },
agentOptions: { provider: 'mock', model: 'mock' },
})
handle.agent.followup(createUserMessage({
content: [{ type: 'text', text: 'Create and load the project skill.' }],
source: { kind: 'user' },
}))
await waitForIdle(ctx, handle.agent)
expect(adapter.requests).toHaveLength(4)
expect(adapter.requests.slice(0, 2).map(request => request.messages.map(messageText).join('\n')))
.toEqual([
expect.not.stringContaining('hot-skill'),
expect.not.stringContaining('hot-skill'),
])
const catalogRequest = adapter.requests[2]?.messages.map(messageText).join('\n')
expect(catalogRequest).toContain('The following skills are available in this session:')
expect(catalogRequest).toContain('- `hot-skill`: Hot-added skill')
const loadedRequest = JSON.stringify(adapter.requests[3]?.messages)
expect(loadedRequest).toContain('<skill_instructions>')
expect(loadedRequest).toContain('Use the freshly loaded body.')
const transcript = handle.agent.session.events.flatMap<Record<string, unknown>>((event) => {
if (event.type === 'user/message'
&& event.data.source.kind === 'plugin'
&& event.data.source.plugin === 'dsh-tool-skill') {
return [{
type: event.type,
source: event.data.source,
text: event.data.content.map(block => block.type === 'text' ? block.text : '').join('\n'),
}]
}
if (event.type === 'tool/result'
&& ['write-skill', 'load-skill'].includes(event.data.message.source.callId)) {
const result = event.data.message.content[0]
return [{
type: event.type,
callId: event.data.message.source.callId,
isError: result.isError,
text: result.content.map(block => block.type === 'text' ? block.text : '').join('\n')
.replaceAll(root, '{{cwd}}'),
}]
}
return []
})
expect(transcript).toMatchInlineSnapshot(`
[
{
"callId": "write-skill",
"isError": false,
"text": "<path>{{cwd}}/.agents/skills/hot-skill/SKILL.md</path>
<type>file</type>
<content>
Created file
</content>",
"type": "tool/result",
},
{
"source": {
"kind": "plugin",
"plugin": "dsh-tool-skill",
},
"text": "<system-reminder>
A skill is a reusable set of task-specific instructions. The following skills are available in this session:
<available_skills>
- \`hot-skill\`: Hot-added skill
</available_skills>
If the user names a skill, or the task clearly matches a skill's description, call the \`skill\` tool with the exact skill name before taking task actions. Load all applicable skills, then follow their full instructions. This catalog contains summaries only; do not infer or follow a skill's instructions until it has been loaded.
</system-reminder>",
"type": "user/message",
},
{
"callId": "load-skill",
"isError": false,
"text": "<skill_content name="hot-skill">
<skill_resources>
Base directory for this skill: {{cwd}}/.agents/skills/hot-skill
Resolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.
</skill_resources>
<skill_instructions>
Use the freshly loaded body.
</skill_instructions>
</skill_content>",
"type": "tool/result",
},
]
`)
await handle.dispose()
await ctx.fiber.dispose()
} finally {
await rm(root, { recursive: true, force: true })
await rm(home, { recursive: true, force: true })
}
})
it('shares top-level dshHome between local skills and the managed bash environment', async () => {
const home = await mkdtemp(join(tmpdir(), 'dsh-agent-core-shared-home-'))
const agentsHome = await mkdtemp(join(tmpdir(), 'dsh-agent-core-shared-agents-'))

View File

@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/examples/cli-demo/README.md
README.md: b8f2bde962738a1a23f0e57218ab0f90e8e0b705
README.zh.md: 322ba3fb3b253d867832534bd33f65df3a5b8d37
README.zh.md: 0e03375ced4e087d44eed7ff33666abf1f2cec10

View File

@@ -2,9 +2,9 @@
[English](README.md) | 中文
无头单次应用及 bin用于在没有交互式 UI 或编辑器客户端的情况下运行一项 agent 任务。它组合 [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md)、JSONL 持久化,以及恰好一个新建顶层 agent。Bin 提交任务,等待其持久轮次结束,渲染所选输出,释放至静默,然后退出。
无头单次应用及 bin用于在没有交互式 UI 或编辑器客户端的情况下运行一项 agent(智能体)任务。它组合 [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md)、JSONL 持久化,以及恰好一个新建顶层 agent。bin 提交任务,等待其持久化的轮次结束状态,渲染所选输出,执行 dispose资源释放直至完全停稳,然后退出。
该包不挂载 console logger、交互式 UI、用户交互服务或 `ask_user_question` 工具。Stdout 专用于所选输出格式;诊断使用 stderr。
该包package不挂载 console logger、交互式 UI、用户交互服务或 `ask_user_question` 工具。Stdout 专用于所选输出格式;诊断使用 stderr。
## 配置
@@ -12,26 +12,26 @@
|---|---|---|
| `provider` | 必填 | 已配置 agent 的提供方路由 |
| `model` | 必填 | 已配置 agent 的模型 |
| `maxParallelToolCalls` | agent-loop 默认值 | 正整数并发工具调用上限;`1` 表示串行 |
| `maxParallelToolCalls` | agent loop 默认值 | 正整数并发工具调用上限;`1` 表示串行 |
| `persona` | 无 | `dsh-system-prompt` 中的部署 persona |
| `toolOrder` | 字典序 | `dsh-system-prompt` 中显式的面向模型工具顺序 |
| `tools` | `{ mode: 'native' }` | 通过 `dsh-agent-spine-demo` 提供的工具注册表呈现配置 |
| `dshHome` | `$DSH_HOME``~/.dsh` | 向模型 bash 公开并用于本地 skill 发现的 Harness 主目录 |
| `dshHome` | `$DSH_HOME``~/.dsh` | 向模型 bash 公开并用于本地 skill(技能)发现的 harness 主目录 |
| `sessionTitle` | 主干示例限制 | 通过 `dsh-agent-spine-demo` 提供的后备标题词数/字节限制 |
| `skills` | 拥有者默认值 | Skill 注册表、本地提供方和面向模型的 skill 工具 |
| `toolBash` | 拥有者默认值 | 面向模型的 bash 配置,包括此生产方对后台任务的用 |
| `skills` | 拥有者默认值 | skill 注册表、本地提供方和面向模型的 skill 工具 |
| `toolBash` | 拥有者默认值 | 面向模型的 bash 配置,包括此生产方对后台任务的显式启用 |
| `toolTasks` | 拥有者默认值 | 通用 `task_output` 等待边界 |
| `persistenceRoot` | `./.sessions` | JSONL 会话根目录 |
| `persistenceCompression` | `'zstd'` | JSONL 工件编码(`'zstd'` 或原始 `'none'` |
| `workspaceContext` | 必填 | Workspace 指令字节预算,或以 `false` 禁用加载 |
| `persistenceCompression` | `'zstd'` | JSONL 产物编码(`'zstd'` 或原始 `'none'` |
| `workspaceContext` | 必填 | 工作区指令字节预算,或以 `false` 禁用加载 |
## CLI 契约
## CLI(命令行界面)契约
```sh
dsh-cli-demo [--config path] [--output-format text|json|stream-json] <task>
```
`--config` 默认为 `./cordis.yml``--output-format` 默认为 `text`。必须恰好提供一个非空位置任务,因此含空格的任务需要加引号。`--help` 在不启动的情况下打印用法。不存在 `-p``--print` 标志。
`--config` 默认为 `./cordis.yml``--output-format` 默认为 `text`。必须恰好提供一个非空的任务位置参数,因此含空格的任务需要加引号。`--help` 在不启动的情况下打印用法。不存在 `-p``--print` 标志。
根 headless-agent 示例提供其叶节点:
@@ -39,7 +39,7 @@ dsh-cli-demo [--config path] [--output-format text|json|stream-json] <task>
pnpm run demo:headless "inspect the failing test and fix it"
```
Loader 配置通过仓库安装的可选原生辅助程序解析裸包说明符,因此根命令不需要特殊 Node 标志。
loader 配置通过仓库安装的可选原生辅助程序解析裸包说明符,因此根命令不需要特殊 Node 标志。
### 输出格式
@@ -47,32 +47,32 @@ Loader 配置通过仓库安装的可选原生辅助程序解析裸包说明符
- `json` 写入一条 DSH 原生结果记录:`{ type: "result", success, sessionId, turn, result, reason, usage? }``usage` 对任务轮次中的每个模型步骤恰好求和一次,包括产生用量但没有提交 assistant 消息的已计费失败重试。
- `stream-json` 将顶层会话任务轮次中的每个规范事件写成 `{ type: "session_event", sessionId, event }`,然后写入同一结果记录。子 agent 活动只通过父工具事件与结果出现。
只有 `reason.kind === "completed"` 会成功退出。其他持久轮次结仍会输出部分文本或结果记录,向 stderr 添加诊断,并以非零状态退出。参数和启动失败会让 stdout 保持为空。SIGINT 与 SIGTERM 会取消活动工作,等待释放,并分别以 130 和 143 退出。
只有 `reason.kind === "completed"` 会成功退出。其他持久化的轮次结束状态仍会输出部分文本或结果记录,向 stderr 添加诊断,并以非零状态退出。参数和启动失败会让 stdout 保持为空。SIGINT 与 SIGTERM 会取消正在进行的工作,等待 dispose 完成,并分别以 130 和 143 退出。
任务轮次会在最终输出前显式刷新。进程退出后,会话日志仍保留在 `persistenceRoot` 下。
## 操作安全
Headless-agent 叶节点提供本地 bash、文件系统、skill、subagent、工作流和 todo 能力。因此任务可以修改启动 workspace、运行命令、生成子 agent并消耗提供方 token。请从目标项目目录运行 CLI检查叶节点的能力与沙箱配置不要把非交互式执行当作批准边界。
headless-agent 叶节点提供本地 bash、文件系统、skill、subagent、工作流和 todo 能力。因此任务可以修改启动工作区、运行命令、spawn 子 agent并消耗提供方 token。请从目标项目目录运行 CLI检查叶节点的能力与沙箱配置不要把非交互式执行当作批准边界。
## 模型体验
### 单次任务轮次
#### 模型所见
#### 模型看到的内容
位置任务会成为一条用户消息。通过 `dsh-agent-spine-demo`,顶层 agent 还会收到已配置的 workspace 指令与 persona、skill 目录、可见工具 schema以及同一轮次后续步骤所需的保留工具结果。
任务位置参数会成为一条用户消息。通过 `dsh-agent-spine-demo`,顶层 agent 还会收到已配置的工作区指令与 persona、skill 目录、可见工具 schema以及同一轮次后续步骤所需的保留工具结果。
#### Token 影响
每个模型步骤中的任务、提示词段、工具 schema、assistant 输出和工具结果都会消耗 token。JSON 事件流和最终渲染不增加模型 token委派的子工作有自己的模型用量不计入父结果的 `usage` 总量。
每个模型步骤中的任务、提示词段、工具 schema、assistant 输出和工具结果都会消耗 token。JSON 事件流式输出和最终渲染不增加模型 token委派的子工作有自己的模型用量不计入父结果的 `usage` 总量。
#### KV Cache 影响
只要单次 agent 的提示词、schema、模型路由和会话前缀保持不变工具轮次历史就追加。改变该组合会建立不同的请求前缀JSON 输出 mode 不影响 cache
只要单次 agent 的提示词、schema、模型路由和会话前缀保持不变工具轮次历史就追加。改变该组合会建立不同的请求前缀JSON 输出模式不影响缓存
## 已知限制与延后工作
## 已知限制与暂缓事项
- **每个进程只创建一个新的顶层会话**:其 workspace cwd 是启动目录此应用不支持恢复、第二条提示词、stdin 上下文或并发顶层会话。
- **没有交互式问题或批准提供方**:需要人回答的工具无法完成,除非其他叶节点按显式策略组合一个非交互式提供方。
- **流只包含顶层会话**:子会话不会平铺到流中,聚合用量只涵盖父任务轮次记录的模型步骤。
- **每个进程只创建一个新的顶层会话**:其工作区 cwd 是启动目录此应用不支持恢复、第二条提示词、stdin 上下文或并发顶层会话。
- **没有交互式问题或批准提供方**:需要人回答的工具无法完成,除非其他叶节点按显式策略组合一个非交互式提供方。
- **流式输出仅限顶层会话**:子会话不会平铺到流中,聚合用量只涵盖父任务轮次记录的模型步骤。

View File

@@ -148,7 +148,7 @@ export function parseCliArgs(args: readonly string[]): CliCommand {
throw new CliArgumentError(`expected exactly one positional task or -p, received ${parsed.positionals.length} positional(s)`)
}
// Cardinality was checked above, so the fallback index zero exists.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// oxlint-disable-next-line typescript/no-non-null-assertion
const task = prompt ?? parsed.positionals[0]!
if (task.trim().length === 0) throw new CliArgumentError('task must not be blank')
@@ -301,7 +301,7 @@ export async function runOneShot(ctx: Context, options: OneShotOptions): Promise
try {
/* v8 ignore next -- skips send only when cancellation wins the listener-registration race above */
if (!firstTurnEnded) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
if (!firstTurnEnded) { // oxlint-disable-line typescript/no-unnecessary-condition
agent.followup(createUserMessage({ content: [{ type: 'text', text: options.task }], source: { kind: 'user' } }))
}
await turnEnded
@@ -361,7 +361,7 @@ async function bootInterruptibly(
return await Promise.race([booting, interruptedBoot])
} catch (error: unknown) {
// The awaited race permits the signal to change after the preflight check.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// oxlint-disable-next-line typescript/no-unnecessary-condition
if (signal.aborted) {
void booting.then(
async (lateContext) => {

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# 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
# pnpm run verify-translation-pairing --write packages/examples/jsonrpc-demo/README.md
README.md: 75e9e3943982c08e53afdbb73d1e9085b2e332bc
README.zh.md: 0e0f8ba33ab4cfbf57e28219a553a5d042b1cbed
README.zh.md: 95a626285c2f531ff6c8cceed297b42626aed98c

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
只包含 bin 的应用,启动外部 `cordis.yml`;其 [`jsonrpc`](../../ui/jsonrpc/README.md) 入口通过按换行分隔的 stdio 为 SDK 客户端提供服务。配置负责组合主干、后端和服务插件。`lib/bin.js` 也是[单文件可执行 runtime](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) 的入口。
只包含 bin 的应用,启动外部 `cordis.yml`;其 [`jsonrpc`](../../ui/jsonrpc/README.md) 入口通过按换行分隔的 stdio 为 SDK 客户端提供服务。配置负责组合主干、后端和服务插件。`lib/bin.js` 也是[单文件可执行运行时](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) 的入口。
## 配置发现
@@ -12,7 +12,7 @@
## 退出生命周期
stdin EOF 和 `SIGTERM`将根上下文释放至静默并以 0 退出;`SIGINT` 完成同样的释放后以 130 退出。EOF 可能按[分发 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) 所述截断正在处理的轮次。`jsonrpc` 插件拥有先响应再退出的协议关闭流程;两条路径均幂等,可以安全竞态
stdin EOF 和 `SIGTERM` dispose释放资源根上下文等待完全停稳后以 0 退出;`SIGINT` 完成同样的 dispose 后以 130 退出。EOF 可能按[分发 Agent Noteagent 决策记录)](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) 所述截断正在处理的轮次。`jsonrpc` 插件拥有先响应再退出的协议关闭流程;两条路径均幂等,即使发生竞态也安全
## stdout 是协议
@@ -20,14 +20,14 @@ stdout 只承载 JSON-RPC 帧。bin 和启动守卫在 stderr 上输出诊断,
## 模型体验
模型通过外部 `cordis.yml` 加载的插件间接获得体验;每个插件拥有自身面向模型的提示词、schema、消息和结果此 bin 不添加任何内容。
模型体验由外部 `cordis.yml` 加载的插件间接提供;这些插件负责所有面向模型的提示词、schema、消息和结果此 bin 不添加任何内容。
#### KV Cache 影响
不会直接失效;具名消费方拥有请求前缀的任何变更。
不会直接失效;由上述消费方负责请求前缀的任何变更。
## 已知限制与延后工作
## 已知限制与暂缓事项
- **bin 无法证明配置提供 JSON-RPC 服务**:不含 `dsh-jsonrpc` 条目的有效配置也能成功启动,但不会提供任何服务。
- **不存在内置或默认配置**:每次启动都必须提供 `DSH_CORDIS_CONFIG` 或位置路径;部署拥有完整插件树和 stdout 纪律。
- **不存在内置或默认配置**:每次启动都必须提供 `DSH_CORDIS_CONFIG` 或位置路径;部署方负责完整插件树和 stdout 纪律。
- **stdin EOF 会截断正在处理的工作**:客户端消失时立即释放根上下文;需要有序完成的调用方应使用协议级 `shutdown` 请求。

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# 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
# pnpm run verify-translation-pairing --write packages/examples/tui-demo/README.md
README.md: 058ebe87af5f041bd19fbfb205a97753ccacf6b9
README.zh.md: 254bee76dff0d400a7b133013e8322898599f73e
README.zh.md: 43681e9c77cbd77459ec0539b69e0ab73274d2c1

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
全屏终端应用组合包:一个 Cordis 插件,组合 [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md)、持久的同会话目标、人类命令注册表与 `/goal` 生产方、JSONL 持久化、键盘支持的用户交互、预创建的 `main` agent以及 [`@deepseek-ai/dsh-tui`](../../ui/tui/README.md)。一份 `cordis.yml` 将它作为单个条目挂载;[`dsh`](../../../apps/cli/README.md) CLI 是启动此类配置的前端入口。
全屏终端应用组合包:一个 Cordis 插件,组合 [`@deepseek-ai/dsh-agent-spine-demo`](../agent-spine-demo/README.md)、持久的同会话目标、人类命令注册表与 `/goal` 生产方、JSONL 持久化、键盘支持的用户交互、预创建的 `main` agent(智能体),以及 [`@deepseek-ai/dsh-tui`](../../ui/tui/README.md)。一份 `cordis.yml` 将它作为一个 Cordis 配置项挂载;[`dsh`](../../../apps/cli/README.md) CLI(命令行界面)是启动此类配置的入口。
管道、脚本和其他非交互式运行应使用 [`@deepseek-ai/dsh-cli-demo`](../cli-demo/README.md)。此组合包需要一对 TTY不提供面向行的回退。
@@ -11,16 +11,16 @@
| 插件 | 设置在此处的原因 |
|---|---|
| `@deepseek-ai/dsh-agent-spine-demo` | 共享服务、面向模型的工具,以及一个已配置的 `main` agent |
| `@deepseek-ai/dsh-commands` | 供 TUI 和命令插件消费的纯人类命令发现与分发 |
| `@deepseek-ai/dsh-command-goal` | 直接在主干的持久目标栈上提供 `/goal` 状态与变更 |
| `@deepseek-ai/dsh-commands` | 供 TUI 和命令插件消费、仅面向人类命令发现与分发 |
| `@deepseek-ai/dsh-command-goal` | 直接在主干的持久目标栈上提供 `/goal` 状态与变更 |
| `@deepseek-ai/dsh-session-persistence-jsonl` | 位于 `persistenceRoot` 下的持久会话日志 |
| `@deepseek-ai/dsh-session-checkpoint-policy` | 模型请求和顶层工具 effect 前的语义持久性屏障,以及已完成步骤的检查点 |
| `@deepseek-ai/dsh-session-query-sqlite` + `@deepseek-ai/dsh-session-reference` | TUI 消费的组合式精确FTS 会话查询与有界 `@session` 快照;面向模型的查询工具仍由叶节点选用 |
| `@deepseek-ai/dsh-user-interaction` | 与提供方无关的人类问题服务 |
| `@deepseek-ai/dsh-tui` | 全屏记录、编辑器、工具卡片、计划与问题 overlay |
| `@deepseek-ai/dsh-tui` | 全屏 transcript文本记录、编辑器、工具卡片、计划与问题 overlay |
| `@deepseek-ai/dsh-tool-ask-user` | 面向模型的 `ask_user_question` 工具 |
可替换的 LLM、bash、文件系统和其他能力提供方仍留在叶节点配置中。`@cordisjs/plugin-hmr` 也仍是仅叶节点使用的开发条目,因为它需要 Loader 内部表层
可替换的 LLM(大语言模型)、bash、文件系统和其他能力提供方仍留在叶节点配置中。`@cordisjs/plugin-hmr` 也仍是仅叶节点使用的开发条目,因为它需要 Loader 内部实现
## 配置
@@ -31,27 +31,27 @@
| `maxParallelToolCalls` | agent-loop 默认值 | 组合包内循环的并发上限 |
| `persona` | 无 | 系统提示词 persona 模板 |
| `toolOrder` | 字典序 | 显式的面向模型工具顺序 |
| `tools` | 拥有者默认值 | 工具呈现 mode |
| `dshHome` | 拥有者默认值 | bash 与 skill 使用的 Harness 主目录 |
| `tools` | 拥有者默认值 | 工具呈现模式 |
| `dshHome` | 拥有者默认值 | bash 与 skill(技能)使用的 harness 主目录 |
| `sessionTitle` | 主干示例限制 | 后备标题词数/字节限制 |
| `skills` | 拥有者默认值 | Skill 注册表、本地提供方和工具配置 |
| `skills` | 拥有者默认值 | skill 注册表、本地提供方和工具配置 |
| `toolBash` | 拥有者默认值 | 面向模型的 bash 工具配置 |
| `toolTasks` | 拥有者默认值 | 后台任务控制工具配置,或 `false` |
| `goals` | 拥有者默认值 | 持久目标领域与模型工具配置;`false` 会移除目标栈与 `/goal` 生产方 |
| `workspaceContext` | 必填 | Workspace 指令配置,或 `false` |
| `persistenceRoot` | `./.sessions` | JSONL 持久化根目录,以及派生 `session-query.db` 索引的父目录 |
| `persistenceCompression` | `'zstd'` | JSONL 工件编码(`'zstd'` 或原始 `'none'` |
| `persistenceCompression` | `'zstd'` | JSONL 产物编码(`'zstd'` 或原始 `'none'` |
| `sessionReferences` | 服务默认值 | 路由到 `dsh-session-reference` 的跨会话候选项与快照限制 |
| `welcome` | `ready.` | TUI 副标题 |
| `resumeCommand` | 无 | 退出和无宿主回退的命令模板;选择器本身使用会话查询与宿主移交 |
| `ui` | 拥有者默认值 | 推理、颜色、卡片高度等 TUI 呈现设置 |
| `ui` | 拥有者默认值 | 推理reasoning、颜色、卡片高度等 TUI 呈现设置 |
| `resumeSessionId` | 无 | 要恢复的确切持久化会话 |
新运行会创建 `main-session-<uuid>` 会话 id并将它同时传给 TUI 与已配置的 agent。恢复运行会将两个组件都绑定到 `resumeSessionId`。TUI 先于主干挂载,因此它可以渲染匹配的配置启动失败,而不会留下空白终端。应用为 `/resume` 组合持久化和会话查询;嵌入宿主还可以提供 `tuiResumeHost`原地移交进程。
新运行会创建 `main-session-<uuid>` 会话 id并将它同时传给 TUI 与已配置的 agent。恢复运行会将两个组件都绑定到 `resumeSessionId`。TUI 先于主干挂载,因此它可以渲染匹配的配置启动失败,而不会留下空白终端。应用为 `/resume` 组合持久化和会话查询;嵌入宿主还可以提供 `tuiResumeHost`用于原地移交进程。
## 前端入口
## 入口
此包不交付 bin。[`dsh`](../../../apps/cli/README.md) CLI 是终端前端入口:裸 `dsh` 启动已交付的 `examples/tui-agent/cordis.yml`(它挂载此组合包),而 `dsh --config <path-to-cordis.yml>` 启动另一个挂载此组合包的叶节点配置。它加载 cwd 下可选的 `.env`,驱动 Cordis Loader并等待完整插件树。仓库安装了 Loader 的可选原生辅助程序,因此裸包说明符可以在纯 Node 下解析。
此包package不交付 bin。[`dsh`](../../../apps/cli/README.md) CLI 是终端入口:裸 `dsh` 启动已交付的 `examples/tui-agent/cordis.yml`(它挂载此组合包),而 `dsh --config <path-to-cordis.yml>` 启动另一个挂载此组合包的叶节点配置。它加载 cwd 下可选的 `.env`,驱动 Cordis Loader并等待完整插件树。仓库安装了 Loader 的可选原生辅助程序,因此裸包说明符可以在纯 Node 下解析。
## 叶节点示例
@@ -78,21 +78,21 @@
### 交互式终端轮次
#### 模型所见
#### 模型看到的内容
每次非空、非命令的编辑器提交都会成为用户消息;运行中轮次内的提交成为 steering。斜杠命令输入和输出仍只面向人类而已接受的 `/goal` 变更会追加领域拥有的模型可见状态。共享主干提供已配置的 persona、workspace 指令、skill 目录、目标控制和可见工具 schema。TUI 渲染本身对模型不可见。
每次非空、非命令的编辑器提交都会成为用户消息;运行中轮次内的提交成为 steering(中途引导)。斜杠命令输入和输出仍只面向人类,而已接受的 `/goal` 变更会追加领域拥有的模型可见状态。共享主干提供已配置的 persona、workspace 指令、skill 目录、目标控制和可见工具 schema。TUI 渲染本身对模型不可见。
#### Token 影响
用户、assistant 与工具历史按常规会话和压缩规则增长。Header、卡片、计划、Markdown 样式和快捷键不增加 token。
用户、assistant 与工具历史按常规会话和压缩compaction规则增长。Header、卡片、计划、Markdown 样式和快捷键不增加 token。
#### KV Cache 影响
只要组合后的提示词、schema、路由和保留历史前缀保持稳定追加。组合变更与压缩可能从第一个变化的 token 起使复用失效。
只要组合后的提示词、schema、路由和保留历史前缀保持稳定保持仅追加。组合方式变更与 compaction 可能从第一个变化的 token 起使复用失效。
### 人类问题答案
#### 模型所见
#### 模型看到的内容
`ask_user_question` 会保留工具调用,以及 `dsh-tool-ask-user` 定义的精简答案或稳定中断错误。问题 overlay 只在终端显示。
@@ -102,11 +102,11 @@
#### KV Cache 影响
追加;答案跟在可复用请求前缀之后。
追加;答案跟在可复用请求前缀之后。
## 已知限制与延后工作
## 已知限制与暂缓事项
- **只支持 TTY**stdin 与 stdout 都必须是终端;自动化使用 `dsh-cli-demo`
- **一个已配置的终端会话**记录与编辑器绑定到一个确切会话 id。
- **一个已配置的终端会话**transcript 与编辑器绑定到一个确切会话 id。
- **应用集群固定不变**JSONL 持久化与 ask-user 工具内置;不同策略需要另一种组合。
- **批准机制独立存在**:此应用回答 `ctx.userInteraction`,而不是 `ctx.approval`;权限提示需要批准服务和回答方。