@wowyuarm/dsh-agent-team 0.1.9 → 0.1.11

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.
Files changed (119) hide show
  1. package/README.md +17 -11
  2. package/README.zh.md +17 -11
  3. package/package.json +61 -47
  4. package/packages/agent-team/README.md +6 -4
  5. package/packages/agent-team/README.zh.md +6 -3
  6. package/packages/agent-team/lib/context-management.js +48 -55
  7. package/packages/agent-team/lib/context-projection.js +22 -8
  8. package/packages/agent-team/lib/context-source.js +163 -23
  9. package/packages/agent-team/lib/index.js +349 -176
  10. package/packages/agent-team/lib/invariant.js +38 -4
  11. package/packages/agent-team/lib/ledger.js +658 -294
  12. package/packages/agent-team/lib/member-context.js +6 -2
  13. package/packages/agent-team/lib/member-time-context.js +141 -0
  14. package/packages/agent-team/lib/pressure-policy.js +34 -11
  15. package/packages/agent-team/lib/progress-nudge.js +12 -4
  16. package/packages/agent-team/lib/session-event-cursor.js +116 -0
  17. package/packages/agent-team/lib/session-remediation.js +493 -0
  18. package/packages/agent-team/lib/spec.js +49 -36
  19. package/packages/agent-team/lib/stored-session-reader.js +138 -0
  20. package/packages/agent-team/lib/time-format.js +56 -0
  21. package/packages/agent-team/lib/typert.host.js +163 -63
  22. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  23. package/packages/agent-team/lib/typert.remote-client.js +105 -32
  24. package/packages/agent-team/lib/types/context-management.d.ts +13 -1
  25. package/packages/agent-team/lib/types/context-management.d.ts.map +1 -1
  26. package/packages/agent-team/lib/types/context-projection.d.ts +8 -0
  27. package/packages/agent-team/lib/types/context-projection.d.ts.map +1 -1
  28. package/packages/agent-team/lib/types/context-source.d.ts +70 -36
  29. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/index.d.ts +110 -9
  31. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  32. package/packages/agent-team/lib/types/invariant.d.ts.map +1 -1
  33. package/packages/agent-team/lib/types/ledger.d.ts +205 -7
  34. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  36. package/packages/agent-team/lib/types/member-time-context.d.ts +83 -0
  37. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -0
  38. package/packages/agent-team/lib/types/pressure-policy.d.ts +18 -0
  39. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
  40. package/packages/agent-team/lib/types/progress-nudge.d.ts.map +1 -1
  41. package/packages/agent-team/lib/types/session-event-cursor.d.ts +119 -0
  42. package/packages/agent-team/lib/types/session-event-cursor.d.ts.map +1 -0
  43. package/packages/agent-team/lib/types/session-remediation.d.ts +172 -0
  44. package/packages/agent-team/lib/types/session-remediation.d.ts.map +1 -0
  45. package/packages/agent-team/lib/types/spec.d.ts.map +1 -1
  46. package/packages/agent-team/lib/types/stored-session-reader.d.ts +92 -0
  47. package/packages/agent-team/lib/types/stored-session-reader.d.ts.map +1 -0
  48. package/packages/agent-team/lib/types/time-format.d.ts +28 -0
  49. package/packages/agent-team/lib/types/time-format.d.ts.map +1 -0
  50. package/packages/agent-team/lib/types/types/entities.d.ts +36 -2
  51. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  52. package/packages/agent-team/lib/types/types/operations.d.ts +45 -19
  53. package/packages/agent-team/lib/types/types/operations.d.ts.map +1 -1
  54. package/packages/agent-team/lib/types/types/requests-results.d.ts +50 -3
  55. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  56. package/packages/agent-team/preset/team-member/agent.cordis.yml +21 -4
  57. package/packages/client-agent-team/README.md +1 -1
  58. package/packages/client-agent-team/README.zh.md +1 -1
  59. package/packages/client-agent-team/lib/client.js +1121 -402
  60. package/packages/client-agent-team/lib/client.js.map +1 -1
  61. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.d.ts.map +1 -1
  62. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +24 -4
  63. package/packages/client-agent-team/lib/types/client/TeamChannelPage.d.ts.map +1 -1
  64. package/packages/client-agent-team/lib/types/client/TeamChannelPage.js +42 -22
  65. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.d.ts.map +1 -1
  66. package/packages/client-agent-team/lib/types/client/TeamChannelsPanel.js +13 -24
  67. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts +11 -5
  68. package/packages/client-agent-team/lib/types/client/TeamComposer.d.ts.map +1 -1
  69. package/packages/client-agent-team/lib/types/client/TeamComposer.js +15 -9
  70. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts +1 -1
  71. package/packages/client-agent-team/lib/types/client/TeamConversation.d.ts.map +1 -1
  72. package/packages/client-agent-team/lib/types/client/TeamConversation.js +8 -1
  73. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts +21 -0
  74. package/packages/client-agent-team/lib/types/client/TeamInboxPage.d.ts.map +1 -0
  75. package/packages/client-agent-team/lib/types/client/TeamInboxPage.js +71 -0
  76. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.d.ts.map +1 -1
  77. package/packages/client-agent-team/lib/types/client/TeamMemberEditor.js +8 -24
  78. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts +9 -2
  79. package/packages/client-agent-team/lib/types/client/TeamMessage.d.ts.map +1 -1
  80. package/packages/client-agent-team/lib/types/client/TeamMessage.js +13 -6
  81. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +8 -0
  82. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  83. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +21 -1
  84. package/packages/client-agent-team/lib/types/client/TeamThreadPage.d.ts.map +1 -1
  85. package/packages/client-agent-team/lib/types/client/TeamThreadPage.js +106 -32
  86. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts +1 -1
  87. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.d.ts.map +1 -1
  88. package/packages/client-agent-team/lib/types/client/TeamWorkspaceBrowser.js +50 -7
  89. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  90. package/packages/client-agent-team/lib/types/client/index.js +25 -9
  91. package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -0
  92. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  93. package/packages/client-agent-team/lib/types/client/locales.js +18 -0
  94. package/packages/client-agent-team/lib/types/client/navigation.d.ts +10 -0
  95. package/packages/client-agent-team/lib/types/client/navigation.d.ts.map +1 -1
  96. package/packages/client-agent-team/lib/types/client/navigation.js +18 -7
  97. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts +41 -0
  98. package/packages/client-agent-team/lib/types/client/scope-coverage.d.ts.map +1 -0
  99. package/packages/client-agent-team/lib/types/client/scope-coverage.js +64 -0
  100. package/packages/client-agent-team/lib/types/client/slots.d.ts +8 -2
  101. package/packages/client-agent-team/lib/types/client/slots.d.ts.map +1 -1
  102. package/packages/client-agent-team/lib/types/client/team-changes.d.ts +26 -1
  103. package/packages/client-agent-team/lib/types/client/team-changes.d.ts.map +1 -1
  104. package/packages/client-agent-team/lib/types/client/team-changes.js +66 -15
  105. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts +20 -0
  106. package/packages/client-agent-team/lib/types/client/team-dialog-save.d.ts.map +1 -0
  107. package/packages/client-agent-team/lib/types/client/team-dialog-save.js +36 -0
  108. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts +9 -0
  109. package/packages/client-agent-team/lib/types/client/team-formatters.d.ts.map +1 -1
  110. package/packages/client-agent-team/lib/types/client/team-formatters.js +34 -6
  111. package/packages/tool-agent-team/README.md +8 -6
  112. package/packages/tool-agent-team/README.zh.md +8 -6
  113. package/packages/tool-agent-team/lib/context-tools.js +18 -14
  114. package/packages/tool-agent-team/lib/host-access.js +20 -0
  115. package/packages/tool-agent-team/lib/index.js +314 -123
  116. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
  117. package/packages/tool-agent-team/lib/types/host-access.d.ts +14 -0
  118. package/packages/tool-agent-team/lib/types/host-access.d.ts.map +1 -0
  119. 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.** Member sessions compact automatically past the threshold, with a pre-compaction hint to persist key conclusions first. Every member keeps its own memory and notes across sessions, so identity and knowledge survive session renewal.
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
- ![Team mode in the DSH Web UI: Channels and seven online Agents in the sidebar; the Main Channel shows Task references and the composer’s task switch](assets/readme/team-mode.png)
30
+ ![Team mode in the DSH Web UI: Channels and online Agent members in the sidebar, with the Main Channel showing Task references](assets/readme/team-mode.png)
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
- ![Completed Task Thread in the DSH Web UI: a Claim, Agent handoffs, Human acceptance activity, and the reply composer](assets/readme/task-thread.png)
36
+ ![Task Thread in the DSH Web UI: Claims, Agent handoffs, Human acceptance activity, and the reply composer](assets/readme/task-thread.png)
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.2-rc.1`. If `dsh` is not installed yet, start DSH with the official package:
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
@@ -80,6 +80,19 @@ Team mode
80
80
 
81
81
  Create an Agent only in a trusted Workspace. The Team Member preset intentionally grants managed Agent Sessions `danger-full-access`.
82
82
 
83
+ ## Not to be confused with
84
+
85
+ Three other DSH plugins carry similar names and solve a different problem — one of them may fit you better:
86
+
87
+ | Plugin | What it is | Its unit of work |
88
+ | --- | --- | --- |
89
+ | [`NanmiCoder/dsh-agent-teams`](https://github.com/NanmiCoder/dsh-agent-teams) | Turns the current DSH session into a captain that assembles sub-agents, splits a goal into dependency-aware tasks, and coordinates them through direct messages | one **session** |
90
+ | [`toolclub/dsh-agent-team-gui`](https://github.com/toolclub/dsh-agent-team-gui) | A reusable plan → implement → review team with a model chosen per member, and a Run Center for token usage | one **workflow run** |
91
+ | [`limuyang2/agent-team`](https://github.com/limuyang2/agent-team) — publishes `@limuyang2/dsh-agent-team` | Builds a team of independent root agents inside one DSH window: mix models and providers, assign one Leader, and let every member work in its own conversation over a shared Workspace | one **assembled team** |
92
+ | **`dsh-agent-team`** (this plugin) | Every agent is a durable Member identity with its own private memory, notes and skills; Channels and responsibilities are yours to assign, and a Task Thread is one line of progress | a **standing team** |
93
+
94
+ The practical difference: a Member you created last week is still the same Member today — same memory, same responsibilities, same private notes — after its session ended, its context rolled over, or DSH restarted. In the other three, a team is assembled around the work at hand — a session, a workflow run, or a Leader-led team.
95
+
83
96
  ## Uninstall
84
97
 
85
98
  Remove the bundle from the profile; this also removes its composed layers:
@@ -108,13 +121,6 @@ dsh web
108
121
 
109
122
  Published packages include built artifacts. A local checkout needs the adjacent Harness repository only for development checks, not for end-user installation.
110
123
 
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
124
  ## Development
119
125
 
120
126
  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
- - **无需操心上下文。** 成员会话超阈值自动压缩,压缩前提示成员先沉淀关键结论。每个成员的 memory 与 notes 跨会话保留,身份与知识不随会话续期丢失。
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
- ![DSH Web UI 中的 Team mode:侧边栏展示频道与 7 位在线 Agent;Main 频道含 Task 引用和 composer 的作为任务开关](assets/readme/team-mode.png)
30
+ ![DSH Web UI 中的 Team mode:侧边栏展示频道与在线 Agent 成员;Main Channel 展示 Task 引用](assets/readme/team-mode.png)
31
31
 
32
32
  ### Task Thread
33
33
 
34
34
  Task Thread 把 Claim、Agent 交接、Human 验收和后续回复保留在同一条可持续阅读的上下文中。
35
35
 
36
- ![DSH Web UI 中已完成的 Task Thread:含 Claim、Agent 交接、Human 验收活动和回复 composer](assets/readme/task-thread.png)
36
+ ![DSH Web UI 中的 Task Thread:含 Claim、Agent 交接、Human 验收活动和回复 composer](assets/readme/task-thread.png)
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.2-rc.1` 完成认证。如果还没有安装 `dsh`,先使用官方 package 启动 DSH:
44
+ 当前版本已针对 DSH `0.1.5-rc.1` 完成认证。如果还没有安装 `dsh`,先使用官方 package 启动 DSH:
45
45
 
