@ai-agent-forge/plugin-subagent-delegate 0.88.10 → 0.88.12
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 +9 -0
- package/agent-forge.json +1 -1
- package/dist/delegate.d.ts +13 -1
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +115 -8
- package/dist/delegate.js.map +1 -1
- package/dist/entry.d.ts +3 -0
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +6 -0
- package/dist/entry.js.map +1 -1
- package/dist/remote-adapter.d.ts.map +1 -1
- package/dist/remote-adapter.js +0 -7
- package/dist/remote-adapter.js.map +1 -1
- package/dist/runner-pool.d.ts.map +1 -1
- package/dist/runner-pool.js +62 -26
- package/dist/runner-pool.js.map +1 -1
- package/dist/subagent-runtime.d.ts +5 -1
- package/dist/subagent-runtime.d.ts.map +1 -1
- package/dist/subagent-runtime.js +180 -22
- package/dist/subagent-runtime.js.map +1 -1
- package/package.json +5 -4
- package/plugin.json +1 -1
package/dist/delegate.js
CHANGED
|
@@ -10,11 +10,15 @@
|
|
|
10
10
|
* result projection (status / reason codes / message counts / short summary).
|
|
11
11
|
* Raw child messages never enter the tool result (context budget spec).
|
|
12
12
|
*
|
|
13
|
-
* The scheduler's deadline fence is tick-driven by design (no hidden timers
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `
|
|
13
|
+
* The scheduler's deadline fence is tick-driven by design (no hidden timers in
|
|
14
|
+
* the scheduler; `tick()` is the only enforcement point). This consumer owns
|
|
15
|
+
* the production wall-clock driver: a lazy ticker runs at
|
|
16
|
+
* `BACKGROUND_DEADLINE_TICK_INTERVAL_MS` while background tasks with pending
|
|
17
|
+
* deadlines are in flight and only calls `runtime.tick()`, so `subagent_run`
|
|
18
|
+
* can expose `deadlineMs` for background submissions (default
|
|
19
|
+
* `DEFAULT_BACKGROUND_TASK_DEADLINE_MS`, 60 minutes). Wait bounds are
|
|
20
|
+
* `taskTimeoutMs` (drain) and the host's `limits.drainTimeoutMs` inside the
|
|
21
|
+
* scheduler.
|
|
18
22
|
*
|
|
19
23
|
* 迁自宿主 `src/capabilities/subagent-delegate.ts`(D-075 S4 第三批拆包)。除 import
|
|
20
24
|
* 来源外保持宿主行为:公共契约(agent-task 键/档案、通信接线、血缘读取、快照)改自
|
|
@@ -720,6 +724,19 @@ function utf8ByteLength(text) {
|
|
|
720
724
|
}
|
|
721
725
|
const DEFAULT_MAX_TASKS_PER_CALL = 4;
|
|
722
726
|
const DEFAULT_TASK_TIMEOUT_MS = 300_000;
|
|
727
|
+
/**
|
|
728
|
+
* 后台委派缺省死线(60 分钟,出厂默认登记见 docs/design/产品默认值清单.md):挂死
|
|
729
|
+
* 后台任务的兜底寿命。`subagent_run background:true` 提交即带 `deadlineAt`;工具参数
|
|
730
|
+
* `deadlineMs`(正整数)可按调用覆盖。死线到达由调度器 tick 强制为 `timed_out`
|
|
731
|
+
* (设计 §5.7);前台任务不走死线(父侧 drain 预算 `taskTimeoutMs` 已有界)。
|
|
732
|
+
*/
|
|
733
|
+
const DEFAULT_BACKGROUND_TASK_DEADLINE_MS = 3_600_000;
|
|
734
|
+
/**
|
|
735
|
+
* 生产 tick 驱动间隔:存在带未决死线的在途后台任务时才启动的墙钟 ticker(惰性启停)。
|
|
736
|
+
* ticker 只调用 `runtime.tick()`,不携带策略——tick 仍是唯一强制点,调度器"测试可控
|
|
737
|
+
* 时钟"语义不变(测试注入 clock 或以假 timers 驱动本间隔即得确定性死线)。
|
|
738
|
+
*/
|
|
739
|
+
const BACKGROUND_DEADLINE_TICK_INTERVAL_MS = 30_000;
|
|
723
740
|
/**
|
|
724
741
|
* 配置通道读取(manifest 默认 + agent-dir 文件合并后的 `api.config`):
|
|
725
742
|
* 非整数/低于下限即 fail fast 并指名键,不让错误配置静默生效。
|
|
@@ -1151,9 +1168,6 @@ export function createCapability(api, options) {
|
|
|
1151
1168
|
progressUnsubscribes.add(unsubscribe);
|
|
1152
1169
|
return host;
|
|
1153
1170
|
},
|
|
1154
|
-
...(baseAdapter.dispose === undefined
|
|
1155
|
-
? {}
|
|
1156
|
-
: { dispose: async () => void (await baseAdapter.dispose?.()) }),
|
|
1157
1171
|
};
|
|
1158
1172
|
const runtime = createSubagentRuntime({
|
|
1159
1173
|
adapter,
|
|
@@ -1162,7 +1176,59 @@ export function createCapability(api, options) {
|
|
|
1162
1176
|
...(sessionAbortSignal === undefined ? {} : { parentSignal: sessionAbortSignal }),
|
|
1163
1177
|
...(limits === undefined ? {} : { limits }),
|
|
1164
1178
|
...(api.logger === undefined ? {} : { logger: api.logger }),
|
|
1179
|
+
// Durable replay assembly(2026-10-13):宿主 durable 设施原样下传(形状即
|
|
1180
|
+
// runtime 的 results 契约);缺席 = 不持久化(回读 undefined,既有语义)。
|
|
1181
|
+
...(options?.results === undefined ? {} : { results: options.results }),
|
|
1165
1182
|
});
|
|
1183
|
+
// ---------------------------------------------------------------------------
|
|
1184
|
+
// 生产 tick 驱动(设计 §5.7):调度器的死线强制点是显式 tick(),本消费者挂载唯一
|
|
1185
|
+
// 的墙钟驱动——存在带未决死线的在途后台任务时才启动 ticker(惰性启停),每跳只调
|
|
1186
|
+
// runtime.tick(),不携带任何策略。无未决死线的用法零定时器;dispose 必停。
|
|
1187
|
+
// ---------------------------------------------------------------------------
|
|
1188
|
+
/** 受监视的后台任务:taskId -> 提交时的绝对死线(仅作记账,强制语义全在 tick)。 */
|
|
1189
|
+
const pendingDeadlines = new Map();
|
|
1190
|
+
let deadlineTicker;
|
|
1191
|
+
const ensureDeadlineTicker = () => {
|
|
1192
|
+
if (deadlineTicker !== undefined || pendingDeadlines.size === 0)
|
|
1193
|
+
return;
|
|
1194
|
+
deadlineTicker = setInterval(() => {
|
|
1195
|
+
// tick 自身不抛(终态投影等内部故障均已兜底);保险兜底不吞任务面,下一跳重试。
|
|
1196
|
+
try {
|
|
1197
|
+
runtime.tick();
|
|
1198
|
+
}
|
|
1199
|
+
catch {
|
|
1200
|
+
// 留待下一跳;显式 tick / cancel 仍可用。
|
|
1201
|
+
}
|
|
1202
|
+
}, BACKGROUND_DEADLINE_TICK_INTERVAL_MS);
|
|
1203
|
+
deadlineTicker.unref?.();
|
|
1204
|
+
};
|
|
1205
|
+
const stopDeadlineTickerIfIdle = () => {
|
|
1206
|
+
if (deadlineTicker === undefined || pendingDeadlines.size > 0)
|
|
1207
|
+
return;
|
|
1208
|
+
clearInterval(deadlineTicker);
|
|
1209
|
+
deadlineTicker = undefined;
|
|
1210
|
+
};
|
|
1211
|
+
const unwatchBackgroundDeadline = (taskId) => {
|
|
1212
|
+
if (!pendingDeadlines.delete(taskId))
|
|
1213
|
+
return;
|
|
1214
|
+
stopDeadlineTickerIfIdle();
|
|
1215
|
+
};
|
|
1216
|
+
/** 任务结算(含被死线强制、取消、异常)即解除监视;reject 通道(persist 失败等)同样解除。 */
|
|
1217
|
+
const watchBackgroundDeadline = (handle, deadlineAt) => {
|
|
1218
|
+
pendingDeadlines.set(handle.id, deadlineAt);
|
|
1219
|
+
ensureDeadlineTicker();
|
|
1220
|
+
void handle
|
|
1221
|
+
.result()
|
|
1222
|
+
.catch(() => { })
|
|
1223
|
+
.then(() => unwatchBackgroundDeadline(handle.id));
|
|
1224
|
+
};
|
|
1225
|
+
const stopDeadlineTicker = () => {
|
|
1226
|
+
if (deadlineTicker !== undefined) {
|
|
1227
|
+
clearInterval(deadlineTicker);
|
|
1228
|
+
deadlineTicker = undefined;
|
|
1229
|
+
}
|
|
1230
|
+
pendingDeadlines.clear();
|
|
1231
|
+
};
|
|
1166
1232
|
/**
|
|
1167
1233
|
* `subagent_run` 的定义按**当前角色表**现场构建(D-081 即时生效):set/remove 之后
|
|
1168
1234
|
* 以同 owner 同名重注册(runtime 语义 = 更新)让新菜单与 `role` 参数枚举在父会话的
|
|
@@ -1184,6 +1250,9 @@ export function createCapability(api, options) {
|
|
|
1184
1250
|
"task's settlement is announced to you (agent-task-settled), but notifications are not per-task acceptances: " +
|
|
1185
1251
|
"accept and act on (todos/goals/next steps) only the final assembly task's report; other settled lines are " +
|
|
1186
1252
|
"status only." +
|
|
1253
|
+
// 死线兜底(设计 §5.7):后台任务缺省 60 分钟死线,挂死任务到点被强制 timed_out。
|
|
1254
|
+
" Background tasks carry a watchdog deadline by default (60 minutes; override per call with `deadlineMs`): " +
|
|
1255
|
+
"a task still running when its deadline passes is force-settled timed_out." +
|
|
1187
1256
|
(roles.size === 0
|
|
1188
1257
|
? ""
|
|
1189
1258
|
: ` Configured subagent roles (pass \`role\`): ${renderRoleMenu()}. A role's instructions frame every task in the call; ` +
|
|
@@ -1238,6 +1307,14 @@ export function createCapability(api, options) {
|
|
|
1238
1307
|
description: "Submit without waiting: return task tickets immediately and keep working; settled results are " +
|
|
1239
1308
|
"announced at your next model round and can be read with subagent_result (optionally waiting).",
|
|
1240
1309
|
})),
|
|
1310
|
+
// 死线兜底(设计 §5.7):仅后台合法——前台任务已有父侧 drain 预算,两种边界
|
|
1311
|
+
// 不混用;前台携带按 invalid_input 拒绝,不留"配了但不生效"的假象。
|
|
1312
|
+
deadlineMs: Type.Optional(Type.Integer({
|
|
1313
|
+
minimum: 1,
|
|
1314
|
+
description: "Watchdog deadline for this call's background tasks, in ms (positive integer; requires background: true). " +
|
|
1315
|
+
`Default ${DEFAULT_BACKGROUND_TASK_DEADLINE_MS} (60 minutes). A background task still running when its ` +
|
|
1316
|
+
"deadline passes is force-settled timed_out (reason deadline_passed).",
|
|
1317
|
+
})),
|
|
1241
1318
|
}),
|
|
1242
1319
|
execute: executeSubagentRun,
|
|
1243
1320
|
});
|
|
@@ -1249,6 +1326,18 @@ export function createCapability(api, options) {
|
|
|
1249
1326
|
// undefined,后续路径与 context 缺省完全一致。
|
|
1250
1327
|
const contextBlock = renderDelegateContext(parseDelegateContext(input.context));
|
|
1251
1328
|
const background = input.background === true;
|
|
1329
|
+
// 死线兜底(设计 §5.7):正整数校验;仅后台合法——前台任务已有父侧 drain 预算,
|
|
1330
|
+
// 两种边界不混用,前台携带按 invalid_input 拒绝(不留"配了但不生效"的假象)。
|
|
1331
|
+
const rawDeadlineMs = input.deadlineMs;
|
|
1332
|
+
if (rawDeadlineMs !== undefined) {
|
|
1333
|
+
if (typeof rawDeadlineMs !== "number" || !Number.isInteger(rawDeadlineMs) || rawDeadlineMs < 1) {
|
|
1334
|
+
throw new SubagentDelegateError("subagent_invalid_input", `subagent_run deadlineMs must be a positive integer (ms), got ${JSON.stringify(rawDeadlineMs)}`);
|
|
1335
|
+
}
|
|
1336
|
+
if (background !== true) {
|
|
1337
|
+
throw new SubagentDelegateError("subagent_invalid_input", "subagent_run deadlineMs applies to background submissions only; pass background: true (foreground tasks are bounded by the drain timeout instead)");
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
const backgroundDeadlineMs = background === true ? (rawDeadlineMs ?? DEFAULT_BACKGROUND_TASK_DEADLINE_MS) : undefined;
|
|
1252
1341
|
// 嵌套深度硬限(退役切片 2,Option A):沿 S2 血缘头回溯本会话层级,已达
|
|
1253
1342
|
// maxNestedDepth 层时整次调用结构化拒绝——递归的兜底边界(不依赖模型自觉)。
|
|
1254
1343
|
// resume 不涉深度(S5 裁定:续写既有会话不计新层级,走 subagent_resume)。
|
|
@@ -1293,6 +1382,9 @@ export function createCapability(api, options) {
|
|
|
1293
1382
|
? `${composeRolePrompt(role, prompt)}\n\n${composeParentView(session, session.getSessionId()) ?? ""}`.trim()
|
|
1294
1383
|
: composeRolePrompt(role, prompt);
|
|
1295
1384
|
try {
|
|
1385
|
+
// 后台死线(设计 §5.7):提交即带绝对 deadlineAt(相对调度器墙钟),强制点在
|
|
1386
|
+
// 调度器 tick;死线只兜"挂死任务",正常结算远早于它。
|
|
1387
|
+
const deadlineAt = backgroundDeadlineMs === undefined ? undefined : Date.now() + backgroundDeadlineMs;
|
|
1296
1388
|
pending.push({
|
|
1297
1389
|
index,
|
|
1298
1390
|
handle: runtime.submit({
|
|
@@ -1311,7 +1403,9 @@ export function createCapability(api, options) {
|
|
|
1311
1403
|
[AGENT_TASK_CHILD_PROFILE_KEY]: role.profile ?? { version: 1, roleId: role.id },
|
|
1312
1404
|
}),
|
|
1313
1405
|
},
|
|
1406
|
+
...(deadlineAt === undefined ? {} : { deadlineAt }),
|
|
1314
1407
|
}),
|
|
1408
|
+
...(deadlineAt === undefined ? {} : { deadlineAt }),
|
|
1315
1409
|
});
|
|
1316
1410
|
}
|
|
1317
1411
|
catch (error) {
|
|
@@ -1333,8 +1427,16 @@ export function createCapability(api, options) {
|
|
|
1333
1427
|
try {
|
|
1334
1428
|
const handle = await item.handle;
|
|
1335
1429
|
tickets.push({ taskId: handle.id });
|
|
1430
|
+
// 死线监视(设计 §5.7):登记未决死线并惰性启动生产 tick 驱动;任务结算
|
|
1431
|
+
//(含被死线强制/取消/异常)即解除并在归零时停下 ticker。
|
|
1432
|
+
if (item.deadlineAt !== undefined)
|
|
1433
|
+
watchBackgroundDeadline(handle, item.deadlineAt);
|
|
1336
1434
|
const sink = options?.backgroundDigestSink;
|
|
1337
1435
|
if (sink !== undefined) {
|
|
1436
|
+
// result() 的 reject 通道在 durable results store persist 失败时打开
|
|
1437
|
+
//(durable replay assembly 启用后真实存在):摘要观察失败不影响任务
|
|
1438
|
+
// 本身(终态已在调度器落库可查),也不产生未处理 rejection;宿主 sink
|
|
1439
|
+
// 自带守卫(sdk.ts 结算回注失败只记 hostLogger warn)。
|
|
1338
1440
|
void handle
|
|
1339
1441
|
.result()
|
|
1340
1442
|
.then((record) => {
|
|
@@ -1980,7 +2082,12 @@ export function createCapability(api, options) {
|
|
|
1980
2082
|
for (const unsubscribe of progressUnsubscribes)
|
|
1981
2083
|
unsubscribe();
|
|
1982
2084
|
progressUnsubscribes.clear();
|
|
2085
|
+
// 生产 tick 驱动必随 dispose 停止(不允许隐藏定时器活过调度器)。
|
|
2086
|
+
stopDeadlineTicker();
|
|
1983
2087
|
// 先释放调度器(任务终态落定),再回收 runner 池(先释放任务再杀进程)。
|
|
2088
|
+
// dispose 的 reject 通道在 durable results store persist 失败时打开(durable
|
|
2089
|
+
// replay assembly 启用后真实存在):释放失败的收尾错误已由 runtime 内部按
|
|
2090
|
+
// 任务暴露,同步 cleanup 路径无法再抛,这里只保证不产生未处理的 rejection。
|
|
1984
2091
|
void runtime
|
|
1985
2092
|
.dispose()
|
|
1986
2093
|
.then(() => pool?.shutdown())
|