@nanmicoder/dsh-agent-teams 0.1.2 → 0.1.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 CHANGED
@@ -1,93 +1,130 @@
1
- # @nanmicoder/dsh-agent-teams
1
+ <p align="right">
2
+ <strong>English</strong> · <a href="./README_ZH.md">简体中文</a>
3
+ </p>
2
4
 
3
- [![npm](https://img.shields.io/npm/v/@nanmicoder/dsh-agent-teams.svg)](https://www.npmjs.com/package/@nanmicoder/dsh-agent-teams)
4
- [![license](https://img.shields.io/npm/l/@nanmicoder/dsh-agent-teams.svg)](LICENSE)
5
+ <p align="center">
6
+ <img src="./assets/readme/hero.svg" width="100%" alt="dsh-agent-teams turns one DeepSeek Harness session into a coordinated multi-agent team">
7
+ </p>
5
8
 
6
- DeepSeek Harness 的 AgentTeams 插件:安装后,任何会话只需一句自然语言(例如"用 AgentTeams 调研一下 XX"),即可驱动一个**多智能体团队**协作完成目标,并在 Web GUI 右上角实时看到团队活动面板。
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/@nanmicoder/dsh-agent-teams"><img src="https://img.shields.io/npm/v/@nanmicoder/dsh-agent-teams.svg" alt="npm version"></a>
11
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/@nanmicoder/dsh-agent-teams.svg" alt="MIT license"></a>
12
+ <img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-202724" alt="DeepSeek Harness plugin">
13
+ </p>
7
14
 
8
- 核心语义移植自 Claude Code AgentTeams:**创建团队**(队长 = 当前会话 agent)→ **拉成员**(可续聊子代理)→ **拆任务并声明依赖** → **成员间直接收发消息**(邮箱直达 + 唤醒,无队长中转)。
15
+ ## One prompt. A working team.
9
16
 
10
- ## 界面预览
17
+ `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.
11
18
 
12
- ![AgentTeams 活动面板](https://raw.githubusercontent.com/NanmiCoder/dsh-agent-teams/main/assets/ui.png)
19
+ Ask in natural language. The plugin provides the team protocol, nine coordination tools, persistent state, and a live Web UI—without requiring a separate workflow engine.
13
20
 
14
- ## 安装
21
+ <p align="center">
22
+ <img src="./assets/ui.png" width="100%" alt="DeepSeek Harness conversation with the AgentTeams live activity panel, members, tasks, dependencies, and reports">
23
+ </p>
15
24
 
16
- **前置要求**:已安装 [DeepSeek Harness](https://github.com/deepseek-ai/DeepSeek-Harness)(`dsh` 命令可用);Node.js `^22.19` 或 `>=24`;pnpm 11。
25
+ ## Why AgentTeams?
17
26
 
18
- 插件已发布到 npm(`@nanmicoder` scope),一条命令装好:
27
+ | Capability | What it changes |
28
+ | --- | --- |
29
+ | **Captain-led delegation** | The current session creates the team, assigns roles, and consolidates the final result. |
30
+ | **Durable members** | Members are continuable DSH sub-agents that can be woken for focused follow-up turns. |
31
+ | **Dependency-aware tasks** | Tasks move through explicit states and cannot be claimed before their dependencies finish. |
32
+ | **Direct messaging** | Members send durable mailbox messages directly to teammates or the captain—no relay required. |
33
+ | **Live activity panel** | The Web UI shows roles, current work, unread messages, task dependencies, and archived team history. |
19
34
 
20
- ```sh
21
- dsh plugin --profile web add @nanmicoder/dsh-agent-teams
22
- ```
35
+ ## Install
23
36
 
24
- `dsh plugin` 会把插件加入 `web` profile,并根据包内的 `dsh.bundle` 声明自动启用它;工具、系统提示和 Web 客户端入口随该 profile 一起加载。
37
+ > [!NOTE]
38
+ > Requires an existing [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) installation.
25
39
 
26
- > **重启生效**:安装完成后,重启正在运行的 DeepSeek Harness Web 服务并刷新页面。
40
+ Choose either plugin source.
27
41
 
28
- 装好后可以用 `dsh plugin --profile web list` 确认插件在列表里。升级用同一条 add 命令即可。
29
-
30
- ### 其他安装方式
31
-
32
- **指定版本**——`latest` 的解析可能受 registry 缓存影响(国内镜像源同步新版本通常有延迟),想钉死版本时:
42
+ ### npm
33
43
 
34
44
  ```sh
35
- dsh plugin --profile web add @nanmicoder/dsh-agent-teams@<version>
45
+ dsh plugin --profile web add @nanmicoder/dsh-agent-teams
36
46
  ```
37
47
 
38
- 版本号见 [npm 发布页](https://www.npmjs.com/package/@nanmicoder/dsh-agent-teams?activeTab=versions)。
39
-
40
- **还没装 DSH,或不想全局安装**——用 `npx` 直接跑,无需预装:
48
+ ### GitHub `main`
41
49
 
42
50
  ```sh
43
- npx -p @deepseek-ai/dsh dsh plugin --profile web add @nanmicoder/dsh-agent-teams
51
+ dsh plugin --profile web add 'git+https://github.com/NanmiCoder/dsh-agent-teams.git#main'
44
52
  ```
45
53
 
46
- **从 GitHub 安装**——想用尚未发布到 npm 的最新提交:
54
+ Validate the composed profile, restart DSH, and refresh the Web UI:
47
55
 
48
56
  ```sh
49
- dsh plugin --profile web add github:NanmiCoder/dsh-agent-teams
57
+ dsh --profile web --dump-config
58
+ dsh web
50
59
  ```
51
60
 
52
- **从源码安装**——要改插件本身,或参与开发:
61
+ Then ask for a team directly:
53
62
 
54
- ```sh
55
- git clone https://github.com/NanmiCoder/dsh-agent-teams.git
56
- cd dsh-agent-teams
57
- pnpm install
58
- pnpm build
59
- dsh plugin --profile web add "link:$(pwd)"
60
- ```
63
+ > Use AgentTeams to review the commits after v0.5.3 from performance, security, and product perspectives. Return one consolidated report.
61
64
 
62
- `link:` 安装后,改完代码跑 `pnpm build` 即时生效,不必重装插件(客户端改动需刷新页面,host 侧改动需重启 dsh 服务)。提交前跑 `pnpm verify` 做离线校验。
65
+ ## How it works
63
66
 
64
- ## 使用
67
+ 1. The current session creates a team and becomes its captain.
68
+ 2. The captain adds role-specific members backed by continuable sub-agents.
69
+ 3. The goal becomes tasks with owners and explicit dependencies.
70
+ 4. Claimed tasks are dispatched through durable mailbox messages that wake each member.
71
+ 5. Members work, update task state, and report directly to the captain or one another.
72
+ 6. The captain presents the combined result, then archives the complete team record.
65
73
 
66
- 安装并重启后,直接对助手说:
74
+ Team state is stored under `<workspace>/.agent-teams/`; the Web panel reads that disk truth and combines it with live sub-agent activity.
67
75
 
68
- > AgentTeams 帮我调研一下开源 RAG 框架的选型,输出对比报告
76
+ Member creation is zero-interaction by default: the plugin snapshots the LLM provider, model, and reasoning effort actually used by the captain's current step, and restores that snapshot on later continuations. 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.
69
77
 
70
- 插件内置提示段会指导模型按协议执行:建团队 → 按角色拉成员 → 拆任务声明依赖 → 领取并唤醒成员 → 轮询收集产出 → 汇报后删除(归档保留)。
78
+ ## Configuration
71
79
 
72
- ## 开发 Skill
80
+ Defaults work without extra setup. A trusted profile can override member behavior:
73
81
 
74
- 仓库按开放 Agent Skills 规范提供 [`dsh-plugin-development`](skills/dsh-plugin-development/SKILL.md),可直接安装:
82
+ ```yaml
83
+ - id: agent-teams
84
+ config:
85
+ stateDir: .agent-teams
86
+ memberProvider: spawn
87
+ memberModel: deepseek-v4
88
+ memberMaxDepth: 1
89
+ maxMembers: 8
90
+ ```
91
+
92
+ `memberProvider` is the sub-agent runtime backend (`spawn` / `fork`), not an LLM provider. Cross-LLM-provider routing uses the optional `provider` + `model` fields of `agent_teams_add_member`; `memberModel` is only a model default for all members.
93
+
94
+ ## Boundaries
95
+
96
+ - One captain leads one active team at a time.
97
+ - Members act only after they are woken; mail remains durable while a participant is idle.
98
+ - State is file-backed and serialized within one DSH process; concurrent processes editing the same team are not coordinated.
99
+ - The activity panel reports persisted state as-is. Models may occasionally finish work without performing the expected task-state update.
100
+
101
+ See [docs/usage.md](./docs/usage.md) for the full tool reference, state model, Web UI behavior, configuration, and known limits.
102
+
103
+ ## Plugin development Skill
104
+
105
+ The repository also ships the open Agent Skills package [`dsh-plugin-development`](./skills/dsh-plugin-development/SKILL.md):
75
106
 
76
107
  ```sh
77
108
  npx skills add NanmiCoder/dsh-agent-teams --skill dsh-plugin-development
78
109
  ```
79
110
 
80
- `skills/dsh-plugin-development/` 是唯一权威源码;`.dsh/skills/` 保存供 DSH 在本仓库作为 cwd 时自动发现的跨平台镜像。修改 Skill 后运行 `pnpm sync:skill`,`pnpm verify` 会检查镜像没有漂移。
111
+ ## Documentation
81
112
 
82
- ## 文档
113
+ | Guide | Covers |
114
+ | --- | --- |
115
+ | [Usage](./docs/usage.md) | Architecture, UI behavior, tools, configuration, limits, and validation |
116
+ | [Verification](./docs/verification-guide.md) | Offline, composition, real e2e, and GUI verification |
117
+ | [Plugin development](./docs/developing-dsh-plugins.md) | Human-readable guide built from this plugin |
118
+ | [README writing](./docs/readme-writing-guide.md) | Repository documentation conventions |
83
119
 
84
- | 文档 | 内容 |
85
- |---|---|
86
- | [docs/usage.md](docs/usage.md) | 工作原理、Web UI 行为、工具一览、配置、已知限制、验证 |
87
- | [docs/verification-guide.md](docs/verification-guide.md) | 四层验证方法(离线 / 组合 / 真实 e2e / ego-browser GUI) |
88
- | [skills/dsh-plugin-development/SKILL.md](skills/dsh-plugin-development/SKILL.md) | 可通过 `npx skills` 安装的 DSH 插件开发 Skill |
89
- | [docs/developing-dsh-plugins.md](docs/developing-dsh-plugins.md) | 面向人类阅读的开发指南(本插件为样例) |
120
+ ## Development
121
+
122
+ ```sh
123
+ pnpm install
124
+ pnpm build
125
+ pnpm verify
126
+ ```
90
127
 
91
128
  ## License
92
129
 
93
- MIT
130
+ [MIT](./LICENSE)
package/README_ZH.md ADDED
@@ -0,0 +1,130 @@
1
+ <p align="right">
2
+ <a href="./README.md">English</a> · <strong>简体中文</strong>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="./assets/readme/hero.svg" width="100%" alt="dsh-agent-teams 把一个 DeepSeek Harness 会话变成可协作的多智能体团队">
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/@nanmicoder/dsh-agent-teams"><img src="https://img.shields.io/npm/v/@nanmicoder/dsh-agent-teams.svg" alt="npm 版本"></a>
11
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/@nanmicoder/dsh-agent-teams.svg" alt="MIT 许可证"></a>
12
+ <img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-202724" alt="DeepSeek Harness 插件">
13
+ </p>
14
+
15
+ ## 一句话,拉起一支真正协作的团队
16
+
17
+ `dsh-agent-teams` 让当前 DeepSeek Harness 会话成为队长:创建可续聊的子 Agent、把目标拆成有依赖的任务,并通过直达消息协调成员工作。
18
+
19
+ 你只需用自然语言提出目标。插件会提供团队协议、9 个协作工具、持久化状态和实时 Web UI,不需要额外的 Workflow 引擎。
20
+
21
+ <p align="center">
22
+ <img src="./assets/ui.png" width="100%" alt="DeepSeek Harness 对话与 AgentTeams 实时活动面板,展示成员、任务依赖和回报">
23
+ </p>
24
+
25
+ ## 为什么需要 AgentTeams?
26
+
27
+ | 能力 | 带来的变化 |
28
+ | --- | --- |
29
+ | **队长式委派** | 当前会话负责建队、分配角色并汇总最终结果。 |
30
+ | **可续聊成员** | 成员是可持续唤醒的 DSH 子 Agent,可以继续执行聚焦的后续轮次。 |
31
+ | **带依赖的任务** | 任务有明确状态;依赖未完成时不能领取。 |
32
+ | **成员直达消息** | 成员通过持久化邮箱直接联系队友或队长,不需要队长中转。 |
33
+ | **实时活动面板** | Web UI 展示角色、当前工作、未读消息、任务依赖和归档历史。 |
34
+
35
+ ## 安装
36
+
37
+ > [!NOTE]
38
+ > 使用前请确保已安装 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)。
39
+
40
+ 任选一种插件来源。
41
+
42
+ ### npm
43
+
44
+ ```sh
45
+ dsh plugin --profile web add @nanmicoder/dsh-agent-teams
46
+ ```
47
+
48
+ ### GitHub `main`
49
+
50
+ ```sh
51
+ dsh plugin --profile web add 'git+https://github.com/NanmiCoder/dsh-agent-teams.git#main'
52
+ ```
53
+
54
+ 检查组合配置、重启 DSH,然后刷新 Web UI:
55
+
56
+ ```sh
57
+ dsh --profile web --dump-config
58
+ dsh web
59
+ ```
60
+
61
+ 接着直接用自然语言拉团队:
62
+
63
+ > 使用 AgentTeams 审查 v0.5.3 之后的提交,分别从性能、安全和产品角度分工,最后输出一份汇总报告。
64
+
65
+ ## 工作方式
66
+
67
+ 1. 当前会话创建团队并成为队长。
68
+ 2. 队长按角色添加由可续聊子 Agent 驱动的成员。
69
+ 3. 目标被拆成有负责人和显式依赖的任务。
70
+ 4. 任务领取后,通过持久化邮箱投递并唤醒对应成员。
71
+ 5. 成员执行任务、更新状态,并直接向队长或其他成员汇报。
72
+ 6. 队长汇总结果,随后归档完整团队记录。
73
+
74
+ 团队状态保存在 `<workspace>/.agent-teams/`;Web 面板读取这份磁盘真相,并与实时子 Agent 活动合并展示。
75
+
76
+ 成员创建默认零交互:插件会快照队长**当前这一步**实际使用的 LLM provider、model 与思考强度,成员后续续跑仍使用这份快照。只有当用户明确提出异构分工(例如“后端用 provider A/model X,前端用 provider B/model Y”)时,队长才会把对应的 `provider` + `model` 传给该成员;不会逐个弹出模型或思考强度选择。
77
+
78
+ ## 配置
79
+
80
+ 默认配置可以直接使用。受信任的 Profile 可以覆盖成员行为:
81
+
82
+ ```yaml
83
+ - id: agent-teams
84
+ config:
85
+ stateDir: .agent-teams
86
+ memberProvider: spawn
87
+ memberModel: deepseek-v4
88
+ memberMaxDepth: 1
89
+ maxMembers: 8
90
+ ```
91
+
92
+ 这里的 `memberProvider` 指子 Agent 的运行后端(`spawn` / `fork`),不是 LLM provider。跨 LLM provider 由 `agent_teams_add_member` 的可选 `provider` + `model` 参数表达;`memberModel` 只是所有成员的模型默认覆盖。
93
+
94
+ ## 使用边界
95
+
96
+ - 一个队长同一时间只能带一个活动团队。
97
+ - 成员被唤醒后才行动;参与者空闲时,消息会持久保存在邮箱中。
98
+ - 状态使用文件持久化,并在单个 DSH 进程内串行操作;多个进程同时修改同一团队不保证一致。
99
+ - 活动面板如实展示持久化状态;模型偶尔可能完成工作却没有按协议更新任务状态。
100
+
101
+ 完整工具列表、状态模型、Web UI 行为、配置与已知限制见 [docs/usage.md](./docs/usage.md)。
102
+
103
+ ## 插件开发 Skill
104
+
105
+ 仓库同时提供开放 Agent Skills 包 [`dsh-plugin-development`](./skills/dsh-plugin-development/SKILL.md):
106
+
107
+ ```sh
108
+ npx skills add NanmiCoder/dsh-agent-teams --skill dsh-plugin-development
109
+ ```
110
+
111
+ ## 文档
112
+
113
+ | 指南 | 内容 |
114
+ | --- | --- |
115
+ | [使用指南](./docs/usage.md) | 架构、UI 行为、工具、配置、限制与验证 |
116
+ | [验证指南](./docs/verification-guide.md) | 离线、组合、真实 e2e 与 GUI 验证 |
117
+ | [插件开发](./docs/developing-dsh-plugins.md) | 基于本插件整理的人类可读开发指南 |
118
+ | [README 写作](./docs/readme-writing-guide.md) | 仓库文档约定 |
119
+
120
+ ## 开发
121
+
122
+ ```sh
123
+ pnpm install
124
+ pnpm build
125
+ pnpm verify
126
+ ```
127
+
128
+ ## 许可证
129
+
130
+ [MIT](./LICENSE)
@@ -0,0 +1,73 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="360" viewBox="0 0 1200 360" role="img" aria-labelledby="title desc">
2
+ <title id="title">dsh-agent-teams</title>
3
+ <desc id="desc">A DeepSeek Harness plugin that turns one captain session into a coordinated team of durable members working through dependent tasks and direct messages.</desc>
4
+
5
+ <defs>
6
+ <marker id="arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto" markerUnits="strokeWidth">
7
+ <path d="M0 0L8 4L0 8Z" fill="#4F8CFF"/>
8
+ </marker>
9
+ </defs>
10
+
11
+ <rect width="1200" height="360" rx="28" fill="#07111F"/>
12
+ <path d="M656 42V318" stroke="#20334C" stroke-width="1.5"/>
13
+
14
+ <g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif">
15
+ <text x="58" y="64" fill="#7F98BB" font-size="17" font-weight="650" letter-spacing="2.2">DEEPSEEK HARNESS · MULTI-AGENT ORCHESTRATION</text>
16
+ <text x="58" y="142" fill="#F4F8FF" font-size="58" font-weight="760" letter-spacing="-2.1">dsh-agent-teams</text>
17
+ <text x="58" y="197" fill="#C4D1E3" font-size="27" font-weight="520">One session becomes a coordinated team.</text>
18
+
19
+ <g font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="15">
20
+ <rect x="58" y="247" width="152" height="42" rx="21" fill="#102642" stroke="#315D91"/>
21
+ <circle cx="81" cy="268" r="6" fill="#4F8CFF"/>
22
+ <text x="98" y="274" fill="#BBD5FF" font-weight="700">CAPTAIN-LED</text>
23
+ <text x="232" y="274" fill="#7189AA">MEMBERS · TASKS · MESSAGES · ARCHIVE</text>
24
+ </g>
25
+
26
+ <g font-family="ui-monospace, SFMono-Regular, Menlo, monospace">
27
+ <text x="704" y="57" fill="#7F98BB" font-size="15" letter-spacing="1.7">LIVE TEAM GRAPH</text>
28
+
29
+ <path d="M790 130C844 130 850 86 912 86" fill="none" stroke="#4F8CFF" stroke-width="1.8"/>
30
+ <path d="M790 130H912" fill="none" stroke="#4F8CFF" stroke-width="1.8"/>
31
+ <path d="M790 130C844 130 850 174 912 174" fill="none" stroke="#4F8CFF" stroke-width="1.8"/>
32
+ <path d="M1040 86V174" fill="none" stroke="#35D5A4" stroke-width="1.4" stroke-dasharray="5 6"/>
33
+
34
+ <circle cx="755" cy="130" r="38" fill="#102642" stroke="#4F8CFF" stroke-width="2"/>
35
+ <circle cx="755" cy="130" r="25" fill="#4F8CFF"/>
36
+ <path d="M745 132L753 140L767 121" fill="none" stroke="#FFFFFF" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
37
+ <text x="712" y="184" fill="#AFC4E0" font-size="14">CAPTAIN</text>
38
+
39
+ <g>
40
+ <rect x="912" y="61" width="222" height="50" rx="12" fill="#101F33" stroke="#2B4567"/>
41
+ <circle cx="936" cy="86" r="8" fill="#4F8CFF"/>
42
+ <text x="955" y="82" fill="#F4F8FF" font-size="15" font-weight="700">RESEARCHER</text>
43
+ <text x="955" y="101" fill="#7F98BB" font-size="12">collect evidence</text>
44
+ </g>
45
+ <g>
46
+ <rect x="912" y="117" width="222" height="50" rx="12" fill="#101F33" stroke="#2B4567"/>
47
+ <circle cx="936" cy="142" r="8" fill="#35D5A4"/>
48
+ <text x="955" y="138" fill="#F4F8FF" font-size="15" font-weight="700">ENGINEER</text>
49
+ <text x="955" y="157" fill="#7F98BB" font-size="12">build and verify</text>
50
+ </g>
51
+ <g>
52
+ <rect x="912" y="173" width="222" height="50" rx="12" fill="#101F33" stroke="#2B4567"/>
53
+ <circle cx="936" cy="198" r="8" fill="#F2BD62"/>
54
+ <text x="955" y="194" fill="#F4F8FF" font-size="15" font-weight="700">REVIEWER</text>
55
+ <text x="955" y="213" fill="#7F98BB" font-size="12">challenge result</text>
56
+ </g>
57
+
58
+ <rect x="700" y="250" width="124" height="54" rx="12" fill="#101F33" stroke="#2B4567"/>
59
+ <text x="719" y="272" fill="#7F98BB" font-size="12">TASK t1</text>
60
+ <text x="719" y="292" fill="#F4F8FF" font-size="14" font-weight="700">RESEARCH</text>
61
+ <path d="M824 277H850" stroke="#4F8CFF" stroke-width="1.8" marker-end="url(#arrow)"/>
62
+
63
+ <rect x="858" y="250" width="124" height="54" rx="12" fill="#101F33" stroke="#2B4567"/>
64
+ <text x="877" y="272" fill="#7F98BB" font-size="12">TASK t2</text>
65
+ <text x="877" y="292" fill="#F4F8FF" font-size="14" font-weight="700">IMPLEMENT</text>
66
+ <path d="M982 277H1008" stroke="#4F8CFF" stroke-width="1.8" marker-end="url(#arrow)"/>
67
+
68
+ <rect x="1016" y="250" width="118" height="54" rx="12" fill="#102A29" stroke="#2E7368"/>
69
+ <text x="1035" y="272" fill="#75B8AC" font-size="12">TASK t3</text>
70
+ <text x="1035" y="292" fill="#9AF0D9" font-size="14" font-weight="700">REVIEW</text>
71
+ </g>
72
+ </g>
73
+ </svg>
package/lib/client.js CHANGED
@@ -1232,4 +1232,4 @@ window.__ModuleLoader__.load({
1232
1232
  }
1233
1233
  });
1234
1234
 
1235
- //# sourceMappingURL=client.js.map
1235
+ //# sourceMappingURL=client.js.map
package/lib/index.js CHANGED
@@ -27,7 +27,7 @@ const WEB_SERVER_KEYS = ['webServer', 'httpServer'];
27
27
  /** Workspace registry service key candidates, newest first. */
28
28
  const WORKSPACE_KEYS = ['workspaceRegistry', 'workspace'];
29
29
  export const name = 'agent-teams';
30
- export const inject = ['tools', 'subagents', 'systemPrompt', 'agents'];
30
+ export const inject = ['tools', 'llm', 'subagents', 'systemPrompt', 'agents'];
31
31
  export const Config = z.object({
32
32
  stateDir: z.string().default('.agent-teams'),
33
33
  memberProvider: z.string().default('spawn'),
@@ -40,7 +40,7 @@ export const Config = z.object({
40
40
  function usageSectionText(toolNames) {
41
41
  return `When the user asks to run something with AgentTeams (e.g. "use AgentTeams to do X"), you are the captain of a multi-agent team. Follow this protocol:
42
42
  1. Call agent_teams_create with a team name and the goal as description. You become the captain and may lead one team at a time.
43
- 2. Call agent_teams_add_member once per role the goal needs (researcher, engineer, reviewer, ...). Members are durable subagents: they wait for your messages, then work a full turn.
43
+ 2. Call agent_teams_add_member once per role the goal needs (researcher, engineer, reviewer, ...). Members are durable subagents: they wait for your messages, then work a full turn. By default each member snapshots your current provider, model, and reasoning effort. Never ask the user to choose these per member; only pass provider/model when the user explicitly requests a different route for that role.
44
44
  3. Break the goal into tasks with agent_teams_create_task; wire dependencies between tasks (a task is claimable only when its dependencies are completed). Assign each task to a member when it fits a role.
45
45
  4. Dispatch work: claim each assigned task (agent_teams_claim_task with assignee) and wake the member with agent_teams_send_message naming its task id and instructions. One task per message keeps turns focused.
46
46
  5. Poll agent_teams_status until members are idle; relay member-to-member messages (agent_teams_send_message with from=<sender>) and collect completed tasks' outputs. If a member reports a blocker, reassign the task or adjust the plan.
package/lib/members.js CHANGED
@@ -11,6 +11,12 @@
11
11
  * which the captain reads through `agent_teams_status`.
12
12
  * @module dsh-agent-teams/members
13
13
  */
14
+ import { installModelSelection } from '@deepseek-ai/dsh-agent';
15
+ // Declaration merge only: makes ctx.subagents visible.
16
+ import { foldSubagentDescriptor } from '@deepseek-ai/dsh-subagent';
17
+ import { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
18
+ import { join } from 'node:path';
19
+ import { readTeamSync } from "./state.js";
14
20
  /** Captain-only AgentTeams tools hidden from newly spawned members. */
15
21
  const MEMBER_DENIED_TOOLS = [
16
22
  'agent_teams_create',
@@ -28,6 +34,141 @@ const MEMBER_DENIED_TOOLS = [
28
34
  function brandedSessionId(value) {
29
35
  return value;
30
36
  }
37
+ const MEMBER_LABEL_PREFIX = 'agent-teams:';
38
+ function pendingSelectionKey(parentSessionId, label) {
39
+ return `${parentSessionId}\u0000${label}`;
40
+ }
41
+ function selectionFromMember(member) {
42
+ if (member?.provider === undefined || member.model === undefined)
43
+ return undefined;
44
+ const provider = member.provider.trim();
45
+ const model = member.model.trim();
46
+ if (provider === '' || model === '')
47
+ return undefined;
48
+ const reasoningEffort = member.reasoningEffort?.trim();
49
+ return {
50
+ provider,
51
+ model,
52
+ ...reasoningEffort === undefined || reasoningEffort === '' ? {} : { reasoningEffort },
53
+ };
54
+ }
55
+ function modelSelection(selection) {
56
+ return {
57
+ provider: selection.provider,
58
+ model: selection.model,
59
+ ...selection.reasoningEffort === undefined
60
+ ? {}
61
+ : { reasoningEffort: ReasoningEffortId(selection.reasoningEffort) },
62
+ };
63
+ }
64
+ /**
65
+ * Resolve one member's complete model selection. Ordinary members snapshot the
66
+ * captain's current request route and reasoning effort. An explicit member
67
+ * provider/model or plugin-level model replaces only that route; the current
68
+ * captain effort remains the inherited policy and is validated against the
69
+ * target model before a child is created.
70
+ */
71
+ export async function resolveMemberLlmSelection(ctx, captain, request, signal) {
72
+ const explicitProvider = request.provider?.trim();
73
+ const explicitModel = request.model?.trim();
74
+ const defaultModel = request.defaultModel?.trim();
75
+ if (request.provider !== undefined && explicitProvider === '') {
76
+ throw new Error('member LLM provider must not be empty');
77
+ }
78
+ if (request.model !== undefined && explicitModel === '') {
79
+ throw new Error('member model must not be empty');
80
+ }
81
+ if (request.defaultModel !== undefined && defaultModel === '') {
82
+ throw new Error('configured memberModel must not be empty');
83
+ }
84
+ if (explicitProvider !== undefined && explicitModel === undefined) {
85
+ throw new Error('an explicit member LLM provider requires an explicit member model');
86
+ }
87
+ const current = captain.session.requestHeader()?.config;
88
+ const provider = explicitProvider ?? current?.provider ?? captain.options.provider;
89
+ const model = explicitModel ?? defaultModel ?? current?.model ?? captain.options.model;
90
+ if (provider === undefined || model === undefined) {
91
+ throw new Error('cannot resolve the member LLM route from the current captain session');
92
+ }
93
+ const resolved = await ctx.llm.resolveCallConfig({
94
+ provider,
95
+ model,
96
+ ...current?.reasoningEffort === undefined
97
+ ? {}
98
+ : { reasoningEffort: current.reasoningEffort },
99
+ }, signal);
100
+ return {
101
+ provider: resolved.provider,
102
+ model: resolved.model,
103
+ ...resolved.reasoningEffort === undefined
104
+ ? {}
105
+ : { reasoningEffort: String(resolved.reasoningEffort) },
106
+ };
107
+ }
108
+ /**
109
+ * Install the member selection bridge for every fresh or cold-resumed
110
+ * continuable child. Fresh creation reads the pending in-memory selection;
111
+ * cold resume restores the same selection from the owning team's durable
112
+ * record. Legacy members without a complete saved route retain Harness's
113
+ * descriptor provider/model behavior.
114
+ */
115
+ export function installMemberSelectionRuntime(ctx, stateDir) {
116
+ const pending = new Map();
117
+ ctx.subagents.registerContinuableSetup((childCtx) => {
118
+ const child = childCtx.agent;
119
+ if (child === undefined)
120
+ return () => undefined;
121
+ const suffix = child.session.events.slice(child.session.header.seedLength ?? 0);
122
+ const descriptor = foldSubagentDescriptor(suffix);
123
+ if (descriptor?.mode !== 'continuable' || !descriptor.label.startsWith(MEMBER_LABEL_PREFIX)) {
124
+ return () => undefined;
125
+ }
126
+ const parentSessionId = child.session.header.parentSession;
127
+ if (parentSessionId === undefined)
128
+ return () => undefined;
129
+ const key = pendingSelectionKey(parentSessionId, descriptor.label);
130
+ let selection = pending.get(key);
131
+ if (selection === undefined) {
132
+ const identity = descriptor.label.slice(MEMBER_LABEL_PREFIX.length);
133
+ const separator = identity.indexOf(':');
134
+ if (separator < 1 || separator === identity.length - 1)
135
+ return () => undefined;
136
+ const teamId = identity.slice(0, separator);
137
+ const memberName = identity.slice(separator + 1);
138
+ const workspace = child.session.header.cwd ?? process.cwd();
139
+ const team = readTeamSync(join(workspace, stateDir), teamId);
140
+ if (team?.captainSessionId !== parentSessionId)
141
+ return () => undefined;
142
+ selection = selectionFromMember(team.members.find(member => member.name === memberName));
143
+ // An old team record has no provider/reasoning snapshot. Its durable
144
+ // Harness descriptor still restores provider/model, so leave it alone.
145
+ if (selection === undefined)
146
+ return () => undefined;
147
+ if (descriptor.agentProvider !== selection.provider || descriptor.agentModel !== selection.model) {
148
+ throw new Error(`agent-teams: saved model route for member "${memberName}" does not match its subagent descriptor`);
149
+ }
150
+ }
151
+ return installModelSelection(childCtx, {
152
+ current: modelSelection(selection),
153
+ assembled: undefined,
154
+ });
155
+ });
156
+ return {
157
+ async withPending(parentSessionId, label, selection, operation) {
158
+ const key = pendingSelectionKey(parentSessionId, label);
159
+ if (pending.has(key)) {
160
+ throw new Error(`member model selection is already pending for "${label}"`);
161
+ }
162
+ pending.set(key, selection);
163
+ try {
164
+ return await operation();
165
+ }
166
+ finally {
167
+ pending.delete(key);
168
+ }
169
+ },
170
+ };
171
+ }
31
172
  /**
32
173
  * The member's system prompt (persona), shadowing the deployment persona for
33
174
  * that child. Self-contained: it replaces the whole persona section.
@@ -65,13 +206,15 @@ export function memberWelcome(team) {
65
206
  * `member.id` with its child session id. On failure nothing is persisted.
66
207
  * @param ctx - the plugin context (injects `subagents`).
67
208
  * @param config - member runtime knobs.
209
+ * @param selections - fresh/cold child model-selection bridge.
210
+ * @param llmSelection - resolved provider/model/reasoning snapshot.
68
211
  * @param captain - the exact live captain agent (the calling agent).
69
212
  * @param team - the team record (read-only here).
70
213
  * @param member - the member draft whose `id` is filled on success.
71
214
  * @param stateDir - configured state directory (for the persona).
72
215
  * @param signal - caller cancellation, forwarded to the start.
73
216
  */
74
- export async function spawnMember(ctx, config, captain, team, member, stateDir, signal) {
217
+ export async function spawnMember(ctx, config, selections, llmSelection, captain, team, member, stateDir, signal) {
75
218
  // Fail loud at the first use: provider registration is a sibling plugin's
76
219
  // effect and may settle after this plugin mounts. Capability checks here
77
220
  // mirror what startContinuable would reject, with an actionable error.
@@ -89,19 +232,23 @@ export async function spawnMember(ctx, config, captain, team, member, stateDir,
89
232
  if (!provider.capabilities.toolFilter) {
90
233
  throw new Error(`agent-teams: provider "${config.provider}" cannot restrict captain-only tools for members`);
91
234
  }
92
- const start = await ctx.subagents.startContinuable({
235
+ const label = `${MEMBER_LABEL_PREFIX}${team.id}:${member.name}`;
236
+ const start = await selections.withPending(captain.id, label, llmSelection, () => (ctx.subagents.startContinuable({
93
237
  provider: config.provider,
94
- label: `agent-teams:${team.id}:${member.name}`,
238
+ label,
95
239
  request: {
96
240
  prompt: [{ type: 'text', text: memberWelcome(team) }],
97
241
  parent: captain,
98
242
  persona: memberPersona(team, member, stateDir),
99
243
  toolFilter: { deny: [...MEMBER_DENIED_TOOLS] },
100
- ...config.model !== undefined ? { agentOptions: { model: config.model } } : {},
244
+ agentOptions: {
245
+ provider: llmSelection.provider,
246
+ model: llmSelection.model,
247
+ },
101
248
  ...config.maxDepth !== undefined ? { maxDepth: config.maxDepth } : {},
102
249
  },
103
250
  signal,
104
- });
251
+ })));
105
252
  member.id = start.childId;
106
253
  }
107
254
  /**
package/lib/state.js CHANGED
@@ -13,6 +13,7 @@
13
13
  * @module dsh-agent-teams/state
14
14
  */
15
15
  import { createHash, randomUUID } from 'node:crypto';
16
+ import { readFileSync } from 'node:fs';
16
17
  import { mkdir, readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
17
18
  import { join } from 'node:path';
18
19
  /** Mailbox key of the captain. */
@@ -142,6 +143,31 @@ export async function readTeam(stateRoot, teamId) {
142
143
  throw error;
143
144
  }
144
145
  }
146
+ /**
147
+ * Synchronously read one team record while a continuable child is being
148
+ * composed. Harness requires child setup contributions to be synchronous;
149
+ * this narrow boundary lets a cold-resumed member restore its durable model
150
+ * selection before its first request can be published.
151
+ * @param stateRoot - resolved absolute state root directory.
152
+ * @param teamId - the team's sanitized id.
153
+ * @returns the team record, or `undefined` when absent.
154
+ */
155
+ export function readTeamSync(stateRoot, teamId) {
156
+ try {
157
+ const raw = readFileSync(join(stateRoot, teamId, 'team.json'), 'utf8');
158
+ const value = JSON.parse(stripLeadingBom(raw));
159
+ if (!isTeamState(value, teamId)) {
160
+ throw new Error(`invalid AgentTeams state in team "${teamId}"`);
161
+ }
162
+ return value;
163
+ }
164
+ catch (error) {
165
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
166
+ return undefined;
167
+ }
168
+ throw error;
169
+ }
170
+ }
145
171
  /**
146
172
  * Persist one team record (inside the caller's lock).
147
173
  * @param stateRoot - resolved absolute state root directory.
@@ -319,7 +345,9 @@ function isTeamMember(value) {
319
345
  && typeof value['name'] === 'string'
320
346
  && value['name'].trim() !== ''
321
347
  && isOptionalString(value['role'])
348
+ && isOptionalString(value['provider'])
322
349
  && isOptionalString(value['model'])
350
+ && isOptionalString(value['reasoningEffort'])
323
351
  && isFiniteNumber(value['joinedAt'])
324
352
  && (value['status'] === 'idle' || value['status'] === 'working' || value['status'] === 'removed');
325
353
  }
package/lib/tools.js CHANGED
@@ -13,7 +13,7 @@ import { defineTool } from '@deepseek-ai/dsh-tools';
13
13
  import { join } from 'node:path';
14
14
  import { appendTeamEvent, captainSessionOf } from "./events.js";
15
15
  import { appendMailbox, archiveTeamDir, CAPTAIN_KEY, createMessage, createTeamDir, findTeamByCaptain, findTeamByParticipant, readMailbox, readTeam, sanitizeKey, transitionError, unsatisfiedDependencies, withTeamLock, writeTeam, } from "./state.js";
16
- import { deliverToMember, interruptMember, memberActivity, spawnMember, } from "./members.js";
16
+ import { deliverToMember, installMemberSelectionRuntime, interruptMember, memberActivity, resolveMemberLlmSelection, spawnMember, } from "./members.js";
17
17
  /** The caller agent, or a loud failure for non-agent callers. */
18
18
  function requireCaptain(exec) {
19
19
  if (!exec.agent) {
@@ -126,6 +126,7 @@ export function steerCaptainReport(captain, from, content) {
126
126
  * @param config - resolved tool config.
127
127
  */
128
128
  export function registerAgentTeamsTools(ctx, config) {
129
+ const memberSelections = installMemberSelectionRuntime(ctx, config.stateDir);
129
130
  ctx.tools.register(defineTool({
130
131
  name: 'agent_teams_create',
131
132
  description: 'Create a new AgentTeams team: you (the calling agent) become the captain. A captain leads one team at a time; create tasks and members afterwards with agent_teams_add_member and agent_teams_create_task.',
@@ -191,11 +192,12 @@ export function registerAgentTeamsTools(ctx, config) {
191
192
  }));
192
193
  ctx.tools.register(defineTool({
193
194
  name: 'agent_teams_add_member',
194
- description: 'Add a member to your team: spawns a durable continuable subagent with a member persona. The member waits for your messages and works on assigned tasks; it can message you and teammates. One team per captain, members are capped by config.',
195
+ description: 'Add a durable continuable member. By default it snapshots the captain\'s current LLM provider, model, and reasoning effort with no user prompt. Supply provider/model only for an explicitly requested role-specific route. The member waits for messages, works on assigned tasks, and can message the team.',
195
196
  parameters: {
196
197
  name: { type: 'string', required: true, description: 'Unique member name inside the team.' },
197
198
  role: { type: 'string', description: 'Role of the member (e.g. researcher, engineer, reviewer).' },
198
- model: { type: 'string', description: 'Optional model override for this member (defaults to the captain\'s model).' },
199
+ provider: { type: 'string', description: 'Optional LLM provider route. Use only when the user explicitly requests a different provider; requires model.' },
200
+ model: { type: 'string', description: 'Optional model override. Omit for the captain\'s current model (or the configured memberModel default).' },
199
201
  },
200
202
  output: {
201
203
  schema: {
@@ -204,12 +206,15 @@ export function registerAgentTeamsTools(ctx, config) {
204
206
  properties: {
205
207
  member_name: { type: 'string', required: true },
206
208
  member_id: { type: 'string', required: true },
209
+ provider: { type: 'string', required: true },
210
+ model: { type: 'string', required: true },
211
+ reasoning_effort: { type: 'string' },
207
212
  status: { type: 'string', required: true },
208
213
  },
209
214
  },
210
215
  render: (args, value) => [{
211
216
  type: 'text',
212
- text: `Member "${value.member_name}" added (subagent id ${value.member_id}, status ${value.status}).`,
217
+ text: `Member "${value.member_name}" added (subagent id ${value.member_id}, ${value.provider}/${value.model}${value.reasoning_effort === undefined ? '' : `, reasoning ${value.reasoning_effort}`}, status ${value.status}).`,
213
218
  }],
214
219
  },
215
220
  async execute(args, exec) {
@@ -232,15 +237,22 @@ export function registerAgentTeamsTools(ctx, config) {
232
237
  if (fresh.members.filter((candidate) => candidate.status !== 'removed').length >= config.maxMembers) {
233
238
  throw new Error(`team "${fresh.name}" is at its member cap (${config.maxMembers})`);
234
239
  }
240
+ const selection = await resolveMemberLlmSelection(ctx, captain, {
241
+ provider: args.provider,
242
+ model: args.model,
243
+ defaultModel: config.memberModel,
244
+ }, exec.signal);
235
245
  const member = {
236
246
  id: '',
237
247
  name: memberName,
238
248
  role: args.role,
239
- model: args.model,
249
+ provider: selection.provider,
250
+ model: selection.model,
251
+ reasoningEffort: selection.reasoningEffort,
240
252
  joinedAt: Date.now(),
241
253
  status: 'idle',
242
254
  };
243
- await spawnMember(ctx, memberRuntime(config), captain, fresh, member, config.stateDir, exec.signal);
255
+ await spawnMember(ctx, memberRuntime(config), memberSelections, selection, captain, fresh, member, config.stateDir, exec.signal);
244
256
  fresh.members.push(member);
245
257
  await writeTeam(stateRoot, fresh);
246
258
  appendTeamEvent(ctx, captainSessionOf(ctx, fresh.captainSessionId, captain.session), 'agent-teams/member-added', {
@@ -249,7 +261,16 @@ export function registerAgentTeamsTools(ctx, config) {
249
261
  name: member.name,
250
262
  ...member.role !== undefined ? { role: member.role } : {},
251
263
  });
252
- return { member_name: member.name, member_id: member.id, status: member.status };
264
+ return {
265
+ member_name: member.name,
266
+ member_id: member.id,
267
+ provider: selection.provider,
268
+ model: selection.model,
269
+ ...selection.reasoningEffort === undefined
270
+ ? {}
271
+ : { reasoning_effort: selection.reasoningEffort },
272
+ status: member.status,
273
+ };
253
274
  });
254
275
  },
255
276
  }));
@@ -620,7 +641,9 @@ export function registerAgentTeamsTools(ctx, config) {
620
641
  .map((member) => ({
621
642
  name: member.name,
622
643
  role: member.role ?? '',
644
+ provider: member.provider ?? '',
623
645
  model: member.model ?? '',
646
+ reasoning_effort: member.reasoningEffort ?? '',
624
647
  status: member.status,
625
648
  activity: member.id !== '' ? (activity.get(member.id) ?? 'unknown') : 'unspawned',
626
649
  }));
@@ -718,7 +741,6 @@ export function registerAgentTeamsTools(ctx, config) {
718
741
  function memberRuntime(config) {
719
742
  return {
720
743
  provider: config.memberProvider,
721
- model: config.memberModel,
722
744
  maxDepth: config.memberMaxDepth,
723
745
  };
724
746
  }
@@ -729,7 +751,11 @@ function renderStatus(value) {
729
751
  `Team "${team.team_name}"${team.description ? ` — ${team.description}` : ''}`,
730
752
  `Viewing as: ${team.viewer}`,
731
753
  `Members (${team.members.length}):`,
732
- ...team.members.map((member) => ` - ${member.name} [${member.role}] ${member.status}/${member.activity}`),
754
+ ...team.members.map((member) => {
755
+ const route = member.provider && member.model ? ` · ${member.provider}/${member.model}` : '';
756
+ const effort = member.reasoning_effort ? ` · reasoning ${member.reasoning_effort}` : '';
757
+ return ` - ${member.name} [${member.role}] ${member.status}/${member.activity}${route}${effort}`;
758
+ }),
733
759
  `Tasks (${team.tasks.length}):`,
734
760
  ...team.tasks.map((task) => {
735
761
  const deps = task.dependencies.length > 0 ? ` (deps: ${task.dependencies.join(',')})` : '';
@@ -12,17 +12,54 @@
12
12
  * @module dsh-agent-teams/members
13
13
  */
14
14
  import type { Context } from '@deepseek-ai/cordis';
15
- import type { Agent } from '@deepseek-ai/dsh-agent';
15
+ import { type Agent } from '@deepseek-ai/dsh-agent';
16
16
  import type { TeamMember, TeamState } from './types.ts';
17
17
  /** Runtime knobs for member spawning, resolved from plugin config. */
18
18
  export interface MemberRuntimeConfig {
19
19
  /** Registered `ctx.subagents` provider name (must support continuable + persona). */
20
20
  provider: string;
21
- /** Optional model override applied to every member. */
22
- model?: string;
23
21
  /** Child delegation depth cap (0 forbids delegation entirely). */
24
22
  maxDepth?: number;
25
23
  }
24
+ /** Durable provider/model/reasoning snapshot for one member. */
25
+ export interface MemberLlmSelection {
26
+ /** Registered LLM provider route. */
27
+ provider: string;
28
+ /** Provider-owned model id. */
29
+ model: string;
30
+ /** Adapter-owned reasoning effort, absent when the target has no explicit/default effort. */
31
+ reasoningEffort?: string;
32
+ }
33
+ /** Optional member-level route requested by the captain. */
34
+ export interface MemberLlmSelectionRequest {
35
+ /** Explicit LLM provider route; requires an explicit model. */
36
+ provider?: string;
37
+ /** Explicit model id; otherwise the plugin default or captain model is used. */
38
+ model?: string;
39
+ /** Plugin-level member model default. */
40
+ defaultModel?: string;
41
+ }
42
+ /** Process-local bridge between spawn admission and synchronous child setup. */
43
+ export interface MemberSelectionRuntime {
44
+ /** Make one selection visible while Harness materializes the fresh child. */
45
+ withPending<T>(parentSessionId: string, label: string, selection: MemberLlmSelection, operation: () => Promise<T>): Promise<T>;
46
+ }
47
+ /**
48
+ * Resolve one member's complete model selection. Ordinary members snapshot the
49
+ * captain's current request route and reasoning effort. An explicit member
50
+ * provider/model or plugin-level model replaces only that route; the current
51
+ * captain effort remains the inherited policy and is validated against the
52
+ * target model before a child is created.
53
+ */
54
+ export declare function resolveMemberLlmSelection(ctx: Context, captain: Agent, request: MemberLlmSelectionRequest, signal?: AbortSignal): Promise<MemberLlmSelection>;
55
+ /**
56
+ * Install the member selection bridge for every fresh or cold-resumed
57
+ * continuable child. Fresh creation reads the pending in-memory selection;
58
+ * cold resume restores the same selection from the owning team's durable
59
+ * record. Legacy members without a complete saved route retain Harness's
60
+ * descriptor provider/model behavior.
61
+ */
62
+ export declare function installMemberSelectionRuntime(ctx: Context, stateDir: string): MemberSelectionRuntime;
26
63
  /**
27
64
  * The member's system prompt (persona), shadowing the deployment persona for
28
65
  * that child. Self-contained: it replaces the whole persona section.
@@ -42,13 +79,15 @@ export declare function memberWelcome(team: TeamState): string;
42
79
  * `member.id` with its child session id. On failure nothing is persisted.
43
80
  * @param ctx - the plugin context (injects `subagents`).
44
81
  * @param config - member runtime knobs.
82
+ * @param selections - fresh/cold child model-selection bridge.
83
+ * @param llmSelection - resolved provider/model/reasoning snapshot.
45
84
  * @param captain - the exact live captain agent (the calling agent).
46
85
  * @param team - the team record (read-only here).
47
86
  * @param member - the member draft whose `id` is filled on success.
48
87
  * @param stateDir - configured state directory (for the persona).
49
88
  * @param signal - caller cancellation, forwarded to the start.
50
89
  */
51
- export declare function spawnMember(ctx: Context, config: MemberRuntimeConfig, captain: Agent, team: TeamState, member: TeamMember, stateDir: string, signal: AbortSignal): Promise<void>;
90
+ export declare function spawnMember(ctx: Context, config: MemberRuntimeConfig, selections: MemberSelectionRuntime, llmSelection: MemberLlmSelection, captain: Agent, team: TeamState, member: TeamMember, stateDir: string, signal: AbortSignal): Promise<void>;
52
91
  /**
53
92
  * Deliver one message to a member as its next FIFO turn. Best effort: a
54
93
  * failure (member gone or not continuable) is logged and reported as `false`
@@ -73,6 +73,16 @@ export declare function createTeamDir(stateRoot: string, state: TeamState): Prom
73
73
  * @param teamId - the team's sanitized id.
74
74
  */
75
75
  export declare function readTeam(stateRoot: string, teamId: string): Promise<TeamState | undefined>;
76
+ /**
77
+ * Synchronously read one team record while a continuable child is being
78
+ * composed. Harness requires child setup contributions to be synchronous;
79
+ * this narrow boundary lets a cold-resumed member restore its durable model
80
+ * selection before its first request can be published.
81
+ * @param stateRoot - resolved absolute state root directory.
82
+ * @param teamId - the team's sanitized id.
83
+ * @returns the team record, or `undefined` when absent.
84
+ */
85
+ export declare function readTeamSync(stateRoot: string, teamId: string): TeamState | undefined;
76
86
  /**
77
87
  * Persist one team record (inside the caller's lock).
78
88
  * @param stateRoot - resolved absolute state root directory.
@@ -39,8 +39,12 @@ export interface TeamMember {
39
39
  name: string;
40
40
  /** Role description, e.g. `researcher`, `engineer`, `reviewer`. */
41
41
  role?: string;
42
- /** Optional model override for this member. */
42
+ /** Resolved LLM provider route captured when this member was created. */
43
+ provider?: string;
44
+ /** Resolved model captured when this member was created. */
43
45
  model?: string;
46
+ /** Resolved reasoning effort captured from the captain's current session. */
47
+ reasoningEffort?: string;
44
48
  joinedAt: number;
45
49
  status: MemberStatus;
46
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanmicoder/dsh-agent-teams",
3
- "version": "0.1.2",
3
+ "version": "0.1.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",
@@ -20,8 +20,10 @@
20
20
  "files": [
21
21
  "lib",
22
22
  "assets/agent-teams",
23
+ "assets/readme",
23
24
  "cordis.patch.yml",
24
- "README.md"
25
+ "README.md",
26
+ "README_ZH.md"
25
27
  ],
26
28
  "license": "MIT",
27
29
  "author": {
@@ -109,4 +111,4 @@
109
111
  "react": "^18.2.0",
110
112
  "react-dom": "^18.2.0"
111
113
  }
112
- }
114
+ }