46
46
  ```sh
47
47
  npx @deepseek-ai/dsh web
@@ -80,6 +80,19 @@ Team mode
80
80
 
81
81
  只在可信 Workspace 中创建 Agent。Team Member preset 会给被管理的 Agent Session 授予 `danger-full-access`。
82
82
 
83
+ ## 与同名插件的区别
84
+
85
+ 另外三个 DSH 插件名字相近,但解决的是不同的问题 —— 其中一个可能更适合你:
86
+
87
+ | 插件 | 它是什么 | 工作单位 |
88
+ | --- | --- | --- |
89
+ | [`NanmiCoder/dsh-agent-teams`](https://github.com/NanmiCoder/dsh-agent-teams) | 把**当前** DSH session 变成 captain,由它组建 sub-agent、把目标拆成带依赖的任务、并通过直接通信协调 | 一个 **session** |
90
+ | [`toolclub/dsh-agent-team-gui`](https://github.com/toolclub/dsh-agent-team-gui) | 可复用的「规划 → 实现 → 评审」团队,每个成员可选不同模型,Run Center 查看 token 用量 | 一次 **workflow run** |
91
+ | [`limuyang2/agent-team`](https://github.com/limuyang2/agent-team)(npm 名 `@limuyang2/dsh-agent-team`) | 在一个 DSH 窗口里组一支独立 root agent 的队:混用模型与 provider、指定一个 Leader,每个成员在自己的会话里工作、共享同一个 Workspace | 一支**组起来执行任务的队** |
92
+ | **`dsh-agent-team`**(本插件) | 每个 agent 是持久 Member 身份,带自己的私有记忆、笔记与技能;Channel 与职责由你分配,Task Thread 是一条进度线 | 一支**常驻团队** |
93
+
94
+ 实际差别:你上周创建的 Member,今天还是同一个 Member —— 同样的记忆、职责和私有笔记 —— 即使它的 session 已结束、上下文已滚动、或 DSH 重启过。另外三个里,团队是围绕手头这次工作组建的 —— 一次 session、一次 workflow run,或一支有 Leader 的队。
95
+
83
96
  ## 卸载
84
97
 
85
98
  从 profile 移除 bundle,同时会移除它组合进来的层:
@@ -108,13 +121,6 @@ dsh web
108
121
 
109
122
  发布包已经包含构建产物。只有开发检查需要相邻的 Harness repository,终端用户安装不需要它。
110
123
 
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
124
  ## 开发
119
125
 
120
126
  维护中的文档入口是 [`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.9",
