@wowyuarm/dsh-agent-team 0.1.9 → 0.1.10
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 +4 -11
- package/README.zh.md +4 -11
- package/package.json +53 -44
- package/packages/agent-team/README.md +2 -2
- package/packages/agent-team/README.zh.md +2 -1
- package/packages/agent-team/lib/context-management.js +8 -5
- package/packages/agent-team/lib/context-projection.js +12 -8
- package/packages/agent-team/lib/context-source.js +163 -23
- package/packages/agent-team/lib/index.js +174 -124
- package/packages/agent-team/lib/ledger.js +111 -30
- package/packages/agent-team/lib/member-time-context.js +126 -0
- package/packages/agent-team/lib/pressure-policy.js +1 -2
- package/packages/agent-team/lib/progress-nudge.js +12 -4
- package/packages/agent-team/lib/session-remediation.js +481 -0
- package/packages/agent-team/lib/spec.js +3 -2
- package/packages/agent-team/lib/time-format.js +56 -0
- package/packages/agent-team/lib/typert.host.js +82 -49
- package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
- package/packages/agent-team/lib/typert.remote-client.js +46 -25
- package/packages/agent-team/lib/types/context-management.d.ts +6 -1
- package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
- package/packages/agent-team/lib/types/context-source.d.ts +70 -36
- package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
- package/packages/agent-team/lib/types/index.d.ts +32 -7
- package/packages/agent-team/lib/types/index.d.ts.map +1 -1
- package/packages/agent-team/lib/types/ledger.d.ts +25 -0
- package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
- package/packages/agent-team/lib/types/member-time-context.d.ts +83 -0
- package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -0
- package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
- package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -1
- package/packages/agent-team/lib/types/session-remediation.d.ts +149 -0
- package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -0
- package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
- package/packages/agent-team/lib/types/time-format.d.ts +28 -0
- package/packages/agent-team/lib/types/time-format.d.ts.map +1 -0
- package/packages/agent-team/lib/types/types/entities.d.ts +8 -0
- package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
- package/packages/agent-team/lib/types/types/requests-results.d.ts +6 -0
- package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
- package/packages/agent-team/preset/team-member/agent.cordis.yml +19 -4
- package/packages/client-agent-team/lib/client.js +80 -54
- package/packages/client-agent-team/lib/client.js.map +1 -1
- package/packages/client-agent-team/lib/types/client/TeamMessage.js +2 -2
- package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +4 -4
- package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
- package/packages/client-agent-team/lib/types/client/index.js +10 -5
- package/packages/client-agent-team/lib/types/client/slots.d.ts +1 -1
- package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
- package/packages/tool-agent-team/README.md +8 -6
- package/packages/tool-agent-team/README.zh.md +8 -6
- package/packages/tool-agent-team/lib/index.js +302 -110
- package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ An opt-in plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-
|
|
|
17
17
|
- **Workspaces organize everything.** Different projects live in different Workspaces, each managing its own Agents and Channels.
|
|
18
18
|
- **The Human routes Channels and responsibilities.** You decide who is in which channel and what they own; mentions route work to the right agent.
|
|
19
19
|
- **Task Threads carry one line of progress.** Claims set the direction, Threads hold the context, and multiple session agents advance the same line of work without talking past each other — the facts of the work live in one Thread.
|
|
20
|
-
- **No context babysitting.**
|
|
20
|
+
- **No context babysitting.** Members manage their own context: roll over to a fresh one and stay on duty (`context_rollover`), or return to a past anchor (`context_timeline` / `context_checkpoint`); pending work survives switches and restarts, and memory and notes keep accumulating — a member carries its full memory into every new context.
|
|
21
21
|
|
|
22
22
|
## Preview
|
|
23
23
|
|
|
@@ -27,13 +27,13 @@ Agent Team is opt-in: after installation the ordinary DSH page stays as-is, and
|
|
|
27
27
|
|
|
28
28
|
Entering Team mode shows Channels, managed Agents, and the collaboration timeline:
|
|
29
29
|
|
|
30
|
-

|
|
31
31
|
|
|
32
32
|
### Task Threads
|
|
33
33
|
|
|
34
34
|
A Task Thread keeps Claims, Agent handoffs, Human acceptance, and follow-up replies in one durable context.
|
|
35
35
|
|
|
36
|
-

