@nanmicoder/dsh-agent-teams 0.1.16-rc.1 → 0.1.16-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -57
- package/README_ZH.md +19 -56
- package/lib/capabilities.js +106 -0
- package/lib/command.js +3 -3
- package/lib/index.js +40 -36
- package/lib/members.js +8 -9
- package/lib/profiles.js +1 -1
- package/lib/state.js +34 -6
- package/lib/tool-names.js +11 -0
- package/lib/tools.js +16 -3
- package/lib/types/capabilities.d.ts +14 -0
- package/lib/types/index.d.ts +3 -1
- package/lib/types/members.d.ts +2 -0
- package/lib/types/state.d.ts +7 -1
- package/lib/types/tool-names.d.ts +4 -0
- package/lib/types/tools.d.ts +3 -0
- package/package.json +4 -3
- package/release-notes/v0.1.16-rc.2.md +33 -0
- package/release-notes/v0.1.16-rc.3.md +33 -0
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
`dsh-agent-teams` turns the current DeepSeek Harness session into a captain that can assemble durable sub-agents, split a goal into dependency-aware tasks, and coordinate work through direct messages.
|
|
24
24
|
|
|
25
|
-
Ask in natural language. The plugin provides the team protocol,
|
|
25
|
+
Ask in natural language. The plugin provides the team protocol, 13 coordination tools, persistent state, an automatic shared-task scheduler, and a live Web UI—without requiring a separate workflow engine.
|
|
26
26
|
|
|
27
27
|
<p align="center">
|
|
28
28
|
<img src="./assets/ui.png" width="100%" alt="DeepSeek Harness conversation with the AgentTeams live activity panel, members, tasks, dependencies, and reports">
|
|
@@ -30,7 +30,7 @@ Ask in natural language. The plugin provides the team protocol, eleven coordinat
|
|
|
30
30
|
|
|
31
31
|
## Releases
|
|
32
32
|
|
|
33
|
-
[v0.1.16-rc.
|
|
33
|
+
[v0.1.16-rc.3](./release-notes/v0.1.16-rc.3.md) targets npm `next`, with a concise fixed team protocol, existing-team reuse guidance, Web approval wakeups, and team-lock cleanup. Choose a version pair below.
|
|
34
34
|
|
|
35
35
|
## Why AgentTeams?
|
|
36
36
|
|
|
@@ -49,77 +49,38 @@ The conversation card and activity panel use Harness's official locale service.
|
|
|
49
49
|
|
|
50
50
|
## Install and choose versions
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
> **0.1.16-rc.1 is a prerelease on the `next` track.** Use the exact version below for the supported 0.1.2 hosts. Plugin 0.1.15 targets Alpha.2; do not use a mutable `latest` tag as a compatibility guarantee. Check the actual running host and profile before updating either side.
|
|
52
|
+
**Recommended pair: DeepSeek Harness `0.1.2-rc.1` + AgentTeams `0.1.16-rc.3`. Both are still prereleases.**
|
|
54
53
|
|
|
55
|
-
|
|
|
54
|
+
| Use case | DeepSeek Harness | AgentTeams plugin |
|
|
56
55
|
| --- | --- | --- |
|
|
57
|
-
| **0.1.2-rc.1
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
| Other versions, source HEAD, embedded Desktop cores | Outside the current matrix | Keep a known working exact pair or complete acceptance before adding a target. |
|
|
56
|
+
| **Recommended installation** | **`0.1.2-rc.1`** | **`0.1.16-rc.3`** |
|
|
57
|
+
| Developer Alpha testing | `0.1.2-alpha.5` | `0.1.16-rc.3` |
|
|
58
|
+
| Retaining an older Alpha | `0.1.2-alpha.2` | `0.1.16-rc.3` |
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
### Ordinary users: keep a matching host and plugin
|
|
65
|
-
|
|
66
|
-
The recommended host installation target is:
|
|
60
|
+
### 1. Install DeepSeek Harness
|
|
67
61
|
|
|
68
62
|
```sh
|
|
69
63
|
npm install --global @deepseek-ai/dsh@0.1.2-rc.1
|
|
70
64
|
dsh --version
|
|
71
65
|
```
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```sh
|
|
76
|
-
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.1
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Restart the actual Harness process after changing either side and refresh the browser. Updating a global CLI does not replace an embedded Desktop core or another source checkout. For an unpublished checkout, use the source build below.
|
|
80
|
-
|
|
81
|
-
An exact npm CLI version can still contain broad transitive dependencies. Preserve a verified lockfile and inspect the actual installation. Do not delete credentials or `.agent-teams` data to address a version mismatch.
|
|
67
|
+
Skip this if you already run this version. Alpha is opt-in: select an exact Alpha version from the table and lock all host dependencies as described in the [maintenance guide](./docs/maintenance-workflow.md).
|
|
82
68
|
|
|
83
|
-
###
|
|
69
|
+
### 2. Install the AgentTeams plugin
|
|
84
70
|
|
|
85
|
-
|
|
71
|
+
This installs into the `web` profile. Replace `web` with your actual profile name if different:
|
|
86
72
|
|
|
87
73
|
```sh
|
|
88
|
-
|
|
89
|
-
pnpm typecheck
|
|
90
|
-
pnpm build
|
|
91
|
-
pnpm verify
|
|
92
|
-
pnpm pack --out ./agent-teams-candidate.tgz
|
|
74
|
+
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.3
|
|
93
75
|
```
|
|
94
76
|
|
|
95
|
-
|
|
77
|
+
**After installation, stop and restart Harness for that profile, then refresh the browser.**
|
|
96
78
|
|
|
97
|
-
|
|
98
|
-
node scripts/doctor.mjs --host-root "/actual/host/package/directory" --json
|
|
99
|
-
dsh plugin --profile agent-teams-preview add --save-exact /absolute/path/agent-teams-candidate.tgz
|
|
100
|
-
node scripts/doctor.mjs --host-root "/actual/host/package/directory" --profile-root "/actual/test/profile/directory" --json
|
|
101
|
-
dsh --profile agent-teams-preview --dump-config
|
|
102
|
-
dsh web --profile agent-teams-preview
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
The doctor checks the DSH dependency cohort, duplicate runtime identities and the profile's plugin version. It reads package metadata without reading credentials or changing configuration. Passing it does not replace team, task and UI acceptance. Rebuild, repack and restart after source changes.
|
|
106
|
-
|
|
107
|
-
### Developers: explicitly test Alpha
|
|
79
|
+
Plugin `0.1.16-rc.3` uses the `next` channel; `latest` still points to `0.1.15`, which targets Alpha.2. Use the exact-version command above. Future plugin prereleases use `next`; only stable plugin releases that pass the full verification matrix may use `latest`.
|
|
108
80
|
|
|
109
|
-
|
|
81
|
+
> Desktop users must check the app's embedded Harness core; upgrading the global CLI does not upgrade it. For older `0.1.0-*` / `0.1.1-*` or unlisted hosts, keep a working pair and follow the [older-version and diagnostic guide](./docs/maintenance-workflow.md).
|
|
110
82
|
|
|
111
|
-
|
|
112
|
-
node scripts/harness-runtime-verify.mjs \
|
|
113
|
-
--host-version 0.1.2-alpha.2 \
|
|
114
|
-
--artifact ./agent-teams-candidate.tgz \
|
|
115
|
-
--report-dir /tmp/agent-teams-alpha2-check
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
This developer command downloads the host into temporary directories without modifying existing user profiles. It uses deterministic model responses with the real CLI, plugin, sessions, tools and subagents. See the [maintenance workflow](./docs/maintenance-workflow.md) for coverage and release requirements.
|
|
119
|
-
|
|
120
|
-
### Retaining an older host / rollback
|
|
121
|
-
|
|
122
|
-
For the historical Harness `0.1.0-rc.8` + plugin `0.1.14` pair, pin both sides. This is not a compatibility claim for every older RC. Keep another already verified older pair until a complete migration is ready. Historical [Alpha.2 compatibility](./docs/alpha2-compatibility.md) and [acceptance](./docs/alpha2-release-acceptance.md) reports describe those specific releases, not the current matrix.
|
|
83
|
+
See the full [compatibility matrix](./compatibility.json), [source installation and Alpha testing guide](./docs/maintenance-workflow.md), and [verification coverage and platform limits](./docs/maintenance-2026-09-06/release/README.md).
|
|
123
84
|
|
|
124
85
|
Then ask for a team directly:
|
|
125
86
|
|
|
@@ -127,7 +88,7 @@ Then ask for a team directly:
|
|
|
127
88
|
|
|
128
89
|
## How it works
|
|
129
90
|
|
|
130
|
-
1.
|
|
91
|
+
1. For a request to use AgentTeams, the captain follows the core protocol already in its system instructions. It continues an existing team and uses `agent_teams_status` when current state needs checking. When no team exists, the goal becomes a staged plan for review.
|
|
131
92
|
2. The captain adds role-specific members backed by continuable sub-agents.
|
|
132
93
|
3. The goal becomes tasks with owners and explicit dependencies.
|
|
133
94
|
4. The shared scheduler uses real `running / idle / ready` state to atomically claim one ready task per idle member and wake it. An interrupted resident attempt stays parked and can resume through a direct message without losing its capability; after a cold process restart, the scheduler retries stranded open work with a fresh attempt.
|
|
@@ -138,6 +99,8 @@ Team state is stored under `<workspace>/.agent-teams/`; the Web panel reads that
|
|
|
138
99
|
|
|
139
100
|
Member creation is zero-interaction by default: a member on the captain's current LLM route snapshots that provider, model, and reasoning effort, while a member on a requested alternative route snapshots the target model's default effort; later continuations restore the resolved snapshot. Only an explicit heterogeneous-team request (for example, “backend on provider A/model X, frontend on provider B/model Y”) supplies a member-specific `provider` + `model`; there is no per-member model or reasoning prompt.
|
|
140
101
|
|
|
102
|
+
Captain sessions keep the concise core protocol and the original 13 native team tools from their first request. All business tools are directly available; no loading tool or extra activation call is needed. Configured profiles retain their bounded directory in the fixed system prompt. Creating, approving, continuing or ending a team does not rewrite the system prompt or tool schemas. Core rules remain available after history compaction or discarded code-mode tool results. Members receive four team tools, fixed member instructions, and their ordinary coding/research tools. Web approval wakes the captain with a control message; later member reports wake it again. See the [fixed protocol and benchmark contract](./docs/progressive-loading.md).
|
|
103
|
+
|
|
141
104
|
## Slash command
|
|
142
105
|
|
|
143
106
|
No “use AgentTeams” phrasing required. The plugin registers the
|
|
@@ -152,7 +115,7 @@ command), describe the goal, and press Enter.
|
|
|
152
115
|
The command pipeline claims the line, then preserves that exact input as an
|
|
153
116
|
ordinary user follow-up so it remains visible in the main chat. The gesture
|
|
154
117
|
boundary adds the deterministic activation directive at pre-step, so the
|
|
155
|
-
|
|
118
|
+
first model request follows the staged planning protocol without a mandatory helper call. The invocation is also durably
|
|
156
119
|
logged (`command/run` / `command/done`).
|
|
157
120
|
|
|
158
121
|
Surfaces without command adjudication (for example the headless CLI) get the
|
package/README_ZH.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
`dsh-agent-teams` 让当前 DeepSeek Harness 会话成为队长:创建可续聊的子 Agent、把目标拆成有依赖的任务,并通过直达消息协调成员工作。
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
你只需用自然语言提出目标。插件会提供精简的固定团队协议、13 个业务工具、持久化状态、自动共享任务调度和实时 Web UI,不需要额外的 Workflow 引擎。
|
|
26
26
|
|
|
27
27
|
<p align="center">
|
|
28
28
|
<img src="./assets/ui.png" width="100%" alt="DeepSeek Harness 对话与 AgentTeams 实时活动面板,展示成员、任务依赖和回报">
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
## 版本更新
|
|
32
32
|
|
|
33
|
-
[v0.1.16-rc.
|
|
33
|
+
[v0.1.16-rc.3](./release-notes/v0.1.16-rc.3.md) 面向 npm `next` 渠道,精简固定团队协议、引导复用已有团队,并修复 Web 批准通知和团队锁清理。安装版本见下方配对表。
|
|
34
34
|
|
|
35
35
|
## 为什么需要 AgentTeams?
|
|
36
36
|
|
|
@@ -48,82 +48,45 @@
|
|
|
48
48
|
|
|
49
49
|
## 安装与版本选择
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
> **0.1.16-rc.1 是 `next` 渠道的预发布版本。** 对当前支持的 0.1.2 宿主,请使用下方精确插件版本。0.1.15 面向 Alpha.2,不能把可变的 `latest` 标签当作兼容保证。请先核对实际运行的宿主和 profile,再更新两端。
|
|
51
|
+
**推荐组合:DeepSeek Harness `0.1.2-rc.1` + AgentTeams `0.1.16-rc.3`。两者都仍是预发布版本。**
|
|
53
52
|
|
|
54
|
-
|
|
|
53
|
+
| 使用场景 | DeepSeek Harness | AgentTeams 插件 |
|
|
55
54
|
| --- | --- | --- |
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
| 其他版本、源码 HEAD、Desktop 内置核心 | 不在当前支持清单中 | 保留已工作的精确组合,或单独完成验收后加入清单。 |
|
|
55
|
+
| **推荐安装** | **`0.1.2-rc.1`** | **`0.1.16-rc.3`** |
|
|
56
|
+
| 开发者测试 Alpha | `0.1.2-alpha.5` | `0.1.16-rc.3` |
|
|
57
|
+
| 保留旧 Alpha | `0.1.2-alpha.2` | `0.1.16-rc.3` |
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
### 普通用户:固定匹配的宿主与插件
|
|
64
|
-
|
|
65
|
-
推荐宿主安装目标为:
|
|
59
|
+
### 1. 安装 DeepSeek Harness
|
|
66
60
|
|
|
67
61
|
```sh
|
|
68
62
|
npm install --global @deepseek-ai/dsh@0.1.2-rc.1
|
|
69
63
|
dsh --version
|
|
70
64
|
```
|
|
71
65
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```sh
|
|
75
|
-
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.1
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
宿主或插件更新后,停止并重启实际运行的 Harness,再刷新浏览器。全局 CLI 升级不会更换 Desktop 内置核心,也不会更新另一个源码工作区。尚未发布的 checkout 可使用下方源码构建方式。
|
|
79
|
-
|
|
80
|
-
npm 的精确 CLI 版本仍可能包含宽范围间接依赖。升级时保留已验证的锁文件,对实际安装路径运行诊断;不要通过删除凭据或 `.agent-teams` 来处理版本错配。
|
|
66
|
+
已有该版本可跳过。Alpha 仅供主动测试:手动指定表中的 Alpha 版本,并按[维护指南](./docs/maintenance-workflow.md)锁定整组宿主依赖。
|
|
81
67
|
|
|
82
|
-
###
|
|
68
|
+
### 2. 安装 AgentTeams 插件
|
|
83
69
|
|
|
84
|
-
|
|
70
|
+
以下安装到 `web` profile;使用其他 profile 时,将 `web` 换成实际名称:
|
|
85
71
|
|
|
86
72
|
```sh
|
|
87
|
-
|
|
88
|
-
pnpm typecheck
|
|
89
|
-
pnpm build
|
|
90
|
-
pnpm verify
|
|
91
|
-
pnpm pack --out ./agent-teams-candidate.tgz
|
|
73
|
+
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.3
|
|
92
74
|
```
|
|
93
75
|
|
|
94
|
-
|
|
76
|
+
**安装后,停止并重新启动该 profile 的 Harness 进程,再刷新浏览器。**
|
|
95
77
|
|
|
96
|
-
|
|
97
|
-
node scripts/doctor.mjs --host-root "/实际运行的宿主包目录" --json
|
|
98
|
-
dsh plugin --profile agent-teams-preview add --save-exact /完整路径/agent-teams-candidate.tgz
|
|
99
|
-
node scripts/doctor.mjs --host-root "/实际运行的宿主包目录" --profile-root "/实际测试profile目录" --json
|
|
100
|
-
dsh --profile agent-teams-preview --dump-config
|
|
101
|
-
dsh web --profile agent-teams-preview
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
`doctor` 检查整组 DSH 包版本、重复运行时身份以及 profile 中的插件版本。它只读文件,不读取凭据、不修改配置;检查通过不替代实际建队、任务执行和 UI 验收。源码更改后需要重新构建、打包和重启。
|
|
105
|
-
|
|
106
|
-
### 开发者:显式测试 Alpha
|
|
78
|
+
插件 `0.1.16-rc.3` 使用 `next` 渠道;当前 `latest` 仍是面向 Alpha.2 的 `0.1.15`。请使用上面的精确版本命令。后续插件预发布版本继续进入 `next`,通过完整验证的正式版本才进入 `latest`。
|
|
107
79
|
|
|
108
|
-
|
|
80
|
+
> Desktop 用户需核对应用内置的 Harness 核心;全局 CLI 升级不会升级桌面内核。旧 `0.1.0-*` / `0.1.1-*` 或其他未列出的宿主,请先保留已工作的组合,参考[旧版本与诊断指引](./docs/maintenance-workflow.md)。
|
|
109
81
|
|
|
110
|
-
|
|
111
|
-
node scripts/harness-runtime-verify.mjs \
|
|
112
|
-
--host-version 0.1.2-alpha.2 \
|
|
113
|
-
--artifact ./agent-teams-candidate.tgz \
|
|
114
|
-
--report-dir /tmp/agent-teams-alpha2-check
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
这是会创建临时目录并下载宿主的开发验收命令,不会修改已有用户 profile。模型适配器使用固定测试响应;CLI、插件、会话、工具与子代理使用真实宿主实现。完整范围和发布流程见[维护流程](./docs/maintenance-workflow.md)。
|
|
118
|
-
|
|
119
|
-
### 保留旧宿主 / 回退
|
|
120
|
-
|
|
121
|
-
对于历史组合 Harness `0.1.0-rc.8` + 插件 `0.1.14`,应固定两端版本;不能据此推断所有旧 RC 都兼容。已使用其他已验证旧组合的用户先保留该组合。历史 [Alpha.2 兼容记录](./docs/alpha2-compatibility.md)和[验收报告](./docs/alpha2-release-acceptance.md)只描述当时版本,不覆盖当前清单。
|
|
82
|
+
完整[兼容清单](./compatibility.json)、[源码安装与 Alpha 验证](./docs/maintenance-workflow.md)、[已验证范围与平台限制](./docs/maintenance-2026-09-06/release/README.md)。
|
|
122
83
|
|
|
123
84
|
接着直接用自然语言拉团队:
|
|
124
85
|
|
|
125
86
|
> 使用 AgentTeams 审查 v0.5.3 之后的提交,分别从性能、安全和产品角度分工,最后输出一份汇总报告。
|
|
126
87
|
|
|
88
|
+
队长会话从第一轮起保留精简的固定核心协议和原有 13 个业务工具,直接调用,无需额外的加载工具或激活调用。已配置模板的精简目录固定保留。创建、批准、继续或结束团队都不会改写系统提示词和工具 schema,会话压缩或代码模式丢弃工具结果也不会丢失核心规则。成员保留四个团队工具、固定成员说明及普通编程/研究工具。Web 批准后会通知并唤醒队长,后续成员报告会再次唤醒它,无需忙轮询。详见[固定协议与 benchmark 标准](./docs/progressive-loading.md)。
|
|
89
|
+
|
|
127
90
|
## 工作方式
|
|
128
91
|
|
|
129
92
|
1. 当前会话创建团队并成为队长。
|
|
@@ -207,7 +170,7 @@ pnpm verify
|
|
|
207
170
|
|
|
208
171
|
在 `cordis.patch.yml` 的 `profiles` 中配置完整团队模板。每个 profile 都提供成员阵容,可独立指定 provider、model、role、reasoning_effort。`taskPlanning: captain` 表示只提供阵容和约束,由 Captain 根据用户目标设计 DAG;省略该字段或设为 `seed` 时,展开模板中的固定任务图。使用 `/agent-teams --profile <名称> <目标>` 显式激活;不会把首个普通 token 隐式识别为 profile。
|
|
209
172
|
|
|
210
|
-
普通 `/agent-teams`
|
|
173
|
+
普通 `/agent-teams` 流程继续已有团队,按需调用 `agent_teams_status` 确认状态;仅在没有当前团队时调用 `agent_teams_create({ profile, approval: "required" })`:只落盘可编辑的成员占位和 DAG,不创建子会话、不领取任务。成员模型和推理等级直接读取 Harness 的模型目录。「返回对话修改」会终止仍在运行的规划轮次,让队长先追问修改方向,再用一次原子操作更新同一份草案;「放弃本次计划」经二次确认后会归档草案、中止轮次,并向模型注入不得自动重建团队的控制上下文。只有点击「确认并启动团队」才会按最终配置原子创建成员并启动就绪任务。运行中团队的停止入口位于该团队的面板标题,点击后需要二次确认,不再占用输入区域。直接工具调用方可显式传 `approval: "automatic"` 保留旧的立即执行路径。审查或测试失败不会解锁下游;自动 repair/review 不依赖 failed review。
|
|
211
174
|
|
|
212
175
|
## 许可证
|
|
213
176
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readTeamSync, readRetiredMemberIdsSync } from "./state.js";
|
|
4
|
+
import { MEMBER_TOOL_NAMES, TEAM_TOOL_NAMES } from "./tool-names.js";
|
|
5
|
+
export const TEAM_ACTIVATION_PROMPT = 'AgentTeams (Agent Teams) provides multi-agent team collaboration. Apply these rules when the user requests it (including /agent-teams) or when continuing an existing team. Mentioning, quoting, discussing, or declining AgentTeams alone is not a request to start work.';
|
|
6
|
+
export const TEAM_MEMBER_PROMPT = 'You are an AgentTeams member. Follow your assigned member persona and task contract. Use agent_teams_claim_task, agent_teams_update_task, agent_teams_send_message and agent_teams_status for your own work. Include the current attempt_id in updates; report completion or failure to the captain. Do not create, approve, edit or resume a team. If your durable membership is unavailable, report that to the parent instead of creating a replacement.';
|
|
7
|
+
function stateRoot(agent, config) {
|
|
8
|
+
return join(agent.session.header.cwd ?? process.cwd(), config.stateDir);
|
|
9
|
+
}
|
|
10
|
+
/** Synchronous startup/HMR hydration must finish before the first assembly. */
|
|
11
|
+
function currentTeam(agent, config) {
|
|
12
|
+
const root = stateRoot(agent, config);
|
|
13
|
+
let entries;
|
|
14
|
+
try {
|
|
15
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === 'ENOENT')
|
|
19
|
+
return undefined;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
let found;
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (!entry.isDirectory() || entry.name === 'archive')
|
|
25
|
+
continue;
|
|
26
|
+
const team = readTeamSync(root, entry.name);
|
|
27
|
+
if (team === undefined || (team.captainSessionId !== agent.id
|
|
28
|
+
&& !team.members.some(member => member.id === agent.id)))
|
|
29
|
+
continue;
|
|
30
|
+
if (found !== undefined)
|
|
31
|
+
throw new Error('ambiguous AgentTeams membership');
|
|
32
|
+
found = team;
|
|
33
|
+
}
|
|
34
|
+
return found;
|
|
35
|
+
}
|
|
36
|
+
/** Call once, after all business definitions have registered. Never per member. */
|
|
37
|
+
export function installTeamCapabilities(ctx, config) {
|
|
38
|
+
const states = new WeakMap();
|
|
39
|
+
const active = new Set();
|
|
40
|
+
let mounted = true;
|
|
41
|
+
// Snapshot policy once: profiles, team state, and tool results must never
|
|
42
|
+
// rewrite this prefix or control whether core instructions are available.
|
|
43
|
+
const captainPrompt = `${TEAM_ACTIVATION_PROMPT}\n\n${config.captainPrompt()}`;
|
|
44
|
+
function attach(agent) {
|
|
45
|
+
const prior = states.get(agent);
|
|
46
|
+
if (prior !== undefined)
|
|
47
|
+
return prior;
|
|
48
|
+
if (!mounted)
|
|
49
|
+
throw new Error('AgentTeams capability provider is disposed');
|
|
50
|
+
// Determine a member's role before its first request and retain it for the
|
|
51
|
+
// lifetime of this scope. Team creation/archive must never rewrite the
|
|
52
|
+
// captain's system/tools prefix, even after a long ordinary conversation.
|
|
53
|
+
let member = config.isPendingMember(agent);
|
|
54
|
+
try {
|
|
55
|
+
member ||= readRetiredMemberIdsSync(stateRoot(agent, config)).has(agent.id);
|
|
56
|
+
const team = currentTeam(agent, config);
|
|
57
|
+
member ||= team !== undefined && team.captainSessionId !== agent.id;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// Unrelated damaged state must not disable ordinary conversation.
|
|
61
|
+
// Business tools still validate durable team state before acting.
|
|
62
|
+
ctx.logger.warn(`agent-teams: capability hydration failed: ${String(error)}`);
|
|
63
|
+
}
|
|
64
|
+
const state = { member, dispose: () => undefined };
|
|
65
|
+
let revoke;
|
|
66
|
+
let disposed = false;
|
|
67
|
+
let releaseLifetime;
|
|
68
|
+
state.dispose = () => {
|
|
69
|
+
if (disposed)
|
|
70
|
+
return;
|
|
71
|
+
disposed = true;
|
|
72
|
+
revoke?.();
|
|
73
|
+
releaseLifetime?.();
|
|
74
|
+
states.delete(agent);
|
|
75
|
+
active.delete(state);
|
|
76
|
+
};
|
|
77
|
+
states.set(agent, state);
|
|
78
|
+
active.add(state);
|
|
79
|
+
try {
|
|
80
|
+
if (member)
|
|
81
|
+
revoke = agent.ctx.tools.restrict({
|
|
82
|
+
deny: TEAM_TOOL_NAMES.filter(name => !MEMBER_TOOL_NAMES.includes(name)),
|
|
83
|
+
});
|
|
84
|
+
releaseLifetime = agent.ctx.effect(() => state.dispose, 'agent-teams: capability lifetime');
|
|
85
|
+
return state;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
state.dispose();
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
ctx.systemPrompt.section({
|
|
93
|
+
name: 'agent-teams:usage', order: config.order ?? 117,
|
|
94
|
+
text: ({ agent }) => {
|
|
95
|
+
return agent !== undefined && states.get(agent)?.member ? TEAM_MEMBER_PROMPT : captainPrompt;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
ctx.on('agent/session-start', ({ agent }) => { attach(agent); });
|
|
99
|
+
ctx.effect(() => () => {
|
|
100
|
+
mounted = false;
|
|
101
|
+
for (const state of [...active])
|
|
102
|
+
state.dispose();
|
|
103
|
+
}, 'agent-teams: capability scopes');
|
|
104
|
+
for (const agent of ctx.agents.list())
|
|
105
|
+
attach(agent);
|
|
106
|
+
}
|
package/lib/command.js
CHANGED
|
@@ -54,11 +54,11 @@ export function invokedAgentTeamsGoal(messages) {
|
|
|
54
54
|
}
|
|
55
55
|
export function buildActivationDirective(goal, profile, taskPlanning = 'seed') {
|
|
56
56
|
const lines = [
|
|
57
|
-
'The user invoked an AgentTeams slash command.
|
|
58
|
-
'
|
|
57
|
+
'The user invoked an AgentTeams slash command. Follow the AgentTeams protocol already in your system instructions. Inspect existing team state with agent_teams_status when needed.',
|
|
58
|
+
'Respect the current team state. Continue an existing plan or team without recreating it. Only when no current team exists, call agent_teams_create with approval="required". Build the complete staged roster and DAG, then stop and ask the user to review the Web plan. Do not approve or start it in this same turn.',
|
|
59
59
|
];
|
|
60
60
|
if (profile !== undefined) {
|
|
61
|
-
lines.push(`Use
|
|
61
|
+
lines.push(`Use profile="${profile}" when creating a new team.`);
|
|
62
62
|
if (taskPlanning === 'captain') {
|
|
63
63
|
lines.push('This profile supplies the roster and guardrails. After create, do not recreate members.', 'Derive the smallest useful task graph from the goal while the team is staged; do not ask the user whether to split, merge, serialize, or parallelize.', 'Independent supplemental work must become separate ready tasks so idle members can run in parallel. Add dependencies only for genuine prerequisites and later synthesis.');
|
|
64
64
|
}
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* AgentTeams for DeepSeek Harness.
|
|
3
3
|
*
|
|
4
4
|
* A host-plane plugin that registers the `agent_teams_*` tools and one usage
|
|
5
|
-
* section
|
|
5
|
+
* agent-scoped usage section. Each session keeps a stable tool set and core
|
|
6
|
+
* instructions. Existing business tools cover the complete team lifecycle.
|
|
7
|
+
* After installation any session can
|
|
6
8
|
* run multi-agent teamwork through natural language (e.g. "use AgentTeams to research X"):
|
|
7
9
|
* the model creates a team (it becomes the captain), spawns members as
|
|
8
10
|
* durable continuable subagents, breaks the goal into tasks with
|
|
@@ -17,7 +19,8 @@
|
|
|
17
19
|
* @module dsh-agent-teams
|
|
18
20
|
*/
|
|
19
21
|
import z from '@deepseek-ai/schemastery';
|
|
20
|
-
import {
|
|
22
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
23
|
+
import { haltTeamWork, stagedPlanApprovedContext, registerAgentTeamsTools, } from "./tools.js";
|
|
21
24
|
import { installAgentTeamsGestureBoundary, registerAgentTeamsCommand } from "./command.js";
|
|
22
25
|
import { readFile } from 'node:fs/promises';
|
|
23
26
|
import { join } from 'node:path';
|
|
@@ -25,7 +28,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
25
28
|
import { collectArchivedTeamsActivity, collectTeamsActivity } from "./snapshot.js";
|
|
26
29
|
import { findTeamByCaptain } from "./state.js";
|
|
27
30
|
import { formatProfilesForPrompt } from "./profiles.js";
|
|
28
|
-
import {
|
|
31
|
+
import { installTeamCapabilities } from "./capabilities.js";
|
|
32
|
+
import { TEAM_TOOL_NAMES } from "./tool-names.js";
|
|
29
33
|
import { authenticatedWebRoutes, readJsonRequest, RequestBodyError } from "./web-routes.js";
|
|
30
34
|
/** Web-server service key candidates, newest first. */
|
|
31
35
|
const WEB_SERVER_KEYS = ['webServer', 'httpServer'];
|
|
@@ -83,18 +87,17 @@ export const Config = z.object({
|
|
|
83
87
|
});
|
|
84
88
|
/** The model-facing usage policy: when and how to drive AgentTeams. */
|
|
85
89
|
export function usageSectionText(toolNames, profilesText = '') {
|
|
86
|
-
return `
|
|
87
|
-
1.
|
|
88
|
-
2.
|
|
89
|
-
3.
|
|
90
|
-
4.
|
|
91
|
-
5.
|
|
92
|
-
6. Tasks carry attempt_id capabilities.
|
|
93
|
-
7.
|
|
94
|
-
8.
|
|
95
|
-
9.
|
|
96
|
-
10.
|
|
97
|
-
|
|
90
|
+
return `AgentTeams captain protocol:
|
|
91
|
+
1. Inspect current team state when needed, using agent_teams_status. Continue existing work without duplicating its roster/tasks. Create only when no current team exists, with the user's goal as description and approval="required"; automatic approval requires an explicit request to run immediately. Staged plans never spawn or schedule work.
|
|
92
|
+
2. Add each needed role once; members inherit your model route unless another is requested/needed. A requested profile goes to create({profile}); it supplies its roster. Seed profiles also supply tasks; captain-planning profiles require your DAG. Do not duplicate either.
|
|
93
|
+
3. Build the complete smallest useful DAG while staged. Every task needs a subject; dependencies represent prerequisites. Give every required contributor a task or explicit message. Present the plan and end your turn for review; never approve in that planning turn. Approve only after a later explicit user approval or the Web action.
|
|
94
|
+
4. Respect Web approve/return/discard control messages. On return, ask what to change before editing; after the answer, use one atomic agent_teams_edit_plan batch (edit downstream references before removals), summarize and await review again. Never inspect or edit .agent-teams state files or plugin source code to revise plans. Discard does not authorize a replacement.
|
|
95
|
+
5. The scheduler dispatches ready tasks after approval. Delegate; do not duplicate slow work or send messages merely to start a stage. Handle reports/user work, then yield when waiting is all that remains: reports wake you automatically. Use status after a delivery or user request, never busy-poll or wait for unassigned members.
|
|
96
|
+
6. Tasks carry attempt_id capabilities. Use the current attempt_id; stale means ownership changed. Pause members only on explicit request; later guidance via send_message continues that same attempt. Retry, transfer or take over through reassign_task first; it revokes the old attempt and waits for quiescence. Prefer a member. Captain implementation/review takeover requires a user request. Every takeover is one ready task at a time, finished in this turn; never yield with captain-owned work open.
|
|
97
|
+
7. Quality kinds (requirements, implementation, verification, review, repair, integration) require objective + acceptance; implementation/repair also require inScope + verify. Derive paths/commands from the workspace/profile, never assume src/ or pnpm test. Review/requirements complete only with verdict=pass; needs_revision/reject fail with findings. Never approve your own implementation or ask for a deliberate failure.
|
|
98
|
+
8. When full quality mode is requested: requirements → implementation → verification → review → integration. Plan the entire DAG while staged, including implementation before requirements finishes and integration depending on review round 1. Failed review automatically adds repair + next review and rewires pending downstream gates. Do not recreate this loop, omit integration or depend on a failed task. Review acceptance judges the latest implementation. Do not put smoke-test scripts into task instructions.
|
|
99
|
+
9. Halted means the user stopped work (including the captain turn). Resume only on a later explicit user request with a reason, via agent_teams_resume or create_task({resume:true,resumeReason}); creating tasks alone never resumes. Escalated means the review loop hit its limit, not a halt. Deployment requires explicit user confirmation.
|
|
100
|
+
10. Wait for all required tasks to be terminal and members idle/ready, present results, then delete/archive unless the user wants to continue. Never discard unfinished work without authorization.
|
|
98
101
|
Tools: ${toolNames}${profilesText === '' ? '' : `\n\n${profilesText}`}`;
|
|
99
102
|
}
|
|
100
103
|
export function apply(ctx, config) {
|
|
@@ -113,28 +116,15 @@ export function apply(ctx, config) {
|
|
|
113
116
|
// concurrent activation — so capability validation happens at the first
|
|
114
117
|
// member spawn (`spawnMember`), the earliest point the provider list is
|
|
115
118
|
// settled, rather than here.
|
|
116
|
-
const toolNames = [
|
|
117
|
-
'agent_teams_create',
|
|
118
|
-
'agent_teams_approve',
|
|
119
|
-
'agent_teams_edit_plan',
|
|
120
|
-
'agent_teams_add_member',
|
|
121
|
-
'agent_teams_remove_member',
|
|
122
|
-
'agent_teams_create_task',
|
|
123
|
-
'agent_teams_reassign_task',
|
|
124
|
-
'agent_teams_claim_task',
|
|
125
|
-
'agent_teams_update_task',
|
|
126
|
-
'agent_teams_send_message',
|
|
127
|
-
'agent_teams_status',
|
|
128
|
-
'agent_teams_resume',
|
|
129
|
-
'agent_teams_delete',
|
|
130
|
-
].join(', ');
|
|
131
|
-
ctx.systemPrompt.section({
|
|
132
|
-
name: 'agent-teams:usage',
|
|
133
|
-
order: config.promptSectionOrder ?? 117,
|
|
134
|
-
text: () => usageSectionText(toolNames, formatProfilesForPrompt(config.profiles ?? {})),
|
|
135
|
-
});
|
|
136
|
-
// Exported for TDD / docs checks. Not a public runtime API.
|
|
137
119
|
const agentTeamsRuntime = registerAgentTeamsTools(ctx, resolved);
|
|
120
|
+
installTeamCapabilities(ctx, {
|
|
121
|
+
stateDir: resolved.stateDir,
|
|
122
|
+
isPendingMember: agentTeamsRuntime.isPendingMember,
|
|
123
|
+
order: config.promptSectionOrder,
|
|
124
|
+
// Keep the bounded profile directory available without extra tool calls.
|
|
125
|
+
// installTeamCapabilities snapshots this once; no business state rewrites it.
|
|
126
|
+
captainPrompt: () => usageSectionText(TEAM_TOOL_NAMES.join(', '), formatProfilesForPrompt(config.profiles)),
|
|
127
|
+
});
|
|
138
128
|
// Deterministic activation surfaces: the closed-namespace `/agent-teams`
|
|
139
129
|
// host command (surfaces in the Web GUI slash menu via the Harness
|
|
140
130
|
// ui-commands client) and the plain-text gesture boundary for surfaces
|
|
@@ -289,6 +279,20 @@ export function apply(ctx, config) {
|
|
|
289
279
|
try {
|
|
290
280
|
if (action === 'approve') {
|
|
291
281
|
const approved = await agentTeamsRuntime.approveStagedTeam(captain, teamId);
|
|
282
|
+
// The browser receives the HTTP result, so the model needs its own
|
|
283
|
+
// control message. steer wakes an idle captain or joins its next
|
|
284
|
+
// step; the tool approve path already returns to the model itself.
|
|
285
|
+
try {
|
|
286
|
+
captain.steer(createUserMessage({
|
|
287
|
+
content: [{ type: 'text', text: stagedPlanApprovedContext(team.name) }],
|
|
288
|
+
source: { kind: 'plugin', plugin: 'dsh-agent-teams' },
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
// Approval is already committed. Do not report a failed approval
|
|
293
|
+
// and invite a retry that could duplicate the user's action.
|
|
294
|
+
ctx.logger.warn(`agent-teams: approval notification failed for ${teamId}: ${String(error)}`);
|
|
295
|
+
}
|
|
292
296
|
res.writeHead(200, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
|
|
293
297
|
res.end(JSON.stringify({ ok: true, phase: 'running', ...approved }));
|
|
294
298
|
return;
|
package/lib/members.js
CHANGED
|
@@ -20,18 +20,11 @@ import { guardSubagentDelivery, installContinuableMemberSetup, queueMemberPrompt
|
|
|
20
20
|
import { acknowledgeMailbox, appendMailbox, CAPTAIN_KEY, createMessage, readRetiredMemberIds, readTeamSync, readTeam, releaseMailboxDelivery, withTeamLock, writeTeam } from "./state.js";
|
|
21
21
|
import { appendTeamEvent, captainSessionOf } from "./events.js";
|
|
22
22
|
import { TERMINAL_TASK_STATUSES } from "./types.js";
|
|
23
|
+
import { CAPTAIN_TOOL_NAMES } from "./tool-names.js";
|
|
23
24
|
/** Persona snapshot of a profile protocol; the full text lives on team.json. */
|
|
24
25
|
export const PERSONA_PROTOCOL_MAX_CHARS = 400;
|
|
25
26
|
/** Captain-only AgentTeams tools hidden from newly spawned members. */
|
|
26
|
-
const MEMBER_DENIED_TOOLS =
|
|
27
|
-
'agent_teams_create',
|
|
28
|
-
'agent_teams_add_member',
|
|
29
|
-
'agent_teams_remove_member',
|
|
30
|
-
'agent_teams_reassign_task',
|
|
31
|
-
'agent_teams_create_task',
|
|
32
|
-
'agent_teams_resume',
|
|
33
|
-
'agent_teams_delete',
|
|
34
|
-
];
|
|
27
|
+
const MEMBER_DENIED_TOOLS = CAPTAIN_TOOL_NAMES;
|
|
35
28
|
/**
|
|
36
29
|
* Restore the SessionId brand on a value that round-tripped through the
|
|
37
30
|
* durable team file. The brand is erased by JSON serialization; the value
|
|
@@ -384,6 +377,12 @@ export function installMemberSelectionRuntime(ctx, stateDir, onFailureSettled) {
|
|
|
384
377
|
};
|
|
385
378
|
});
|
|
386
379
|
return {
|
|
380
|
+
isPendingMember(agent) {
|
|
381
|
+
const parent = agent.session.header.parentSession;
|
|
382
|
+
const descriptor = foldSubagentDescriptor(sessionOwnEvents(agent.session));
|
|
383
|
+
return parent !== undefined && descriptor?.mode === 'continuable'
|
|
384
|
+
&& pending.has(pendingSelectionKey(parent, descriptor.label));
|
|
385
|
+
},
|
|
387
386
|
async withPending(parentSessionId, label, selection, operation) {
|
|
388
387
|
const key = pendingSelectionKey(parentSessionId, label);
|
|
389
388
|
if (pending.has(key)) {
|
package/lib/profiles.js
CHANGED
|
@@ -116,7 +116,7 @@ function formatProfileListingLine(entry) {
|
|
|
116
116
|
? 'captain planning'
|
|
117
117
|
: countLabel(Array.isArray(entry.config.tasks) ? entry.config.tasks.length : 0, 'task');
|
|
118
118
|
const counts = `(${countLabel(memberCount, 'member')}, ${graph})`;
|
|
119
|
-
const summary = protocolSummary(entry.config.protocol);
|
|
119
|
+
const summary = protocolSummary(entry.config.protocol) ?? protocolSummary(entry.config.description);
|
|
120
120
|
return summary === undefined
|
|
121
121
|
? `- ${entry.name} ${counts}`
|
|
122
122
|
: `- ${entry.name} ${counts}: ${summary}`;
|
package/lib/state.js
CHANGED
|
@@ -37,15 +37,29 @@ export async function withTeamLock(key, fn) {
|
|
|
37
37
|
const previous = locks.get(key) ?? Promise.resolve();
|
|
38
38
|
let release;
|
|
39
39
|
const gate = new Promise((resolve) => { release = resolve; });
|
|
40
|
-
|
|
40
|
+
const tail = previous.then(() => gate);
|
|
41
|
+
locks.set(key, tail);
|
|
41
42
|
await previous;
|
|
42
43
|
try {
|
|
43
44
|
return await fn();
|
|
44
45
|
}
|
|
45
46
|
finally {
|
|
46
47
|
release();
|
|
48
|
+
// Drop this key's queue entry once we are still its tail, so settled
|
|
49
|
+
// teams do not leave one resolved promise chained forever (the same
|
|
50
|
+
// cleanup discipline as the scheduler's serializeMember). A successor
|
|
51
|
+
// that already appended itself owns the map slot; keep its entry.
|
|
52
|
+
if (locks.get(key) === tail)
|
|
53
|
+
locks.delete(key);
|
|
47
54
|
}
|
|
48
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Keys with an in-process lock queue (held or waiting), snapshot for
|
|
58
|
+
* diagnostics and leak checks. The queue promises themselves stay private.
|
|
59
|
+
*/
|
|
60
|
+
export function teamLockQueueKeys() {
|
|
61
|
+
return [...locks.keys()];
|
|
62
|
+
}
|
|
49
63
|
/** Longest key emitted before truncating and appending a digest. */
|
|
50
64
|
const MAX_KEY_LENGTH = 48;
|
|
51
65
|
/** Short stable digest, used to keep otherwise-colliding keys distinct. */
|
|
@@ -228,13 +242,27 @@ export async function writeTeam(stateRoot, state) {
|
|
|
228
242
|
await atomicWriteText(join(stateRoot, state.id, 'team.json'), JSON.stringify(state, null, 2));
|
|
229
243
|
}
|
|
230
244
|
/** Read the durable set of member session ids retired by remove/delete. */
|
|
245
|
+
function parseRetiredMemberIds(raw) {
|
|
246
|
+
const parsed = JSON.parse(stripLeadingBom(raw));
|
|
247
|
+
if (!Array.isArray(parsed) || parsed.some(value => typeof value !== 'string' || value === '')) {
|
|
248
|
+
throw new Error('invalid AgentTeams retired member index');
|
|
249
|
+
}
|
|
250
|
+
return new Set(parsed);
|
|
251
|
+
}
|
|
252
|
+
/** Synchronous role hydration before the host's first prompt assembly. */
|
|
253
|
+
export function readRetiredMemberIdsSync(stateRoot) {
|
|
254
|
+
try {
|
|
255
|
+
return parseRetiredMemberIds(readFileSync(join(stateRoot, RETIRED_MEMBERS_FILE), 'utf8'));
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
if (error.code === 'ENOENT')
|
|
259
|
+
return new Set();
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
231
263
|
export async function readRetiredMemberIds(stateRoot) {
|
|
232
264
|
try {
|
|
233
|
-
|
|
234
|
-
if (!Array.isArray(parsed) || parsed.some(value => typeof value !== 'string' || value === '')) {
|
|
235
|
-
throw new Error('invalid AgentTeams retired member index');
|
|
236
|
-
}
|
|
237
|
-
return new Set(parsed);
|
|
265
|
+
return parseRetiredMemberIds(await readFile(join(stateRoot, RETIRED_MEMBERS_FILE), 'utf8'));
|
|
238
266
|
}
|
|
239
267
|
catch (error) {
|
|
240
268
|
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Stable business API names; exposure changes never rename these operations. */
|
|
2
|
+
export const TEAM_TOOL_NAMES = [
|
|
3
|
+
'agent_teams_create', 'agent_teams_approve', 'agent_teams_edit_plan',
|
|
4
|
+
'agent_teams_add_member', 'agent_teams_remove_member', 'agent_teams_create_task',
|
|
5
|
+
'agent_teams_reassign_task', 'agent_teams_claim_task', 'agent_teams_update_task',
|
|
6
|
+
'agent_teams_send_message', 'agent_teams_status', 'agent_teams_resume', 'agent_teams_delete',
|
|
7
|
+
];
|
|
8
|
+
export const MEMBER_TOOL_NAMES = [
|
|
9
|
+
'agent_teams_claim_task', 'agent_teams_update_task', 'agent_teams_send_message', 'agent_teams_status',
|
|
10
|
+
];
|
|
11
|
+
export const CAPTAIN_TOOL_NAMES = TEAM_TOOL_NAMES.filter(name => !MEMBER_TOOL_NAMES.includes(name));
|
package/lib/tools.js
CHANGED
|
@@ -276,6 +276,15 @@ export async function haltTeamWork(input) {
|
|
|
276
276
|
alreadyHalted: halted.alreadyHalted,
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
|
+
/** Web approval has no tool result in the captain's conversation. */
|
|
280
|
+
export function stagedPlanApprovedContext(teamName) {
|
|
281
|
+
return [
|
|
282
|
+
`The user approved the staged AgentTeams plan "${teamName}" from the pre-run review UI.`,
|
|
283
|
+
'Approval has committed; the scheduler owns dispatch of the approved team. Do not approve again, recreate the roster, or send messages merely to start assigned tasks.',
|
|
284
|
+
'Acknowledge the approval and handle any reports or user work already pending. Yield only when waiting for members is the remaining action. Their reports will wake you automatically; do not busy-poll status or keep a turn running just to wait.',
|
|
285
|
+
'On a report, inspect the result and coordinate the next necessary action. If work has since been halted, respect that state and resume only on an explicit user request.',
|
|
286
|
+
].join('\n');
|
|
287
|
+
}
|
|
279
288
|
/** Context queued after the human rejects a staged plan. */
|
|
280
289
|
export function stagedPlanDiscardContext(teamName) {
|
|
281
290
|
return [
|
|
@@ -524,6 +533,7 @@ export function registerAgentTeamsTools(ctx, config) {
|
|
|
524
533
|
return { teamId: discarded.teamId };
|
|
525
534
|
};
|
|
526
535
|
const runtime = {
|
|
536
|
+
isPendingMember: memberSelections.isPendingMember,
|
|
527
537
|
updateStagedPlan,
|
|
528
538
|
updateStagedPlanBatch,
|
|
529
539
|
approveStagedTeam,
|
|
@@ -584,7 +594,10 @@ export function registerAgentTeamsTools(ctx, config) {
|
|
|
584
594
|
const current = await findTeamByParticipant(stateRoot, captain.id);
|
|
585
595
|
if (current !== undefined) {
|
|
586
596
|
const relationship = current.captainSessionId === captain.id ? 'lead' : 'belong to';
|
|
587
|
-
|
|
597
|
+
const guidance = current.captainSessionId === captain.id
|
|
598
|
+
? 'Use agent_teams_status and continue the existing team. Do not delete and recreate it merely to continue work. End it only when the user explicitly wants a separate new team.'
|
|
599
|
+
: 'Continue your assigned member work and report to your captain; do not create a separate team.';
|
|
600
|
+
throw new Error(`you already ${relationship} team "${current.name}" (id ${current.id}). ${guidance}`);
|
|
588
601
|
}
|
|
589
602
|
return withTeamLock(teamLockKey(stateRoot, teamId), async () => {
|
|
590
603
|
const existing = await readTeam(stateRoot, teamId);
|
|
@@ -1873,7 +1886,7 @@ export function registerAgentTeamsTools(ctx, config) {
|
|
|
1873
1886
|
}));
|
|
1874
1887
|
ctx.tools.register(defineTool({
|
|
1875
1888
|
name: 'agent_teams_delete',
|
|
1876
|
-
description: 'End your team: interrupts
|
|
1889
|
+
description: 'End and archive your team: interrupts members and moves the current tasks and mailboxes out of active state for later inspection. Use when the work is done or explicitly abandoned. A same-name archive replaces its previous generation.',
|
|
1877
1890
|
parameters: {},
|
|
1878
1891
|
output: {
|
|
1879
1892
|
schema: {
|
|
@@ -1886,7 +1899,7 @@ export function registerAgentTeamsTools(ctx, config) {
|
|
|
1886
1899
|
},
|
|
1887
1900
|
render: (args, value) => [{
|
|
1888
1901
|
type: 'text',
|
|
1889
|
-
text: `Team "${value.team_name}"
|
|
1902
|
+
text: `Team "${value.team_name}" ended and archived.`,
|
|
1890
1903
|
}],
|
|
1891
1904
|
},
|
|
1892
1905
|
async execute(_args, exec) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Stable, agent-scoped presentation. Business authority stays in the tools. */
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
4
|
+
export declare const TEAM_ACTIVATION_PROMPT = "AgentTeams (Agent Teams) provides multi-agent team collaboration. Apply these rules when the user requests it (including /agent-teams) or when continuing an existing team. Mentioning, quoting, discussing, or declining AgentTeams alone is not a request to start work.";
|
|
5
|
+
export declare const TEAM_MEMBER_PROMPT = "You are an AgentTeams member. Follow your assigned member persona and task contract. Use agent_teams_claim_task, agent_teams_update_task, agent_teams_send_message and agent_teams_status for your own work. Include the current attempt_id in updates; report completion or failure to the captain. Do not create, approve, edit or resume a team. If your durable membership is unavailable, report that to the parent instead of creating a replacement.";
|
|
6
|
+
interface CapabilityConfig {
|
|
7
|
+
stateDir: string;
|
|
8
|
+
isPendingMember: (agent: Agent) => boolean;
|
|
9
|
+
captainPrompt: () => string;
|
|
10
|
+
order?: number;
|
|
11
|
+
}
|
|
12
|
+
/** Call once, after all business definitions have registered. Never per member. */
|
|
13
|
+
export declare function installTeamCapabilities(ctx: Context, config: CapabilityConfig): void;
|
|
14
|
+
export {};
|
package/lib/types/index.d.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* AgentTeams for DeepSeek Harness.
|
|
3
3
|
*
|
|
4
4
|
* A host-plane plugin that registers the `agent_teams_*` tools and one usage
|
|
5
|
-
* section
|
|
5
|
+
* agent-scoped usage section. Each session keeps a stable tool set and core
|
|
6
|
+
* instructions. Existing business tools cover the complete team lifecycle.
|
|
7
|
+
* After installation any session can
|
|
6
8
|
* run multi-agent teamwork through natural language (e.g. "use AgentTeams to research X"):
|
|
7
9
|
* the model creates a team (it becomes the captain), spawns members as
|
|
8
10
|
* durable continuable subagents, breaks the goal into tasks with
|
package/lib/types/members.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export interface MemberLlmSelectionRequest {
|
|
|
63
63
|
}
|
|
64
64
|
/** Process-local bridge between spawn admission and synchronous child setup. */
|
|
65
65
|
export interface MemberSelectionRuntime {
|
|
66
|
+
/** Trusted fresh-child admission, before the durable member id is written. */
|
|
67
|
+
isPendingMember(agent: Agent): boolean;
|
|
66
68
|
/** Make one selection visible while Harness materializes the fresh child. */
|
|
67
69
|
withPending<T>(parentSessionId: string, label: string, selection: MemberLlmSelection, operation: () => Promise<T>): Promise<T>;
|
|
68
70
|
}
|
package/lib/types/state.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ export declare const CAPTAIN_KEY = "captain";
|
|
|
23
23
|
* @returns the mutation's result.
|
|
24
24
|
*/
|
|
25
25
|
export declare function withTeamLock<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Keys with an in-process lock queue (held or waiting), snapshot for
|
|
28
|
+
* diagnostics and leak checks. The queue promises themselves stay private.
|
|
29
|
+
*/
|
|
30
|
+
export declare function teamLockQueueKeys(): readonly string[];
|
|
26
31
|
/**
|
|
27
32
|
* Fold a free-form name into a safe path/key segment.
|
|
28
33
|
*
|
|
@@ -101,7 +106,8 @@ export declare function readTeamSync(stateRoot: string, teamId: string): TeamSta
|
|
|
101
106
|
* @param state - the record to persist.
|
|
102
107
|
*/
|
|
103
108
|
export declare function writeTeam(stateRoot: string, state: TeamState): Promise<void>;
|
|
104
|
-
/**
|
|
109
|
+
/** Synchronous role hydration before the host's first prompt assembly. */
|
|
110
|
+
export declare function readRetiredMemberIdsSync(stateRoot: string): Set<string>;
|
|
105
111
|
export declare function readRetiredMemberIds(stateRoot: string): Promise<Set<string>>;
|
|
106
112
|
/** Atomically add session ids to the durable retired-member deny-list. */
|
|
107
113
|
export declare function recordRetiredMemberIds(stateRoot: string, memberIds: readonly string[]): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Stable business API names; exposure changes never rename these operations. */
|
|
2
|
+
export declare const TEAM_TOOL_NAMES: readonly ["agent_teams_create", "agent_teams_approve", "agent_teams_edit_plan", "agent_teams_add_member", "agent_teams_remove_member", "agent_teams_create_task", "agent_teams_reassign_task", "agent_teams_claim_task", "agent_teams_update_task", "agent_teams_send_message", "agent_teams_status", "agent_teams_resume", "agent_teams_delete"];
|
|
3
|
+
export declare const MEMBER_TOOL_NAMES: readonly string[];
|
|
4
|
+
export declare const CAPTAIN_TOOL_NAMES: ("agent_teams_create" | "agent_teams_approve" | "agent_teams_edit_plan" | "agent_teams_add_member" | "agent_teams_remove_member" | "agent_teams_create_task" | "agent_teams_reassign_task" | "agent_teams_claim_task" | "agent_teams_update_task" | "agent_teams_send_message" | "agent_teams_status" | "agent_teams_resume" | "agent_teams_delete")[];
|
package/lib/types/tools.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export type StagedPlanMutation = {
|
|
|
62
62
|
};
|
|
63
63
|
/** Runtime bridge shared by model-facing tools and the Web staging surface. */
|
|
64
64
|
export interface AgentTeamsRuntime {
|
|
65
|
+
isPendingMember(agent: Agent): boolean;
|
|
65
66
|
updateStagedPlan(captain: Agent, teamId: string, mutation: StagedPlanMutation, signal?: AbortSignal): Promise<TeamState>;
|
|
66
67
|
updateStagedPlanBatch(captain: Agent, teamId: string, mutations: readonly StagedPlanMutation[], signal?: AbortSignal): Promise<TeamState>;
|
|
67
68
|
approveStagedTeam(captain: Agent, teamId: string, signal?: AbortSignal): Promise<{
|
|
@@ -88,6 +89,8 @@ export declare function haltTeamWork(input: {
|
|
|
88
89
|
cancelledTasks: number;
|
|
89
90
|
alreadyHalted: boolean;
|
|
90
91
|
}>;
|
|
92
|
+
/** Web approval has no tool result in the captain's conversation. */
|
|
93
|
+
export declare function stagedPlanApprovedContext(teamName: string): string;
|
|
91
94
|
/** Context queued after the human rejects a staged plan. */
|
|
92
95
|
export declare function stagedPlanDiscardContext(teamName: string): string;
|
|
93
96
|
/** Model-facing continuation that turns the review UI back into a conversation. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanmicoder/dsh-agent-teams",
|
|
3
|
-
"version": "0.1.16-rc.
|
|
3
|
+
"version": "0.1.16-rc.3",
|
|
4
4
|
"description": "AgentTeams for DeepSeek Harness: multi-agent team collaboration (captain, members, tasks with dependencies, messaging) driven by natural language, with a tree monitor in the web GUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -223,12 +223,13 @@
|
|
|
223
223
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
224
224
|
"sync:skill": "node scripts/sync-skill.mjs",
|
|
225
225
|
"verify:skill": "node scripts/sync-skill.mjs --check",
|
|
226
|
-
"verify": "node scripts/verify.mjs && node scripts/fallback-tdd.mjs && node scripts/member-failure-tdd.mjs && node scripts/quality-gates-tdd.mjs && node scripts/lifecycle-verify.mjs && node scripts/stress-verify.mjs && pnpm verify:web-routes && pnpm verify:release && pnpm verify:skill && pnpm verify:harness-contract && pnpm verify:http-body && pnpm verify:compatibility",
|
|
226
|
+
"verify": "node scripts/verify.mjs && node scripts/fallback-tdd.mjs && node scripts/member-failure-tdd.mjs && node scripts/quality-gates-tdd.mjs && node scripts/lifecycle-verify.mjs && node scripts/stress-verify.mjs && pnpm verify:web-routes && pnpm verify:release && pnpm verify:skill && pnpm verify:harness-contract && pnpm verify:http-body && pnpm verify:compatibility && pnpm verify:capabilities",
|
|
227
227
|
"verify:web-routes": "node scripts/web-routes-verify.mjs",
|
|
228
228
|
"verify:release": "node --test scripts/release-metadata.test.mjs",
|
|
229
229
|
"verify:harness-contract": "node scripts/harness-compat-tdd.mjs && node scripts/lifecycle-verify.mjs --modern-harness && node scripts/member-failure-tdd.mjs --modern-harness",
|
|
230
230
|
"verify:compatibility": "node scripts/compatibility.mjs && node --test scripts/compatibility.test.mjs && node scripts/doctor.mjs",
|
|
231
231
|
"verify:http-body": "node --test scripts/http-body.test.mjs",
|
|
232
|
-
"doctor": "node scripts/doctor.mjs"
|
|
232
|
+
"doctor": "node scripts/doctor.mjs",
|
|
233
|
+
"verify:capabilities": "node --test scripts/capabilities.test.mjs"
|
|
233
234
|
}
|
|
234
235
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# AgentTeams v0.1.16-rc.2 — unpublished candidate
|
|
2
|
+
|
|
3
|
+
This tag did not publish: the Windows verification job rejected an absolute filesystem path used as an ESM import in a test. The release gate correctly skipped npm and GitHub publication. See [v0.1.16-rc.3](./v0.1.16-rc.3.md) for the replacement candidate.
|
|
4
|
+
|
|
5
|
+
This prerelease keeps the original 13 business tools directly available, shortens the fixed team instructions, guides captains to continue existing work, and notifies the captain when a Web plan is approved. It also includes the team-lock cleanup from [#143](https://github.com/NanmiCoder/dsh-agent-teams/pull/143).
|
|
6
|
+
|
|
7
|
+
The npm channel remains `next`. Supported Harness versions remain `0.1.2-rc.1` (recommended), `0.1.2-alpha.5`, and `0.1.2-alpha.2`. This release does not change `latest` or extend support to older embedded Desktop cores.
|
|
8
|
+
|
|
9
|
+
## Changes
|
|
10
|
+
|
|
11
|
+
- **Existing-team reuse ([#146](https://github.com/NanmiCoder/dsh-agent-teams/issues/146)).** Continue the current team and inspect state only when needed. A duplicate create error directs the captain back to the existing team instead of instructing it to end or leave first. Existing work, approval requirements and creation guards remain intact.
|
|
12
|
+
- **Fixed instruction overhead ([#138](https://github.com/NanmiCoder/dsh-agent-teams/issues/138)).** Keep a concise core protocol and configured profile directory in the fixed system prompt. Captains use the original 13 business tools; members see four team tools plus their ordinary coding/research tools. Team activation, approval and archive do not rewrite the plugin's system/tools prefix. No `agent_teams_open` tool or progressive-loading step is shipped.
|
|
13
|
+
- **Rules survive history changes.** Slash commands, natural-language requests, original tool allowlists, PTC code execution, result pruning, history compaction and cold restoration can use the business tools directly. Core rules do not depend on retaining a helper's result.
|
|
14
|
+
- **Web approval wakes the captain.** Approve & Run sends a control message after committing approval and starting scheduling. The captain can yield while waiting and be woken again by member reports. Repeated or failed approvals do not send a success notification.
|
|
15
|
+
- **Settled team locks are released.** Drop a settled queue entry only after its last waiter finishes, including rejection paths, while preserving serialization. Thanks to [spacexun2](https://github.com/spacexun2) for #143. This focused cleanup does not resolve the broader OOM investigation.
|
|
16
|
+
|
|
17
|
+
## Verification
|
|
18
|
+
|
|
19
|
+
The release workflow requires Ubuntu and Windows typecheck/build/repository verification, then installs one packed candidate through the published CLI/Loader on all three exact Harness cohorts. Nine scenarios per host cover lifecycle, two cold restores, fallback, failure, idle wakeup, six entry paths after ordinary conversation, authenticated Web approval, and protocol/compaction compatibility. The publish job verifies and publishes that same candidate file.
|
|
20
|
+
|
|
21
|
+
Pre-release source acceptance also used the real `deepseek-official / deepseek-v4.1-flash-expires-on-0910` model with `max` reasoning. A three-member review and a follow-up from an older session containing `open` history both passed external report/task/source checks; neither called the removed tool. The follow-up retained the same team and all three member identities. See the [source acceptance record](https://github.com/NanmiCoder/dsh-agent-teams/blob/v0.1.16-rc.2/docs/no-open-verification.json) for exact artifacts and limitations.
|
|
22
|
+
|
|
23
|
+
This is not a claim of lower total model cost or identical success rates across all work. The fresh real-model trial made some unnecessary dispatch/status calls. Stable plugin prefixes avoid this plugin's lifecycle-driven prefix changes; provider cache behavior, other host context, deployment changes and cache expiry remain separate.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Confirm that the actual running Harness belongs to the supported version matrix, then install into the profile you use:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.2
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Restart the actual Harness process and refresh Web after upgrading. Updating a global CLI does not replace a Desktop application's embedded core.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# AgentTeams v0.1.16-rc.3
|
|
2
|
+
|
|
3
|
+
This prerelease keeps the original 13 business tools directly available, shortens the fixed team instructions, guides captains to continue existing work, and notifies the captain when a Web plan is approved. It also includes the team-lock cleanup from [#143](https://github.com/NanmiCoder/dsh-agent-teams/pull/143).
|
|
4
|
+
|
|
5
|
+
The npm channel remains `next`. Supported Harness versions remain `0.1.2-rc.1` (recommended), `0.1.2-alpha.5`, and `0.1.2-alpha.2`. This release does not change `latest` or extend support to older embedded Desktop cores.
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Existing-team reuse ([#146](https://github.com/NanmiCoder/dsh-agent-teams/issues/146)).** Continue the current team and inspect state only when needed. A duplicate create error directs the captain back to the existing team instead of instructing it to end or leave first. Existing work, approval requirements and creation guards remain intact.
|
|
10
|
+
- **Fixed instruction overhead ([#138](https://github.com/NanmiCoder/dsh-agent-teams/issues/138)).** Keep a concise core protocol and configured profile directory in the fixed system prompt. Captains use the original 13 business tools; members see four team tools plus their ordinary coding/research tools. Team activation, approval and archive do not rewrite the plugin's system/tools prefix. No `agent_teams_open` tool or progressive-loading step is shipped.
|
|
11
|
+
- **Rules survive history changes.** Slash commands, natural-language requests, original tool allowlists, PTC code execution, result pruning, history compaction and cold restoration can use the business tools directly. Core rules do not depend on retaining a helper's result.
|
|
12
|
+
- **Web approval wakes the captain.** Approve & Run sends a control message after committing approval and starting scheduling. The captain can yield while waiting and be woken again by member reports. Repeated or failed approvals do not send a success notification.
|
|
13
|
+
- **Settled team locks are released.** Drop a settled queue entry only after its last waiter finishes, including rejection paths, while preserving serialization. Thanks to [spacexun2](https://github.com/spacexun2) for #143. This focused cleanup does not resolve the broader OOM investigation.
|
|
14
|
+
|
|
15
|
+
## Verification
|
|
16
|
+
|
|
17
|
+
The rc.2 tag was blocked by a Windows-only ESM path error in the new tests; no rc.2 package was published. This release uses file URLs for dynamic imports in the capability tests and real-model benchmark runner. The lifecycle test also waits for actual downstream delivery instead of assuming scheduling finishes within 20 ms, with an intentionally delayed host delivery as regression coverage. Runtime code and assets are unchanged from the locally accepted candidate.
|
|
18
|
+
|
|
19
|
+
The release workflow requires Ubuntu and Windows typecheck/build/repository verification, then installs one packed candidate through the published CLI/Loader on all three exact Harness cohorts. Nine scenarios per host cover lifecycle, two cold restores, fallback, failure, idle wakeup, six entry paths after ordinary conversation, authenticated Web approval, and protocol/compaction compatibility. The publish job verifies and publishes that same candidate file.
|
|
20
|
+
|
|
21
|
+
Pre-release source acceptance also used the real `deepseek-official / deepseek-v4.1-flash-expires-on-0910` model with `max` reasoning. A three-member review and a follow-up from an older session containing `open` history both passed external report/task/source checks; neither called the removed tool. The follow-up retained the same team and all three member identities. See the [source acceptance record](https://github.com/NanmiCoder/dsh-agent-teams/blob/v0.1.16-rc.3/docs/no-open-verification.json) for exact artifacts and limitations.
|
|
22
|
+
|
|
23
|
+
This is not a claim of lower total model cost or identical success rates across all work. The fresh real-model trial made some unnecessary dispatch/status calls. Stable plugin prefixes avoid this plugin's lifecycle-driven prefix changes; provider cache behavior, other host context, deployment changes and cache expiry remain separate.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Confirm that the actual running Harness belongs to the supported version matrix, then install into the profile you use:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
dsh plugin --profile web add --save-exact @nanmicoder/dsh-agent-teams@0.1.16-rc.3
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Restart the actual Harness process and refresh Web after upgrading. Updating a global CLI does not replace a Desktop application's embedded core.
|