3
+ "version": "0.1.11",
4
4
  "description": "A persistent agent team for long-running collaboration in DeepSeek Harness",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,7 +23,9 @@
23
23
  "generate:typert": "node --import tsx scripts/generate-typert.mjs",
24
24
  "prepack": "npm run build",
25
25
  "clean:build-outputs": "node scripts/clean-build-outputs.mjs",
26
- "test": "npm run generate:typert && vitest run",
26
+ "check:docs": "node scripts/check-docs.mjs",
27
+ "check:core-skills": "node scripts/check-core-skills.mjs",
28
+ "test": "npm run generate:typert && npm run check:docs && npm run check:core-skills && vitest run",
27
29
  "test:browser": "npm run build && node scripts/run-browser-test.mjs",
28
30
  "preview": "node scripts/check-preview-credentials.mjs && npm run build && node scripts/run-preview.mjs",
29
31
  "preview:ui": "npm run build && node scripts/run-ui-preview.mjs",
@@ -51,7 +53,7 @@
51
53
  }
52
54
  },
53
55
  "dependencies": {
54
- "@deepseek-ai/dsh-storage-sqlite": ">=0.1.2-rc.1 <0.2.0",
56
+ "@deepseek-ai/dsh-storage-sqlite": ">=0.1.5-rc.1 <0.2.0",
55
57
  "zod": "^4.4.3"
56
58
  },
57
59
  "devDependencies": {
@@ -106,6 +108,14 @@
106
108
  "types": "./packages/agent-team/lib/types/member-context.d.ts",
107
109
  "default": "./packages/agent-team/lib/member-context.js"
108
110
  },
111
+ "./member-time-context": {
112
+ "types": "./packages/agent-team/lib/types/member-time-context.d.ts",
113
+ "default": "./packages/agent-team/lib/member-time-context.js"
114
+ },
115
+ "./time-format": {
116
+ "types": "./packages/agent-team/lib/types/time-format.d.ts",
117
+ "default": "./packages/agent-team/lib/time-format.js"
118
+ },
109
119
  "./member-skills": {
110
120
  "types": "./packages/agent-team/lib/types/member-skills.d.ts",
111
121
  "default": "./packages/agent-team/lib/member-skills.js"
@@ -122,56 +132,60 @@
122
132
  },