|
|
37
37
|
|
|
38
38
|
If this looks useful, a star on [GitHub](https://github.com/wowyuarm/dsh-agent-team) helps other DSH users find it.
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@ If this looks useful, a star on [GitHub](https://github.com/wowyuarm/dsh-agent-t
|
|
|
41
41
|
|
|
42
42
|
### 1. Check DSH
|
|
43
43
|
|
|
44
|
-
This release is certified against DSH `0.1.
|
|
44
|
+
This release is certified against DSH `0.1.5-rc.1`. If `dsh` is not installed yet, start DSH with the official package:
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
47
|
npx @deepseek-ai/dsh web
|
|
@@ -108,13 +108,6 @@ dsh web
|
|
|
108
108
|
|
|
109
109
|
Published packages include built artifacts. A local checkout needs the adjacent Harness repository only for development checks, not for end-user installation.
|
|
110
110
|
|
|
111
|
-
## Compatibility and limits
|
|
112
|
-
|
|
113
|
-
- This release is certified against DSH `0.1.2-rc.1`, and requires it: earlier DSH versions are not supported.
|
|
114
|
-
- The bundle is single-host. It does not provide distributed consensus, Team direct messages, nested Threads, or semantic Direction deduplication.
|
|
115
|
-
- The current DSH SQLite Session schema rejects databases from older DSH versions. Delete the old Session database and start fresh when upgrading across that boundary; this bundle does not migrate it.
|
|
116
|
-
- Team-managed Agent Sessions use `danger-full-access`. Use them only in trusted Workspaces.
|
|
117
|
-
|
|
118
111
|
## Development
|
|
119
112
|
|
|
120
113
|
Read [`docs/README.md`](docs/README.md) for the maintained documentation index. The usual checks are:
|
package/README.zh.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
- **Workspace 组织一切。** 不同项目放在不同 Workspace,各自管理自己的 Agents 与 Channels。
|
|
18
18
|
- **Human 管 Channel 与职责。** 你决定谁在哪个频道、负责什么;@提及把工作路由到对的 Agent。
|
|
19
19
|
- **Task Thread 串联推进。** 用 Task 认领方向、Thread 保持上下文,多个 Session Agent 围绕同一条工作线推进而不散乱。工作事实落在同一条 Thread 里,成员之间不会各说各的。
|
|
20
|
-
- **无需操心上下文。**
|
|
20
|
+
- **无需操心上下文。** 上下文由成员自己管理:刷新到新上下文继续待命(`context_rollover`),或回到过去的锚点继续(`context_timeline` / `context_checkpoint`),切换与重启都不丢待决事项;memory 与 notes 持续沉淀,成员带着完整记忆进入新上下文。
|
|
21
21
|
|
|
22
22
|
## 预览
|
|
23
23
|
|
|
@@ -27,13 +27,13 @@ Agent Team 是按需启用的:安装后普通 DSH 页面保持原样,Team mo
|
|
|
27
27
|
|
|
28
28
|
进入 Team mode 后是频道、受管 Agent 与协作时间线:
|
|
29
29
|
|
|
30
|
-

|
|
31
31
|
|
|
32
32
|
### Task Thread
|
|
33
33
|
|
|
34
34
|
Task Thread 把 Claim、Agent 交接、Human 验收和后续回复保留在同一条可持续阅读的上下文中。
|
|
35
35
|
|
|
36
|
-

|
|
37
37
|
|
|
38
38
|
如果觉得有用,欢迎在 [GitHub](https://github.com/wowyuarm/dsh-agent-team) 点个 star,帮更多 DSH 用户发现它。
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@ Task Thread 把 Claim、Agent 交接、Human 验收和后续回复保留在同
|
|
|
41
41
|
|
|
42
42
|
### 1. 检查 DSH
|
|
43
43
|
|
|
44
|
-
当前版本已针对 DSH `0.1.
|
|
44
|
+
当前版本已针对 DSH `0.1.5-rc.1` 完成认证。如果还没有安装 `dsh`,先使用官方 package 启动 DSH:
|
|
45
45
|
|
|
46
46
|
```sh
|
|
47
47
|
npx @deepseek-ai/dsh web
|
|
@@ -108,13 +108,6 @@ dsh web
|
|
|
108
108
|
|
|
109
109
|
发布包已经包含构建产物。只有开发检查需要相邻的 Harness repository,终端用户安装不需要它。
|
|
110
110
|
|
|
111
|
-
## 兼容性与限制
|
|
112
|
-
|
|
113
|
-
- 当前版本已针对 DSH `0.1.2-rc.1` 完成认证,并且要求该版本:更早的 DSH 版本不受支持。
|
|
114
|
-
- Bundle 是单 Host,不提供分布式共识、Team direct message、嵌套 Thread 或 Direction 语义去重。
|
|
115
|
-
- 当前 DSH SQLite Session schema 不接受旧版 DSH 的数据库。跨越该边界升级时,删除旧 Session 数据库并重新开始;本 bundle 不负责迁移。
|
|
116
|
-
- Team 管理的 Agent Session 使用 `danger-full-access`。只在可信 Workspace 中使用。
|
|
117
|
-
|
|
118
111
|
## 开发
|
|
119
112
|
|
|
120
113
|
维护中的文档入口是 [`docs/README.zh.md`](docs/README.zh.md)。常用检查命令:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wowyuarm/dsh-agent-team",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "A persistent agent team for long-running collaboration in DeepSeek Harness",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@deepseek-ai/dsh-storage-sqlite": ">=0.1.
|
|
54
|
+
"@deepseek-ai/dsh-storage-sqlite": ">=0.1.5-rc.1 <0.2.0",
|
|
55
55
|
"zod": "^4.4.3"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
@@ -106,6 +106,14 @@
|
|
|
106
106
|
"types": "./packages/agent-team/lib/types/member-context.d.ts",
|
|
107
107
|
"default": "./packages/agent-team/lib/member-context.js"
|
|
108
108
|
},
|
|
109
|
+
"./member-time-context": {
|
|
110
|
+
"types": "./packages/agent-team/lib/types/member-time-context.d.ts",
|
|
111
|
+
"default": "./packages/agent-team/lib/member-time-context.js"
|
|
112
|
+
},
|
|
113
|
+
"./time-format": {
|
|
114
|
+
"types": "./packages/agent-team/lib/types/time-format.d.ts",
|
|
115
|
+
"default": "./packages/agent-team/lib/time-format.js"
|
|
116
|
+
},
|
|
109
117
|
"./member-skills": {
|
|
110
118
|
"types": "./packages/agent-team/lib/types/member-skills.d.ts",
|
|
111
119
|
"default": "./packages/agent-team/lib/member-skills.js"
|
|
@@ -122,48 +130,49 @@
|
|
|
122
130
|
},
|
|
123
131
|
"peerDependencies": {
|
|
124
132
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
125
|
-
"@deepseek-ai/dsh-agent": ">=0.1.
|
|
126
|
-
"@deepseek-ai/dsh-agent-default-model": ">=0.1.
|
|
127
|
-
"@deepseek-ai/dsh-agent-presets": ">=0.1.
|
|
128
|
-
"@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.
|
|
129
|
-
"@deepseek-ai/dsh-api-remotes": ">=0.1.
|
|
130
|
-
"@deepseek-ai/dsh-api-session-controller": ">=0.1.
|
|
131
|
-
"@deepseek-ai/dsh-api-workspace-controller": ">=0.1.
|
|
132
|
-
"@deepseek-ai/dsh-brand": ">=0.1.
|
|
133
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.
|
|
134
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.
|
|
135
|
-
"@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.
|
|
136
|
-
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.
|
|
137
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.
|
|
138
|
-
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.
|
|
139
|
-
"@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.
|
|
140
|
-
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.
|
|
141
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.
|
|
142
|
-
"@deepseek-ai/dsh-client-ui-workspace": ">=0.1.
|
|
143
|
-
"@deepseek-ai/dsh-command-compact": ">=0.1.
|
|
144
|
-
"@deepseek-ai/dsh-compaction": ">=0.1.
|
|
145
|
-
"@deepseek-ai/dsh-home-paths": ">=0.1.
|
|
146
|
-
"@deepseek-ai/dsh-invariants": ">=0.1.
|
|
147
|
-
"@deepseek-ai/dsh-llm": ">=0.1.
|
|
148
|
-
"@deepseek-ai/dsh-sandbox-policy": ">=0.1.
|
|
149
|
-
"@deepseek-ai/dsh-scope": ">=0.1.
|
|
150
|
-
"@deepseek-ai/dsh-session": ">=0.1.
|
|
151
|
-
"@deepseek-ai/dsh-session-
|
|
152
|
-
"@deepseek-ai/dsh-
|
|
153
|
-
"@deepseek-ai/dsh-skill
|
|
154
|
-
"@deepseek-ai/dsh-
|
|
155
|
-
"@deepseek-ai/dsh-
|
|
156
|
-
"@deepseek-ai/dsh-
|
|
157
|
-
"@deepseek-ai/dsh-tool-
|
|
158
|
-
"@deepseek-ai/dsh-tool-fs
|
|
159
|
-
"@deepseek-ai/dsh-tool-
|
|
160
|
-
"@deepseek-ai/dsh-tool-
|
|
161
|
-
"@deepseek-ai/dsh-tool-
|
|
162
|
-
"@deepseek-ai/dsh-tool-
|
|
163
|
-
"@deepseek-ai/dsh-tool-
|
|
164
|
-
"@deepseek-ai/dsh-
|
|
165
|
-
"@deepseek-ai/dsh-
|
|
166
|
-
"@deepseek-ai/dsh-
|
|
133
|
+
"@deepseek-ai/dsh-agent": ">=0.1.5-rc.1 <0.2.0",
|
|
134
|
+
"@deepseek-ai/dsh-agent-default-model": ">=0.1.5-rc.1 <0.2.0",
|
|
135
|
+
"@deepseek-ai/dsh-agent-presets": ">=0.1.5-rc.1 <0.2.0",
|
|
136
|
+
"@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.5-rc.1 <0.2.0",
|
|
137
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.1.5-rc.1 <0.2.0",
|
|
138
|
+
"@deepseek-ai/dsh-api-session-controller": ">=0.1.5-rc.1 <0.2.0",
|
|
139
|
+
"@deepseek-ai/dsh-api-workspace-controller": ">=0.1.5-rc.1 <0.2.0",
|
|
140
|
+
"@deepseek-ai/dsh-brand": ">=0.1.5-rc.1 <0.2.0",
|
|
141
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.2.0",
|
|
142
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.2.0",
|
|
143
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.5-rc.1 <0.2.0",
|
|
144
|
+
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.1 <0.2.0",
|
|
145
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.1.5-rc.1 <0.2.0",
|
|
146
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.1 <0.2.0",
|
|
147
|
+
"@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.5-rc.1 <0.2.0",
|
|
148
|
+
"@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.5-rc.1 <0.2.0",
|
|
149
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.2.0",
|
|
150
|
+
"@deepseek-ai/dsh-client-ui-workspace": ">=0.1.5-rc.1 <0.2.0",
|
|
151
|
+
"@deepseek-ai/dsh-command-compact": ">=0.1.5-rc.1 <0.2.0",
|
|
152
|
+
"@deepseek-ai/dsh-compaction": ">=0.1.5-rc.1 <0.2.0",
|
|
153
|
+
"@deepseek-ai/dsh-home-paths": ">=0.1.5-rc.1 <0.2.0",
|
|
154
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.5-rc.1 <0.2.0",
|
|
155
|
+
"@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.2.0",
|
|
156
|
+
"@deepseek-ai/dsh-sandbox-policy": ">=0.1.5-rc.1 <0.2.0",
|
|
157
|
+
"@deepseek-ai/dsh-scope": ">=0.1.5-rc.1 <0.2.0",
|
|
158
|
+
"@deepseek-ai/dsh-session": ">=0.1.5-rc.1 <0.2.0",
|
|
159
|
+
"@deepseek-ai/dsh-session-format-catalog": ">=0.1.5-rc.1 <0.2.0",
|
|
160
|
+
"@deepseek-ai/dsh-session-persistence": ">=0.1.5-rc.1 <0.2.0",
|
|
161
|
+
"@deepseek-ai/dsh-skill": ">=0.1.5-rc.1 <0.2.0",
|
|
162
|
+
"@deepseek-ai/dsh-skill-filesystem": ">=0.1.5-rc.1 <0.2.0",
|
|
163
|
+
"@deepseek-ai/dsh-storage-domain": ">=0.1.5-rc.1 <0.2.0",
|
|
164
|
+
"@deepseek-ai/dsh-token-meter": ">=0.1.5-rc.1 <0.2.0",
|
|
165
|
+
"@deepseek-ai/dsh-tool-bash": ">=0.1.5-rc.1 <0.2.0",
|
|
166
|
+
"@deepseek-ai/dsh-tool-fs": ">=0.1.5-rc.1 <0.2.0",
|
|
167
|
+
"@deepseek-ai/dsh-tool-fs-search": ">=0.1.5-rc.1 <0.2.0",
|
|
168
|
+
"@deepseek-ai/dsh-tool-jobs": ">=0.1.5-rc.1 <0.2.0",
|
|
169
|
+
"@deepseek-ai/dsh-tool-pwsh": ">=0.1.5-rc.1 <0.2.0",
|
|
170
|
+
"@deepseek-ai/dsh-tool-skill": ">=0.1.5-rc.1 <0.2.0",
|
|
171
|
+
"@deepseek-ai/dsh-tool-todo": ">=0.1.5-rc.1 <0.2.0",
|
|
172
|
+
"@deepseek-ai/dsh-tool-web": ">=0.1.5-rc.1 <0.2.0",
|
|
173
|
+
"@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.2.0",
|
|
174
|
+
"@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.2.0",
|
|
175
|
+
"@deepseek-ai/dsh-workspace": ">=0.1.5-rc.1 <0.2.0",
|
|
167
176
|
"react": "^18.2.0"
|
|
168
177
|
},
|
|
169
178
|
"keywords": [
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
The Host capability for one Agent Team in a dshHome. `ctx.agentTeam` owns the append-only operation ledger, reconstructs the current collaboration projection, and is the lifecycle owner for member Agents managed by the same capability. Thread Attention and the Member Inbox are durable Host projections. When unread state changes, this package sends one bounded, coalesced context notification through the Agent's public safe-boundary API; it never interrupts an active request or acts as a Session delivery worker. The [Agent Team architecture note](
|
|
5
|
+
The Host capability for one Agent Team in a dshHome. `ctx.agentTeam` owns the append-only operation ledger, reconstructs the current collaboration projection, and is the lifecycle owner for member Agents managed by the same capability. Thread Attention and the Member Inbox are durable Host projections. When unread state changes, this package sends one bounded, coalesced context notification through the Agent's public safe-boundary API; it never interrupts an active request or acts as a Session delivery worker. The [Agent Team architecture note](../../.scratch/archive/2026-08/m1/design/agent-notes/2026-08-15-agent-team-operation-ledger.md) owns the persistence and package-topology decisions.
|
|
6
6
|
|
|
7
7
|
## Service contract
|
|
8
8
|
|
|
@@ -65,4 +65,4 @@ The Host ledger and Human status reads do not alter model requests or cache reus
|
|
|
65
65
|
- **Single Host writer** — concurrent processes over one dshHome are unsupported; operation serialization is process-local.
|
|
66
66
|
- **Permanent ledger** — M1 provides neither snapshots nor compaction, so storage grows with committed collaboration facts.
|
|
67
67
|
- **No remote provider seam** — the package combines the capability definition and its only implementation until a real remote Consumer requires another Provider.
|
|
68
|
-
- **
|
|
68
|
+
- **No Session migration of its own** — Member Sessions ride the Host's Session persistence and its released-format migration chain; this package provides no Team ledger or Member Session migration, compatibility read, or fallback.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 中文
|
|
4
4
|
|
|
5
|
-
一个 dshHome 内唯一 Agent Team 的 Host capability。`ctx.agentTeam` 拥有 append-only operation ledger、重建当前协作 projection,并作为同一 capability 内 Member Agent 的 lifecycle owner。Thread Attention 和 Member Inbox 是 Host 的持久 projection。未读状态变化时,本包通过 Agent 的公开安全边界 API 发送一次有界、合并的 context 通知;不会中断正在执行的请求,也不运行 Session delivery worker。[Agent Team 架构 Agent Note](
|
|
5
|
+
一个 dshHome 内唯一 Agent Team 的 Host capability。`ctx.agentTeam` 拥有 append-only operation ledger、重建当前协作 projection,并作为同一 capability 内 Member Agent 的 lifecycle owner。Thread Attention 和 Member Inbox 是 Host 的持久 projection。未读状态变化时,本包通过 Agent 的公开安全边界 API 发送一次有界、合并的 context 通知;不会中断正在执行的请求,也不运行 Session delivery worker。[Agent Team 架构 Agent Note](../../.scratch/archive/2026-08/m1/design/agent-notes/2026-08-15-agent-team-operation-ledger.md)记录持久化和包拓扑决策。
|
|
6
6
|
|
|
7
7
|
## Service 约定
|
|
8
8
|
|
|
@@ -65,3 +65,4 @@ Host ledger 和 Human status read 不改变模型请求或 cache reuse。
|
|
|
65
65
|
- **单 Host writer** — 不支持多个进程并发写同一 dshHome;operation serialization 只在进程内生效。
|
|
66
66
|
- **永久 ledger** — M1 不提供 snapshot 或 compaction,storage 会随已提交协作事实增长。
|
|
67
67
|
- **没有 remote provider seam** — 在真实 remote Consumer 需要另一 Provider 前,本包合并 capability definition 和唯一实现。
|
|
68
|
+
- **自身不提供 Session 迁移** — Member Sessions 依赖 Host 的 Session persistence 与其已发布格式迁移链;本包不提供 Team ledger 或 Member Session 迁移、兼容读取或回退。
|
|
@@ -19,10 +19,8 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { SessionId as SessionIdBrand } from '@deepseek-ai/dsh-session';
|
|
21
21
|
import { createHash } from 'node:crypto';
|
|
22
|
-
import { createCheckpointContinuationMessage, createHandoffMessage } from "./context-source.js";
|
|
22
|
+
import { AGENT_TEAM_PLUGIN_ID, createCheckpointContinuationMessage, createHandoffMessage, isAgentTeamContextSource } from "./context-source.js";
|
|
23
23
|
import { CONTEXT_CHECKPOINT_TOOL_NAME, CONTEXT_ROLLOVER_TOOL_NAME, continuationDelivered, foldContextProjection, } from "./context-projection.js";
|
|
24
|
-
/** Plugin identity of the Agent Team Host, for recognizing own notices. */
|
|
25
|
-
const AGENT_TEAM_PLUGIN_ID = '@wowyuarm/dsh-agent-team';
|
|
26
24
|
/** Stable summary of the one-shot rollover pressure notice (ticket 03 wires delivery). */
|
|
27
25
|
export const CONTEXT_PRESSURE_NOTICE_SUMMARY = 'Context pressure: prepare a handoff';
|
|
28
26
|
export class ContextManagementCoordinator {
|
|
@@ -133,10 +131,15 @@ export class ContextManagementCoordinator {
|
|
|
133
131
|
this.capturedInput.delete(memberId);
|
|
134
132
|
return captured;
|
|
135
133
|
}
|
|
136
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Whether one queued message is a Team-owned notice the rederived Inbox
|
|
136
|
+
* replaces. Handoff and continuation envelopes carry the same plugin
|
|
137
|
+
* attribution but are ordinary delivered context the new generation keeps, so
|
|
138
|
+
* they are excluded rather than dropped.
|
|
139
|
+
*/
|
|
137
140
|
isTeamNotice(message) {
|
|
138
141
|
const source = message.source;
|
|
139
|
-
return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID;
|
|
142
|
+
return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID && !isAgentTeamContextSource(message);
|
|
140
143
|
}
|
|
141
144
|
/** Drop one Member's bookkeeping; the Host calls this on dispose/removal. */
|
|
142
145
|
stopTracking(memberId) {
|
|
@@ -20,9 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { createHash } from 'node:crypto';
|
|
22
22
|
import { z } from 'zod';
|
|
23
|
-
import { isCheckpointContinuationMessage } from "./context-source.js";
|
|
24
|
-
/** Plugin identity of the Agent Team Host, for recognizing own notices. */
|
|
25
|
-
const AGENT_TEAM_PLUGIN_ID = '@wowyuarm/dsh-agent-team';
|
|
23
|
+
import { AGENT_TEAM_PLUGIN_ID, continuationCheckpointRefOf, handoffOf, isAgentTeamContextSource, isCheckpointContinuationMessage } from "./context-source.js";
|
|
26
24
|
/** Summary marker of the pre-compaction memory hint. */
|
|
27
25
|
const PRE_COMPACTION_NOTICE_SUMMARY = 'Compaction is imminent; consider persisting key conclusions.';
|
|
28
26
|
/** Team tool whose successful mutations are semantic timeline candidates. */
|
|
@@ -246,7 +244,7 @@ function applyContextEvent(state, event, sessionId) {
|
|
|
246
244
|
*/
|
|
247
245
|
function boundaryFromUserMessage(sessionId, seq, message, seenThreads) {
|
|
248
246
|
const source = message.source;
|
|
249
|
-
if (
|
|
247
|
+
if (handoffOf(message) !== undefined) {
|
|
250
248
|
return { key: `handoff:${seq}`, source: 'handoff', label: 'context handoff', seq, turn: -1, turnEndSeq: -1 };
|
|
251
249
|
}
|
|
252
250
|
if (source.kind !== 'plugin' || source.plugin !== AGENT_TEAM_PLUGIN_ID)
|
|
@@ -441,9 +439,10 @@ function applyUserMessage(state, seq, message, sessionId) {
|
|
|
441
439
|
}
|
|
442
440
|
// The quiet continuation notice delivered for one checkpoint completes its
|
|
443
441
|
// delivery state; replay repair reads this to avoid re-scheduling it.
|
|
444
|
-
|
|
442
|
+
const continuation = continuationCheckpointRefOf(message);
|
|
443
|
+
if (continuation === undefined)
|
|
445
444
|
return next;
|
|
446
|
-
const checkpointRef =
|
|
445
|
+
const checkpointRef = continuation;
|
|
447
446
|
const existing = next.continuations.find(entry => entry.checkpointRef === checkpointRef);
|
|
448
447
|
if (existing !== undefined) {
|
|
449
448
|
if (existing.deliveredSeq !== -1)
|
|
@@ -469,10 +468,15 @@ function applyAssistantMessage(state, event) {
|
|
|
469
468
|
export function carriedInputOf(state) {
|
|
470
469
|
return state.carriedCandidates.filter(candidate => !candidate.consumed).map(candidate => candidate.message);
|
|
471
470
|
}
|
|
472
|
-
/**
|
|
471
|
+
/**
|
|
472
|
+
* Whether one queued message is a Team-owned notice the rederived Inbox
|
|
473
|
+
* replaces. Handoff and continuation envelopes carry the same plugin
|
|
474
|
+
* attribution but are ordinary delivered context the new generation keeps, so
|
|
475
|
+
* they are excluded rather than dropped.
|
|
476
|
+
*/
|
|
473
477
|
function isTeamNotice(message) {
|
|
474
478
|
const source = message.source;
|
|
475
|
-
return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID;
|
|
479
|
+
return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID && !isAgentTeamContextSource(message);
|
|
476
480
|
}
|
|
477
481
|
/** Whether a quiet continuation for one checkpoint was already delivered in this Session. */
|
|
478
482
|
export function continuationDelivered(state, checkpointRef) {
|
|
@@ -1,35 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Plugin-attributed message sources for Agent Team context management.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Both sources ride ordinary `UserMessage`s under the shipped `plugin` kind
|
|
5
|
+
* with the `snapshot` context form — the same shape the Harness's own
|
|
6
|
+
* system-prompt producer writes. This module declares no `MessageSourceMap`
|
|
7
|
+
* member of its own, and carries no bespoke source members: Session format
|
|
8
|
+
* migration validates a `plugin` source against a closed member list
|
|
9
|
+
* (`kind`, `plugin`, `form`, `sections`, `summary`), and refuses every logged
|
|
10
|
+
* Session that carries anything else. A plugin-declared kind is type-legal yet
|
|
11
|
+
* refused the same way. See `docs/dsh-release-compatibility.md`
|
|
12
|
+
* § "Session message sources".
|
|
13
|
+
*
|
|
14
|
+
* Everything the Host needs to read back therefore rides the admitted payload
|
|
15
|
+
* slots: the handoff envelope and the checkpoint correlation both travel as
|
|
16
|
+
* named {@link ContextSnapshotSection} contributions, distinguished by their
|
|
17
|
+
* stable section names. Sections are the format's designed slot for structured
|
|
18
|
+
* producer payload, and they render as named contributions on any
|
|
19
|
+
* snapshot-aware surface.
|
|
20
|
+
*
|
|
21
|
+
* The validators below are the single place that recognizes these messages, so
|
|
22
|
+
* callers never match on localized body text.
|
|
8
23
|
* @module @wowyuarm/dsh-agent-team/context-source
|
|
9
24
|
*/
|
|
10
25
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
11
|
-
/**
|
|
12
|
-
export const
|
|
26
|
+
/** Plugin identity attributing every Agent Team message source. */
|
|
27
|
+
export const AGENT_TEAM_PLUGIN_ID = '@wowyuarm/dsh-agent-team';
|
|
13
28
|
/** Handoff snapshot section name carrying the model-authored prose. */
|
|
14
29
|
export const HANDOFF_SECTION_NAME = 'HANDOFF';
|
|
30
|
+
/** Stable section name marking a checkpoint continuation and carrying its ref. */
|
|
31
|
+
export const CHECKPOINT_SECTION_NAME = 'Checkpoint';
|
|
32
|
+
/** Fixed text of the quiet checkpoint continuation delivered on the next turn. */
|
|
33
|
+
export const CHECKPOINT_CONTINUATION_TEXT = 'A context checkpoint was recorded at the end of the previous turn. Continue the work you were doing.';
|
|
15
34
|
/**
|
|
16
35
|
* Build the first model-facing context of one rollover generation. The Host
|
|
17
36
|
* owns only the verifiable envelope; the prose is the Member's own handoff.
|
|
37
|
+
*
|
|
38
|
+
* The envelope sections are additive structure, not the only carrier of these
|
|
39
|
+
* facts: {@link handoffBody} already states them in the model-facing text, so a
|
|
40
|
+
* surface that renders only the body loses nothing.
|
|
18
41
|
*/
|
|
19
42
|
export function createHandoffMessage(input) {
|
|
20
43
|
return createUserMessage({
|
|
21
44
|
content: [{ type: 'text', text: handoffBody(input) }],
|
|
22
45
|
source: {
|
|
23
|
-
kind: '
|
|
46
|
+
kind: 'plugin',
|
|
47
|
+
plugin: AGENT_TEAM_PLUGIN_ID,
|
|
24
48
|
form: 'snapshot',
|
|
25
|
-
|
|
26
|
-
previousSessionId: input.previousSessionId,
|
|
27
|
-
newSessionId: input.newSessionId,
|
|
28
|
-
trigger: input.trigger,
|
|
29
|
-
handoffEventSeq: input.handoffEventSeq,
|
|
30
|
-
...(input.checkpointRef === undefined ? {} : { checkpointRef: input.checkpointRef }),
|
|
31
|
-
...(input.relatedFiles === undefined || input.relatedFiles.length === 0 ? {} : { relatedFiles: input.relatedFiles.map(file => file.path) }),
|
|
32
|
-
sections: [{ name: HANDOFF_SECTION_NAME, text: input.handoff }],
|
|
49
|
+
sections: handoffSections(input),
|
|
33
50
|
},
|
|
34
51
|
});
|
|
35
52
|
}
|
|
@@ -38,22 +55,145 @@ export function createHandoffMessage(input) {
|
|
|
38
55
|
* concluded its turn. Delivery is scheduled only after the checkpoint's
|
|
39
56
|
* successful tool result is durable, so a result-render failure can never
|
|
40
57
|
* leave a ghost continuation behind.
|
|
58
|
+
*
|
|
59
|
+
* This is a `snapshot` rather than a `notice` for one reason: the projection
|
|
60
|
+
* must read the checkpoint ref back out of the durable log to record delivery,
|
|
61
|
+
* and `sections` is the only admitted payload slot that carries structure. A
|
|
62
|
+
* notice would have forced the ref into its human-readable one-line summary.
|
|
41
63
|
*/
|
|
42
64
|
export function createCheckpointContinuationMessage(checkpointRef) {
|
|
43
65
|
return createUserMessage({
|
|
44
|
-
content: [{ type: 'text', text:
|
|
45
|
-
source: {
|
|
66
|
+
content: [{ type: 'text', text: CHECKPOINT_CONTINUATION_TEXT }],
|
|
67
|
+
source: {
|
|
68
|
+
kind: 'plugin',
|
|
69
|
+
plugin: AGENT_TEAM_PLUGIN_ID,
|
|
70
|
+
form: 'snapshot',
|
|
71
|
+
sections: [{ name: CHECKPOINT_SECTION_NAME, text: checkpointRef }],
|
|
72
|
+
},
|
|
46
73
|
});
|
|
47
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Read one message's snapshot sections when it is this plugin's own snapshot.
|
|
77
|
+
* @param message - candidate user message.
|
|
78
|
+
* @returns the sections, or `undefined` when another producer owns the message.
|
|
79
|
+
*/
|
|
80
|
+
function ownSections(message) {
|
|
81
|
+
const source = message.source;
|
|
82
|
+
if (source.kind !== 'plugin' || source.plugin !== AGENT_TEAM_PLUGIN_ID)
|
|
83
|
+
return undefined;
|
|
84
|
+
if (source.form !== 'snapshot')
|
|
85
|
+
return undefined;
|
|
86
|
+
return source.sections;
|
|
87
|
+
}
|
|
88
|
+
/** The text of one named section, or undefined when it is absent. */
|
|
89
|
+
function sectionText(sections, name) {
|
|
90
|
+
return sections.find(section => section.name === name)?.text;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Decode the `Related files` section. The Host writes the exact path array as
|
|
94
|
+
* JSON, which round-trips every path a file system admits — including one
|
|
95
|
+
* containing a comma, which the `', '`-joined form this replaced could not.
|
|
96
|
+
* Sections written before that encoding are still read; the legacy split is a
|
|
97
|
+
* read-side accommodation for old generations, never a write path.
|
|
98
|
+
*/
|
|
99
|
+
function parseRelatedFiles(text) {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(text);
|
|
102
|
+
if (Array.isArray(parsed) && parsed.every(path => typeof path === 'string' && path.length > 0)) {
|
|
103
|
+
return parsed;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Not JSON: the section predates the JSON encoding.
|
|
108
|
+
}
|
|
109
|
+
return text.split(', ').filter(path => path.length > 0);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The rollover handoff one message carries, when it is one.
|
|
113
|
+
* @param message - candidate user message.
|
|
114
|
+
* @returns the envelope, or `undefined` when the message is not a handoff.
|
|
115
|
+
*/
|
|
116
|
+
export function handoffOf(message) {
|
|
117
|
+
const sections = ownSections(message);
|
|
118
|
+
if (sections === undefined)
|
|
119
|
+
return undefined;
|
|
120
|
+
const handoff = sectionText(sections, HANDOFF_SECTION_NAME);
|
|
121
|
+
if (handoff === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
const previousSessionId = sectionText(sections, HANDOFF_PREVIOUS_SESSION);
|
|
124
|
+
const newSessionId = sectionText(sections, HANDOFF_NEW_SESSION);
|
|
125
|
+
const trigger = sectionText(sections, HANDOFF_TRIGGER);
|
|
126
|
+
const handoffEventSeq = sectionText(sections, HANDOFF_EVENT_SEQ);
|
|
127
|
+
if (previousSessionId === undefined || newSessionId === undefined)
|
|
128
|
+
return undefined;
|
|
129
|
+
if (trigger !== 'model' && trigger !== 'pressure')
|
|
130
|
+
return undefined;
|
|
131
|
+
const seq = Number(handoffEventSeq);
|
|
132
|
+
if (handoffEventSeq === undefined || !Number.isSafeInteger(seq))
|
|
133
|
+
return undefined;
|
|
134
|
+
const checkpointRef = sectionText(sections, HANDOFF_CHECKPOINT);
|
|
135
|
+
const relatedFiles = sectionText(sections, HANDOFF_RELATED_FILES);
|
|
136
|
+
return {
|
|
137
|
+
previousSessionId,
|
|
138
|
+
newSessionId,
|
|
139
|
+
trigger,
|
|
140
|
+
handoffEventSeq: seq,
|
|
141
|
+
...(checkpointRef === undefined ? {} : { checkpointRef }),
|
|
142
|
+
...(relatedFiles === undefined ? {} : { relatedFiles: parseRelatedFiles(relatedFiles) }),
|
|
143
|
+
sections,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The checkpoint ref one continuation notice carries, when the message is one.
|
|
148
|
+
* @param message - candidate user message.
|
|
149
|
+
* @returns the checkpoint ref, or `undefined` when the message is not a continuation.
|
|
150
|
+
*/
|
|
151
|
+
export function continuationCheckpointRefOf(message) {
|
|
152
|
+
const sections = ownSections(message);
|
|
153
|
+
if (sections === undefined || sections.length !== 1)
|
|
154
|
+
return undefined;
|
|
155
|
+
const ref = sectionText(sections, CHECKPOINT_SECTION_NAME);
|
|
156
|
+
return ref === undefined || ref.length === 0 ? undefined : ref;
|
|
157
|
+
}
|
|
48
158
|
/** Whether one user message is a rollover handoff snapshot. */
|
|
49
159
|
export function isHandoffMessage(message) {
|
|
50
|
-
return message
|
|
160
|
+
return handoffOf(message) !== undefined;
|
|
51
161
|
}
|
|
52
|
-
/** Whether one user message is a checkpoint continuation
|
|
162
|
+
/** Whether one user message is a checkpoint continuation, optionally for one checkpoint. */
|
|
53
163
|
export function isCheckpointContinuationMessage(message, checkpointRef) {
|
|
54
|
-
const
|
|
55
|
-
return
|
|
56
|
-
|
|
164
|
+
const ref = continuationCheckpointRefOf(message);
|
|
165
|
+
return ref !== undefined && (checkpointRef === undefined || ref === checkpointRef);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Whether one message carries a rollover-handoff or checkpoint-continuation
|
|
169
|
+
* envelope. Ordinary Team notices share this plugin's attribution, so callers
|
|
170
|
+
* that replace rederived notices must exclude these two families explicitly.
|
|
171
|
+
*/
|
|
172
|
+
export function isAgentTeamContextSource(message) {
|
|
173
|
+
return isHandoffMessage(message) || isCheckpointContinuationMessage(message);
|
|
174
|
+
}
|
|
175
|
+
/** Envelope section names; stable, because they are read back from the log.
|
|
176
|
+
* Exported for the legacy-artifact remediation, which rewrites pre-0.1.10
|
|
177
|
+
* envelopes into exactly these names — one shared vocabulary, no drift. */
|
|
178
|
+
export const HANDOFF_PREVIOUS_SESSION = 'Previous session';
|
|
179
|
+
export const HANDOFF_NEW_SESSION = 'New session';
|
|
180
|
+
export const HANDOFF_TRIGGER = 'Trigger';
|
|
181
|
+
export const HANDOFF_EVENT_SEQ = 'Handoff event seq';
|
|
182
|
+
export const HANDOFF_CHECKPOINT = 'Continued from checkpoint';
|
|
183
|
+
export const HANDOFF_RELATED_FILES = 'Related files';
|
|
184
|
+
/** The envelope contributions of one handoff, prose first. */
|
|
185
|
+
function handoffSections(input) {
|
|
186
|
+
return [
|
|
187
|
+
{ name: HANDOFF_SECTION_NAME, text: input.handoff },
|
|
188
|
+
{ name: HANDOFF_PREVIOUS_SESSION, text: input.previousSessionId },
|
|
189
|
+
{ name: HANDOFF_NEW_SESSION, text: input.newSessionId },
|
|
190
|
+
{ name: HANDOFF_TRIGGER, text: input.trigger },
|
|
191
|
+
{ name: HANDOFF_EVENT_SEQ, text: String(input.handoffEventSeq) },
|
|
192
|
+
...(input.checkpointRef === undefined ? [] : [{ name: HANDOFF_CHECKPOINT, text: input.checkpointRef }]),
|
|
193
|
+
...(input.relatedFiles === undefined || input.relatedFiles.length === 0
|
|
194
|
+
? []
|
|
195
|
+
: [{ name: HANDOFF_RELATED_FILES, text: JSON.stringify(input.relatedFiles.map(file => file.path)) }]),
|
|
196
|
+
];
|
|
57
197
|
}
|
|
58
198
|
function handoffBody(input) {
|
|
59
199
|
const lines = [
|