@deepseek-ai/dsh-experimental-agent-team 0.1.6-alpha.2 → 0.1.7-alpha.2
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.i18n.yaml +2 -2
- package/README.md +8 -4
- package/README.zh.md +8 -4
- package/lib/index.js +14 -74
- package/lib/invariant.js +6 -8
- package/lib/typert.host.js +51 -189
- package/lib/typert.remote-client.d.ts +1 -7
- package/lib/typert.remote-client.js +3 -151
- package/lib/types/client.d.ts +2 -2
- package/lib/types/client.js +1 -1
- package/lib/types/index.d.ts +2 -18
- package/lib/types/index.js +0 -41
- package/lib/types/projection.js +10 -10
- package/lib/types/roster.d.ts +1 -1
- package/lib/types/roster.js +8 -4
- package/lib/types/types.d.ts +1 -12
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +29 -27
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/experimental/agent-team/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 6ae7d82214ca9e041324e353057ba6850675c043
|
|
6
|
+
README.zh.md: 89176c285a8bd9d5a1875618dffb0b2eb4890a3e
|
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
|
|
|
60
60
|
|
|
61
61
|
Ask the Lead to create a teammate: give it a unique lowercase name such as `reviewer` and describe its job. A teammate starts fresh with no memory of the Lead's conversation, or as a fork that inherits the Lead's completed turns; the creation request chooses which. Teammate names are permanent — even a teammate whose creation failed keeps its name, and no name is ever reused.
|
|
62
62
|
|
|
63
|
-
The roster shows every member with its role (`lead` or `teammate`) and current status: `running`, `
|
|
63
|
+
The roster shows every member with its role (`lead` or `teammate`) and current status: `running`, `inactive` (no turn is executing, whether loaded or stored), `provisioning`, or `failed`. A member that is not loaded receives its messages when it wakes.
|
|
64
64
|
|
|
65
65
|
Only the Lead can create teammates or interrupt them.
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ Only the Lead can create teammates or interrupt them.
|
|
|
68
68
|
|
|
69
69
|
Any member can send a message to any other member or to the Lead. A live member receives it immediately; an offline member's messages queue and arrive when it resumes. Messages are never lost and never delivered twice.
|
|
70
70
|
|
|
71
|
-
Every message uses Steer: a running target receives it at the nearest step boundary
|
|
71
|
+
Every message uses Steer: a running target receives it at the nearest step boundary; an inactive target starts a turn if loaded or cold-resumes otherwise. The sender always sees the outcome — accepted by the target inbox, or retained as queued when delivery is temporarily unavailable. A queued message is already safely stored, so it must not be resent.
|
|
72
72
|
|
|
73
73
|
### Shared task board
|
|
74
74
|
|
|
@@ -145,6 +145,10 @@ Tasks are complete versioned snapshots; every mutation carries `expectedRevision
|
|
|
145
145
|
|
|
146
146
|
Team events are appended to the exact live Lead Session and flushed before the operation reports success or wakes waiters. `team/member`, `team/task`, `team/message/queued`, and `team/message/delivered` are log-only: they never enter the conversation surface, so derived model history is untouched by coordination records. Session event `seq` and `time` own ordering and timing; snapshots do not duplicate them. The `./invariant` companion replays each candidate Team event against its committed prefix and rejects invalid transitions before append.
|
|
147
147
|
|
|
148
|
+
Native V4 Team event and checkpoint admission reject retired `tool-result` content before it can enter mailbox state. Historical conversion belongs to the Session-format migration; the Team projection does not convert old wrappers.
|
|
149
|
+
|
|
150
|
+
Mailbox projection and checkpoint admission preserve every decoded JSON field of accepted content outside the locally declared validators, including an own `__proto__` key. Local field checks cover `text`, `reasoning`, `image`, and `tool-call`; accepted unknown tags remain opaque. Team projection cache version 4 rebuilds checkpoints from earlier cache versions from the Session log; the Session format version is unchanged.
|
|
151
|
+
|
|
148
152
|
### Disposal
|
|
149
153
|
|
|
150
154
|
Disposal closes admission, aborts and awaits admitted creation and mailbox-dispatch transactions, then asks the continuation owner to release the roster's exact live direct children and their descendants; non-Team continuable children of the Lead remain untouched. Cleanup failures make disposal fail visibly, bounded by `disposalTimeoutMs`.
|
|
@@ -169,7 +173,7 @@ Read these pages when the package-level contract is not enough. They move from t
|
|
|
169
173
|
|
|
170
174
|
### Browser Remote
|
|
171
175
|
|
|
172
|
-
`TeamService`
|
|
176
|
+
`TeamService` exposes the read-only `agentTeams/view` Remote method for browser clients. Task creation and updates belong to Team agents through the service and model tools. The `./remote` export supplies the Client contribution mounted by the Web UI, while `./client` exports browser-safe roster and task views.
|
|
173
177
|
|
|
174
178
|
## Model Experience
|
|
175
179
|
|
|
@@ -198,7 +202,7 @@ These limits describe what a team cannot do yet or what needs special operationa
|
|
|
198
202
|
- **One process and one shared checkout** — members share cwd and observe edits immediately; this package provides no worktree, remote member, merge, or filesystem lock.
|
|
199
203
|
- **Advisory write scopes** — Bash, formatters, code generators, and direct external writers can bypass filesystem version checks; Leads must coordinate ownership and review the final diff.
|
|
200
204
|
- **Flat immutable roster** — only the Lead creates direct teammates; there is no nested Team, rename, deletion, or name reuse.
|
|
201
|
-
- **No automatic ownership release** —
|
|
205
|
+
- **No automatic ownership release** — inactivity, interruption, process exit, and failed work do not release a task owner.
|
|
202
206
|
- **Mailbox is not cross-process exactly-once** — concurrent harness processes over one Team are unsupported.
|
|
203
207
|
|
|
204
208
|
<a id="dev-note"></a>
|
package/README.zh.md
CHANGED
|
@@ -60,7 +60,7 @@ kind: "package-reference"
|
|
|
60
60
|
|
|
61
61
|
请 Lead 创建 teammate:给它一个唯一的小写名字(例如 `reviewer`)并描述其职责。teammate 可以 fresh 启动(不携带 Lead 对话的任何记忆),也可以作为 fork 启动(继承 Lead 已完成的轮次);创建请求决定用哪种。teammate 名字是永久的——即使创建失败的 teammate 也保留其名字,任何名字都不会被复用。
|
|
62
62
|
|
|
63
|
-
roster 显示每个成员的职责(`lead` 或 `teammate`)与当前状态:`running`、`
|
|
63
|
+
roster 显示每个成员的职责(`lead` 或 `teammate`)与当前状态:`running`、`inactive`(当前没有执行轮次,包括已加载和仅存储的成员)、`provisioning` 或 `failed`。未加载的成员会在唤醒后收到其消息。
|
|
64
64
|
|
|
65
65
|
只有 Lead 可以创建 teammate 或中断它们。
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ roster 显示每个成员的职责(`lead` 或 `teammate`)与当前状态:`
|
|
|
68
68
|
|
|
69
69
|
任何成员都可以向任何其他成员或 Lead 发送消息。live 成员会立即收到;离线成员的消息会排队,并在其恢复后到达。消息不会丢失,也不会重复投递。
|
|
70
70
|
|
|
71
|
-
每条消息都使用 Steer:running target 在最近的步骤边界收到消息,
|
|
71
|
+
每条消息都使用 Steer:running target 在最近的步骤边界收到消息,inactive target 在已加载时启动一个轮次,否则冷恢复。发送方始终能看到结果——target inbox 已接受,或在投递暂时不可用时保留为 queued。排队的消息已经安全存储,因此绝不能重发。
|
|
72
72
|
|
|
73
73
|
### 共享任务板
|
|
74
74
|
|
|
@@ -145,6 +145,10 @@ Lead 可以停止 teammate 的当前轮次,而不会删除其排队的消息
|
|
|
145
145
|
|
|
146
146
|
Team 事件追加到精确的 live Lead 会话,并在操作报告成功或唤醒等待者之前 flush。`team/member`、`team/task`、`team/message/queued` 与 `team/message/delivered` 仅存在于日志:它们从不进入会话表面,因此派生模型历史不受协作记录影响。顺序与时间由会话事件的 `seq` 与 `time` 负责,快照不重复保存。`./invariant` 伴生插件把每条候选 Team 事件对照已提交前缀回放,并在 append 前拒绝非法转换。
|
|
147
147
|
|
|
148
|
+
原生 V4 的 Team 事件及检查点准入会拒绝退役的 `tool-result` 内容,防止它进入邮箱状态。历史转换由 Session 格式迁移负责,Team 投影不转换旧包装。
|
|
149
|
+
|
|
150
|
+
Mailbox 投影与 checkpoint 准入保留本地声明的校验器之外获准内容中全部已解码 JSON 字段,包括自有 `__proto__` 键。本地字段检查覆盖 `text`、`reasoning`、`image` 和 `tool-call`;获准的未知标签保持不透明。Team 投影缓存版本 4 从 Session 日志重建较早缓存版本的 checkpoint;Session 格式版本保持不变。
|
|
151
|
+
|
|
148
152
|
### Dispose
|
|
149
153
|
|
|
150
154
|
dispose 会关闭准入、中止并等待已获准的创建与 mailbox dispatch 事务,再让 continuation owner 释放 roster 中确切的 live direct child 及其后代;Lead 的非 Team continuable child 不受影响。cleanup 失败会让 dispose 明确失败,并以 `disposalTimeoutMs` 为上限。
|
|
@@ -169,7 +173,7 @@ dispose 会关闭准入、中止并等待已获准的创建与 mailbox dispatch
|
|
|
169
173
|
|
|
170
174
|
### 浏览器 Remote
|
|
171
175
|
|
|
172
|
-
`TeamService`
|
|
176
|
+
`TeamService` 向浏览器客户端公开只读的 `agentTeams/view` Remote method。任务创建与更新由 Team agent 通过服务和模型工具执行。`./remote` 导出由 Web UI 挂载的 Client contribution,`./client` 导出可供浏览器使用的成员与任务视图。
|
|
173
177
|
|
|
174
178
|
## 模型体验
|
|
175
179
|
|
|
@@ -198,7 +202,7 @@ Peer 消息追加在 target 可复用历史前缀之后。冷恢复会先复用
|
|
|
198
202
|
- **单进程、共享 checkout**——成员共享 cwd,修改立即可见;本包不提供 worktree、远端成员、merge 或文件锁。
|
|
199
203
|
- **write scope 仅作提示**——Bash、formatter、代码生成器与直接外部写入可以绕过文件版本检查;Lead 必须协调 owner 并检查最终 diff。
|
|
200
204
|
- **扁平且不可变的 roster**——只有 Lead 可以创建直接 teammate;不支持嵌套 Team、重命名、删除或名字复用。
|
|
201
|
-
- **不会自动释放 owner
|
|
205
|
+
- **不会自动释放 owner**——成员不活动、interrupt、进程退出与工作失败都不会释放任务 owner。
|
|
202
206
|
- **mailbox 不保证跨进程 exactly-once**——不支持多个 harness 进程并发操作同一 Team。
|
|
203
207
|
|
|
204
208
|
<a id="dev-note"></a>
|
package/lib/index.js
CHANGED
|
@@ -440,7 +440,7 @@ var TeamRoster = class {
|
|
|
440
440
|
id: root.id,
|
|
441
441
|
name: "lead",
|
|
442
442
|
role: "lead",
|
|
443
|
-
status: root
|
|
443
|
+
status: availability(root),
|
|
444
444
|
...root.options.model === void 0 ? {} : { model: root.options.model },
|
|
445
445
|
diagnostics: []
|
|
446
446
|
}];
|
|
@@ -451,7 +451,7 @@ var TeamRoster = class {
|
|
|
451
451
|
id: member.id,
|
|
452
452
|
name: member.name,
|
|
453
453
|
role: "teammate",
|
|
454
|
-
status: member.phase === "failed" ? "failed" : member.phase === "provisioning" ? "provisioning" : live
|
|
454
|
+
status: member.phase === "failed" ? "failed" : member.phase === "provisioning" ? "provisioning" : availability(live),
|
|
455
455
|
description: member.description,
|
|
456
456
|
provider: member.provider,
|
|
457
457
|
context: member.context,
|
|
@@ -508,7 +508,7 @@ var TeamRoster = class {
|
|
|
508
508
|
if (target.id === membership.root.id) throw new TeamError("the Team Lead cannot interrupt itself", "TEAM_INVALID_TARGET");
|
|
509
509
|
const live = this.ctx.agents.get(target.id);
|
|
510
510
|
if (live === void 0) return { previousStatus: "inactive" };
|
|
511
|
-
const previousStatus = live
|
|
511
|
+
const previousStatus = availability(live);
|
|
512
512
|
this.ctx.subagents.interrupt(target.id, {
|
|
513
513
|
kind: "ancestor",
|
|
514
514
|
agent: caller
|
|
@@ -691,7 +691,7 @@ var TeamRoster = class {
|
|
|
691
691
|
id: member.id,
|
|
692
692
|
name: member.name,
|
|
693
693
|
role: "teammate",
|
|
694
|
-
status: live
|
|
694
|
+
status: availability(live),
|
|
695
695
|
description: member.description,
|
|
696
696
|
provider: member.provider,
|
|
697
697
|
context: member.context,
|
|
@@ -724,6 +724,10 @@ var TeamRoster = class {
|
|
|
724
724
|
return foldSubagentDescriptor(agent.session.snapshotEvents(agent.session.inheritedEventCount)) !== void 0;
|
|
725
725
|
}
|
|
726
726
|
};
|
|
727
|
+
/** Turn availability is independent of whether the Agent is loaded. */
|
|
728
|
+
function availability(agent) {
|
|
729
|
+
return agent?.status === "running" ? "running" : "inactive";
|
|
730
|
+
}
|
|
727
731
|
//#endregion
|
|
728
732
|
//#region lib/types/mailbox.js
|
|
729
733
|
/** Durable Team mailbox admission, target-local dispatch, acknowledgement, and recovery. */
|
|
@@ -1083,13 +1087,11 @@ const contentBlockSchema = z$1.lazy(() => z$1.union([
|
|
|
1083
1087
|
name: z$1.string(),
|
|
1084
1088
|
arguments: z$1.string()
|
|
1085
1089
|
}).strict(),
|
|
1086
|
-
z$1.
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}).strict(),
|
|
1092
|
-
z$1.object({ type: z$1.string().min(1) }).loose().refine((block) => !coreContentBlockTypes.has(block.type), { message: "known content block types must match their declared fields" })
|
|
1090
|
+
z$1.custom((value) => {
|
|
1091
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1092
|
+
const type = value.type;
|
|
1093
|
+
return typeof type === "string" && type.length > 0 && !coreContentBlockTypes.has(type);
|
|
1094
|
+
})
|
|
1093
1095
|
]));
|
|
1094
1096
|
const teamMemberSnapshotSchema = z$1.object({
|
|
1095
1097
|
id: sessionIdSchema,
|
|
@@ -1282,7 +1284,7 @@ function applyCurrentTeamEvent(state, event) {
|
|
|
1282
1284
|
/** Host-only Team projection selected by the projected Session identity. */
|
|
1283
1285
|
const teamProjectionDefinition = {
|
|
1284
1286
|
key: "agentTeam",
|
|
1285
|
-
stateVersion:
|
|
1287
|
+
stateVersion: 4,
|
|
1286
1288
|
stateSchema: teamProjectionEntrySchema,
|
|
1287
1289
|
init: (header) => emptyTeamState(header.id),
|
|
1288
1290
|
apply: (state, event) => {
|
|
@@ -1606,14 +1608,10 @@ let TeamService = (() => {
|
|
|
1606
1608
|
let _classSuper = TypertRemoteService;
|
|
1607
1609
|
let _instanceExtraInitializers = [];
|
|
1608
1610
|
let _remoteView_decorators;
|
|
1609
|
-
let _remoteCreateTask_decorators;
|
|
1610
|
-
let _remoteUpdateTask_decorators;
|
|
1611
1611
|
return class TeamService extends _classSuper {
|
|
1612
1612
|
static {
|
|
1613
1613
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
1614
1614
|
_remoteView_decorators = [Remote("view")];
|
|
1615
|
-
_remoteCreateTask_decorators = [Remote("createTask")];
|
|
1616
|
-
_remoteUpdateTask_decorators = [Remote("updateTask")];
|
|
1617
1615
|
__esDecorate(this, null, _remoteView_decorators, {
|
|
1618
1616
|
kind: "method",
|
|
1619
1617
|
name: "remoteView",
|
|
@@ -1625,28 +1623,6 @@ let TeamService = (() => {
|
|
|
1625
1623
|
},
|
|
1626
1624
|
metadata: _metadata
|
|
1627
1625
|
}, null, _instanceExtraInitializers);
|
|
1628
|
-
__esDecorate(this, null, _remoteCreateTask_decorators, {
|
|
1629
|
-
kind: "method",
|
|
1630
|
-
name: "remoteCreateTask",
|
|
1631
|
-
static: false,
|
|
1632
|
-
private: false,
|
|
1633
|
-
access: {
|
|
1634
|
-
has: (obj) => "remoteCreateTask" in obj,
|
|
1635
|
-
get: (obj) => obj.remoteCreateTask
|
|
1636
|
-
},
|
|
1637
|
-
metadata: _metadata
|
|
1638
|
-
}, null, _instanceExtraInitializers);
|
|
1639
|
-
__esDecorate(this, null, _remoteUpdateTask_decorators, {
|
|
1640
|
-
kind: "method",
|
|
1641
|
-
name: "remoteUpdateTask",
|
|
1642
|
-
static: false,
|
|
1643
|
-
private: false,
|
|
1644
|
-
access: {
|
|
1645
|
-
has: (obj) => "remoteUpdateTask" in obj,
|
|
1646
|
-
get: (obj) => obj.remoteUpdateTask
|
|
1647
|
-
},
|
|
1648
|
-
metadata: _metadata
|
|
1649
|
-
}, null, _instanceExtraInitializers);
|
|
1650
1626
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, {
|
|
1651
1627
|
enumerable: true,
|
|
1652
1628
|
configurable: true,
|
|
@@ -1823,42 +1799,6 @@ let TeamService = (() => {
|
|
|
1823
1799
|
tasks: this.listTasks(agent)
|
|
1824
1800
|
};
|
|
1825
1801
|
}
|
|
1826
|
-
/**
|
|
1827
|
-
* Create one shared task through the generated Remote API.
|
|
1828
|
-
* @param agent - exact live Team member creating the task.
|
|
1829
|
-
* @param request - task text, blockers, and advisory write scopes.
|
|
1830
|
-
* @returns the revision-one task or a typed Team rejection.
|
|
1831
|
-
*/
|
|
1832
|
-
remoteCreateTask(agent, request) {
|
|
1833
|
-
return this.taskMutationResult(this.createTask(agent, request));
|
|
1834
|
-
}
|
|
1835
|
-
/**
|
|
1836
|
-
* Apply one task mutation and preserve Team rejections as business results.
|
|
1837
|
-
* @param agent - exact live Team member authorizing the mutation.
|
|
1838
|
-
* @param request - task identity, expected revision, action, and action fields.
|
|
1839
|
-
* @returns the committed task or a typed Team rejection.
|
|
1840
|
-
*/
|
|
1841
|
-
remoteUpdateTask(agent, request) {
|
|
1842
|
-
return this.taskMutationResult(this.updateTask(agent, request));
|
|
1843
|
-
}
|
|
1844
|
-
/** Preserve Team task rejections while allowing unexpected failures to reject the Remote call. */
|
|
1845
|
-
async taskMutationResult(operation) {
|
|
1846
|
-
try {
|
|
1847
|
-
return {
|
|
1848
|
-
ok: true,
|
|
1849
|
-
value: await operation
|
|
1850
|
-
};
|
|
1851
|
-
} catch (error) {
|
|
1852
|
-
if (!(error instanceof TeamError)) throw error;
|
|
1853
|
-
return {
|
|
1854
|
-
ok: false,
|
|
1855
|
-
error: {
|
|
1856
|
-
code: error.code === "TEAM_TASK_STALE_REVISION" ? "team-task-conflict" : "team-rejected",
|
|
1857
|
-
message: error.message
|
|
1858
|
-
}
|
|
1859
|
-
};
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
1802
|
/** Queue one contained recovery pass after publication has unwound. */
|
|
1863
1803
|
scheduleRecovery(agent) {
|
|
1864
1804
|
queueMicrotask(() => {
|
package/lib/invariant.js
CHANGED
|
@@ -128,13 +128,11 @@ const contentBlockSchema = z.lazy(() => z.union([
|
|
|
128
128
|
name: z.string(),
|
|
129
129
|
arguments: z.string()
|
|
130
130
|
}).strict(),
|
|
131
|
-
z.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}).strict(),
|
|
137
|
-
z.object({ type: z.string().min(1) }).loose().refine((block) => !coreContentBlockTypes.has(block.type), { message: "known content block types must match their declared fields" })
|
|
131
|
+
z.custom((value) => {
|
|
132
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
133
|
+
const type = value.type;
|
|
134
|
+
return typeof type === "string" && type.length > 0 && !coreContentBlockTypes.has(type);
|
|
135
|
+
})
|
|
138
136
|
]));
|
|
139
137
|
const teamMemberSnapshotSchema = z.object({
|
|
140
138
|
id: sessionIdSchema,
|
|
@@ -327,7 +325,7 @@ function applyCurrentTeamEvent(state, event) {
|
|
|
327
325
|
/** Host-only Team projection selected by the projected Session identity. */
|
|
328
326
|
const teamProjectionDefinition = {
|
|
329
327
|
key: "agentTeam",
|
|
330
|
-
stateVersion:
|
|
328
|
+
stateVersion: 4,
|
|
331
329
|
stateSchema: teamProjectionEntrySchema,
|
|
332
330
|
init: (header) => emptyTeamState(header.id),
|
|
333
331
|
apply: (state, event) => {
|