123
133
  "peerDependencies": {
124
134
  "@deepseek-ai/cordis": "^4.0.1",
125
- "@deepseek-ai/dsh-agent": ">=0.1.2-rc.1 <0.2.0",
126
- "@deepseek-ai/dsh-agent-default-model": ">=0.1.2-rc.1 <0.2.0",
127
- "@deepseek-ai/dsh-agent-presets": ">=0.1.2-rc.1 <0.2.0",
128
- "@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.2-rc.1 <0.2.0",
129
- "@deepseek-ai/dsh-api-remotes": ">=0.1.2-rc.1 <0.2.0",
130
- "@deepseek-ai/dsh-api-session-controller": ">=0.1.2-rc.1 <0.2.0",
131
- "@deepseek-ai/dsh-api-workspace-controller": ">=0.1.2-rc.1 <0.2.0",
132
- "@deepseek-ai/dsh-brand": ">=0.1.2-rc.1 <0.2.0",
133
- "@deepseek-ai/dsh-client-locale": ">=0.1.2-rc.1 <0.2.0",
134
- "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.2-rc.1 <0.2.0",
135
- "@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.2-rc.1 <0.2.0",
136
- "@deepseek-ai/dsh-client-ui-layout": ">=0.1.2-rc.1 <0.2.0",
137
- "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.2-rc.1 <0.2.0",
138
- "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.2-rc.1 <0.2.0",
139
- "@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.2-rc.1 <0.2.0",
140
- "@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.2-rc.1 <0.2.0",
141
- "@deepseek-ai/dsh-client-ui-slots": ">=0.1.2-rc.1 <0.2.0",
142
- "@deepseek-ai/dsh-client-ui-workspace": ">=0.1.2-rc.1 <0.2.0",
143
- "@deepseek-ai/dsh-command-compact": ">=0.1.2-rc.1 <0.2.0",
144
- "@deepseek-ai/dsh-compaction": ">=0.1.2-rc.1 <0.2.0",
145
- "@deepseek-ai/dsh-home-paths": ">=0.1.2-rc.1 <0.2.0",
146
- "@deepseek-ai/dsh-invariants": ">=0.1.2-rc.1 <0.2.0",
147
- "@deepseek-ai/dsh-llm": ">=0.1.2-rc.1 <0.2.0",
148
- "@deepseek-ai/dsh-sandbox-policy": ">=0.1.2-rc.1 <0.2.0",
149
- "@deepseek-ai/dsh-scope": ">=0.1.2-rc.1 <0.2.0",
150
- "@deepseek-ai/dsh-session": ">=0.1.2-rc.1 <0.2.0",
151
- "@deepseek-ai/dsh-session-persistence": ">=0.1.2-rc.1 <0.2.0",
152
- "@deepseek-ai/dsh-skill": ">=0.1.2-rc.1 <0.2.0",
153
- "@deepseek-ai/dsh-skill-filesystem": ">=0.1.2-rc.1 <0.2.0",
154
- "@deepseek-ai/dsh-storage-domain": ">=0.1.2-rc.1 <0.2.0",
155
- "@deepseek-ai/dsh-token-meter": ">=0.1.2-rc.1 <0.2.0",
156
- "@deepseek-ai/dsh-tool-bash": ">=0.1.2-rc.1 <0.2.0",
157
- "@deepseek-ai/dsh-tool-fs": ">=0.1.2-rc.1 <0.2.0",
158
- "@deepseek-ai/dsh-tool-fs-search": ">=0.1.2-rc.1 <0.2.0",
159
- "@deepseek-ai/dsh-tool-jobs": ">=0.1.2-rc.1 <0.2.0",
160
- "@deepseek-ai/dsh-tool-pwsh": ">=0.1.2-rc.1 <0.2.0",
161
- "@deepseek-ai/dsh-tool-skill": ">=0.1.2-rc.1 <0.2.0",
162
- "@deepseek-ai/dsh-tool-todo": ">=0.1.2-rc.1 <0.2.0",
163
- "@deepseek-ai/dsh-tool-web": ">=0.1.2-rc.1 <0.2.0",
164
- "@deepseek-ai/dsh-tools": ">=0.1.2-rc.1 <0.2.0",
165
- "@deepseek-ai/dsh-typert-protocol": ">=0.1.2-rc.1 <0.2.0",
166
- "@deepseek-ai/dsh-workspace": ">=0.1.2-rc.1 <0.2.0",
135
+ "@deepseek-ai/dsh-agent": ">=0.1.5-rc.1 <0.1.6",
136
+ "@deepseek-ai/dsh-agent-default-model": ">=0.1.5-rc.1 <0.1.6",
137
+ "@deepseek-ai/dsh-agent-presets": ">=0.1.5-rc.1 <0.1.6",
138
+ "@deepseek-ai/dsh-agent-tool-presentation": ">=0.1.5-rc.1 <0.1.6",
139
+ "@deepseek-ai/dsh-api-remotes": ">=0.1.5-rc.1 <0.1.6",
140
+ "@deepseek-ai/dsh-api-session-controller": ">=0.1.5-rc.1 <0.1.6",
141
+ "@deepseek-ai/dsh-api-workspace-controller": ">=0.1.5-rc.1 <0.1.6",
142
+ "@deepseek-ai/dsh-brand": ">=0.1.5-rc.1 <0.1.6",
143
+ "@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1 <0.1.6",
144
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.5-rc.1 <0.1.6",
145
+ "@deepseek-ai/dsh-client-ui-input-trigger": ">=0.1.5-rc.1 <0.1.6",
146
+ "@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.1 <0.1.6",
147
+ "@deepseek-ai/dsh-client-ui-primitives": ">=0.1.5-rc.1 <0.1.6",
148
+ "@deepseek-ai/dsh-client-ui-renderer": ">=0.1.5-rc.1 <0.1.6",
149
+ "@deepseek-ai/dsh-client-ui-settings-general": ">=0.1.5-rc.1 <0.1.6",
150
+ "@deepseek-ai/dsh-client-ui-sidebar": ">=0.1.5-rc.1 <0.1.6",
151
+ "@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.1.6",
152
+ "@deepseek-ai/dsh-client-ui-workspace": ">=0.1.5-rc.1 <0.1.6",
153
+ "@deepseek-ai/dsh-command-compact": ">=0.1.5-rc.1 <0.1.6",
154
+ "@deepseek-ai/dsh-compaction": ">=0.1.5-rc.1 <0.1.6",
155
+ "@deepseek-ai/dsh-home-paths": ">=0.1.5-rc.1 <0.1.6",
156
+ "@deepseek-ai/dsh-invariants": ">=0.1.5-rc.1 <0.1.6",
157
+ "@deepseek-ai/dsh-llm": ">=0.1.5-rc.1 <0.1.6",
158
+ "@deepseek-ai/dsh-sandbox-policy": ">=0.1.5-rc.1 <0.1.6",
159
+ "@deepseek-ai/dsh-scope": ">=0.1.5-rc.1 <0.1.6",
160
+ "@deepseek-ai/dsh-session": ">=0.1.5-rc.1 <0.1.6",
161
+ "@deepseek-ai/dsh-session-format-catalog": ">=0.1.5-rc.1 <0.1.6",
162
+ "@deepseek-ai/dsh-session-persistence": ">=0.1.5-rc.1 <0.1.6",
163
+ "@deepseek-ai/dsh-skill": ">=0.1.5-rc.1 <0.1.6",
164
+ "@deepseek-ai/dsh-skill-filesystem": ">=0.1.5-rc.1 <0.1.6",
165
+ "@deepseek-ai/dsh-storage-domain": ">=0.1.5-rc.1 <0.1.6",
166
+ "@deepseek-ai/dsh-token-meter": ">=0.1.5-rc.1 <0.1.6",
167
+ "@deepseek-ai/dsh-tool-bash": ">=0.1.5-rc.1 <0.1.6",
168
+ "@deepseek-ai/dsh-tool-fs": ">=0.1.5-rc.1 <0.1.6",
169
+ "@deepseek-ai/dsh-tool-fs-search": ">=0.1.5-rc.1 <0.1.6",
170
+ "@deepseek-ai/dsh-tool-jobs": ">=0.1.5-rc.1 <0.1.6",
171
+ "@deepseek-ai/dsh-tool-pwsh": ">=0.1.5-rc.1 <0.1.6",
172
+ "@deepseek-ai/dsh-tool-skill": ">=0.1.5-rc.1 <0.1.6",
173
+ "@deepseek-ai/dsh-tool-todo": ">=0.1.5-rc.1 <0.1.6",
174
+ "@deepseek-ai/dsh-tool-web": ">=0.1.5-rc.1 <0.1.6",
175
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.1.6",
176
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.1.6",
177
+ "@deepseek-ai/dsh-workspace": ">=0.1.5-rc.1 <0.1.6",
167
178
  "react": "^18.2.0"
168
179
  },
