@ai-agent-forge/plugin-subagent-delegate 0.88.13 → 0.88.15
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/MANUAL.md +19 -23
- package/README.md +59 -54
- package/agent-forge.json +1 -1
- package/dist/defaults.d.ts +30 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +30 -0
- package/dist/defaults.js.map +1 -0
- package/dist/delegate.d.ts +37 -17
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +453 -163
- package/dist/delegate.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/remote-adapter.d.ts.map +1 -1
- package/dist/remote-adapter.js +5 -0
- package/dist/remote-adapter.js.map +1 -1
- package/dist/render.d.ts +67 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +325 -0
- package/dist/render.js.map +1 -0
- package/dist/runner-pool.d.ts.map +1 -1
- package/dist/runner-pool.js +2 -0
- package/dist/runner-pool.js.map +1 -1
- package/dist/scheduler-capability.d.ts +39 -0
- package/dist/scheduler-capability.d.ts.map +1 -0
- package/dist/scheduler-capability.js +266 -0
- package/dist/scheduler-capability.js.map +1 -0
- package/dist/subagent-runtime.d.ts +17 -3
- package/dist/subagent-runtime.d.ts.map +1 -1
- package/dist/subagent-runtime.js +181 -8
- package/dist/subagent-runtime.js.map +1 -1
- package/package.json +2 -2
- package/plugin.json +9 -7
package/dist/runner-pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-pool.js","sourceRoot":"","sources":["../src/runner-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 池化 runner adapter(D-045 / pooled 切片增量 2)。\n *\n * `AgentTaskAdapter` 的 runner 池实现:按 `maxSessionsPerRunner` 选\"空闲槽位最多\"\n * 的 runner(确定性);无空闲槽位且未达 `maxRunnerProcesses` 时按需 spawn;runner\n * 空闲超时退出(不迁移任务);进程死亡时在途任务以 `runner_lost` 结算(D-044 §4.3\n * 投影 failed + reasonCode subagent_runner_lost)。\n *\n * 分层约束:调度器(SubagentRuntime)继续持有队列与准入;本层只提供\"容量 + 进程\n * 生命周期\"。宿主接线必须保证 `maxConcurrentSubagents <= maxRunnerProcesses *\n * maxSessionsPerRunner`,否则超出容量的准入会以 `subagent_runner_capacity` 失败。\n * spawn 由 `spawnRunner` 注入:生产侧经 stdio 派生子进程,测试注入进程内 fake。\n *\n * 迁自宿主 `src/plugins/subagent-task/runner-pool.ts`(D-075 S4 第三批);公共契约改自\n * plugin-sdk,wire 协议类型改自 @agent-forge/protocol(宿主侧同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport type { AgentTaskAdapter, AgentTaskCreateRequest, AgentTaskHost, SessionAPI } from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskChannelV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\nimport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\n\nexport interface SubagentRunnerSpawnHandleV1 {\n\t/** 与 runner 进程对话的通道(父侧)。 */\n\treadonly channel: SubagentTaskChannelV1;\n\t/** 进程退出通知:error 非空表示异常退出。 */\n\tonExit(handler: (error?: Error) => void): void;\n\t/** 请求进程退出(空闲回收与池关闭使用)。 */\n\tkill(): void;\n}\n\nexport interface SubagentRunnerPoolOptionsV1 {\n\tspawnRunner(): Promise<SubagentRunnerSpawnHandleV1> | SubagentRunnerSpawnHandleV1;\n\tmaxRunnerProcesses: number;\n\tmaxSessionsPerRunner: number;\n\tidleRunnerTimeoutMs: number;\n\t/**\n\t * 宿主全局并发(调度器 maxConcurrentSubagents)。提供时参与 fail-fast 校验:\n\t * 必须 <= maxRunnerProcesses * maxSessionsPerRunner,否则超出容量的准入会以容量错误失败。\n\t */\n\tmaxConcurrentSubagents?: number;\n\t/** 就绪握手超时(默认 5000ms):runner 未在期限内应答 hello 视为启动失败。 */\n\thandshakeTimeoutMs?: number;\n\t/** 确定性时钟(默认 Date.now)。 */\n\tclock?: () => number;\n\tidleCheckIntervalMs?: number;\n\tonDiagnostic?(message: string): void;\n}\n\nexport interface SubagentRunnerPoolStatsV1 {\n\treadonly runners: number;\n\treadonly aliveRunners: number;\n\treadonly liveTasks: number;\n\treadonly spawnedTotal: number;\n}\n\nexport interface SubagentRunnerPoolV1 extends AgentTaskAdapter {\n\t/** D-044 §5.6:按 wire taskId(= host.session.getSessionId())订阅运行中进度。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void;\n\t/** 空闲回收扫描(宿主心跳调用;也可由内部定时器驱动)。 */\n\tsweep(): void;\n\tstats(): SubagentRunnerPoolStatsV1;\n\tshutdown(): Promise<void>;\n}\n\nexport class SubagentRunnerPoolError extends Error {\n\treadonly code:\n\t\t| \"subagent_runner_capacity\"\n\t\t| \"subagent_runner_lost\"\n\t\t| \"subagent_pool_closed\"\n\t\t| \"subagent_pool_config_invalid\";\n\n\tconstructor(\n\t\tcode:\n\t\t\t| \"subagent_runner_capacity\"\n\t\t\t| \"subagent_runner_lost\"\n\t\t\t| \"subagent_pool_closed\"\n\t\t\t| \"subagent_pool_config_invalid\",\n\t\tmessage: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SubagentRunnerPoolError\";\n\t\tthis.code = code;\n\t}\n}\n\nconst MAX_RUNNER_PROCESSES = 5;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 5000;\n\n/**\n * 宿主接线 fail-fast 校验(D-044 §8):配置违规在构造期抛出,不静默钳制。\n * `maxRunnerProcesses = 0` 表示不启用 pooled(由宿主决定不构造本 adapter),\n * 因此本校验要求 >= 1。\n */\nexport function validateSubagentRunnerPoolOptionsV1(options: {\n\tmaxRunnerProcesses: number;\n\tmaxSessionsPerRunner: number;\n\tmaxConcurrentSubagents?: number;\n\tidleRunnerTimeoutMs: number;\n\thandshakeTimeoutMs?: number;\n}): void {\n\tconst fail = (message: string): never => {\n\t\tthrow new SubagentRunnerPoolError(\"subagent_pool_config_invalid\", message);\n\t};\n\tif (\n\t\t!Number.isInteger(options.maxRunnerProcesses) ||\n\t\toptions.maxRunnerProcesses < 1 ||\n\t\toptions.maxRunnerProcesses > MAX_RUNNER_PROCESSES\n\t) {\n\t\tfail(\n\t\t\t`maxRunnerProcesses must be an integer between 1 and ${MAX_RUNNER_PROCESSES}, got ${String(options.maxRunnerProcesses)}`,\n\t\t);\n\t}\n\tif (!Number.isInteger(options.maxSessionsPerRunner) || options.maxSessionsPerRunner < 1) {\n\t\tfail(`maxSessionsPerRunner must be a positive integer, got ${String(options.maxSessionsPerRunner)}`);\n\t}\n\tif (typeof options.maxConcurrentSubagents === \"number\") {\n\t\tif (!Number.isInteger(options.maxConcurrentSubagents) || options.maxConcurrentSubagents < 1) {\n\t\t\tfail(`maxConcurrentSubagents must be a positive integer, got ${String(options.maxConcurrentSubagents)}`);\n\t\t}\n\t\tconst capacity = options.maxRunnerProcesses * options.maxSessionsPerRunner;\n\t\tif (options.maxConcurrentSubagents > capacity) {\n\t\t\tfail(`maxConcurrentSubagents (${options.maxConcurrentSubagents}) exceeds runner capacity (${capacity})`);\n\t\t}\n\t}\n\tif (!Number.isInteger(options.idleRunnerTimeoutMs) || options.idleRunnerTimeoutMs < 1) {\n\t\tfail(`idleRunnerTimeoutMs must be a positive integer, got ${String(options.idleRunnerTimeoutMs)}`);\n\t}\n\tif (\n\t\toptions.handshakeTimeoutMs !== undefined &&\n\t\t(!Number.isInteger(options.handshakeTimeoutMs) || options.handshakeTimeoutMs < 1)\n\t) {\n\t\tfail(`handshakeTimeoutMs must be a positive integer, got ${String(options.handshakeTimeoutMs)}`);\n\t}\n}\n\n/**\n * 就绪握手:在把通道交给 remote adapter 之前做一次 hello 往返,确认 runner 存活\n * 且协议版本一致;超时/版本不符视为启动失败(调用方负责 kill)。\n */\nasync function handshakeRunnerV1(\n\tchannel: SubagentTaskChannelV1,\n\ttimeoutMs: number,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tsignal.throwIfAborted();\n\tconst id = `hello:${randomUUID().slice(0, 8)}`;\n\tconst iterator = channel[Symbol.asyncIterator]();\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst timeout = new Promise<never>((_resolve, reject) => {\n\t\ttimer = setTimeout(\n\t\t\t() => reject(new SubagentTaskProtocolError(`runner handshake timed out after ${timeoutMs}ms`, \"runner_lost\")),\n\t\t\ttimeoutMs,\n\t\t);\n\t});\n\tlet rejectCancelled!: (reason: unknown) => void;\n\tconst cancelled = new Promise<never>((_resolve, reject) => {\n\t\trejectCancelled = reject;\n\t});\n\tconst onAbort = (): void => rejectCancelled(signal.reason);\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\ttry {\n\t\tawait Promise.race([\n\t\t\tchannel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, op: \"hello\" }),\n\t\t\tcancelled,\n\t\t\ttimeout,\n\t\t]);\n\t\tfor (;;) {\n\t\t\tconst nextPromise = iterator.next();\n\t\t\tvoid nextPromise.catch(() => {});\n\t\t\tconst next = await Promise.race([nextPromise, timeout, cancelled]);\n\t\t\tif (next.done) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"runner closed during handshake\", \"runner_lost\");\n\t\t\t}\n\t\t\tconst env = next.value;\n\t\t\tif (env.kind !== \"response\" || env.id !== id) continue; // 握手期不应有其它信封:忽略等待\n\t\t\tif (!env.ok) {\n\t\t\t\tthrow new SubagentTaskProtocolError(`runner rejected handshake: ${env.message}`, env.code);\n\t\t\t}\n\t\t\tif (env.protocolVersion !== SUBAGENT_TASK_PROTOCOL_VERSION) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`subagent-task protocol mismatch: runner=${String(env.protocolVersion)} host=${SUBAGENT_TASK_PROTOCOL_VERSION}`,\n\t\t\t\t\t\"invalid_request\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\ninterface PoolRunner {\n\treadonly adapter: AgentTaskAdapter;\n\treadonly handle: SubagentRunnerSpawnHandleV1;\n\treadonly liveTasks: Set<string>;\n\t/**\n\t * 分配中(adapter.create 已发起、回执未到)的预留槽位。并发 create 必须在等待\n\t * 回执期间就占位,否则同一 runner 会被超发(压测:40 个并发 create 全落在同一个\n\t * 刚 spawn 的 runner 上,扇出从未发生)。\n\t */\n\tpending: number;\n\talive: boolean;\n\tidleSince: number;\n}\n\nfunction slotsUsed(runner: PoolRunner): number {\n\treturn runner.liveTasks.size + runner.pending;\n}\n\nexport function createPooledAgentTaskAdapterV1(options: SubagentRunnerPoolOptionsV1): SubagentRunnerPoolV1 {\n\t// 配置违规在构造期 fail-fast(D-044 §8),不静默钳制。\n\tvalidateSubagentRunnerPoolOptionsV1(options);\n\tconst clock = options.clock ?? Date.now;\n\tconst handshakeTimeoutMs = options.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS;\n\tconst diagnostic = options.onDiagnostic ?? ((): void => {});\n\tconst runners: PoolRunner[] = [];\n\t/** wire taskId(= host.session.getSessionId())-> 承载它的 runner adapter,用于进度转发。 */\n\tconst taskRunnerAdapters = new Map<string, AgentTaskAdapter>();\n\tlet spawnedTotal = 0;\n\tlet closed = false;\n\tlet sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tlet spawnInFlight: Promise<PoolRunner> | undefined;\n\tlet pendingSpawnHandle: SubagentRunnerSpawnHandleV1 | undefined;\n\tconst shutdownController = new AbortController();\n\n\t/** 摘除已死 runner(句柄与状态都不再需要),避免长寿命池按 spawn 次数增长。 */\n\tconst pruneDeadRunners = (): void => {\n\t\tfor (let index = runners.length - 1; index >= 0; index -= 1) {\n\t\t\tif (!runners[index]?.alive) runners.splice(index, 1);\n\t\t}\n\t};\n\n\tconst markDead = (runner: PoolRunner, error?: Error): void => {\n\t\tif (!runner.alive) return;\n\t\trunner.alive = false;\n\t\trunner.liveTasks.clear();\n\t\tdiagnostic(`subagent runner lost: ${error?.message ?? \"process exited\"}`);\n\t};\n\n\tconst trackRunner = (handle: SubagentRunnerSpawnHandleV1): PoolRunner => {\n\t\tconst runner: PoolRunner = {\n\t\t\tadapter: createRemoteAgentTaskAdapter(handle.channel),\n\t\t\thandle,\n\t\t\tliveTasks: new Set<string>(),\n\t\t\tpending: 0,\n\t\t\talive: true,\n\t\t\tidleSince: clock(),\n\t\t};\n\t\thandle.onExit((error?: Error) => markDead(runner, error));\n\t\trunners.push(runner);\n\t\tspawnedTotal += 1;\n\t\treturn runner;\n\t};\n\n\tconst spawnRunner = async (): Promise<PoolRunner> => {\n\t\tshutdownController.signal.throwIfAborted();\n\t\t// 并发 create 共享同一次 spawn,避免超发进程。\n\t\tspawnInFlight ??= (async () => {\n\t\t\tconst handle = await options.spawnRunner();\n\t\t\tpendingSpawnHandle = handle;\n\t\t\ttry {\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t// 就绪握手在把通道交给 remote adapter 之前完成(adapter 启动后独占读取)。\n\t\t\t\tawait handshakeRunnerV1(handle.channel, handshakeTimeoutMs, shutdownController.signal);\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t} catch (error) {\n\t\t\t\t// 握手失败:进程不可用,回收并上抛(调用方按启动失败处理)。\n\t\t\t\ttry {\n\t\t\t\t\thandle.kill();\n\t\t\t\t} catch {\n\t\t\t\t\t// 已退出:忽略\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn trackRunner(handle);\n\t\t})().finally(() => {\n\t\t\t// 清理在赋值后的微任务执行;同步 spawn 抛错不能把失败 Promise 留在池中。\n\t\t\tspawnInFlight = undefined;\n\t\t\tpendingSpawnHandle = undefined;\n\t\t});\n\t\treturn spawnInFlight;\n\t};\n\n\tconst pickRunner = (): PoolRunner | undefined => {\n\t\tlet best: PoolRunner | undefined;\n\t\tlet bestFree = 0;\n\t\tfor (const runner of runners) {\n\t\t\tif (!runner.alive) continue;\n\t\t\tconst free = options.maxSessionsPerRunner - slotsUsed(runner);\n\t\t\tif (free > bestFree) {\n\t\t\t\tbest = runner;\n\t\t\t\tbestFree = free;\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t};\n\n\tconst createOnRunner = async (runner: PoolRunner, request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t// 首选和恢复 runner 共用准入,异步 spawn 完成不代表池仍可创建任务。\n\t\tshutdownController.signal.throwIfAborted();\n\t\trunner.pending += 1;\n\t\tlet host: AgentTaskHost;\n\t\ttry {\n\t\t\thost = await runner.adapter.create(request);\n\t\t} finally {\n\t\t\trunner.pending -= 1;\n\t\t}\n\t\t// 回执可能晚于 shutdown;关闭后的任务由 runner 回收,不再发布给调度器。\n\t\tshutdownController.signal.throwIfAborted();\n\t\tif (!runner.alive) {\n\t\t\tthrow new SubagentTaskProtocolError(\"subagent runner lost before task publication\", \"runner_lost\");\n\t\t}\n\t\tconst taskId = host.session.getSessionId();\n\t\trunner.liveTasks.add(taskId);\n\t\ttaskRunnerAdapters.set(taskId, runner.adapter);\n\t\trunner.idleSince = 0;\n\t\tconst remoteSession = host.session;\n\t\t// 包装 session:保留远程会话身份与 steer;dispose 时归还槽位。\n\t\t// 事实面(getActiveTools/getModel)必须一并透传:档案核验靠它自证,包装层吞掉\n\t\t// 就等于把\"已核验\"变成\"无法核验\"。\n\t\tconst remoteGetActiveTools = remoteSession.getActiveTools?.bind(remoteSession);\n\t\tconst session: SessionAPI = {\n\t\t\tgetSessionId: () => remoteSession.getSessionId(),\n\t\t\t...(remoteSession.getAgentSessionId === undefined\n\t\t\t\t? {}\n\t\t\t\t: { getAgentSessionId: remoteSession.getAgentSessionId.bind(remoteSession) }),\n\t\t\tgetMessages: () => remoteSession.getMessages(),\n\t\t\tisIdle: () => remoteSession.isIdle(),\n\t\t\tprompt: (text) => remoteSession.prompt(text),\n\t\t\t...(remoteSession.steer === undefined ? {} : { steer: remoteSession.steer.bind(remoteSession) }),\n\t\t\tabort: () => remoteSession.abort(),\n\t\t\twaitForIdle: () => remoteSession.waitForIdle(),\n\t\t\tappendEntry: (customType, data) => remoteSession.appendEntry(customType, data),\n\t\t\tgetBranchEntries: () => remoteSession.getBranchEntries(),\n\t\t\t...(remoteGetActiveTools === undefined ? {} : { getActiveTools: () => remoteGetActiveTools() }),\n\t\t\t...(remoteSession.getModel === undefined ? {} : { getModel: () => remoteSession.getModel?.() }),\n\t\t};\n\t\treturn {\n\t\t\tsession,\n\t\t\trun: (prompt, signal) => host.run(prompt, signal),\n\t\t\tcancel: (reason) => host.cancel(reason),\n\t\t\tdispose: async () => {\n\t\t\t\trunner.liveTasks.delete(taskId);\n\t\t\t\ttaskRunnerAdapters.delete(taskId);\n\t\t\t\tif (runner.liveTasks.size === 0) runner.idleSince = clock();\n\t\t\t\tawait host.dispose();\n\t\t\t},\n\t\t};\n\t};\n\n\tconst sweep = (): void => {\n\t\tif (closed) return;\n\t\tpruneDeadRunners();\n\t\tconst now = clock();\n\t\tfor (const runner of runners) {\n\t\t\t// pending > 0 = create 仍在途(真实 runner 的 spawn+握手+会话创建可达\n\t\t\t// 数秒):在途创建是活跃工作,不是空闲——sweep 不得打点也不得回收,\n\t\t\t// 否则激进 idleRunnerTimeoutMs 下 create 中途通道被杀(live 用例实证)。\n\t\t\tif (!runner.alive || runner.pending > 0 || runner.liveTasks.size > 0) continue;\n\t\t\tif (runner.idleSince === 0) runner.idleSince = now;\n\t\t\tif (now - runner.idleSince < options.idleRunnerTimeoutMs) continue;\n\t\t\t// 空闲超时回收:退出前必须无活跃任务(不迁移),dead 标记阻止后续分配。\n\t\t\trunner.alive = false;\n\t\t\tdiagnostic(\"subagent runner idle exit\");\n\t\t\ttry {\n\t\t\t\trunner.handle.kill();\n\t\t\t} catch {\n\t\t\t\t// 进程已退出:忽略\n\t\t\t}\n\t\t}\n\t};\n\n\tconst adapter: SubagentRunnerPoolV1 = {\n\t\t/** D-044 §5.6:转发到承载该任务的 runner 远程 adapter。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\tconst runnerAdapter = taskRunnerAdapters.get(taskId) as\n\t\t\t\t| (AgentTaskAdapter & { onTaskProgress?: (id: string, cb: typeof listener) => () => void })\n\t\t\t\t| undefined;\n\t\t\treturn runnerAdapter?.onTaskProgress?.(taskId, listener) ?? (() => {});\n\t\t},\n\t\tasync create(request: AgentTaskCreateRequest): Promise<AgentTaskHost> {\n\t\t\tif (closed) throw new SubagentRunnerPoolError(\"subagent_pool_closed\", \"subagent runner pool is closed\");\n\t\t\tpruneDeadRunners();\n\t\t\t// 放置循环:并发 create 共享同一次 spawn,因此拿到共享结果后必须**重新**挑选\n\t\t\t// 有空槽的 runner(新 spawn 的那个同样有槽位上限),容量耗尽才报错。\n\t\t\tlet runner = pickRunner();\n\t\t\twhile (runner === undefined) {\n\t\t\t\tif (runners.filter((candidate) => candidate.alive).length >= options.maxRunnerProcesses) {\n\t\t\t\t\tthrow new SubagentRunnerPoolError(\n\t\t\t\t\t\t\"subagent_runner_capacity\",\n\t\t\t\t\t\t`no runner capacity: ${options.maxRunnerProcesses} runner(s) at ${options.maxSessionsPerRunner} session(s) each`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait spawnRunner();\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\trunner = pickRunner();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await createOnRunner(runner, request);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof SubagentTaskProtocolError && error.code === \"runner_lost\") {\n\t\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t\t// 分配期失败无副作用:换一个 runner 重试一次;无可用槽位且不能扩则上抛容量错误。\n\t\t\t\t\tmarkDead(runner, error);\n\t\t\t\t\tlet fallback = pickRunner();\n\t\t\t\t\twhile (fallback === undefined) {\n\t\t\t\t\t\tif (runners.filter((candidate) => candidate.alive).length >= options.maxRunnerProcesses) {\n\t\t\t\t\t\t\tthrow new SubagentRunnerPoolError(\"subagent_runner_lost\", \"runner lost and no spare capacity\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait spawnRunner();\n\t\t\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t\t\t// 共享 spawn 的空槽可能已被另一恢复或普通创建预留,必须重新挑选。\n\t\t\t\t\t\tfallback = pickRunner();\n\t\t\t\t\t}\n\t\t\t\t\tif (fallback !== runner) return createOnRunner(fallback, request);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tsweep,\n\t\tstats(): SubagentRunnerPoolStatsV1 {\n\t\t\treturn {\n\t\t\t\trunners: runners.length,\n\t\t\t\taliveRunners: runners.filter((runner) => runner.alive).length,\n\t\t\t\tliveTasks: runners.reduce((total, runner) => total + runner.liveTasks.size, 0),\n\t\t\t\tspawnedTotal,\n\t\t\t};\n\t\t},\n\t\tasync shutdown(): Promise<void> {\n\t\t\tif (closed) return;\n\t\t\tclosed = true;\n\t\t\tshutdownController.abort(\n\t\t\t\tnew SubagentRunnerPoolError(\"subagent_pool_closed\", \"subagent runner pool is closed\"),\n\t\t\t);\n\t\t\tif (sweepTimer !== undefined) clearInterval(sweepTimer);\n\t\t\t// 正在 spawn 的句柄归 spawnRunner 回收;握手可取消,已登记 runner 在下面释放。\n\t\t\tif (pendingSpawnHandle !== undefined && spawnInFlight !== undefined) await Promise.allSettled([spawnInFlight]);\n\t\t\tconst alive = runners.filter((runner) => runner.alive);\n\t\t\tawait Promise.allSettled(alive.map((runner) => runner.adapter.dispose?.()));\n\t\t\tfor (const runner of alive) {\n\t\t\t\trunner.alive = false;\n\t\t\t\ttry {\n\t\t\t\t\trunner.handle.kill();\n\t\t\t\t} catch {\n\t\t\t\t\t// 已退出:忽略\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n\n\tif (options.idleCheckIntervalMs !== undefined && options.idleCheckIntervalMs > 0) {\n\t\tsweepTimer = setInterval(sweep, options.idleCheckIntervalMs);\n\t\tsweepTimer.unref?.();\n\t}\n\n\treturn adapter;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"runner-pool.js","sourceRoot":"","sources":["../src/runner-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 池化 runner adapter(D-045 / pooled 切片增量 2)。\n *\n * `AgentTaskAdapter` 的 runner 池实现:按 `maxSessionsPerRunner` 选\"空闲槽位最多\"\n * 的 runner(确定性);无空闲槽位且未达 `maxRunnerProcesses` 时按需 spawn;runner\n * 空闲超时退出(不迁移任务);进程死亡时在途任务以 `runner_lost` 结算(D-044 §4.3\n * 投影 failed + reasonCode subagent_runner_lost)。\n *\n * 分层约束:调度器(SubagentRuntime)继续持有队列与准入;本层只提供\"容量 + 进程\n * 生命周期\"。宿主接线必须保证 `maxConcurrentSubagents <= maxRunnerProcesses *\n * maxSessionsPerRunner`,否则超出容量的准入会以 `subagent_runner_capacity` 失败。\n * spawn 由 `spawnRunner` 注入:生产侧经 stdio 派生子进程,测试注入进程内 fake。\n *\n * 迁自宿主 `src/plugins/subagent-task/runner-pool.ts`(D-075 S4 第三批);公共契约改自\n * plugin-sdk,wire 协议类型改自 @agent-forge/protocol(宿主侧同名模块已下沉该包)。\n */\nimport { randomUUID } from \"node:crypto\";\nimport type { AgentTaskAdapter, AgentTaskCreateRequest, AgentTaskHost, SessionAPI } from \"@agent-forge/plugin-sdk\";\nimport {\n\tSUBAGENT_TASK_PROTOCOL_VERSION,\n\ttype SubagentTaskChannelV1,\n\tSubagentTaskProtocolError,\n} from \"@agent-forge/protocol/subagent\";\nimport { createRemoteAgentTaskAdapter } from \"./remote-adapter.ts\";\n\nexport interface SubagentRunnerSpawnHandleV1 {\n\t/** 与 runner 进程对话的通道(父侧)。 */\n\treadonly channel: SubagentTaskChannelV1;\n\t/** 进程退出通知:error 非空表示异常退出。 */\n\tonExit(handler: (error?: Error) => void): void;\n\t/** 请求进程退出(空闲回收与池关闭使用)。 */\n\tkill(): void;\n}\n\nexport interface SubagentRunnerPoolOptionsV1 {\n\tspawnRunner(): Promise<SubagentRunnerSpawnHandleV1> | SubagentRunnerSpawnHandleV1;\n\tmaxRunnerProcesses: number;\n\tmaxSessionsPerRunner: number;\n\tidleRunnerTimeoutMs: number;\n\t/**\n\t * 宿主全局并发(调度器 maxConcurrentSubagents)。提供时参与 fail-fast 校验:\n\t * 必须 <= maxRunnerProcesses * maxSessionsPerRunner,否则超出容量的准入会以容量错误失败。\n\t */\n\tmaxConcurrentSubagents?: number;\n\t/** 就绪握手超时(默认 5000ms):runner 未在期限内应答 hello 视为启动失败。 */\n\thandshakeTimeoutMs?: number;\n\t/** 确定性时钟(默认 Date.now)。 */\n\tclock?: () => number;\n\tidleCheckIntervalMs?: number;\n\tonDiagnostic?(message: string): void;\n}\n\nexport interface SubagentRunnerPoolStatsV1 {\n\treadonly runners: number;\n\treadonly aliveRunners: number;\n\treadonly liveTasks: number;\n\treadonly spawnedTotal: number;\n}\n\nexport interface SubagentRunnerPoolV1 extends AgentTaskAdapter {\n\t/** D-044 §5.6:按 wire taskId(= host.session.getSessionId())订阅运行中进度。 */\n\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void;\n\t/** 空闲回收扫描(宿主心跳调用;也可由内部定时器驱动)。 */\n\tsweep(): void;\n\tstats(): SubagentRunnerPoolStatsV1;\n\tshutdown(): Promise<void>;\n}\n\nexport class SubagentRunnerPoolError extends Error {\n\treadonly code:\n\t\t| \"subagent_runner_capacity\"\n\t\t| \"subagent_runner_lost\"\n\t\t| \"subagent_pool_closed\"\n\t\t| \"subagent_pool_config_invalid\";\n\n\tconstructor(\n\t\tcode:\n\t\t\t| \"subagent_runner_capacity\"\n\t\t\t| \"subagent_runner_lost\"\n\t\t\t| \"subagent_pool_closed\"\n\t\t\t| \"subagent_pool_config_invalid\",\n\t\tmessage: string,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SubagentRunnerPoolError\";\n\t\tthis.code = code;\n\t}\n}\n\nconst MAX_RUNNER_PROCESSES = 5;\nconst DEFAULT_HANDSHAKE_TIMEOUT_MS = 5000;\n\n/**\n * 宿主接线 fail-fast 校验(D-044 §8):配置违规在构造期抛出,不静默钳制。\n * `maxRunnerProcesses = 0` 表示不启用 pooled(由宿主决定不构造本 adapter),\n * 因此本校验要求 >= 1。\n */\nexport function validateSubagentRunnerPoolOptionsV1(options: {\n\tmaxRunnerProcesses: number;\n\tmaxSessionsPerRunner: number;\n\tmaxConcurrentSubagents?: number;\n\tidleRunnerTimeoutMs: number;\n\thandshakeTimeoutMs?: number;\n}): void {\n\tconst fail = (message: string): never => {\n\t\tthrow new SubagentRunnerPoolError(\"subagent_pool_config_invalid\", message);\n\t};\n\tif (\n\t\t!Number.isInteger(options.maxRunnerProcesses) ||\n\t\toptions.maxRunnerProcesses < 1 ||\n\t\toptions.maxRunnerProcesses > MAX_RUNNER_PROCESSES\n\t) {\n\t\tfail(\n\t\t\t`maxRunnerProcesses must be an integer between 1 and ${MAX_RUNNER_PROCESSES}, got ${String(options.maxRunnerProcesses)}`,\n\t\t);\n\t}\n\tif (!Number.isInteger(options.maxSessionsPerRunner) || options.maxSessionsPerRunner < 1) {\n\t\tfail(`maxSessionsPerRunner must be a positive integer, got ${String(options.maxSessionsPerRunner)}`);\n\t}\n\tif (typeof options.maxConcurrentSubagents === \"number\") {\n\t\tif (!Number.isInteger(options.maxConcurrentSubagents) || options.maxConcurrentSubagents < 1) {\n\t\t\tfail(`maxConcurrentSubagents must be a positive integer, got ${String(options.maxConcurrentSubagents)}`);\n\t\t}\n\t\tconst capacity = options.maxRunnerProcesses * options.maxSessionsPerRunner;\n\t\tif (options.maxConcurrentSubagents > capacity) {\n\t\t\tfail(`maxConcurrentSubagents (${options.maxConcurrentSubagents}) exceeds runner capacity (${capacity})`);\n\t\t}\n\t}\n\tif (!Number.isInteger(options.idleRunnerTimeoutMs) || options.idleRunnerTimeoutMs < 1) {\n\t\tfail(`idleRunnerTimeoutMs must be a positive integer, got ${String(options.idleRunnerTimeoutMs)}`);\n\t}\n\tif (\n\t\toptions.handshakeTimeoutMs !== undefined &&\n\t\t(!Number.isInteger(options.handshakeTimeoutMs) || options.handshakeTimeoutMs < 1)\n\t) {\n\t\tfail(`handshakeTimeoutMs must be a positive integer, got ${String(options.handshakeTimeoutMs)}`);\n\t}\n}\n\n/**\n * 就绪握手:在把通道交给 remote adapter 之前做一次 hello 往返,确认 runner 存活\n * 且协议版本一致;超时/版本不符视为启动失败(调用方负责 kill)。\n */\nasync function handshakeRunnerV1(\n\tchannel: SubagentTaskChannelV1,\n\ttimeoutMs: number,\n\tsignal: AbortSignal,\n): Promise<void> {\n\tsignal.throwIfAborted();\n\tconst id = `hello:${randomUUID().slice(0, 8)}`;\n\tconst iterator = channel[Symbol.asyncIterator]();\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst timeout = new Promise<never>((_resolve, reject) => {\n\t\ttimer = setTimeout(\n\t\t\t() => reject(new SubagentTaskProtocolError(`runner handshake timed out after ${timeoutMs}ms`, \"runner_lost\")),\n\t\t\ttimeoutMs,\n\t\t);\n\t});\n\tlet rejectCancelled!: (reason: unknown) => void;\n\tconst cancelled = new Promise<never>((_resolve, reject) => {\n\t\trejectCancelled = reject;\n\t});\n\tconst onAbort = (): void => rejectCancelled(signal.reason);\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\ttry {\n\t\tawait Promise.race([\n\t\t\tchannel.write({ v: SUBAGENT_TASK_PROTOCOL_VERSION, kind: \"request\", id, op: \"hello\" }),\n\t\t\tcancelled,\n\t\t\ttimeout,\n\t\t]);\n\t\tfor (;;) {\n\t\t\tconst nextPromise = iterator.next();\n\t\t\tvoid nextPromise.catch(() => {});\n\t\t\tconst next = await Promise.race([nextPromise, timeout, cancelled]);\n\t\t\tif (next.done) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\"runner closed during handshake\", \"runner_lost\");\n\t\t\t}\n\t\t\tconst env = next.value;\n\t\t\tif (env.kind !== \"response\" || env.id !== id) continue; // 握手期不应有其它信封:忽略等待\n\t\t\tif (!env.ok) {\n\t\t\t\tthrow new SubagentTaskProtocolError(`runner rejected handshake: ${env.message}`, env.code);\n\t\t\t}\n\t\t\tif (env.protocolVersion !== SUBAGENT_TASK_PROTOCOL_VERSION) {\n\t\t\t\tthrow new SubagentTaskProtocolError(\n\t\t\t\t\t`subagent-task protocol mismatch: runner=${String(env.protocolVersion)} host=${SUBAGENT_TASK_PROTOCOL_VERSION}`,\n\t\t\t\t\t\"invalid_request\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\ninterface PoolRunner {\n\treadonly adapter: AgentTaskAdapter;\n\treadonly handle: SubagentRunnerSpawnHandleV1;\n\treadonly liveTasks: Set<string>;\n\t/**\n\t * 分配中(adapter.create 已发起、回执未到)的预留槽位。并发 create 必须在等待\n\t * 回执期间就占位,否则同一 runner 会被超发(压测:40 个并发 create 全落在同一个\n\t * 刚 spawn 的 runner 上,扇出从未发生)。\n\t */\n\tpending: number;\n\talive: boolean;\n\tidleSince: number;\n}\n\nfunction slotsUsed(runner: PoolRunner): number {\n\treturn runner.liveTasks.size + runner.pending;\n}\n\nexport function createPooledAgentTaskAdapterV1(options: SubagentRunnerPoolOptionsV1): SubagentRunnerPoolV1 {\n\t// 配置违规在构造期 fail-fast(D-044 §8),不静默钳制。\n\tvalidateSubagentRunnerPoolOptionsV1(options);\n\tconst clock = options.clock ?? Date.now;\n\tconst handshakeTimeoutMs = options.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS;\n\tconst diagnostic = options.onDiagnostic ?? ((): void => {});\n\tconst runners: PoolRunner[] = [];\n\t/** wire taskId(= host.session.getSessionId())-> 承载它的 runner adapter,用于进度转发。 */\n\tconst taskRunnerAdapters = new Map<string, AgentTaskAdapter>();\n\tlet spawnedTotal = 0;\n\tlet closed = false;\n\tlet sweepTimer: ReturnType<typeof setInterval> | undefined;\n\tlet spawnInFlight: Promise<PoolRunner> | undefined;\n\tlet pendingSpawnHandle: SubagentRunnerSpawnHandleV1 | undefined;\n\tconst shutdownController = new AbortController();\n\n\t/** 摘除已死 runner(句柄与状态都不再需要),避免长寿命池按 spawn 次数增长。 */\n\tconst pruneDeadRunners = (): void => {\n\t\tfor (let index = runners.length - 1; index >= 0; index -= 1) {\n\t\t\tif (!runners[index]?.alive) runners.splice(index, 1);\n\t\t}\n\t};\n\n\tconst markDead = (runner: PoolRunner, error?: Error): void => {\n\t\tif (!runner.alive) return;\n\t\trunner.alive = false;\n\t\trunner.liveTasks.clear();\n\t\tdiagnostic(`subagent runner lost: ${error?.message ?? \"process exited\"}`);\n\t};\n\n\tconst trackRunner = (handle: SubagentRunnerSpawnHandleV1): PoolRunner => {\n\t\tconst runner: PoolRunner = {\n\t\t\tadapter: createRemoteAgentTaskAdapter(handle.channel),\n\t\t\thandle,\n\t\t\tliveTasks: new Set<string>(),\n\t\t\tpending: 0,\n\t\t\talive: true,\n\t\t\tidleSince: clock(),\n\t\t};\n\t\thandle.onExit((error?: Error) => markDead(runner, error));\n\t\trunners.push(runner);\n\t\tspawnedTotal += 1;\n\t\treturn runner;\n\t};\n\n\tconst spawnRunner = async (): Promise<PoolRunner> => {\n\t\tshutdownController.signal.throwIfAborted();\n\t\t// 并发 create 共享同一次 spawn,避免超发进程。\n\t\tspawnInFlight ??= (async () => {\n\t\t\tconst handle = await options.spawnRunner();\n\t\t\tpendingSpawnHandle = handle;\n\t\t\ttry {\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t// 就绪握手在把通道交给 remote adapter 之前完成(adapter 启动后独占读取)。\n\t\t\t\tawait handshakeRunnerV1(handle.channel, handshakeTimeoutMs, shutdownController.signal);\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t} catch (error) {\n\t\t\t\t// 握手失败:进程不可用,回收并上抛(调用方按启动失败处理)。\n\t\t\t\ttry {\n\t\t\t\t\thandle.kill();\n\t\t\t\t} catch {\n\t\t\t\t\t// 已退出:忽略\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn trackRunner(handle);\n\t\t})().finally(() => {\n\t\t\t// 清理在赋值后的微任务执行;同步 spawn 抛错不能把失败 Promise 留在池中。\n\t\t\tspawnInFlight = undefined;\n\t\t\tpendingSpawnHandle = undefined;\n\t\t});\n\t\treturn spawnInFlight;\n\t};\n\n\tconst pickRunner = (): PoolRunner | undefined => {\n\t\tlet best: PoolRunner | undefined;\n\t\tlet bestFree = 0;\n\t\tfor (const runner of runners) {\n\t\t\tif (!runner.alive) continue;\n\t\t\tconst free = options.maxSessionsPerRunner - slotsUsed(runner);\n\t\t\tif (free > bestFree) {\n\t\t\t\tbest = runner;\n\t\t\t\tbestFree = free;\n\t\t\t}\n\t\t}\n\t\treturn best;\n\t};\n\n\tconst createOnRunner = async (runner: PoolRunner, request: AgentTaskCreateRequest): Promise<AgentTaskHost> => {\n\t\t// 首选和恢复 runner 共用准入,异步 spawn 完成不代表池仍可创建任务。\n\t\tshutdownController.signal.throwIfAborted();\n\t\trunner.pending += 1;\n\t\tlet host: AgentTaskHost;\n\t\ttry {\n\t\t\thost = await runner.adapter.create(request);\n\t\t} finally {\n\t\t\trunner.pending -= 1;\n\t\t}\n\t\t// 回执可能晚于 shutdown;关闭后的任务由 runner 回收,不再发布给调度器。\n\t\tshutdownController.signal.throwIfAborted();\n\t\tif (!runner.alive) {\n\t\t\tthrow new SubagentTaskProtocolError(\"subagent runner lost before task publication\", \"runner_lost\");\n\t\t}\n\t\tconst taskId = host.session.getSessionId();\n\t\trunner.liveTasks.add(taskId);\n\t\ttaskRunnerAdapters.set(taskId, runner.adapter);\n\t\trunner.idleSince = 0;\n\t\tconst remoteSession = host.session;\n\t\t// 包装 session:保留远程会话身份与 steer;dispose 时归还槽位。\n\t\t// 事实面(getActiveTools/getModel)必须一并透传:档案核验靠它自证,包装层吞掉\n\t\t// 就等于把\"已核验\"变成\"无法核验\"。\n\t\tconst remoteGetActiveTools = remoteSession.getActiveTools?.bind(remoteSession);\n\t\tconst remoteGetWebSearch = remoteSession.getWebSearch?.bind(remoteSession);\n\t\tconst session: SessionAPI = {\n\t\t\tgetSessionId: () => remoteSession.getSessionId(),\n\t\t\t...(remoteSession.getAgentSessionId === undefined\n\t\t\t\t? {}\n\t\t\t\t: { getAgentSessionId: remoteSession.getAgentSessionId.bind(remoteSession) }),\n\t\t\tgetMessages: () => remoteSession.getMessages(),\n\t\t\tisIdle: () => remoteSession.isIdle(),\n\t\t\tprompt: (text) => remoteSession.prompt(text),\n\t\t\t...(remoteSession.steer === undefined ? {} : { steer: remoteSession.steer.bind(remoteSession) }),\n\t\t\tabort: () => remoteSession.abort(),\n\t\t\twaitForIdle: () => remoteSession.waitForIdle(),\n\t\t\tappendEntry: (customType, data) => remoteSession.appendEntry(customType, data),\n\t\t\tgetBranchEntries: () => remoteSession.getBranchEntries(),\n\t\t\t...(remoteGetActiveTools === undefined ? {} : { getActiveTools: () => remoteGetActiveTools() }),\n\t\t\t...(remoteSession.getModel === undefined ? {} : { getModel: () => remoteSession.getModel?.() }),\n\t\t\t...(remoteGetWebSearch === undefined ? {} : { getWebSearch: () => remoteGetWebSearch() }),\n\t\t};\n\t\treturn {\n\t\t\tsession,\n\t\t\trun: (prompt, signal) => host.run(prompt, signal),\n\t\t\tcancel: (reason) => host.cancel(reason),\n\t\t\tdispose: async () => {\n\t\t\t\trunner.liveTasks.delete(taskId);\n\t\t\t\ttaskRunnerAdapters.delete(taskId);\n\t\t\t\tif (runner.liveTasks.size === 0) runner.idleSince = clock();\n\t\t\t\tawait host.dispose();\n\t\t\t},\n\t\t};\n\t};\n\n\tconst sweep = (): void => {\n\t\tif (closed) return;\n\t\tpruneDeadRunners();\n\t\tconst now = clock();\n\t\tfor (const runner of runners) {\n\t\t\t// pending > 0 = create 仍在途(真实 runner 的 spawn+握手+会话创建可达\n\t\t\t// 数秒):在途创建是活跃工作,不是空闲——sweep 不得打点也不得回收,\n\t\t\t// 否则激进 idleRunnerTimeoutMs 下 create 中途通道被杀(live 用例实证)。\n\t\t\tif (!runner.alive || runner.pending > 0 || runner.liveTasks.size > 0) continue;\n\t\t\tif (runner.idleSince === 0) runner.idleSince = now;\n\t\t\tif (now - runner.idleSince < options.idleRunnerTimeoutMs) continue;\n\t\t\t// 空闲超时回收:退出前必须无活跃任务(不迁移),dead 标记阻止后续分配。\n\t\t\trunner.alive = false;\n\t\t\tdiagnostic(\"subagent runner idle exit\");\n\t\t\ttry {\n\t\t\t\trunner.handle.kill();\n\t\t\t} catch {\n\t\t\t\t// 进程已退出:忽略\n\t\t\t}\n\t\t}\n\t};\n\n\tconst adapter: SubagentRunnerPoolV1 = {\n\t\t/** D-044 §5.6:转发到承载该任务的 runner 远程 adapter。 */\n\t\tonTaskProgress(taskId: string, listener: (message: string | undefined, seq: number) => void): () => void {\n\t\t\tconst runnerAdapter = taskRunnerAdapters.get(taskId) as\n\t\t\t\t| (AgentTaskAdapter & { onTaskProgress?: (id: string, cb: typeof listener) => () => void })\n\t\t\t\t| undefined;\n\t\t\treturn runnerAdapter?.onTaskProgress?.(taskId, listener) ?? (() => {});\n\t\t},\n\t\tasync create(request: AgentTaskCreateRequest): Promise<AgentTaskHost> {\n\t\t\tif (closed) throw new SubagentRunnerPoolError(\"subagent_pool_closed\", \"subagent runner pool is closed\");\n\t\t\tpruneDeadRunners();\n\t\t\t// 放置循环:并发 create 共享同一次 spawn,因此拿到共享结果后必须**重新**挑选\n\t\t\t// 有空槽的 runner(新 spawn 的那个同样有槽位上限),容量耗尽才报错。\n\t\t\tlet runner = pickRunner();\n\t\t\twhile (runner === undefined) {\n\t\t\t\tif (runners.filter((candidate) => candidate.alive).length >= options.maxRunnerProcesses) {\n\t\t\t\t\tthrow new SubagentRunnerPoolError(\n\t\t\t\t\t\t\"subagent_runner_capacity\",\n\t\t\t\t\t\t`no runner capacity: ${options.maxRunnerProcesses} runner(s) at ${options.maxSessionsPerRunner} session(s) each`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tawait spawnRunner();\n\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\trunner = pickRunner();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn await createOnRunner(runner, request);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof SubagentTaskProtocolError && error.code === \"runner_lost\") {\n\t\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t\t// 分配期失败无副作用:换一个 runner 重试一次;无可用槽位且不能扩则上抛容量错误。\n\t\t\t\t\tmarkDead(runner, error);\n\t\t\t\t\tlet fallback = pickRunner();\n\t\t\t\t\twhile (fallback === undefined) {\n\t\t\t\t\t\tif (runners.filter((candidate) => candidate.alive).length >= options.maxRunnerProcesses) {\n\t\t\t\t\t\t\tthrow new SubagentRunnerPoolError(\"subagent_runner_lost\", \"runner lost and no spare capacity\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tawait spawnRunner();\n\t\t\t\t\t\tshutdownController.signal.throwIfAborted();\n\t\t\t\t\t\t// 共享 spawn 的空槽可能已被另一恢复或普通创建预留,必须重新挑选。\n\t\t\t\t\t\tfallback = pickRunner();\n\t\t\t\t\t}\n\t\t\t\t\tif (fallback !== runner) return createOnRunner(fallback, request);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tsweep,\n\t\tstats(): SubagentRunnerPoolStatsV1 {\n\t\t\treturn {\n\t\t\t\trunners: runners.length,\n\t\t\t\taliveRunners: runners.filter((runner) => runner.alive).length,\n\t\t\t\tliveTasks: runners.reduce((total, runner) => total + runner.liveTasks.size, 0),\n\t\t\t\tspawnedTotal,\n\t\t\t};\n\t\t},\n\t\tasync shutdown(): Promise<void> {\n\t\t\tif (closed) return;\n\t\t\tclosed = true;\n\t\t\tshutdownController.abort(\n\t\t\t\tnew SubagentRunnerPoolError(\"subagent_pool_closed\", \"subagent runner pool is closed\"),\n\t\t\t);\n\t\t\tif (sweepTimer !== undefined) clearInterval(sweepTimer);\n\t\t\t// 正在 spawn 的句柄归 spawnRunner 回收;握手可取消,已登记 runner 在下面释放。\n\t\t\tif (pendingSpawnHandle !== undefined && spawnInFlight !== undefined) await Promise.allSettled([spawnInFlight]);\n\t\t\tconst alive = runners.filter((runner) => runner.alive);\n\t\t\tawait Promise.allSettled(alive.map((runner) => runner.adapter.dispose?.()));\n\t\t\tfor (const runner of alive) {\n\t\t\t\trunner.alive = false;\n\t\t\t\ttry {\n\t\t\t\t\trunner.handle.kill();\n\t\t\t\t} catch {\n\t\t\t\t\t// 已退出:忽略\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n\n\tif (options.idleCheckIntervalMs !== undefined && options.idleCheckIntervalMs > 0) {\n\t\tsweepTimer = setInterval(sweep, options.idleCheckIntervalMs);\n\t\tsweepTimer.unref?.();\n\t}\n\n\treturn adapter;\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-forge.agent-task-scheduler@1` 提供方(联网检索设计 §5.6,P1b)。
|
|
3
|
+
*
|
|
4
|
+
* 把已创建的 `SubagentRuntime` 的 one-shot 面经公共能力目录暴露:submit / status /
|
|
5
|
+
* result / cancel / drain(请求与响应 union 见 plugin-sdk 的 agent-task-scheduler 契约)。
|
|
6
|
+
* 不新建第二套调度器、不走 `api.agents.create`:队列、准入、预算、终态与父取消全部
|
|
7
|
+
* 复用 runtime;本模块只做请求校验、metadata 契约键注入和公共结果投影。
|
|
8
|
+
*
|
|
9
|
+
* requester 作用域由提供方绑定:runtime 实例绑定 owner/parentSessionId,本模块把同一
|
|
10
|
+
* 三元组作为 scope 回读的 requester,请求里不收 owner/session 字段(收到也忽略——
|
|
11
|
+
* 作用域不是调用方可选的)。活跃任务走 submit 时保存的 handle 映射(submit 返回的
|
|
12
|
+
* taskId → `SubagentTaskHandleV1`);handle 映射未命中时(如提供方重建后的历史 taskId)
|
|
13
|
+
* 回落 runtime 的范围化读面(peek/result/cancelById,durable 回读含崩溃孤儿自愈)。
|
|
14
|
+
*
|
|
15
|
+
* 错误契约:请求形状错误与本模块的未知 taskId 拒绝以 Error 抛出(经能力目录 reject
|
|
16
|
+
* 冒泡,保留原始 message);runtime 的同步拒绝(预算/队列/失效)与终态 persist 失败
|
|
17
|
+
* 原样冒泡,不吞不改——消费方负责捕获并投影。
|
|
18
|
+
*/
|
|
19
|
+
import { type AgentTaskSchedulerResultV1, type AgentTaskSchedulerStatusSnapshotV1, type CapabilityAPI, type DisposableRegistration } from "@agent-forge/plugin-sdk";
|
|
20
|
+
import type { SchedulerTaskRecordV1, SubagentRuntimeStatus, SubagentRuntimeV1 } from "./subagent-runtime.ts";
|
|
21
|
+
/** status 快照投影:在途原样(queued/admitted/running),终态与 result 同映射。 */
|
|
22
|
+
export declare function projectSchedulerStatusV1(status: SubagentRuntimeStatus): AgentTaskSchedulerStatusSnapshotV1;
|
|
23
|
+
/** 终态调度记录 → 公共结果投影(冻结、JSON 可序列化)。 */
|
|
24
|
+
export declare function projectSchedulerResultV1(record: SchedulerTaskRecordV1): AgentTaskSchedulerResultV1;
|
|
25
|
+
export interface AgentTaskSchedulerProviderOptionsV1 {
|
|
26
|
+
/** 已创建的调度器实例(本提供方不创建、不释放它——生命周期归宿主装配)。 */
|
|
27
|
+
readonly runtime: SubagentRuntimeV1;
|
|
28
|
+
/** scope 三元组的 owner(与 runtime 绑定值一致;用于范围化回读与文档)。 */
|
|
29
|
+
readonly owner: string;
|
|
30
|
+
/** scope 三元组的父会话 id;同时作为血缘键注入子任务 metadata。 */
|
|
31
|
+
readonly parentSessionId: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 创建能力提供方工厂:返回的函数把 handler 经 `api.capabilities.provide` 注册为
|
|
35
|
+
* `agent-forge.agent-task-scheduler@1`(manifest 的 `provides` 必须声明同一 id,
|
|
36
|
+
* 能力目录在 provide 时强制校验),返回目录的 DisposableRegistration(dispose 即摘除)。
|
|
37
|
+
*/
|
|
38
|
+
export declare function createAgentTaskSchedulerCapabilityProviderV1(options: AgentTaskSchedulerProviderOptionsV1): (api: CapabilityAPI) => DisposableRegistration;
|
|
39
|
+
//# sourceMappingURL=scheduler-capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-capability.d.ts","sourceRoot":"","sources":["../src/scheduler-capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAON,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EAEvC,KAAK,aAAa,EAElB,KAAK,sBAAsB,EAG3B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACX,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EAEjB,MAAM,uBAAuB,CAAC;AA0B/B,sGAAgE;AAChE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,kCAAkC,CAG1G;AAsGD,mFAAqC;AACrC,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,0BAA0B,CAclG;AAED,MAAM,WAAW,mCAAmC;IACnD,gHAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,oGAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wFAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,4CAA4C,CAC3D,OAAO,EAAE,mCAAmC,GAC1C,CAAC,GAAG,EAAE,aAAa,KAAK,sBAAsB,CAgGhD","sourcesContent":["/**\n * `agent-forge.agent-task-scheduler@1` 提供方(联网检索设计 §5.6,P1b)。\n *\n * 把已创建的 `SubagentRuntime` 的 one-shot 面经公共能力目录暴露:submit / status /\n * result / cancel / drain(请求与响应 union 见 plugin-sdk 的 agent-task-scheduler 契约)。\n * 不新建第二套调度器、不走 `api.agents.create`:队列、准入、预算、终态与父取消全部\n * 复用 runtime;本模块只做请求校验、metadata 契约键注入和公共结果投影。\n *\n * requester 作用域由提供方绑定:runtime 实例绑定 owner/parentSessionId,本模块把同一\n * 三元组作为 scope 回读的 requester,请求里不收 owner/session 字段(收到也忽略——\n * 作用域不是调用方可选的)。活跃任务走 submit 时保存的 handle 映射(submit 返回的\n * taskId → `SubagentTaskHandleV1`);handle 映射未命中时(如提供方重建后的历史 taskId)\n * 回落 runtime 的范围化读面(peek/result/cancelById,durable 回读含崩溃孤儿自愈)。\n *\n * 错误契约:请求形状错误与本模块的未知 taskId 拒绝以 Error 抛出(经能力目录 reject\n * 冒泡,保留原始 message);runtime 的同步拒绝(预算/队列/失效)与终态 persist 失败\n * 原样冒泡,不吞不改——消费方负责捕获并投影。\n */\n\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_SCHEDULER_CAPABILITY_ID,\n\tAGENT_TASK_SCHEDULER_MAX_TEXT_BYTES,\n\ttype AgentTaskSchedulerResponseV1,\n\ttype AgentTaskSchedulerResultStatusV1,\n\ttype AgentTaskSchedulerResultV1,\n\ttype AgentTaskSchedulerStatusSnapshotV1,\n\tbuildPluginErrorV1,\n\ttype CapabilityAPI,\n\tcreateDisposableRegistration,\n\ttype DisposableRegistration,\n\ttype PluginErrorV1,\n\tparseAgentTaskSchedulerRequestV1,\n} from \"@agent-forge/plugin-sdk\";\nimport type {\n\tSchedulerTaskRecordV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\n\n/**\n * 终态词汇投影(设计 §5.6 状态表):drain_timeout→timed_out、runner_lost→failed。\n * result/drain 投影专用(输入是终态调度记录);在途状态按类型穷举收敛为 failed,\n * 运行路径不可达(parseSchedulerRecord 只接受终态记录)。\n */\nfunction resultStatusOf(status: SubagentRuntimeStatus): AgentTaskSchedulerResultStatusV1 {\n\tswitch (status) {\n\t\tcase \"succeeded\":\n\t\t\treturn \"succeeded\";\n\t\tcase \"failed\":\n\t\t\treturn \"failed\";\n\t\tcase \"cancelled\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"timed_out\":\n\t\tcase \"drain_timeout\":\n\t\t\treturn \"timed_out\";\n\t\tcase \"runner_lost\":\n\t\tcase \"queued\":\n\t\tcase \"admitted\":\n\t\tcase \"running\":\n\t\t\treturn \"failed\";\n\t}\n}\n\n/** status 快照投影:在途原样(queued/admitted/running),终态与 result 同映射。 */\nexport function projectSchedulerStatusV1(status: SubagentRuntimeStatus): AgentTaskSchedulerStatusSnapshotV1 {\n\tif (status === \"queued\" || status === \"admitted\" || status === \"running\") return status;\n\treturn resultStatusOf(status);\n}\n\n/** 文本抽取:content 为字符串或 text 块数组(与 delegate 投影同一形状假设)。 */\nfunction messageText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content === \"\" ? undefined : content;\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst block = item as Record<string, unknown>;\n\t\tif (block.type !== \"text\" || typeof block.text !== \"string\") continue;\n\t\tparts.push(block.text);\n\t}\n\tconst text = parts.join(\"\");\n\treturn text === \"\" ? undefined : text;\n}\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder(\"utf8\", { fatal: false });\n\n/** UTF-8 有界截断:超限时按字节切并在码点边界回退,不产生半字符。 */\nfunction boundText(text: string, maxBytes: number): string {\n\tconst bytes = textEncoder.encode(text);\n\tif (bytes.length <= maxBytes) return text;\n\tlet end = maxBytes;\n\twhile (end > 0 && (bytes[end]! & 0xc0) === 0x80) end -= 1;\n\treturn textDecoder.decode(bytes.subarray(0, end));\n}\n\n/** 最后一条带文本 assistant 消息 → ≤32 KiB 的 text/citation 投影;找不到(或全无文本)省略。 */\nfunction assistantProjection(messages: readonly unknown[]):\n\t| {\n\t\t\treadonly text: string;\n\t\t\treadonly citations?: readonly { readonly url: string; readonly title?: string }[];\n\t }\n\t| undefined {\n\tfor (let index = messages.length - 1; index >= 0; index -= 1) {\n\t\tconst message = messages[index];\n\t\tif (!message || typeof message !== \"object\") continue;\n\t\tconst record = message as Record<string, unknown>;\n\t\tif (record.role !== \"assistant\" && record.type !== \"assistant\") continue;\n\t\tconst text = messageText(record.content);\n\t\tif (text === undefined) continue;\n\t\tconst citations = messageCitations(record.content);\n\t\treturn {\n\t\t\ttext: boundText(text, AGENT_TASK_SCHEDULER_MAX_TEXT_BYTES),\n\t\t\t...(citations === undefined ? {} : { citations }),\n\t\t};\n\t}\n\treturn undefined;\n}\n\nconst MAX_RESULT_CITATIONS = 64;\n\n/**\n * Provider-attested citations ride the text blocks. They are metadata, not\n * evidence text: only http(s) URL and title are carried, de-duplicated in\n * first-occurrence order and bounded.\n */\nfunction messageCitations(content: unknown): readonly { readonly url: string; readonly title?: string }[] | undefined {\n\tif (!Array.isArray(content)) return undefined;\n\tconst citations: Array<{ readonly url: string; readonly title?: string }> = [];\n\tconst seen = new Set<string>();\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst block = item as Record<string, unknown>;\n\t\tif (block.type !== \"text\" || !Array.isArray(block.citations)) continue;\n\t\tfor (const raw of block.citations) {\n\t\t\tif (citations.length >= MAX_RESULT_CITATIONS) break;\n\t\t\tif (!raw || typeof raw !== \"object\") continue;\n\t\t\tconst citation = raw as Record<string, unknown>;\n\t\t\tif (typeof citation.url !== \"string\") continue;\n\t\t\tlet url: URL;\n\t\t\ttry {\n\t\t\t\turl = new URL(citation.url);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") continue;\n\t\t\tconst title = typeof citation.title === \"string\" ? citation.title : undefined;\n\t\t\tconst key = `${citation.url}\\u0000${title ?? \"\"}`;\n\t\t\tif (seen.has(key)) continue;\n\t\t\tseen.add(key);\n\t\t\tcitations.push({ url: citation.url, ...(title === undefined ? {} : { title }) });\n\t\t}\n\t}\n\treturn citations.length === 0 ? undefined : citations;\n}\n\n/**\n * 结构化错误信封:保留调度记录里的 reasonCode/reason(设计 §5.6 \"failed 保留原始\n * 错误\")。两者都缺席(正常成功/无因取消)省略;只有其一时候补另一个。\n */\nfunction errorOf(record: SchedulerTaskRecordV1): PluginErrorV1 | undefined {\n\tif (record.reasonCode === undefined && record.reason === undefined) return undefined;\n\treturn buildPluginErrorV1({\n\t\tversion: 1,\n\t\tcode: record.reasonCode ?? `subagent_${record.status}`,\n\t\tmessage: record.reason ?? record.reasonCode ?? record.status,\n\t});\n}\n\n/** 终态调度记录 → 公共结果投影(冻结、JSON 可序列化)。 */\nexport function projectSchedulerResultV1(record: SchedulerTaskRecordV1): AgentTaskSchedulerResultV1 {\n\tconst projection = assistantProjection(record.messages);\n\tconst error = errorOf(record);\n\treturn Object.freeze({\n\t\tversion: 1 as const,\n\t\ttaskId: record.taskId,\n\t\tstatus: resultStatusOf(record.status),\n\t\t...(projection === undefined ? {} : { text: projection.text }),\n\t\tmessageCount: record.messages.length,\n\t\t...(record.sessionId === \"\" ? undefined : { sessionId: record.sessionId }),\n\t\t...(record.facts === undefined ? {} : { facts: record.facts }),\n\t\t...(projection?.citations === undefined ? {} : { citations: projection.citations }),\n\t\t...(error === undefined ? {} : { error: Object.freeze(error) }),\n\t});\n}\n\nexport interface AgentTaskSchedulerProviderOptionsV1 {\n\t/** 已创建的调度器实例(本提供方不创建、不释放它——生命周期归宿主装配)。 */\n\treadonly runtime: SubagentRuntimeV1;\n\t/** scope 三元组的 owner(与 runtime 绑定值一致;用于范围化回读与文档)。 */\n\treadonly owner: string;\n\t/** scope 三元组的父会话 id;同时作为血缘键注入子任务 metadata。 */\n\treadonly parentSessionId: string;\n}\n\n/**\n * 创建能力提供方工厂:返回的函数把 handler 经 `api.capabilities.provide` 注册为\n * `agent-forge.agent-task-scheduler@1`(manifest 的 `provides` 必须声明同一 id,\n * 能力目录在 provide 时强制校验),返回目录的 DisposableRegistration(dispose 即摘除)。\n */\nexport function createAgentTaskSchedulerCapabilityProviderV1(\n\toptions: AgentTaskSchedulerProviderOptionsV1,\n): (api: CapabilityAPI) => DisposableRegistration {\n\tconst requester = { owner: options.owner, parentSessionId: options.parentSessionId };\n\t/** 本提供方 submit 过的任务(taskId → handle);活跃与已终态都在(handle.status 可读终态)。 */\n\tconst handles = new Map<string, SubagentTaskHandleV1>();\n\n\tconst unknownTask = (taskId: string): Error =>\n\t\tnew Error(`agent-task-scheduler: no task ${taskId} in this provider scope`);\n\n\tconst handler = async (input: unknown): Promise<AgentTaskSchedulerResponseV1> => {\n\t\tconst parsed = parseAgentTaskSchedulerRequestV1(input);\n\t\tif (!parsed.ok) throw new Error(`agent-task-scheduler: ${parsed.message}`);\n\t\tconst request = parsed.value;\n\t\tif (request.action === \"submit\") {\n\t\t\tconst payload = request.request;\n\t\t\t// 契约键注入:profile 从请求字段进 metadata 传输通道;血缘键绑定本提供方父会话。\n\t\t\t// 展开在注入之前——调用方自带的其他 metadata 键全部保留,两个契约键以提供方为准。\n\t\t\tconst handle = await options.runtime.submit({\n\t\t\t\tprompt: payload.prompt,\n\t\t\t\tmetadata: {\n\t\t\t\t\t...payload.metadata,\n\t\t\t\t\t[AGENT_TASK_PARENT_SESSION_KEY]: options.parentSessionId,\n\t\t\t\t\t[AGENT_TASK_CHILD_PROFILE_KEY]: payload.profile,\n\t\t\t\t},\n\t\t\t\t...(payload.deadlineAt === undefined ? {} : { deadlineAt: payload.deadlineAt }),\n\t\t\t});\n\t\t\thandles.set(handle.id, handle);\n\t\t\treturn Object.freeze({ version: 1 as const, action: \"submit\" as const, taskId: handle.id });\n\t\t}\n\t\tconst handle = handles.get(request.taskId);\n\t\tif (request.action === \"status\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\treturn Object.freeze({\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\taction: \"status\" as const,\n\t\t\t\t\tstatus: projectSchedulerStatusV1(handle.status()),\n\t\t\t\t});\n\t\t\t}\n\t\t\t// handle 映射未命中:范围化 peek 兜底(durable 自愈的 runner_lost 历史任务)。\n\t\t\tconst peeked = options.runtime.peek(request.taskId, requester);\n\t\t\treturn Object.freeze({\n\t\t\t\tversion: 1 as const,\n\t\t\t\taction: \"status\" as const,\n\t\t\t\tstatus: peeked === undefined ? \"unknown\" : projectSchedulerStatusV1(peeked.status),\n\t\t\t});\n\t\t}\n\t\tif (request.action === \"result\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\treturn Object.freeze({\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\taction: \"result\" as const,\n\t\t\t\t\tresult: projectSchedulerResultV1(await handle.result()),\n\t\t\t\t});\n\t\t\t}\n\t\t\t// 范围化回读兜底;undefined(不存在/越界同型)映射为不带 result 字段的信封。\n\t\t\tconst record = await options.runtime.result(request.taskId, requester);\n\t\t\treturn Object.freeze({\n\t\t\t\tversion: 1 as const,\n\t\t\t\taction: \"result\" as const,\n\t\t\t\t...(record === undefined ? {} : { result: projectSchedulerResultV1(record) }),\n\t\t\t});\n\t\t}\n\t\tif (request.action === \"cancel\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\tawait handle.cancel(request.reason);\n\t\t\t\treturn Object.freeze({ version: 1 as const, action: \"cancel\" as const });\n\t\t\t}\n\t\t\tconst outcome = await options.runtime.cancelById(request.taskId, requester, request.reason);\n\t\t\tif (outcome.outcome === \"not_found\") throw unknownTask(request.taskId);\n\t\t\treturn Object.freeze({ version: 1 as const, action: \"cancel\" as const });\n\t\t}\n\t\t// drain:只对本院提交过的任务有界等待;外部 taskId 无执行体可等待,明确失败。\n\t\tif (handle === undefined) throw unknownTask(request.taskId);\n\t\tconst record = await handle.drain(request.timeoutMs === undefined ? undefined : { timeoutMs: request.timeoutMs });\n\t\treturn Object.freeze({\n\t\t\tversion: 1 as const,\n\t\t\taction: \"drain\" as const,\n\t\t\tresult: projectSchedulerResultV1(record),\n\t\t});\n\t};\n\n\treturn (api: CapabilityAPI) => {\n\t\tconst registration = api.capabilities.provide<unknown, AgentTaskSchedulerResponseV1>(\n\t\t\t{ id: AGENT_TASK_SCHEDULER_CAPABILITY_ID, version: 1, kind: \"service\" },\n\t\t\thandler,\n\t\t);\n\t\t// 目录的 registration 只摘 handler;这里补一层把 handle 映射一并清空,释放后\n\t\t// provider 实例不保留任何任务句柄(runtime 自身的释放仍归宿主装配)。\n\t\treturn createDisposableRegistration(\n\t\t\t\"plugin-capability\",\n\t\t\t() => {\n\t\t\t\thandles.clear();\n\t\t\t\treturn registration.dispose();\n\t\t\t},\n\t\t\tregistration.id,\n\t\t);\n\t};\n}\n"]}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-forge.agent-task-scheduler@1` 提供方(联网检索设计 §5.6,P1b)。
|
|
3
|
+
*
|
|
4
|
+
* 把已创建的 `SubagentRuntime` 的 one-shot 面经公共能力目录暴露:submit / status /
|
|
5
|
+
* result / cancel / drain(请求与响应 union 见 plugin-sdk 的 agent-task-scheduler 契约)。
|
|
6
|
+
* 不新建第二套调度器、不走 `api.agents.create`:队列、准入、预算、终态与父取消全部
|
|
7
|
+
* 复用 runtime;本模块只做请求校验、metadata 契约键注入和公共结果投影。
|
|
8
|
+
*
|
|
9
|
+
* requester 作用域由提供方绑定:runtime 实例绑定 owner/parentSessionId,本模块把同一
|
|
10
|
+
* 三元组作为 scope 回读的 requester,请求里不收 owner/session 字段(收到也忽略——
|
|
11
|
+
* 作用域不是调用方可选的)。活跃任务走 submit 时保存的 handle 映射(submit 返回的
|
|
12
|
+
* taskId → `SubagentTaskHandleV1`);handle 映射未命中时(如提供方重建后的历史 taskId)
|
|
13
|
+
* 回落 runtime 的范围化读面(peek/result/cancelById,durable 回读含崩溃孤儿自愈)。
|
|
14
|
+
*
|
|
15
|
+
* 错误契约:请求形状错误与本模块的未知 taskId 拒绝以 Error 抛出(经能力目录 reject
|
|
16
|
+
* 冒泡,保留原始 message);runtime 的同步拒绝(预算/队列/失效)与终态 persist 失败
|
|
17
|
+
* 原样冒泡,不吞不改——消费方负责捕获并投影。
|
|
18
|
+
*/
|
|
19
|
+
import { AGENT_TASK_CHILD_PROFILE_KEY, AGENT_TASK_PARENT_SESSION_KEY, AGENT_TASK_SCHEDULER_CAPABILITY_ID, AGENT_TASK_SCHEDULER_MAX_TEXT_BYTES, buildPluginErrorV1, createDisposableRegistration, parseAgentTaskSchedulerRequestV1, } from "@agent-forge/plugin-sdk";
|
|
20
|
+
/**
|
|
21
|
+
* 终态词汇投影(设计 §5.6 状态表):drain_timeout→timed_out、runner_lost→failed。
|
|
22
|
+
* result/drain 投影专用(输入是终态调度记录);在途状态按类型穷举收敛为 failed,
|
|
23
|
+
* 运行路径不可达(parseSchedulerRecord 只接受终态记录)。
|
|
24
|
+
*/
|
|
25
|
+
function resultStatusOf(status) {
|
|
26
|
+
switch (status) {
|
|
27
|
+
case "succeeded":
|
|
28
|
+
return "succeeded";
|
|
29
|
+
case "failed":
|
|
30
|
+
return "failed";
|
|
31
|
+
case "cancelled":
|
|
32
|
+
return "cancelled";
|
|
33
|
+
case "timed_out":
|
|
34
|
+
case "drain_timeout":
|
|
35
|
+
return "timed_out";
|
|
36
|
+
case "runner_lost":
|
|
37
|
+
case "queued":
|
|
38
|
+
case "admitted":
|
|
39
|
+
case "running":
|
|
40
|
+
return "failed";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** status 快照投影:在途原样(queued/admitted/running),终态与 result 同映射。 */
|
|
44
|
+
export function projectSchedulerStatusV1(status) {
|
|
45
|
+
if (status === "queued" || status === "admitted" || status === "running")
|
|
46
|
+
return status;
|
|
47
|
+
return resultStatusOf(status);
|
|
48
|
+
}
|
|
49
|
+
/** 文本抽取:content 为字符串或 text 块数组(与 delegate 投影同一形状假设)。 */
|
|
50
|
+
function messageText(content) {
|
|
51
|
+
if (typeof content === "string")
|
|
52
|
+
return content === "" ? undefined : content;
|
|
53
|
+
if (!Array.isArray(content))
|
|
54
|
+
return undefined;
|
|
55
|
+
const parts = [];
|
|
56
|
+
for (const item of content) {
|
|
57
|
+
if (!item || typeof item !== "object")
|
|
58
|
+
continue;
|
|
59
|
+
const block = item;
|
|
60
|
+
if (block.type !== "text" || typeof block.text !== "string")
|
|
61
|
+
continue;
|
|
62
|
+
parts.push(block.text);
|
|
63
|
+
}
|
|
64
|
+
const text = parts.join("");
|
|
65
|
+
return text === "" ? undefined : text;
|
|
66
|
+
}
|
|
67
|
+
const textEncoder = new TextEncoder();
|
|
68
|
+
const textDecoder = new TextDecoder("utf8", { fatal: false });
|
|
69
|
+
/** UTF-8 有界截断:超限时按字节切并在码点边界回退,不产生半字符。 */
|
|
70
|
+
function boundText(text, maxBytes) {
|
|
71
|
+
const bytes = textEncoder.encode(text);
|
|
72
|
+
if (bytes.length <= maxBytes)
|
|
73
|
+
return text;
|
|
74
|
+
let end = maxBytes;
|
|
75
|
+
while (end > 0 && (bytes[end] & 0xc0) === 0x80)
|
|
76
|
+
end -= 1;
|
|
77
|
+
return textDecoder.decode(bytes.subarray(0, end));
|
|
78
|
+
}
|
|
79
|
+
/** 最后一条带文本 assistant 消息 → ≤32 KiB 的 text/citation 投影;找不到(或全无文本)省略。 */
|
|
80
|
+
function assistantProjection(messages) {
|
|
81
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
82
|
+
const message = messages[index];
|
|
83
|
+
if (!message || typeof message !== "object")
|
|
84
|
+
continue;
|
|
85
|
+
const record = message;
|
|
86
|
+
if (record.role !== "assistant" && record.type !== "assistant")
|
|
87
|
+
continue;
|
|
88
|
+
const text = messageText(record.content);
|
|
89
|
+
if (text === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
const citations = messageCitations(record.content);
|
|
92
|
+
return {
|
|
93
|
+
text: boundText(text, AGENT_TASK_SCHEDULER_MAX_TEXT_BYTES),
|
|
94
|
+
...(citations === undefined ? {} : { citations }),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const MAX_RESULT_CITATIONS = 64;
|
|
100
|
+
/**
|
|
101
|
+
* Provider-attested citations ride the text blocks. They are metadata, not
|
|
102
|
+
* evidence text: only http(s) URL and title are carried, de-duplicated in
|
|
103
|
+
* first-occurrence order and bounded.
|
|
104
|
+
*/
|
|
105
|
+
function messageCitations(content) {
|
|
106
|
+
if (!Array.isArray(content))
|
|
107
|
+
return undefined;
|
|
108
|
+
const citations = [];
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
for (const item of content) {
|
|
111
|
+
if (!item || typeof item !== "object")
|
|
112
|
+
continue;
|
|
113
|
+
const block = item;
|
|
114
|
+
if (block.type !== "text" || !Array.isArray(block.citations))
|
|
115
|
+
continue;
|
|
116
|
+
for (const raw of block.citations) {
|
|
117
|
+
if (citations.length >= MAX_RESULT_CITATIONS)
|
|
118
|
+
break;
|
|
119
|
+
if (!raw || typeof raw !== "object")
|
|
120
|
+
continue;
|
|
121
|
+
const citation = raw;
|
|
122
|
+
if (typeof citation.url !== "string")
|
|
123
|
+
continue;
|
|
124
|
+
let url;
|
|
125
|
+
try {
|
|
126
|
+
url = new URL(citation.url);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
132
|
+
continue;
|
|
133
|
+
const title = typeof citation.title === "string" ? citation.title : undefined;
|
|
134
|
+
const key = `${citation.url}\u0000${title ?? ""}`;
|
|
135
|
+
if (seen.has(key))
|
|
136
|
+
continue;
|
|
137
|
+
seen.add(key);
|
|
138
|
+
citations.push({ url: citation.url, ...(title === undefined ? {} : { title }) });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return citations.length === 0 ? undefined : citations;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 结构化错误信封:保留调度记录里的 reasonCode/reason(设计 §5.6 "failed 保留原始
|
|
145
|
+
* 错误")。两者都缺席(正常成功/无因取消)省略;只有其一时候补另一个。
|
|
146
|
+
*/
|
|
147
|
+
function errorOf(record) {
|
|
148
|
+
if (record.reasonCode === undefined && record.reason === undefined)
|
|
149
|
+
return undefined;
|
|
150
|
+
return buildPluginErrorV1({
|
|
151
|
+
version: 1,
|
|
152
|
+
code: record.reasonCode ?? `subagent_${record.status}`,
|
|
153
|
+
message: record.reason ?? record.reasonCode ?? record.status,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/** 终态调度记录 → 公共结果投影(冻结、JSON 可序列化)。 */
|
|
157
|
+
export function projectSchedulerResultV1(record) {
|
|
158
|
+
const projection = assistantProjection(record.messages);
|
|
159
|
+
const error = errorOf(record);
|
|
160
|
+
return Object.freeze({
|
|
161
|
+
version: 1,
|
|
162
|
+
taskId: record.taskId,
|
|
163
|
+
status: resultStatusOf(record.status),
|
|
164
|
+
...(projection === undefined ? {} : { text: projection.text }),
|
|
165
|
+
messageCount: record.messages.length,
|
|
166
|
+
...(record.sessionId === "" ? undefined : { sessionId: record.sessionId }),
|
|
167
|
+
...(record.facts === undefined ? {} : { facts: record.facts }),
|
|
168
|
+
...(projection?.citations === undefined ? {} : { citations: projection.citations }),
|
|
169
|
+
...(error === undefined ? {} : { error: Object.freeze(error) }),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 创建能力提供方工厂:返回的函数把 handler 经 `api.capabilities.provide` 注册为
|
|
174
|
+
* `agent-forge.agent-task-scheduler@1`(manifest 的 `provides` 必须声明同一 id,
|
|
175
|
+
* 能力目录在 provide 时强制校验),返回目录的 DisposableRegistration(dispose 即摘除)。
|
|
176
|
+
*/
|
|
177
|
+
export function createAgentTaskSchedulerCapabilityProviderV1(options) {
|
|
178
|
+
const requester = { owner: options.owner, parentSessionId: options.parentSessionId };
|
|
179
|
+
/** 本提供方 submit 过的任务(taskId → handle);活跃与已终态都在(handle.status 可读终态)。 */
|
|
180
|
+
const handles = new Map();
|
|
181
|
+
const unknownTask = (taskId) => new Error(`agent-task-scheduler: no task ${taskId} in this provider scope`);
|
|
182
|
+
const handler = async (input) => {
|
|
183
|
+
const parsed = parseAgentTaskSchedulerRequestV1(input);
|
|
184
|
+
if (!parsed.ok)
|
|
185
|
+
throw new Error(`agent-task-scheduler: ${parsed.message}`);
|
|
186
|
+
const request = parsed.value;
|
|
187
|
+
if (request.action === "submit") {
|
|
188
|
+
const payload = request.request;
|
|
189
|
+
// 契约键注入:profile 从请求字段进 metadata 传输通道;血缘键绑定本提供方父会话。
|
|
190
|
+
// 展开在注入之前——调用方自带的其他 metadata 键全部保留,两个契约键以提供方为准。
|
|
191
|
+
const handle = await options.runtime.submit({
|
|
192
|
+
prompt: payload.prompt,
|
|
193
|
+
metadata: {
|
|
194
|
+
...payload.metadata,
|
|
195
|
+
[AGENT_TASK_PARENT_SESSION_KEY]: options.parentSessionId,
|
|
196
|
+
[AGENT_TASK_CHILD_PROFILE_KEY]: payload.profile,
|
|
197
|
+
},
|
|
198
|
+
...(payload.deadlineAt === undefined ? {} : { deadlineAt: payload.deadlineAt }),
|
|
199
|
+
});
|
|
200
|
+
handles.set(handle.id, handle);
|
|
201
|
+
return Object.freeze({ version: 1, action: "submit", taskId: handle.id });
|
|
202
|
+
}
|
|
203
|
+
const handle = handles.get(request.taskId);
|
|
204
|
+
if (request.action === "status") {
|
|
205
|
+
if (handle !== undefined) {
|
|
206
|
+
return Object.freeze({
|
|
207
|
+
version: 1,
|
|
208
|
+
action: "status",
|
|
209
|
+
status: projectSchedulerStatusV1(handle.status()),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// handle 映射未命中:范围化 peek 兜底(durable 自愈的 runner_lost 历史任务)。
|
|
213
|
+
const peeked = options.runtime.peek(request.taskId, requester);
|
|
214
|
+
return Object.freeze({
|
|
215
|
+
version: 1,
|
|
216
|
+
action: "status",
|
|
217
|
+
status: peeked === undefined ? "unknown" : projectSchedulerStatusV1(peeked.status),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (request.action === "result") {
|
|
221
|
+
if (handle !== undefined) {
|
|
222
|
+
return Object.freeze({
|
|
223
|
+
version: 1,
|
|
224
|
+
action: "result",
|
|
225
|
+
result: projectSchedulerResultV1(await handle.result()),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
// 范围化回读兜底;undefined(不存在/越界同型)映射为不带 result 字段的信封。
|
|
229
|
+
const record = await options.runtime.result(request.taskId, requester);
|
|
230
|
+
return Object.freeze({
|
|
231
|
+
version: 1,
|
|
232
|
+
action: "result",
|
|
233
|
+
...(record === undefined ? {} : { result: projectSchedulerResultV1(record) }),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (request.action === "cancel") {
|
|
237
|
+
if (handle !== undefined) {
|
|
238
|
+
await handle.cancel(request.reason);
|
|
239
|
+
return Object.freeze({ version: 1, action: "cancel" });
|
|
240
|
+
}
|
|
241
|
+
const outcome = await options.runtime.cancelById(request.taskId, requester, request.reason);
|
|
242
|
+
if (outcome.outcome === "not_found")
|
|
243
|
+
throw unknownTask(request.taskId);
|
|
244
|
+
return Object.freeze({ version: 1, action: "cancel" });
|
|
245
|
+
}
|
|
246
|
+
// drain:只对本院提交过的任务有界等待;外部 taskId 无执行体可等待,明确失败。
|
|
247
|
+
if (handle === undefined)
|
|
248
|
+
throw unknownTask(request.taskId);
|
|
249
|
+
const record = await handle.drain(request.timeoutMs === undefined ? undefined : { timeoutMs: request.timeoutMs });
|
|
250
|
+
return Object.freeze({
|
|
251
|
+
version: 1,
|
|
252
|
+
action: "drain",
|
|
253
|
+
result: projectSchedulerResultV1(record),
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
return (api) => {
|
|
257
|
+
const registration = api.capabilities.provide({ id: AGENT_TASK_SCHEDULER_CAPABILITY_ID, version: 1, kind: "service" }, handler);
|
|
258
|
+
// 目录的 registration 只摘 handler;这里补一层把 handle 映射一并清空,释放后
|
|
259
|
+
// provider 实例不保留任何任务句柄(runtime 自身的释放仍归宿主装配)。
|
|
260
|
+
return createDisposableRegistration("plugin-capability", () => {
|
|
261
|
+
handles.clear();
|
|
262
|
+
return registration.dispose();
|
|
263
|
+
}, registration.id);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=scheduler-capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduler-capability.js","sourceRoot":"","sources":["../src/scheduler-capability.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `agent-forge.agent-task-scheduler@1` 提供方(联网检索设计 §5.6,P1b)。\n *\n * 把已创建的 `SubagentRuntime` 的 one-shot 面经公共能力目录暴露:submit / status /\n * result / cancel / drain(请求与响应 union 见 plugin-sdk 的 agent-task-scheduler 契约)。\n * 不新建第二套调度器、不走 `api.agents.create`:队列、准入、预算、终态与父取消全部\n * 复用 runtime;本模块只做请求校验、metadata 契约键注入和公共结果投影。\n *\n * requester 作用域由提供方绑定:runtime 实例绑定 owner/parentSessionId,本模块把同一\n * 三元组作为 scope 回读的 requester,请求里不收 owner/session 字段(收到也忽略——\n * 作用域不是调用方可选的)。活跃任务走 submit 时保存的 handle 映射(submit 返回的\n * taskId → `SubagentTaskHandleV1`);handle 映射未命中时(如提供方重建后的历史 taskId)\n * 回落 runtime 的范围化读面(peek/result/cancelById,durable 回读含崩溃孤儿自愈)。\n *\n * 错误契约:请求形状错误与本模块的未知 taskId 拒绝以 Error 抛出(经能力目录 reject\n * 冒泡,保留原始 message);runtime 的同步拒绝(预算/队列/失效)与终态 persist 失败\n * 原样冒泡,不吞不改——消费方负责捕获并投影。\n */\n\nimport {\n\tAGENT_TASK_CHILD_PROFILE_KEY,\n\tAGENT_TASK_PARENT_SESSION_KEY,\n\tAGENT_TASK_SCHEDULER_CAPABILITY_ID,\n\tAGENT_TASK_SCHEDULER_MAX_TEXT_BYTES,\n\ttype AgentTaskSchedulerResponseV1,\n\ttype AgentTaskSchedulerResultStatusV1,\n\ttype AgentTaskSchedulerResultV1,\n\ttype AgentTaskSchedulerStatusSnapshotV1,\n\tbuildPluginErrorV1,\n\ttype CapabilityAPI,\n\tcreateDisposableRegistration,\n\ttype DisposableRegistration,\n\ttype PluginErrorV1,\n\tparseAgentTaskSchedulerRequestV1,\n} from \"@agent-forge/plugin-sdk\";\nimport type {\n\tSchedulerTaskRecordV1,\n\tSubagentRuntimeStatus,\n\tSubagentRuntimeV1,\n\tSubagentTaskHandleV1,\n} from \"./subagent-runtime.ts\";\n\n/**\n * 终态词汇投影(设计 §5.6 状态表):drain_timeout→timed_out、runner_lost→failed。\n * result/drain 投影专用(输入是终态调度记录);在途状态按类型穷举收敛为 failed,\n * 运行路径不可达(parseSchedulerRecord 只接受终态记录)。\n */\nfunction resultStatusOf(status: SubagentRuntimeStatus): AgentTaskSchedulerResultStatusV1 {\n\tswitch (status) {\n\t\tcase \"succeeded\":\n\t\t\treturn \"succeeded\";\n\t\tcase \"failed\":\n\t\t\treturn \"failed\";\n\t\tcase \"cancelled\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"timed_out\":\n\t\tcase \"drain_timeout\":\n\t\t\treturn \"timed_out\";\n\t\tcase \"runner_lost\":\n\t\tcase \"queued\":\n\t\tcase \"admitted\":\n\t\tcase \"running\":\n\t\t\treturn \"failed\";\n\t}\n}\n\n/** status 快照投影:在途原样(queued/admitted/running),终态与 result 同映射。 */\nexport function projectSchedulerStatusV1(status: SubagentRuntimeStatus): AgentTaskSchedulerStatusSnapshotV1 {\n\tif (status === \"queued\" || status === \"admitted\" || status === \"running\") return status;\n\treturn resultStatusOf(status);\n}\n\n/** 文本抽取:content 为字符串或 text 块数组(与 delegate 投影同一形状假设)。 */\nfunction messageText(content: unknown): string | undefined {\n\tif (typeof content === \"string\") return content === \"\" ? undefined : content;\n\tif (!Array.isArray(content)) return undefined;\n\tconst parts: string[] = [];\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst block = item as Record<string, unknown>;\n\t\tif (block.type !== \"text\" || typeof block.text !== \"string\") continue;\n\t\tparts.push(block.text);\n\t}\n\tconst text = parts.join(\"\");\n\treturn text === \"\" ? undefined : text;\n}\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder(\"utf8\", { fatal: false });\n\n/** UTF-8 有界截断:超限时按字节切并在码点边界回退,不产生半字符。 */\nfunction boundText(text: string, maxBytes: number): string {\n\tconst bytes = textEncoder.encode(text);\n\tif (bytes.length <= maxBytes) return text;\n\tlet end = maxBytes;\n\twhile (end > 0 && (bytes[end]! & 0xc0) === 0x80) end -= 1;\n\treturn textDecoder.decode(bytes.subarray(0, end));\n}\n\n/** 最后一条带文本 assistant 消息 → ≤32 KiB 的 text/citation 投影;找不到(或全无文本)省略。 */\nfunction assistantProjection(messages: readonly unknown[]):\n\t| {\n\t\t\treadonly text: string;\n\t\t\treadonly citations?: readonly { readonly url: string; readonly title?: string }[];\n\t }\n\t| undefined {\n\tfor (let index = messages.length - 1; index >= 0; index -= 1) {\n\t\tconst message = messages[index];\n\t\tif (!message || typeof message !== \"object\") continue;\n\t\tconst record = message as Record<string, unknown>;\n\t\tif (record.role !== \"assistant\" && record.type !== \"assistant\") continue;\n\t\tconst text = messageText(record.content);\n\t\tif (text === undefined) continue;\n\t\tconst citations = messageCitations(record.content);\n\t\treturn {\n\t\t\ttext: boundText(text, AGENT_TASK_SCHEDULER_MAX_TEXT_BYTES),\n\t\t\t...(citations === undefined ? {} : { citations }),\n\t\t};\n\t}\n\treturn undefined;\n}\n\nconst MAX_RESULT_CITATIONS = 64;\n\n/**\n * Provider-attested citations ride the text blocks. They are metadata, not\n * evidence text: only http(s) URL and title are carried, de-duplicated in\n * first-occurrence order and bounded.\n */\nfunction messageCitations(content: unknown): readonly { readonly url: string; readonly title?: string }[] | undefined {\n\tif (!Array.isArray(content)) return undefined;\n\tconst citations: Array<{ readonly url: string; readonly title?: string }> = [];\n\tconst seen = new Set<string>();\n\tfor (const item of content) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst block = item as Record<string, unknown>;\n\t\tif (block.type !== \"text\" || !Array.isArray(block.citations)) continue;\n\t\tfor (const raw of block.citations) {\n\t\t\tif (citations.length >= MAX_RESULT_CITATIONS) break;\n\t\t\tif (!raw || typeof raw !== \"object\") continue;\n\t\t\tconst citation = raw as Record<string, unknown>;\n\t\t\tif (typeof citation.url !== \"string\") continue;\n\t\t\tlet url: URL;\n\t\t\ttry {\n\t\t\t\turl = new URL(citation.url);\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") continue;\n\t\t\tconst title = typeof citation.title === \"string\" ? citation.title : undefined;\n\t\t\tconst key = `${citation.url}\\u0000${title ?? \"\"}`;\n\t\t\tif (seen.has(key)) continue;\n\t\t\tseen.add(key);\n\t\t\tcitations.push({ url: citation.url, ...(title === undefined ? {} : { title }) });\n\t\t}\n\t}\n\treturn citations.length === 0 ? undefined : citations;\n}\n\n/**\n * 结构化错误信封:保留调度记录里的 reasonCode/reason(设计 §5.6 \"failed 保留原始\n * 错误\")。两者都缺席(正常成功/无因取消)省略;只有其一时候补另一个。\n */\nfunction errorOf(record: SchedulerTaskRecordV1): PluginErrorV1 | undefined {\n\tif (record.reasonCode === undefined && record.reason === undefined) return undefined;\n\treturn buildPluginErrorV1({\n\t\tversion: 1,\n\t\tcode: record.reasonCode ?? `subagent_${record.status}`,\n\t\tmessage: record.reason ?? record.reasonCode ?? record.status,\n\t});\n}\n\n/** 终态调度记录 → 公共结果投影(冻结、JSON 可序列化)。 */\nexport function projectSchedulerResultV1(record: SchedulerTaskRecordV1): AgentTaskSchedulerResultV1 {\n\tconst projection = assistantProjection(record.messages);\n\tconst error = errorOf(record);\n\treturn Object.freeze({\n\t\tversion: 1 as const,\n\t\ttaskId: record.taskId,\n\t\tstatus: resultStatusOf(record.status),\n\t\t...(projection === undefined ? {} : { text: projection.text }),\n\t\tmessageCount: record.messages.length,\n\t\t...(record.sessionId === \"\" ? undefined : { sessionId: record.sessionId }),\n\t\t...(record.facts === undefined ? {} : { facts: record.facts }),\n\t\t...(projection?.citations === undefined ? {} : { citations: projection.citations }),\n\t\t...(error === undefined ? {} : { error: Object.freeze(error) }),\n\t});\n}\n\nexport interface AgentTaskSchedulerProviderOptionsV1 {\n\t/** 已创建的调度器实例(本提供方不创建、不释放它——生命周期归宿主装配)。 */\n\treadonly runtime: SubagentRuntimeV1;\n\t/** scope 三元组的 owner(与 runtime 绑定值一致;用于范围化回读与文档)。 */\n\treadonly owner: string;\n\t/** scope 三元组的父会话 id;同时作为血缘键注入子任务 metadata。 */\n\treadonly parentSessionId: string;\n}\n\n/**\n * 创建能力提供方工厂:返回的函数把 handler 经 `api.capabilities.provide` 注册为\n * `agent-forge.agent-task-scheduler@1`(manifest 的 `provides` 必须声明同一 id,\n * 能力目录在 provide 时强制校验),返回目录的 DisposableRegistration(dispose 即摘除)。\n */\nexport function createAgentTaskSchedulerCapabilityProviderV1(\n\toptions: AgentTaskSchedulerProviderOptionsV1,\n): (api: CapabilityAPI) => DisposableRegistration {\n\tconst requester = { owner: options.owner, parentSessionId: options.parentSessionId };\n\t/** 本提供方 submit 过的任务(taskId → handle);活跃与已终态都在(handle.status 可读终态)。 */\n\tconst handles = new Map<string, SubagentTaskHandleV1>();\n\n\tconst unknownTask = (taskId: string): Error =>\n\t\tnew Error(`agent-task-scheduler: no task ${taskId} in this provider scope`);\n\n\tconst handler = async (input: unknown): Promise<AgentTaskSchedulerResponseV1> => {\n\t\tconst parsed = parseAgentTaskSchedulerRequestV1(input);\n\t\tif (!parsed.ok) throw new Error(`agent-task-scheduler: ${parsed.message}`);\n\t\tconst request = parsed.value;\n\t\tif (request.action === \"submit\") {\n\t\t\tconst payload = request.request;\n\t\t\t// 契约键注入:profile 从请求字段进 metadata 传输通道;血缘键绑定本提供方父会话。\n\t\t\t// 展开在注入之前——调用方自带的其他 metadata 键全部保留,两个契约键以提供方为准。\n\t\t\tconst handle = await options.runtime.submit({\n\t\t\t\tprompt: payload.prompt,\n\t\t\t\tmetadata: {\n\t\t\t\t\t...payload.metadata,\n\t\t\t\t\t[AGENT_TASK_PARENT_SESSION_KEY]: options.parentSessionId,\n\t\t\t\t\t[AGENT_TASK_CHILD_PROFILE_KEY]: payload.profile,\n\t\t\t\t},\n\t\t\t\t...(payload.deadlineAt === undefined ? {} : { deadlineAt: payload.deadlineAt }),\n\t\t\t});\n\t\t\thandles.set(handle.id, handle);\n\t\t\treturn Object.freeze({ version: 1 as const, action: \"submit\" as const, taskId: handle.id });\n\t\t}\n\t\tconst handle = handles.get(request.taskId);\n\t\tif (request.action === \"status\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\treturn Object.freeze({\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\taction: \"status\" as const,\n\t\t\t\t\tstatus: projectSchedulerStatusV1(handle.status()),\n\t\t\t\t});\n\t\t\t}\n\t\t\t// handle 映射未命中:范围化 peek 兜底(durable 自愈的 runner_lost 历史任务)。\n\t\t\tconst peeked = options.runtime.peek(request.taskId, requester);\n\t\t\treturn Object.freeze({\n\t\t\t\tversion: 1 as const,\n\t\t\t\taction: \"status\" as const,\n\t\t\t\tstatus: peeked === undefined ? \"unknown\" : projectSchedulerStatusV1(peeked.status),\n\t\t\t});\n\t\t}\n\t\tif (request.action === \"result\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\treturn Object.freeze({\n\t\t\t\t\tversion: 1 as const,\n\t\t\t\t\taction: \"result\" as const,\n\t\t\t\t\tresult: projectSchedulerResultV1(await handle.result()),\n\t\t\t\t});\n\t\t\t}\n\t\t\t// 范围化回读兜底;undefined(不存在/越界同型)映射为不带 result 字段的信封。\n\t\t\tconst record = await options.runtime.result(request.taskId, requester);\n\t\t\treturn Object.freeze({\n\t\t\t\tversion: 1 as const,\n\t\t\t\taction: \"result\" as const,\n\t\t\t\t...(record === undefined ? {} : { result: projectSchedulerResultV1(record) }),\n\t\t\t});\n\t\t}\n\t\tif (request.action === \"cancel\") {\n\t\t\tif (handle !== undefined) {\n\t\t\t\tawait handle.cancel(request.reason);\n\t\t\t\treturn Object.freeze({ version: 1 as const, action: \"cancel\" as const });\n\t\t\t}\n\t\t\tconst outcome = await options.runtime.cancelById(request.taskId, requester, request.reason);\n\t\t\tif (outcome.outcome === \"not_found\") throw unknownTask(request.taskId);\n\t\t\treturn Object.freeze({ version: 1 as const, action: \"cancel\" as const });\n\t\t}\n\t\t// drain:只对本院提交过的任务有界等待;外部 taskId 无执行体可等待,明确失败。\n\t\tif (handle === undefined) throw unknownTask(request.taskId);\n\t\tconst record = await handle.drain(request.timeoutMs === undefined ? undefined : { timeoutMs: request.timeoutMs });\n\t\treturn Object.freeze({\n\t\t\tversion: 1 as const,\n\t\t\taction: \"drain\" as const,\n\t\t\tresult: projectSchedulerResultV1(record),\n\t\t});\n\t};\n\n\treturn (api: CapabilityAPI) => {\n\t\tconst registration = api.capabilities.provide<unknown, AgentTaskSchedulerResponseV1>(\n\t\t\t{ id: AGENT_TASK_SCHEDULER_CAPABILITY_ID, version: 1, kind: \"service\" },\n\t\t\thandler,\n\t\t);\n\t\t// 目录的 registration 只摘 handler;这里补一层把 handle 映射一并清空,释放后\n\t\t// provider 实例不保留任何任务句柄(runtime 自身的释放仍归宿主装配)。\n\t\treturn createDisposableRegistration(\n\t\t\t\"plugin-capability\",\n\t\t\t() => {\n\t\t\t\thandles.clear();\n\t\t\t\treturn registration.dispose();\n\t\t\t},\n\t\t\tregistration.id,\n\t\t);\n\t};\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { AgentTaskAdapter, DurableServiceV1, PluginConfigValue } from "@agent-forge/plugin-sdk";
|
|
1
|
+
import type { AgentTaskAdapter, AgentTaskSchedulerFactsV1, DurableServiceV1, PluginConfigValue } from "@agent-forge/plugin-sdk";
|
|
2
2
|
import { type AgentTaskRegistryV1 } from "./multi-agent-tasks.ts";
|
|
3
3
|
/** 调度器权威状态(§4.3);其余词汇(DTO/registry/Operation)都是它的投影。 */
|
|
4
4
|
export type SubagentRuntimeStatus = "queued" | "admitted" | "running" | "succeeded" | "failed" | "cancelled" | "timed_out" | "drain_timeout" | "runner_lost";
|
|
5
5
|
export interface SubagentRuntimeLimitsV1 {
|
|
6
|
-
/** 同时运行的最大子代理数(admission gate 容量)。默认
|
|
6
|
+
/** 同时运行的最大子代理数(admission gate 容量)。默认 12(DEFAULT_SUBAGENT_LIMITS)。 */
|
|
7
7
|
maxConcurrentSubagents?: number;
|
|
8
8
|
/** 等待准入的最大排队深度;超出即 submit 结构化失败。默认 200。 */
|
|
9
9
|
maxQueueDepth?: number;
|
|
@@ -18,7 +18,7 @@ export interface SubagentRuntimeLimitsV1 {
|
|
|
18
18
|
/** 取消/drain 的有界等待时长;超时终态 drain_timeout。默认 30000。 */
|
|
19
19
|
drainTimeoutMs?: number;
|
|
20
20
|
/**
|
|
21
|
-
* 终态记录(`result()` 回读的权威存储)保留条数上限,默认
|
|
21
|
+
* 终态记录(`result()` 回读的权威存储)保留条数上限,默认 512。超出按落库顺序淘汰
|
|
22
22
|
* 最旧记录(被淘汰的 taskId 回读为 undefined)——长会话高频委派不能无界增长。
|
|
23
23
|
*/
|
|
24
24
|
maxRetainedRecords?: number;
|
|
@@ -50,6 +50,20 @@ export interface SchedulerTaskRecordV1 {
|
|
|
50
50
|
readonly sessionId: string;
|
|
51
51
|
/** 已按预算截断的有界消息快照。 */
|
|
52
52
|
readonly messages: readonly unknown[];
|
|
53
|
+
/**
|
|
54
|
+
* 子会话创建后的可核验事实(联网检索设计 §5.6,P1b):allocate 路径在 `adapter.create`
|
|
55
|
+
* 成功后读取(getActiveTools/getModel + child profile 的 mode);宿主不暴露
|
|
56
|
+
* `getActiveTools` 或读取失败时整个 facts 省略——消费方(research 验收)据此失败,
|
|
57
|
+
* 绝不伪造。对象冻结、JSON 可序列化。
|
|
58
|
+
*/
|
|
59
|
+
readonly facts?: AgentTaskSchedulerFactsV1;
|
|
60
|
+
/**
|
|
61
|
+
* 任务层结果:仅任务级拒绝时出现——子代理活着但声明不做该任务,结算仍是调度终态
|
|
62
|
+
* `succeeded`,"做完"与"拒做"由本字段区分。字面量封闭联合,未来可扩。
|
|
63
|
+
*/
|
|
64
|
+
readonly taskOutcome?: "refused";
|
|
65
|
+
/** 拒绝原因;仅与 taskOutcome 同时出现。 */
|
|
66
|
+
readonly refusalReason?: string;
|
|
53
67
|
/** artifact 分页保留字段:本切片不产出。 */
|
|
54
68
|
readonly outputArtifactRef?: string;
|
|
55
69
|
readonly messagesArtifactRef?: string;
|