169
180
  "keywords": [
181
+ "agent-team",
170
182
  "deepseek-harness",
171
183
  "dsh",
172
184
  "dsh-plugin",
173
- "agent-team",
174
185
  "multi-agent",
175
- "ai-agents"
186
+ "agent-orchestration",
187
+ "ai-agents",
188
+ "deepseek",
189
+ "multi-agent-systems"
176
190
  ]
177
191
  }
@@ -2,16 +2,18 @@
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](../../../.agents/notes/proposed/architecture/2026-08-15-agent-team-operation-ledger.md) owns the persistence and package-topology decisions.
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
 
9
9
  The Service consumes `ctx.storageDomain`, `ctx.workspaceRegistry`, `ctx.agents`, `ctx.agentDefaultModel`, `ctx.agentPresets`, `ctx.tools`, `ctx.sessions`, and `ctx.sessionPersistence`. It opens the versioned `agent_team` Domain before Cordis publishes `ctx.agentTeam`. The first boot appends one `team/initialized` operation for the stable Human Member; later boots replay the same operation and do not append another record.
10
10
 
11
- `status()` returns the current durable sequence, operation count, channel count, Agent Member count, and Human Member ref. It performs no model request and no storage write. `validateLedger()` checks the package-owned projection against the durable operation table.
11
+ `status()` returns the current durable sequence, operation count, channel count, Agent Member count, and Human Member ref. It performs no model request and no storage write. `validateLedger()` checks the package-owned projection against the durable operation table. The invariant companion re-derives that whole table at mount — an unreplayable ledger fails startup — but adopts the record-level replay the ledger constructor already ran while nothing has committed since, gated on the record count, head sequence, and head operation id, which only the operations table's single writer can change. Any commit in between, and every later validation, replays the durable records again. Afterwards the invariant re-derives once per burst of commits, after the committing call has returned, so a Thread read never waits on an O(ledger) replay; a divergence is logged where it is detected and re-raised on every later commit until a replay comes back clean.
12
12
 
13
13
  Every operation record carries a positive global sequence, unique operation and request ids, an actor snapshot, and the previous operation id. Replay rejects invalid record fields, table-key/id mismatches, sequence gaps, broken previous links, repeated ids, and invalid state transitions. An identical request-id retry returns the original receipt; a changed payload with the same request id rejects.
14
14
 
15
+ One durable record stores progress instead of the projection it reported. A `team/thread-read` receipt carries the Workspace, Member, Thread ref, optional Task ref, read watermark, and Inbox delta; the Thread, its facts, the anchor, the reader's Attention, and the unread count left behind are re-derived from the projection on every replay. Records written before this form froze that whole picture beside the delta: one strict union accepts both shapes, the legacy record keeps its own full derivation as its expected value, and loading normalizes and validates it without rewriting a stored byte. A record that fits neither shape — a receipt carrying a picture field, a legacy record missing the Task it belongs to or one of its facts — fails the domain open rather than being guessed at. An identical retry of a committed read returns the original receipt with the picture the current projection derives.
16
+
15
17
  ## Durability and lifecycle
16
18
 
17
19
  `storage-domain` validates every record at the durable read boundary and rejects a backend unit stamped with another version. The Team updates its projection only after `KvTable.put()` resolves. Its Fiber owns the Domain handle; disposal rejects new Service calls through Cordis removal, drains accepted Domain writes, and closes the backend unit before the name can reopen.
@@ -32,7 +34,7 @@ Adding a Member to a Channel grants future read/send/claim authority but injects
32
34
 
33
35
  Member replies require the exact current Thread revision and atomically update Message and Thread facts. `threadRef` is the primary collaboration identity; released task-only Clients may send a Host-resolved `taskRef` alias for taskful Threads, while Task/Claim operations remain Task-ref based. Unread work must be read before a mutation; stale revisions are rejected after that unread gate. A closed Task rejects replies and new Attention; reopening restores the Task without restoring prior Attention. Taskless Threads still support replies, follow, mentions, Inbox, read, and history, but have no Claims or Task-resolution path. Top-level Messages may mention Agents directly: mentioned Members start following the new Thread. In an existing Thread, a Human reply mentioning an unfollowed Agent requires a process-local, one-use confirmation token before the operation commits, while such Member replies are rejected with member_not_following. Message facts carry their structured mention refs, and the Client renders mention chips only for those Members. Claim/done/release and Task changes are ordered host-authored Activities. Active Claims exclude only the same normalized Direction; different Directions can run concurrently. Task state is derived from Claims unless Human acceptance or closure overrides it. Close releases active Claims and clears Thread Attention atomically. Member removal marks the member inactive, releases owned active Claims, clears its Attention and direct markers, and archives the session after the durable commit. Message and Activity facts share one bounded sequence cursor.
34
36
 
35
- `changes()` is the Client invalidation stream. Each request declares one optional `scope` — workspace, channel, or thread — plus an abortable transport signal; a committed operation wakes only waiters whose scope matches the scopes derived from that operation (member lifecycle and presence wake their Workspace; content operations wake their Channel and Thread). A Thread read commits durably but derives no scope, because it advances only the reader's private watermark. After each commit the Host notifies only the Members whose Inbox projection the operation can have changed — the operation's Attention/marker delta plus current followers of the touched Threads — never every live Agent.
37
+ `changes()` is the Client invalidation stream. Each request declares one optional `scope` — workspace, channel, or thread — plus an abortable transport signal; a committed operation wakes only waiters whose scope matches the scopes derived from that operation (member lifecycle and presence wake their Workspace; content operations wake their Channel and Thread). A Thread read derives no scope, because it advances only the reader's private watermark — and a read that finds nothing unread for its reader (no watermark to advance, no marker to consume) appends no operation at all: it answers with the same projection-derived picture and no receipt, so an already-read Thread costs neither a durable write nor a replay. After each commit the Host notifies only the Members whose Inbox projection the operation can have changed — the operation's Attention/marker delta plus current followers of the touched Threads — never every live Agent.
36
38
 
37
39
  M1 supports one Host writer. The ledger is permanent and has no snapshot or compaction path.
38
40
 
@@ -65,4 +67,4 @@ The Host ledger and Human status reads do not alter model requests or cache reus
65
67
  - **Single Host writer** — concurrent processes over one dshHome are unsupported; operation serialization is process-local.
66
68
  - **Permanent ledger** — M1 provides neither snapshots nor compaction, so storage grows with committed collaboration facts.
67
69
  - **No remote provider seam** — the package combines the capability definition and its only implementation until a real remote Consumer requires another Provider.
68
- - **Current DSH SQLite only** — SQLite Session persistence uses the current DSH schema. Delete old Session databases and create new Member sessions; this package provides no migration, compatibility read, or fallback.
70
+ - **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,16 +2,18 @@
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](../../../.agents/notes/proposed/architecture/2026-08-15-agent-team-operation-ledger.md)记录持久化和包拓扑决策。
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
 
9
9
  Service 使用 `ctx.storageDomain`、`ctx.workspaceRegistry`、`ctx.agents`、`ctx.agentDefaultModel`、`ctx.agentPresets`、`ctx.tools`、`ctx.sessions` 和 `ctx.sessionPersistence`,并在 Cordis 发布 `ctx.agentTeam` 前打开带版本的 `agent_team` Domain。首次启动为稳定 Human Member 追加一条 `team/initialized` operation;后续启动重放同一 operation,不追加新记录。
10
10
 
11
- `status()` 返回当前持久 sequence、operation 数量、channel 数量、Agent Member 数量和 Human Member ref。它不发起模型请求,也不写 storage。`validateLedger()` 对照持久 operation table 检查包内 projection。
11
+ `status()` 返回当前持久 sequence、operation 数量、channel 数量、Agent Member 数量和 Human Member ref。它不发起模型请求,也不写 storage。`validateLedger()` 对照持久 operation table 检查包内 projection。invariant companion 在挂载时完整重导该表——重放不通过的账本会让启动失败——但当这期间没有任何提交落地时,它会复用账本构造期已经跑过的那次记录级重放:该复用只能用一次,并受三项同一性检查把关(记录条数、末条 sequence、末条 operation id),而这三项只有 operations 表的唯一写者——账本的 commit 路径——能改变。期间任何一次提交、以及此后的每次校验,都会重新重放持久记录。此后每批提交只跑一次,且安排在这次提交调用返回**之后**执行,所以打开 Thread 不会等待 O(账本) 的重放。漂移由这次延后重放记录日志,并在随后每次提交上重新抛出,直到某次重放干净为止。
12
12
 
13
13
  每条 operation record 包含正数全局 sequence、唯一 operation/request id、actor snapshot 和前一条 operation id。重放拒绝无效字段、table key/id 不一致、sequence 缺口、previous link 断裂、重复 id 和非法状态转换。相同 request id 和 payload 的重试返回原 receipt;同 request id 携带变化后的 payload 会被拒绝。
14
14
 
15
+ 有一类记录存的是「进度」,而不是它当场报告的那份投影。`team/thread-read` receipt 只携带 Workspace、Member、Thread ref、可选 Task ref、read watermark 与 Inbox delta;Thread、其 facts、anchor、读者的 Attention 与读完后剩余的未读计数,都在每次重放时从 projection 重新派生,因此重放一条读不再需要克隆一份假设投影、也不再重新数未读。这个形态之前写入的记录会把整份画面连同 delta 一起冻结:同一个 strict union 同时接受两形,旧记录以自身完整派生作为 expected 值,加载时就地 normalize 与校验,绝不改写任何已存储字节。两形都不符的记录——receipt 里多带画面字段、旧记录缺了所属 Task 或缺了一条 fact——会让整个 domain 打不开,而不是被猜测。对一次已提交读的相同重试返回原 receipt,画面取自当前 projection,从不返回冻结的旧画面。
16
+
15
17
  ## 持久化与生命周期
16
18
 
17
19
  `storage-domain` 在持久读取处校验每条 record,并拒绝被其他版本标记的 backend unit。Team 只在 `KvTable.put()` 完成后更新 projection。其 Fiber 持有 Domain handle;dispose 通过 Cordis 移除拒绝新的 Service 调用,排空已接受的 Domain write,并在名称可重新打开前关闭 backend unit。
@@ -32,7 +34,7 @@ Skills 是 Member 私有的:preset 不带共享 skill-filesystem row,Host
32
34
 
33
35
  Member reply 必须携带准确的当前 Thread revision,并在一个 operation 内更新 Message 和 Thread facts。`threadRef` 是协作主身份;released task-only Client 可为 taskful Thread 传入 Host-resolved `taskRef` alias,而 Task/Claim 操作仍以 Task ref 为准。未读工作必须先 read;revision 过期时拒绝写入。Closed Task 拒绝 reply 和新的 Attention;reopen 恢复 Task,但不恢复之前的 Attention。taskless Thread 仍支持 reply、follow、mention、Inbox、read 和 history,但没有 Claim 或 Task resolution path。顶层消息可以直接 mention Agent:被 mention 的 Member 会开始关注新 Thread。在既有 Thread 中,Human 的 reply 提到 unfollowed Agent 时必须先取得 process-local one-use confirmation token 才提交 operation;Member 的此类 reply 会以 member_not_following 拒绝。Message fact 携带自身的 structured mention refs,Client 只为这些 Member 渲染 mention chip。claim/done/release 和 Task change 是有序的 host-authored Activity。Active Claim 只排斥相同的 normalized Direction;不同 Direction 可以并行。Task status 从 Claims 派生,Human accept/close 是覆盖事实。Close 原子释放 active Claims 并清除 Thread Attention。Member remove 原子标记 inactive、释放 owned active Claims、清除该成员的 Attention 和 direct markers,再归档 session。Message 与 Activity facts 共用一个有界 sequence cursor。
34
36
 
35
- `changes()` 是 Client 失效通知流。每个请求声明一个可选 `scope`(workspace、channel 或 thread)和可取消的传输 signal;一次提交的 operation 只唤醒 scope 与该 operation 派生范围匹配的 waiter(成员生命周期与 presence 唤醒其 Workspace,内容操作唤醒其 Channel 与 Thread)。Thread read 会持久化提交但不派生任何 scope,因为它只推进读者自己的私有水位。每次提交后,Host 只通知 Inbox projection 可能被该 operation 改变的 Member——即 operation 的 Attention/marker delta 加上被触及 Thread 的当前关注者——而不是全部在线 Agent。
37
+ `changes()` 是 Client 失效通知流。每个请求声明一个可选 `scope`(workspace、channel 或 thread)和可取消的传输 signal;一次提交的 operation 只唤醒 scope 与该 operation 派生范围匹配的 waiter(成员生命周期与 presence 唤醒其 Workspace,内容操作唤醒其 Channel 与 Thread)。Thread read 不派生任何 scope,因为它只推进读者自己的私有水位——而一次读如果对读者没有任何未读(没有水位可推进、没有 marker 可消费),就完全不追加 operation:它返回同一份由 projection 派生的画面且不带 receipt,所以已读完的 Thread 既不付一次持久写、也不付一次重放。每次提交后,Host 只通知 Inbox projection 可能被该 operation 改变的 Member——即 operation 的 Attention/marker delta 加上被触及 Thread 的当前关注者——而不是全部在线 Agent。
36
38
 
37
39
  M1 支持单个 Host writer。Ledger 永久保留,不提供 snapshot 或 compaction。
38
40
 
@@ -65,3 +67,4 @@ Host ledger 和 Human status read 不改变模型请求或 cache reuse。
65
67
  - **单 Host writer** — 不支持多个进程并发写同一 dshHome;operation serialization 只在进程内生效。
66
68
  - **永久 ledger** — M1 不提供 snapshot 或 compaction,storage 会随已提交协作事实增长。
67
69
  - **没有 remote provider seam** — 在真实 remote Consumer 需要另一 Provider 前,本包合并 capability definition 和唯一实现。
70
+ - **自身不提供 Session 迁移** — Member Sessions 依赖 Host 的 Session persistence 与其已发布格式迁移链;本包不提供 Team ledger 或 Member Session 迁移、兼容读取或回退。
@@ -19,12 +19,26 @@
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';
26
+ /**
27
+ * Rebuild one Member's in-process intent from the projection's pending
28
+ * rollover. Three call sites consume it — the live result, crash recovery
29
+ * with the turn still open, and crash recovery past the turn end — and they
30
+ * must agree field for field; this is the single definition of that list.
31
+ */
32
+ function intentFromPending(pending) {
33
+ return {
34
+ toolCallId: pending.toolCallId,
35
+ resultSeq: pending.resultSeq,
36
+ turn: pending.turn,
37
+ handoff: pending.handoff,
38
+ ...(pending.checkpointRef === undefined ? {} : { checkpointRef: pending.checkpointRef }),
39
+ relatedFiles: pending.relatedFiles,
40
+ };
41
+ }
28
42
  export class ContextManagementCoordinator {
29
43
  options;
30
44
  members = new Map();
@@ -133,10 +147,15 @@ export class ContextManagementCoordinator {
133
147
  this.capturedInput.delete(memberId);
134
148
  return captured;
135
149
  }
136
- /** Whether one queued message is a Team-owned notice the rederived Inbox replaces. */
150
+ /**
151
+ * Whether one queued message is a Team-owned notice the rederived Inbox
152
+ * replaces. Handoff and continuation envelopes carry the same plugin
153
+ * attribution but are ordinary delivered context the new generation keeps, so
154
+ * they are excluded rather than dropped.
155
+ */
137
156
  isTeamNotice(message) {
138
157
  const source = message.source;
139
- return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID;
158
+ return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID && !isAgentTeamContextSource(message);
140
159
  }
141
160
  /** Drop one Member's bookkeeping; the Host calls this on dispose/removal. */
142
161
  stopTracking(memberId) {
@@ -163,18 +182,7 @@ export class ContextManagementCoordinator {
163
182
  return;
164
183
  if (this.members.has(memberId))
165
184
  return;
166
- this.members.set(memberId, {
167
- agent,
168
- intent: {
169
- toolCallId: pending.toolCallId,
170
- resultSeq: pending.resultSeq,
171
- turn: pending.turn,
172
- handoff: pending.handoff,
173
- ...(pending.checkpointRef === undefined ? {} : { checkpointRef: pending.checkpointRef }),
174
- relatedFiles: pending.relatedFiles,
175
- },
176
- turnEnded: false,
177
- });
185
+ this.members.set(memberId, { agent, intent: intentFromPending(pending), turnEnded: false });
178
186
  }
179
187
  onUserMessage(memberId, _agent, event) {
180
188
  // Quiet-continuation delivery bookkeeping is projection-owned; the
@@ -213,6 +221,23 @@ export class ContextManagementCoordinator {
213
221
  this.members.delete(memberId);
214
222
  });
215
223
  }
224
+ /**
225
+ * Claim the in-process latch for one resolved checkpoint continuation.
226
+ * Returns the latch key when this caller won it, or undefined when the
227
+ * checkpoint never concluded a turn, was already delivered durably, or is
228
+ * latched already. The caller releases the latch on its own failure path.
229
+ */
230
+ claimContinuationLatch(memberId, state, checkpoint) {
231
+ if (checkpoint.turnEndSeq === -1)
232
+ return undefined;
233
+ if (continuationDelivered(state, checkpoint.checkpointRef))
234
+ return undefined;
235
+ const latch = `${memberId}:${checkpoint.checkpointRef}`;
236
+ if (this.scheduledContinuations.has(latch))
237
+ return undefined;
238
+ this.scheduledContinuations.add(latch);
239
+ return latch;
240
+ }
216
241
  /**
217
242
  * Quiet follow-ups for checkpoints resolved by the turn that just ended.
218
243
  * A successful `context_checkpoint` result concludes its turn; the Host
@@ -230,14 +255,9 @@ export class ContextManagementCoordinator {
230
255
  if (state === undefined)
231
256
  return;
232
257
  for (const checkpoint of state.checkpoints) {
233
- if (checkpoint.turnEndSeq === -1)
234
- continue;
235
- if (continuationDelivered(state, checkpoint.checkpointRef))
258
+ const latch = this.claimContinuationLatch(memberId, state, checkpoint);
259
+ if (latch === undefined)
236
260
  continue;
237
- const latch = `${memberId}:${checkpoint.checkpointRef}`;
238
- if (this.scheduledContinuations.has(latch))
239
- continue;
240
- this.scheduledContinuations.add(latch);
241
261
  // The turn/end observer fires inside the session append publication
242
262
  // (a synchronous followup would reenter the publishing append), and a
243
263
  // next-turn message queued while the driver is still converging never
@@ -307,18 +327,7 @@ export class ContextManagementCoordinator {
307
327
  if (pending.turnEndSeq === -1) {
308
328
  // The containing turn never ended durably; treat the intent as still
309
329
  // waiting and observe the live events from here.
310
- this.members.set(memberId, {
311
- agent,
312
- intent: {
313
- toolCallId: pending.toolCallId,
314
- resultSeq: pending.resultSeq,
315
- turn: pending.turn,
316
- handoff: pending.handoff,
317
- ...(pending.checkpointRef === undefined ? {} : { checkpointRef: pending.checkpointRef }),
318
- relatedFiles: pending.relatedFiles,
319
- },
320
- turnEnded: false,
321
- });
330
+ this.members.set(memberId, { agent, intent: intentFromPending(pending), turnEnded: false });
322
331
  return;
323
332
  }
324
333
  // The turn already ended before the crash; the Agent is idle at
@@ -326,18 +335,7 @@ export class ContextManagementCoordinator {
326
335
  const member = this.options.memberForAgent(agent);
327
336
  if (member === undefined)
328
337
  return;
329
- const transition = {
330
- agent,
331
- intent: {
332
- toolCallId: pending.toolCallId,
333
- resultSeq: pending.resultSeq,
334
- turn: pending.turn,
335
- handoff: pending.handoff,
336
- ...(pending.checkpointRef === undefined ? {} : { checkpointRef: pending.checkpointRef }),
337
- relatedFiles: pending.relatedFiles,
338
- },
339
- turnEnded: true,
340
- };
338
+ const transition = { agent, intent: intentFromPending(pending), turnEnded: true };
341
339
  this.members.set(memberId, transition);
342
340
  void this.performTransition(memberId, member, transition);
343
341
  }
@@ -355,14 +353,9 @@ export class ContextManagementCoordinator {
355
353
  if (memberId === undefined)
356
354
  return;
357
355
  for (const checkpoint of state.checkpoints) {
358
- if (checkpoint.turnEndSeq === -1)
359
- continue;
360
- if (continuationDelivered(state, checkpoint.checkpointRef))
361
- continue;
362
- const latch = `${memberId}:${checkpoint.checkpointRef}`;
363
- if (this.scheduledContinuations.has(latch))
356
+ const latch = this.claimContinuationLatch(memberId, state, checkpoint);
357
+ if (latch === undefined)
364
358
  continue;
365
- this.scheduledContinuations.add(latch);
366
359
  try {
367
360
  agent.followup(createCheckpointContinuationMessage(checkpoint.checkpointRef));
368
361
  }
@@ -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. */
@@ -178,6 +176,16 @@ export function foldContextProjection(events, inheritedEventCount = 0, sessionId
178
176
  }
179
177
  return state;
180
178
  }
179
+ /**
180
+ * The same fold as {@link foldContextProjection}, as the `{ start, step }` pair
181
+ * the incremental Session cursor consumes. The cursor route and the cold fold
182
+ * therefore share one transition function: a Session's projection cannot
183
+ * depend on which of the two read it.
184
+ */
185
+ export const contextProjectionFold = (sessionId) => ({
186
+ start: emptyState(),
187
+ step: (state, event) => applyContextEvent(state, event, sessionId),
188
+ });
181
189
  /**
182
190
  * The host-only projection unit; no wire view is published. The definition is
183
191
  * a factory: each Session folds with its own identity so checkpoint refs
@@ -246,7 +254,7 @@ function applyContextEvent(state, event, sessionId) {
246
254
  */
247
255
  function boundaryFromUserMessage(sessionId, seq, message, seenThreads) {
248
256
  const source = message.source;
249
- if (source.kind === 'agent-team-context-handoff') {
257
+ if (handoffOf(message) !== undefined) {
250
258
  return { key: `handoff:${seq}`, source: 'handoff', label: 'context handoff', seq, turn: -1, turnEndSeq: -1 };
251
259
  }
252
260
  if (source.kind !== 'plugin' || source.plugin !== AGENT_TEAM_PLUGIN_ID)
@@ -441,9 +449,10 @@ function applyUserMessage(state, seq, message, sessionId) {
441
449
  }
442
450
  // The quiet continuation notice delivered for one checkpoint completes its
443
451
  // delivery state; replay repair reads this to avoid re-scheduling it.
444
- if (message.source.kind !== 'agent-team-context-continuation')
452
+ const continuation = continuationCheckpointRefOf(message);
453
+ if (continuation === undefined)
445
454
  return next;
446
- const checkpointRef = message.source.checkpointRef;
455
+ const checkpointRef = continuation;
447
456
  const existing = next.continuations.find(entry => entry.checkpointRef === checkpointRef);
448
457
  if (existing !== undefined) {
449
458
  if (existing.deliveredSeq !== -1)
@@ -469,10 +478,15 @@ function applyAssistantMessage(state, event) {
469
478
  export function carriedInputOf(state) {
470
479
  return state.carriedCandidates.filter(candidate => !candidate.consumed).map(candidate => candidate.message);
471
480
  }
472
- /** Whether one queued message is a Team-owned notice the rederived Inbox replaces. */
481
+ /**
482
+ * Whether one queued message is a Team-owned notice the rederived Inbox
483
+ * replaces. Handoff and continuation envelopes carry the same plugin
484
+ * attribution but are ordinary delivered context the new generation keeps, so
485
+ * they are excluded rather than dropped.
486
+ */
473
487
  function isTeamNotice(message) {
474
488
  const source = message.source;
475
- return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID;
489
+ return source.kind === 'plugin' && source.plugin === AGENT_TEAM_PLUGIN_ID && !isAgentTeamContextSource(message);
476
490
  }
477
491
  /** Whether a quiet continuation for one checkpoint was already delivered in this Session. */
478
492
  export function continuationDelivered(state, checkpointRef) {