@geminixiang/mikan 1.0.0-beta.20 → 1.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +18 -11
  3. package/dist/adapters/buffered-responder.d.ts +60 -0
  4. package/dist/adapters/buffered-responder.d.ts.map +1 -0
  5. package/dist/adapters/buffered-responder.js +201 -0
  6. package/dist/adapters/buffered-responder.js.map +1 -0
  7. package/dist/adapters/discord/context.d.ts.map +1 -1
  8. package/dist/adapters/discord/context.js +42 -177
  9. package/dist/adapters/discord/context.js.map +1 -1
  10. package/dist/adapters/github/bot.d.ts +14 -76
  11. package/dist/adapters/github/bot.d.ts.map +1 -1
  12. package/dist/adapters/github/bot.js +52 -443
  13. package/dist/adapters/github/bot.js.map +1 -1
  14. package/dist/adapters/github/client.d.ts +4 -0
  15. package/dist/adapters/github/client.d.ts.map +1 -1
  16. package/dist/adapters/github/client.js +5 -0
  17. package/dist/adapters/github/client.js.map +1 -1
  18. package/dist/adapters/github/context.d.ts.map +1 -1
  19. package/dist/adapters/github/context.js +32 -104
  20. package/dist/adapters/github/context.js.map +1 -1
  21. package/dist/adapters/github/github-ops.d.ts +90 -0
  22. package/dist/adapters/github/github-ops.d.ts.map +1 -0
  23. package/dist/adapters/github/github-ops.js +405 -0
  24. package/dist/adapters/github/github-ops.js.map +1 -0
  25. package/dist/adapters/github/repo.d.ts +2 -0
  26. package/dist/adapters/github/repo.d.ts.map +1 -1
  27. package/dist/adapters/github/repo.js +5 -0
  28. package/dist/adapters/github/repo.js.map +1 -1
  29. package/dist/adapters/github/tools/checks.d.ts.map +1 -1
  30. package/dist/adapters/github/tools/checks.js +6 -17
  31. package/dist/adapters/github/tools/checks.js.map +1 -1
  32. package/dist/adapters/github/tools/issue.d.ts.map +1 -1
  33. package/dist/adapters/github/tools/issue.js +6 -17
  34. package/dist/adapters/github/tools/issue.js.map +1 -1
  35. package/dist/adapters/github/tools/pr.d.ts.map +1 -1
  36. package/dist/adapters/github/tools/pr.js +6 -17
  37. package/dist/adapters/github/tools/pr.js.map +1 -1
  38. package/dist/adapters/github/tools/read.d.ts.map +1 -1
  39. package/dist/adapters/github/tools/read.js +6 -17
  40. package/dist/adapters/github/tools/read.js.map +1 -1
  41. package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
  42. package/dist/adapters/github/tools/review-reply.js +6 -17
  43. package/dist/adapters/github/tools/review-reply.js.map +1 -1
  44. package/dist/adapters/github/tools/sync.d.ts.map +1 -1
  45. package/dist/adapters/github/tools/sync.js +6 -17
  46. package/dist/adapters/github/tools/sync.js.map +1 -1
  47. package/dist/adapters/slack/bot.js +1 -1
  48. package/dist/adapters/slack/bot.js.map +1 -1
  49. package/dist/adapters/telegram/context.d.ts.map +1 -1
  50. package/dist/adapters/telegram/context.js +33 -151
  51. package/dist/adapters/telegram/context.js.map +1 -1
  52. package/dist/agent.d.ts +0 -1
  53. package/dist/agent.d.ts.map +1 -1
  54. package/dist/agent.js +28 -32
  55. package/dist/agent.js.map +1 -1
  56. package/dist/cli/arg-grammar.d.ts +25 -0
  57. package/dist/cli/arg-grammar.d.ts.map +1 -0
  58. package/dist/cli/arg-grammar.js +59 -0
  59. package/dist/cli/arg-grammar.js.map +1 -0
  60. package/dist/cli/boot.d.ts +16 -0
  61. package/dist/cli/boot.d.ts.map +1 -0
  62. package/dist/cli/boot.js +119 -0
  63. package/dist/cli/boot.js.map +1 -0
  64. package/dist/cli/ext.js +9 -11
  65. package/dist/cli/ext.js.map +1 -1
  66. package/dist/commands/extensions.js +2 -2
  67. package/dist/commands/extensions.js.map +1 -1
  68. package/dist/commands/login.d.ts.map +1 -1
  69. package/dist/commands/login.js +5 -2
  70. package/dist/commands/login.js.map +1 -1
  71. package/dist/commands/model.d.ts.map +1 -1
  72. package/dist/commands/model.js +8 -8
  73. package/dist/commands/model.js.map +1 -1
  74. package/dist/commands/sandbox.d.ts.map +1 -1
  75. package/dist/commands/sandbox.js +7 -5
  76. package/dist/commands/sandbox.js.map +1 -1
  77. package/dist/config.d.ts +0 -2
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/config.js +8 -41
  80. package/dist/config.js.map +1 -1
  81. package/dist/env-manifest.d.ts +35 -0
  82. package/dist/env-manifest.d.ts.map +1 -0
  83. package/dist/env-manifest.js +225 -0
  84. package/dist/env-manifest.js.map +1 -0
  85. package/dist/events.d.ts +0 -10
  86. package/dist/events.d.ts.map +1 -1
  87. package/dist/events.js +9 -82
  88. package/dist/events.js.map +1 -1
  89. package/dist/execution-resolver.d.ts +1 -0
  90. package/dist/execution-resolver.d.ts.map +1 -1
  91. package/dist/execution-resolver.js +33 -36
  92. package/dist/execution-resolver.js.map +1 -1
  93. package/dist/harness/event-format.d.ts +66 -0
  94. package/dist/harness/event-format.d.ts.map +1 -0
  95. package/dist/harness/event-format.js +112 -0
  96. package/dist/harness/event-format.js.map +1 -0
  97. package/dist/harness/extensions/loader.d.ts +9 -6
  98. package/dist/harness/extensions/loader.d.ts.map +1 -1
  99. package/dist/harness/extensions/loader.js +35 -50
  100. package/dist/harness/extensions/loader.js.map +1 -1
  101. package/dist/harness/extensions/types.d.ts +10 -14
  102. package/dist/harness/extensions/types.d.ts.map +1 -1
  103. package/dist/harness/extensions/types.js.map +1 -1
  104. package/dist/harness/index.d.ts +1 -0
  105. package/dist/harness/index.d.ts.map +1 -1
  106. package/dist/harness/index.js +1 -0
  107. package/dist/harness/index.js.map +1 -1
  108. package/dist/harness/runner.d.ts +16 -0
  109. package/dist/harness/runner.d.ts.map +1 -1
  110. package/dist/harness/runner.js +27 -1
  111. package/dist/harness/runner.js.map +1 -1
  112. package/dist/harness/subagent-runner.d.ts +18 -1
  113. package/dist/harness/subagent-runner.d.ts.map +1 -1
  114. package/dist/harness/subagent-runner.js +62 -30
  115. package/dist/harness/subagent-runner.js.map +1 -1
  116. package/dist/index.d.ts +2 -2
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +2 -2
  119. package/dist/index.js.map +1 -1
  120. package/dist/main.js +69 -121
  121. package/dist/main.js.map +1 -1
  122. package/dist/observability/instrument.js +6 -4
  123. package/dist/observability/instrument.js.map +1 -1
  124. package/dist/observability/sentry.d.ts.map +1 -1
  125. package/dist/observability/sentry.js +3 -2
  126. package/dist/observability/sentry.js.map +1 -1
  127. package/dist/runtime/conversation-runtime.js +13 -3
  128. package/dist/runtime/conversation-runtime.js.map +1 -1
  129. package/dist/runtime/types.d.ts +4 -0
  130. package/dist/runtime/types.d.ts.map +1 -1
  131. package/dist/runtime/types.js.map +1 -1
  132. package/dist/sandbox/cloudflare.d.ts +1 -0
  133. package/dist/sandbox/cloudflare.d.ts.map +1 -1
  134. package/dist/sandbox/cloudflare.js +4 -1
  135. package/dist/sandbox/cloudflare.js.map +1 -1
  136. package/dist/sandbox/container.d.ts +1 -0
  137. package/dist/sandbox/container.d.ts.map +1 -1
  138. package/dist/sandbox/container.js +4 -1
  139. package/dist/sandbox/container.js.map +1 -1
  140. package/dist/sandbox/firecracker.d.ts +1 -0
  141. package/dist/sandbox/firecracker.d.ts.map +1 -1
  142. package/dist/sandbox/firecracker.js +4 -1
  143. package/dist/sandbox/firecracker.js.map +1 -1
  144. package/dist/sandbox/gondolin-bootstrap.d.ts +26 -0
  145. package/dist/sandbox/gondolin-bootstrap.d.ts.map +1 -0
  146. package/dist/sandbox/gondolin-bootstrap.js +27 -0
  147. package/dist/sandbox/gondolin-bootstrap.js.map +1 -0
  148. package/dist/sandbox/gondolin-contract.d.ts +125 -0
  149. package/dist/sandbox/gondolin-contract.d.ts.map +1 -0
  150. package/dist/sandbox/gondolin-contract.js +155 -0
  151. package/dist/sandbox/gondolin-contract.js.map +1 -0
  152. package/dist/sandbox/gondolin-fleet.d.ts +1 -1
  153. package/dist/sandbox/gondolin-fleet.d.ts.map +1 -1
  154. package/dist/sandbox/gondolin-fleet.js +1 -1
  155. package/dist/sandbox/gondolin-fleet.js.map +1 -1
  156. package/dist/sandbox/gondolin-gateway.d.ts +1 -0
  157. package/dist/sandbox/gondolin-gateway.d.ts.map +1 -1
  158. package/dist/sandbox/gondolin-gateway.js +13 -6
  159. package/dist/sandbox/gondolin-gateway.js.map +1 -1
  160. package/dist/sandbox/gondolin-inventory.d.ts +2 -16
  161. package/dist/sandbox/gondolin-inventory.d.ts.map +1 -1
  162. package/dist/sandbox/gondolin-inventory.js +2 -12
  163. package/dist/sandbox/gondolin-inventory.js.map +1 -1
  164. package/dist/sandbox/gondolin-placement.d.ts +0 -2
  165. package/dist/sandbox/gondolin-placement.d.ts.map +1 -1
  166. package/dist/sandbox/gondolin-placement.js +0 -6
  167. package/dist/sandbox/gondolin-placement.js.map +1 -1
  168. package/dist/sandbox/gondolin-recovery.d.ts +33 -0
  169. package/dist/sandbox/gondolin-recovery.d.ts.map +1 -0
  170. package/dist/sandbox/gondolin-recovery.js +39 -0
  171. package/dist/sandbox/gondolin-recovery.js.map +1 -0
  172. package/dist/sandbox/gondolin-remote.d.ts +2 -5
  173. package/dist/sandbox/gondolin-remote.d.ts.map +1 -1
  174. package/dist/sandbox/gondolin-remote.js +12 -39
  175. package/dist/sandbox/gondolin-remote.js.map +1 -1
  176. package/dist/sandbox/gondolin-worker-client.d.ts +8 -12
  177. package/dist/sandbox/gondolin-worker-client.d.ts.map +1 -1
  178. package/dist/sandbox/gondolin-worker-client.js +13 -15
  179. package/dist/sandbox/gondolin-worker-client.js.map +1 -1
  180. package/dist/sandbox/gondolin-worker.d.ts +2 -40
  181. package/dist/sandbox/gondolin-worker.d.ts.map +1 -1
  182. package/dist/sandbox/gondolin-worker.js.map +1 -1
  183. package/dist/sandbox/gondolin.d.ts +1 -0
  184. package/dist/sandbox/gondolin.d.ts.map +1 -1
  185. package/dist/sandbox/gondolin.js +8 -4
  186. package/dist/sandbox/gondolin.js.map +1 -1
  187. package/dist/sandbox/host.d.ts +1 -0
  188. package/dist/sandbox/host.d.ts.map +1 -1
  189. package/dist/sandbox/host.js +3 -0
  190. package/dist/sandbox/host.js.map +1 -1
  191. package/dist/sandbox/index.d.ts +9 -1
  192. package/dist/sandbox/index.d.ts.map +1 -1
  193. package/dist/sandbox/index.js +14 -0
  194. package/dist/sandbox/index.js.map +1 -1
  195. package/dist/sandbox/types.d.ts +5 -0
  196. package/dist/sandbox/types.d.ts.map +1 -1
  197. package/dist/sandbox/types.js.map +1 -1
  198. package/dist/sandbox/utils.d.ts +1 -0
  199. package/dist/sandbox/utils.d.ts.map +1 -1
  200. package/dist/sandbox/utils.js +5 -2
  201. package/dist/sandbox/utils.js.map +1 -1
  202. package/dist/sessions/chat-history-sync.d.ts +32 -0
  203. package/dist/sessions/chat-history-sync.d.ts.map +1 -0
  204. package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +24 -83
  205. package/dist/sessions/chat-history-sync.js.map +1 -0
  206. package/dist/sessions/conversation-log.d.ts +13 -0
  207. package/dist/sessions/conversation-log.d.ts.map +1 -0
  208. package/dist/sessions/conversation-log.js +47 -0
  209. package/dist/sessions/conversation-log.js.map +1 -0
  210. package/dist/sessions/rotation.d.ts +2 -0
  211. package/dist/sessions/rotation.d.ts.map +1 -0
  212. package/dist/sessions/rotation.js +39 -0
  213. package/dist/sessions/rotation.js.map +1 -0
  214. package/dist/sessions/store.d.ts.map +1 -1
  215. package/dist/sessions/store.js +4 -10
  216. package/dist/sessions/store.js.map +1 -1
  217. package/dist/sessions/types.d.ts +2 -2
  218. package/dist/sessions/types.d.ts.map +1 -1
  219. package/dist/sessions/types.js.map +1 -1
  220. package/dist/settings-mutation.d.ts +23 -0
  221. package/dist/settings-mutation.d.ts.map +1 -0
  222. package/dist/settings-mutation.js +42 -0
  223. package/dist/settings-mutation.js.map +1 -0
  224. package/dist/tools/event.d.ts.map +1 -1
  225. package/dist/tools/event.js +27 -46
  226. package/dist/tools/event.js.map +1 -1
  227. package/dist/tools/host-fn-tool.d.ts +21 -0
  228. package/dist/tools/host-fn-tool.d.ts.map +1 -0
  229. package/dist/tools/host-fn-tool.js +32 -0
  230. package/dist/tools/host-fn-tool.js.map +1 -0
  231. package/dist/tools/index.d.ts +1 -0
  232. package/dist/tools/index.d.ts.map +1 -1
  233. package/dist/tools/index.js +1 -0
  234. package/dist/tools/index.js.map +1 -1
  235. package/dist/tools/react.d.ts.map +1 -1
  236. package/dist/tools/react.js +6 -17
  237. package/dist/tools/react.js.map +1 -1
  238. package/dist/tools/read.d.ts.map +1 -1
  239. package/dist/tools/read.js +7 -26
  240. package/dist/tools/read.js.map +1 -1
  241. package/dist/tools/sandbox.d.ts.map +1 -1
  242. package/dist/tools/sandbox.js +5 -2
  243. package/dist/tools/sandbox.js.map +1 -1
  244. package/dist/tools/subagent-slots.d.ts +28 -0
  245. package/dist/tools/subagent-slots.d.ts.map +1 -0
  246. package/dist/tools/subagent-slots.js +57 -0
  247. package/dist/tools/subagent-slots.js.map +1 -0
  248. package/dist/tools/subagent.d.ts +7 -2
  249. package/dist/tools/subagent.d.ts.map +1 -1
  250. package/dist/tools/subagent.js +160 -111
  251. package/dist/tools/subagent.js.map +1 -1
  252. package/dist/tools/types.d.ts +10 -9
  253. package/dist/tools/types.d.ts.map +1 -1
  254. package/dist/tools/types.js.map +1 -1
  255. package/dist/types.d.ts +5 -24
  256. package/dist/types.d.ts.map +1 -1
  257. package/dist/types.js.map +1 -1
  258. package/dist/utils/date.d.ts +1 -1
  259. package/dist/utils/date.js +1 -1
  260. package/dist/utils/date.js.map +1 -1
  261. package/dist/vault/disabled.d.ts.map +1 -1
  262. package/dist/vault/disabled.js +0 -1
  263. package/dist/vault/disabled.js.map +1 -1
  264. package/dist/vault/index.d.ts +0 -2
  265. package/dist/vault/index.d.ts.map +1 -1
  266. package/dist/vault/index.js +0 -10
  267. package/dist/vault/index.js.map +1 -1
  268. package/dist/vault/injection.d.ts +20 -0
  269. package/dist/vault/injection.d.ts.map +1 -0
  270. package/dist/vault/injection.js +27 -0
  271. package/dist/vault/injection.js.map +1 -0
  272. package/dist/vault/types.d.ts +0 -2
  273. package/dist/vault/types.d.ts.map +1 -1
  274. package/dist/vault/types.js.map +1 -1
  275. package/dist/web/admin/portal.d.ts +3 -3
  276. package/dist/web/admin/portal.d.ts.map +1 -1
  277. package/dist/web/admin/portal.js +41 -39
  278. package/dist/web/admin/portal.js.map +1 -1
  279. package/dist/web/admin/types.d.ts +3 -0
  280. package/dist/web/admin/types.d.ts.map +1 -1
  281. package/dist/web/admin/types.js.map +1 -1
  282. package/dist/web/agent-events/portal.d.ts.map +1 -1
  283. package/dist/web/agent-events/portal.js +2 -1
  284. package/dist/web/agent-events/portal.js.map +1 -1
  285. package/package.json +1 -1
  286. package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
  287. package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
  288. package/dist/sessions/agent-memory-file-manager.js.map +0 -1
  289. package/dist/vault/routing.d.ts +0 -4
  290. package/dist/vault/routing.d.ts.map +0 -1
  291. package/dist/vault/routing.js +0 -6
  292. package/dist/vault/routing.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/tools/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { SandboxConfig } from \"../sandbox/index.js\";\nimport type { ResourceLimits, SandboxResourceController } from \"../types.js\";\nimport { resolveActorVaultKey } from \"../vault/routing.js\";\n\nconst sandboxSchema = Type.Object({\n action: Type.Union([Type.Literal(\"status\"), Type.Literal(\"set\")], {\n description: \"Use status to inspect current limits, or set to apply temporary limits.\",\n }),\n cpus: Type.Optional(\n Type.String({\n description: \"CPU limit for action=set, for example '0.5', '1', or '2'.\",\n }),\n ),\n memory: Type.Optional(\n Type.String({\n description: \"Docker memory limit for action=set, for example '512m', '1g', or '4g'.\",\n }),\n ),\n});\n\ntype SandboxToolParams = {\n action: \"status\" | \"set\";\n cpus?: string;\n memory?: string;\n};\n\ninterface SandboxToolContext {\n userId: string;\n conversationId: string;\n}\n\ninterface SandboxToolController {\n sandbox: SandboxConfig;\n resourceController?: Pick<SandboxResourceController, \"getLimitStatus\" | \"setLimits\">;\n}\n\nexport function createSandboxTool(controller: SandboxToolController): {\n tool: AgentTool<typeof sandboxSchema>;\n setSandboxContext: (context: SandboxToolContext) => void;\n} {\n let sandboxContext: SandboxToolContext | null = null;\n\n const tool: AgentTool<typeof sandboxSchema> = {\n name: \"sandbox\",\n label: \"sandbox\",\n description:\n \"Inspect or temporarily set CPU/memory limits for the current managed sandbox. Limits apply to this conversation's runtime and are cleared when it stops.\",\n parameters: sandboxSchema,\n execute: async (_toolCallId: string, params: SandboxToolParams, signal?: AbortSignal) => {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n if (!sandboxContext) {\n throw new Error(\"Sandbox context not configured\");\n }\n if (\n (controller.sandbox.type !== \"image\" && controller.sandbox.type !== \"gondolin\") ||\n !controller.resourceController\n ) {\n throw new Error(\"The sandbox tool only supports image:* and gondolin:* managed sandboxes\");\n }\n\n const containerKey = resolveActorVaultKey(\n controller.sandbox,\n sandboxContext.userId,\n sandboxContext.conversationId,\n );\n\n if (params.action === \"set\") {\n const limits = normalizeLimits(params);\n const status = await controller.resourceController.setLimits(containerKey, limits);\n return textResult(\n `Updated sandbox limits for ${containerKey}: ${formatLimits(status.limits)}. These temporary limits are cleared when the sandbox runtime stops.`,\n );\n }\n\n const status = controller.resourceController.getLimitStatus(containerKey);\n return textResult(\n `Sandbox limits for ${containerKey}: ${formatLimits(status.limits)}${status.boosted ? \" (boosted)\" : \"\"}.`,\n );\n },\n };\n\n return {\n tool,\n setSandboxContext: (context: SandboxToolContext) => {\n sandboxContext = context;\n },\n };\n}\n\nfunction normalizeLimits(params: SandboxToolParams): ResourceLimits {\n const cpus = normalizeLimitValue(\"cpus\", params.cpus);\n const memory = normalizeLimitValue(\"memory\", params.memory);\n if (!cpus && !memory) {\n throw new Error(\"action=set requires cpus and/or memory\");\n }\n return { ...(cpus ? { cpus } : {}), ...(memory ? { memory } : {}) };\n}\n\nfunction normalizeLimitValue(name: string, value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n if (!/^[A-Za-z0-9_.-]+$/.test(trimmed)) {\n throw new Error(`${name} must not contain whitespace or shell metacharacters`);\n }\n return trimmed;\n}\n\nfunction formatLimits(limits: ResourceLimits | undefined): string {\n return `CPU ${limits?.cpus ?? \"unlimited\"} / Memory ${limits?.memory ?? \"unlimited\"}`;\n}\n\nfunction textResult(text: string): {\n content: Array<{ type: \"text\"; text: string }>;\n details: undefined;\n} {\n return { content: [{ type: \"text\", text }], details: undefined };\n}\n"]}
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/tools/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Type } from \"@sinclair/typebox\";\nimport type { SandboxConfig } from \"../sandbox/index.js\";\nimport type { ResourceLimits, SandboxResourceController } from \"../types.js\";\nimport { actorKey } from \"../sandbox/identity.js\";\n\nconst sandboxSchema = Type.Object({\n action: Type.Union([Type.Literal(\"status\"), Type.Literal(\"set\")], {\n description: \"Use status to inspect current limits, or set to apply temporary limits.\",\n }),\n cpus: Type.Optional(\n Type.String({\n description: \"CPU limit for action=set, for example '0.5', '1', or '2'.\",\n }),\n ),\n memory: Type.Optional(\n Type.String({\n description: \"Docker memory limit for action=set, for example '512m', '1g', or '4g'.\",\n }),\n ),\n});\n\ntype SandboxToolParams = {\n action: \"status\" | \"set\";\n cpus?: string;\n memory?: string;\n};\n\ninterface SandboxToolContext {\n userId: string;\n conversationId: string;\n}\n\ninterface SandboxToolController {\n sandbox: SandboxConfig;\n resourceController?: Pick<SandboxResourceController, \"getLimitStatus\" | \"setLimits\">;\n}\n\nexport function createSandboxTool(controller: SandboxToolController): {\n tool: AgentTool<typeof sandboxSchema>;\n setSandboxContext: (context: SandboxToolContext) => void;\n} {\n let sandboxContext: SandboxToolContext | null = null;\n\n const tool: AgentTool<typeof sandboxSchema> = {\n name: \"sandbox\",\n label: \"sandbox\",\n description:\n \"Inspect or temporarily set CPU/memory limits for the current managed sandbox. Limits apply to this conversation's runtime and are cleared when it stops.\",\n parameters: sandboxSchema,\n execute: async (_toolCallId: string, params: SandboxToolParams, signal?: AbortSignal) => {\n if (signal?.aborted) {\n throw new Error(\"Operation aborted\");\n }\n if (!sandboxContext) {\n throw new Error(\"Sandbox context not configured\");\n }\n if (\n (controller.sandbox.type !== \"image\" && controller.sandbox.type !== \"gondolin\") ||\n !controller.resourceController\n ) {\n throw new Error(\"The sandbox tool only supports image:* and gondolin:* managed sandboxes\");\n }\n\n const containerKey = actorKey(controller.sandbox, {\n userId: sandboxContext.userId,\n conversationId: sandboxContext.conversationId,\n });\n\n if (params.action === \"set\") {\n const limits = normalizeLimits(params);\n const status = await controller.resourceController.setLimits(containerKey, limits);\n return textResult(\n `Updated sandbox limits for ${containerKey}: ${formatLimits(status.limits)}. These temporary limits are cleared when the sandbox runtime stops.`,\n );\n }\n\n const status = controller.resourceController.getLimitStatus(containerKey);\n return textResult(\n `Sandbox limits for ${containerKey}: ${formatLimits(status.limits)}${status.boosted ? \" (boosted)\" : \"\"}.`,\n );\n },\n };\n\n return {\n tool,\n setSandboxContext: (context: SandboxToolContext) => {\n sandboxContext = context;\n },\n };\n}\n\nfunction normalizeLimits(params: SandboxToolParams): ResourceLimits {\n const cpus = normalizeLimitValue(\"cpus\", params.cpus);\n const memory = normalizeLimitValue(\"memory\", params.memory);\n if (!cpus && !memory) {\n throw new Error(\"action=set requires cpus and/or memory\");\n }\n return { ...(cpus ? { cpus } : {}), ...(memory ? { memory } : {}) };\n}\n\nfunction normalizeLimitValue(name: string, value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n if (!/^[A-Za-z0-9_.-]+$/.test(trimmed)) {\n throw new Error(`${name} must not contain whitespace or shell metacharacters`);\n }\n return trimmed;\n}\n\nfunction formatLimits(limits: ResourceLimits | undefined): string {\n return `CPU ${limits?.cpus ?? \"unlimited\"} / Memory ${limits?.memory ?? \"unlimited\"}`;\n}\n\nfunction textResult(text: string): {\n content: Array<{ type: \"text\"; text: string }>;\n details: undefined;\n} {\n return { content: [{ type: \"text\", text }], details: undefined };\n}\n"]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Process-wide subagent fan-out account. The per-conversation queues
3
+ * serialize agent runs, and each run's subagent tool bounds its own fan-out
4
+ * — but without a shared ceiling, N busy conversations hold N × per-run-cap
5
+ * live subagent sessions. Every subagent launch draws a slot from one shared
6
+ * pool; the per-run cap and this global ceiling are the two bounds, both
7
+ * enforced at the same seam (the tool's slot acquisition).
8
+ */
9
+ /** Default process-wide ceiling on concurrently live subagent sessions. */
10
+ export declare const DEFAULT_GLOBAL_SUBAGENT_SLOTS = 8;
11
+ /** Async slot pool: at most `capacity` concurrent holders, FIFO waiters. */
12
+ export declare class SubagentSlotPool {
13
+ readonly capacity: number;
14
+ private held;
15
+ private waiters;
16
+ constructor(capacity: number);
17
+ /** Currently held slots (for tests and capacity reporting). */
18
+ get inFlight(): number;
19
+ /**
20
+ * Resolve with a release function once a slot frees up. Call the release
21
+ * exactly once; releasing hands the slot to the oldest waiter.
22
+ */
23
+ acquire(): Promise<() => void>;
24
+ private releaser;
25
+ }
26
+ /** A pool that never blocks — the default when no shared ceiling is wired. */
27
+ export declare function unboundedSlotPool(): SubagentSlotPool;
28
+ //# sourceMappingURL=subagent-slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-slots.d.ts","sourceRoot":"","sources":["../../src/tools/subagent-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,4EAA4E;AAC5E,qBAAa,gBAAgB;IAIf,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAHrC,OAAO,CAAC,IAAI,CAAK;IACjB,OAAO,CAAC,OAAO,CAAyB;IAExC,YAAqB,QAAQ,EAAE,MAAM,EAIpC;IAED,+DAA+D;IAC/D,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,CAUnC;IAED,OAAO,CAAC,QAAQ;CAUjB;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,IAAI,gBAAgB,CAEpD"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Process-wide subagent fan-out account. The per-conversation queues
3
+ * serialize agent runs, and each run's subagent tool bounds its own fan-out
4
+ * — but without a shared ceiling, N busy conversations hold N × per-run-cap
5
+ * live subagent sessions. Every subagent launch draws a slot from one shared
6
+ * pool; the per-run cap and this global ceiling are the two bounds, both
7
+ * enforced at the same seam (the tool's slot acquisition).
8
+ */
9
+ /** Default process-wide ceiling on concurrently live subagent sessions. */
10
+ export const DEFAULT_GLOBAL_SUBAGENT_SLOTS = 8;
11
+ /** Async slot pool: at most `capacity` concurrent holders, FIFO waiters. */
12
+ export class SubagentSlotPool {
13
+ constructor(capacity) {
14
+ this.capacity = capacity;
15
+ this.held = 0;
16
+ this.waiters = [];
17
+ if (!(capacity >= 1)) {
18
+ throw new Error(`SubagentSlotPool capacity must be >= 1, got ${capacity}`);
19
+ }
20
+ }
21
+ /** Currently held slots (for tests and capacity reporting). */
22
+ get inFlight() {
23
+ return this.held;
24
+ }
25
+ /**
26
+ * Resolve with a release function once a slot frees up. Call the release
27
+ * exactly once; releasing hands the slot to the oldest waiter.
28
+ */
29
+ async acquire() {
30
+ if (this.held < this.capacity) {
31
+ this.held += 1;
32
+ return this.releaser();
33
+ }
34
+ await new Promise((resolve) => {
35
+ this.waiters.push(resolve);
36
+ });
37
+ this.held += 1;
38
+ return this.releaser();
39
+ }
40
+ releaser() {
41
+ let released = false;
42
+ return () => {
43
+ if (released)
44
+ return;
45
+ released = true;
46
+ this.held -= 1;
47
+ const next = this.waiters.shift();
48
+ if (next)
49
+ next();
50
+ };
51
+ }
52
+ }
53
+ /** A pool that never blocks — the default when no shared ceiling is wired. */
54
+ export function unboundedSlotPool() {
55
+ return new SubagentSlotPool(Number.MAX_SAFE_INTEGER);
56
+ }
57
+ //# sourceMappingURL=subagent-slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-slots.js","sourceRoot":"","sources":["../../src/tools/subagent-slots.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,4EAA4E;AAC5E,MAAM,OAAO,gBAAgB;IAI3B,YAAqB,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;QAH7B,SAAI,GAAG,CAAC,CAAC;QACT,YAAO,GAAsB,EAAE,CAAC;QAGtC,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,+CAA+C,QAAQ,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;YACf,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;QACf,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IAEO,QAAQ;QACd,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;YACf,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,IAAI;gBAAE,IAAI,EAAE,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;AACvD,CAAC","sourcesContent":["/**\n * Process-wide subagent fan-out account. The per-conversation queues\n * serialize agent runs, and each run's subagent tool bounds its own fan-out\n * — but without a shared ceiling, N busy conversations hold N × per-run-cap\n * live subagent sessions. Every subagent launch draws a slot from one shared\n * pool; the per-run cap and this global ceiling are the two bounds, both\n * enforced at the same seam (the tool's slot acquisition).\n */\n\n/** Default process-wide ceiling on concurrently live subagent sessions. */\nexport const DEFAULT_GLOBAL_SUBAGENT_SLOTS = 8;\n\n/** Async slot pool: at most `capacity` concurrent holders, FIFO waiters. */\nexport class SubagentSlotPool {\n private held = 0;\n private waiters: Array<() => void> = [];\n\n constructor(readonly capacity: number) {\n if (!(capacity >= 1)) {\n throw new Error(`SubagentSlotPool capacity must be >= 1, got ${capacity}`);\n }\n }\n\n /** Currently held slots (for tests and capacity reporting). */\n get inFlight(): number {\n return this.held;\n }\n\n /**\n * Resolve with a release function once a slot frees up. Call the release\n * exactly once; releasing hands the slot to the oldest waiter.\n */\n async acquire(): Promise<() => void> {\n if (this.held < this.capacity) {\n this.held += 1;\n return this.releaser();\n }\n await new Promise<void>((resolve) => {\n this.waiters.push(resolve);\n });\n this.held += 1;\n return this.releaser();\n }\n\n private releaser(): () => void {\n let released = false;\n return () => {\n if (released) return;\n released = true;\n this.held -= 1;\n const next = this.waiters.shift();\n if (next) next();\n };\n }\n}\n\n/** A pool that never blocks — the default when no shared ceiling is wired. */\nexport function unboundedSlotPool(): SubagentSlotPool {\n return new SubagentSlotPool(Number.MAX_SAFE_INTEGER);\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { type TSchema } from "@sinclair/typebox";
3
3
  import type { SubagentRunOutput, SubagentRunRequest, SubagentRunResult } from "../harness/types.js";
4
+ import { type SubagentSlotPool } from "./subagent-slots.js";
4
5
  declare const subagentSchema: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TObject<{
5
6
  task: import("@sinclair/typebox").TString;
6
7
  label: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -63,7 +64,11 @@ declare const subagentSchema: import("@sinclair/typebox").TUnion<[import("@sincl
63
64
  }>;
64
65
  }>]>;
65
66
  type RunSubagent = <TOutputSchema extends TSchema | undefined = undefined>(request: SubagentRunRequest<TOutputSchema>) => Promise<SubagentRunResult<SubagentRunOutput<TOutputSchema>>>;
66
- /** Create the normal agent's bounded subagent delegation and DAG tool. */
67
- export declare function createSubagentTool(runSubagent: RunSubagent): AgentTool<typeof subagentSchema>;
67
+ /**
68
+ * Create the normal agent's bounded subagent delegation and DAG tool.
69
+ * `globalSlots` is the process-wide fan-out account shared across every
70
+ * conversation's tool instance; omitted, fan-out is bounded per run only.
71
+ */
72
+ export declare function createSubagentTool(runSubagent: RunSubagent, globalSlots?: SubagentSlotPool): AgentTool<typeof subagentSchema>;
68
73
  export {};
69
74
  //# sourceMappingURL=subagent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../src/tools/subagent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAA2B,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAqDpG,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoBlB,CAAC;AAMH,KAAK,WAAW,GAAG,CAAC,aAAa,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EACvE,OAAO,EAAE,kBAAkB,CAAC,aAAa,CAAC,KACvC,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AA6MlE,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC,OAAO,cAAc,CAAC,CAyF7F"}
1
+ {"version":3,"file":"subagent.d.ts","sourceRoot":"","sources":["../../src/tools/subagent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAA2B,MAAM,+BAA+B,CAAC;AACxF,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAqD/E,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAwBlB,CAAC;AAMH,KAAK,WAAW,GAAG,CAAC,aAAa,SAAS,OAAO,GAAG,SAAS,GAAG,SAAS,EACvE,OAAO,EAAE,kBAAkB,CAAC,aAAa,CAAC,KACvC,OAAO,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AA8RlE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,WAAW,GAAE,gBAAsC,GAClD,SAAS,CAAC,OAAO,cAAc,CAAC,CAgElC"}
@@ -1,11 +1,12 @@
1
1
  import { Type } from "@sinclair/typebox";
2
+ import { unboundedSlotPool } from "./subagent-slots.js";
2
3
  const MAX_DAG_NODES = 8;
3
4
  const MAX_DAG_EDGES = 16;
4
5
  const MAX_DAG_DEPTH = 4;
5
- const MAX_DAG_CONCURRENCY = 4;
6
+ const MAX_CONCURRENT_SUBAGENTS = 4;
6
7
  const MAX_DEPENDENCY_OUTPUT_CHARS = 4000;
7
8
  const taskProperties = {
8
- task: Type.String({ description: "Self-contained task for a fresh subagent." }),
9
+ task: Type.String({ minLength: 1, description: "Self-contained task for a fresh subagent." }),
9
10
  label: Type.Optional(Type.String({ maxLength: 64, description: "Short progress label for this subagent." })),
10
11
  systemPrompt: Type.Optional(Type.String({ description: "Optional role or behavior instructions for the subagent." })),
11
12
  input: Type.Optional(Type.Unknown({ description: "Optional JSON-serializable structured input for the task." })),
@@ -48,11 +49,26 @@ const subagentSchema = Type.Union([
48
49
  Type.Object({
49
50
  dag: Type.Object({
50
51
  nodes: Type.Array(dagNodeSchema, { minItems: 1, maxItems: MAX_DAG_NODES }),
51
- maxConcurrency: Type.Optional(Type.Integer({ minimum: 1, maximum: MAX_DAG_CONCURRENCY, default: MAX_DAG_CONCURRENCY })),
52
+ maxConcurrency: Type.Optional(Type.Integer({
53
+ minimum: 1,
54
+ maximum: MAX_CONCURRENT_SUBAGENTS,
55
+ default: MAX_CONCURRENT_SUBAGENTS,
56
+ })),
52
57
  }),
53
58
  ...sharedProperties,
54
59
  }),
55
60
  ]);
61
+ const STATUS_MARKER = {
62
+ pending: "○",
63
+ running: "●",
64
+ completed: "✓",
65
+ failed: "✗",
66
+ cancelled: "✗",
67
+ timeout: "✗",
68
+ budget_exceeded: "✗",
69
+ invalid_output: "✗",
70
+ skipped: "⊘",
71
+ };
56
72
  class SubagentProgressTracker {
57
73
  constructor(mode, items, onUpdate) {
58
74
  this.mode = mode;
@@ -73,18 +89,11 @@ class SubagentProgressTracker {
73
89
  ...item,
74
90
  status: this.states.get(item.id) ?? "pending",
75
91
  }));
76
- const settled = nodes.filter((node) => ["completed", "failed", "skipped"].includes(node.status)).length;
77
- const marker = {
78
- pending: "○",
79
- running: "●",
80
- completed: "✓",
81
- failed: "✗",
82
- skipped: "⊘",
83
- };
92
+ const settled = nodes.filter((node) => node.status !== "pending" && node.status !== "running").length;
84
93
  const modeLabel = this.mode === "dag" ? "DAG" : this.mode === "parallel" ? "parallel" : "run";
85
94
  const progressLabel = [
86
95
  `Subagent ${modeLabel} ${settled}/${nodes.length}`,
87
- ...nodes.map((node) => `${marker[node.status]} ${node.label}`),
96
+ ...nodes.map((node) => `${STATUS_MARKER[node.status]} ${node.label}`),
88
97
  ].join(" · ");
89
98
  this.onUpdate({
90
99
  content: [],
@@ -95,14 +104,13 @@ class SubagentProgressTracker {
95
104
  function taskLabel(task, fallback) {
96
105
  return task.label?.trim() || task.task.trim().slice(0, 48) || fallback;
97
106
  }
98
- function resultProgressStatus(result) {
99
- return result.status === "completed" ? "completed" : "failed";
100
- }
101
- function formatResult(result) {
102
- if (result.status !== "completed") {
103
- return `Subagent ${result.status}${result.error ? `: ${result.error}` : ""}`;
107
+ function formatOutcome(outcome) {
108
+ if (outcome.status !== "completed") {
109
+ return `Subagent ${outcome.status}${outcome.error ? `: ${outcome.error}` : ""}`;
104
110
  }
105
- return typeof result.output === "string" ? result.output : JSON.stringify(result.output, null, 2);
111
+ return typeof outcome.output === "string"
112
+ ? outcome.output
113
+ : JSON.stringify(outcome.output, null, 2);
106
114
  }
107
115
  function buildRequest(task, shared, signal) {
108
116
  const outputSchema = shared.outputSchema;
@@ -166,6 +174,48 @@ function buildDagWaves(nodes) {
166
174
  }
167
175
  return waves;
168
176
  }
177
+ function itemForNode(node) {
178
+ return {
179
+ id: node.id,
180
+ label: node.label?.trim() || node.id,
181
+ task: node,
182
+ dependsOn: node.dependsOn ?? [],
183
+ };
184
+ }
185
+ /** Normalize every tool mode into one plan: nodes, waves, concurrency. */
186
+ function buildPlan(params) {
187
+ if ("dag" in params) {
188
+ const waves = buildDagWaves(params.dag.nodes).map((wave) => wave.map(itemForNode));
189
+ const requested = params.dag.maxConcurrency ?? MAX_CONCURRENT_SUBAGENTS;
190
+ return {
191
+ mode: "dag",
192
+ items: params.dag.nodes.map(itemForNode),
193
+ waves,
194
+ concurrency: Math.max(1, Math.min(MAX_CONCURRENT_SUBAGENTS, Math.floor(requested))),
195
+ };
196
+ }
197
+ if ("tasks" in params) {
198
+ const items = params.tasks.map((task, index) => ({
199
+ id: String(index),
200
+ label: taskLabel(task, String(index + 1)),
201
+ task,
202
+ dependsOn: [],
203
+ }));
204
+ return { mode: "parallel", items, waves: [items], concurrency: MAX_CONCURRENT_SUBAGENTS };
205
+ }
206
+ const item = { id: "0", label: taskLabel(params, "subagent"), task: params, dependsOn: [] };
207
+ return { mode: "single", items: [item], waves: [[item]], concurrency: 1 };
208
+ }
209
+ /** Run `worker` over every item with at most `limit` in flight. */
210
+ async function forEachConcurrent(items, limit, worker) {
211
+ let cursor = 0;
212
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, async () => {
213
+ while (cursor < items.length) {
214
+ const index = cursor++;
215
+ await worker(items[index], index);
216
+ }
217
+ }));
218
+ }
169
219
  function dependencyOutput(outcome) {
170
220
  if (outcome.status !== "completed")
171
221
  return undefined;
@@ -175,111 +225,110 @@ function dependencyOutput(outcome) {
175
225
  return null;
176
226
  if (serialized.length <= MAX_DEPENDENCY_OUTPUT_CHARS)
177
227
  return value;
228
+ // Oversized structured output becomes a marked string — the shape is lost,
229
+ // which the tool description warns downstream consumers about.
178
230
  return `${serialized.slice(0, MAX_DEPENDENCY_OUTPUT_CHARS)}\n[truncated]`;
179
231
  }
180
- function dagRequest(node, shared, outcomes, signal) {
181
- const dependencies = Object.fromEntries((node.dependsOn ?? []).map((id) => [id, dependencyOutput(outcomes.get(id))]));
182
- const input = node.dependsOn && node.dependsOn.length > 0
183
- ? { ...(node.input !== undefined ? { input: node.input } : {}), dependencies }
184
- : node.input;
185
- return buildRequest({ ...node, ...(input !== undefined ? { input } : {}) }, shared, signal);
232
+ function planRequest(item, shared, outcomes, signal) {
233
+ if (item.dependsOn.length === 0)
234
+ return buildRequest(item.task, shared, signal);
235
+ const dependencies = Object.fromEntries(item.dependsOn.map((id) => [id, dependencyOutput(outcomes.get(id))]));
236
+ const input = {
237
+ ...(item.task.input !== undefined ? { input: item.task.input } : {}),
238
+ dependencies,
239
+ };
240
+ return buildRequest({ ...item.task, input }, shared, signal);
186
241
  }
187
- async function runDag(nodes, maxConcurrency, shared, runSubagent, progress, signal) {
188
- const waves = buildDagWaves(nodes);
189
- const concurrency = Math.max(1, Math.min(MAX_DAG_CONCURRENCY, Math.floor(maxConcurrency)));
242
+ /**
243
+ * One executor for every mode: wave barriers, a bounded slot pool inside
244
+ * each wave, and one global slot per actual subagent launch — the seam where
245
+ * both the per-run cap and the process-wide ceiling are enforced.
246
+ */
247
+ async function runWaves(plan, shared, runSubagent, progress, globalSlots, signal) {
190
248
  const outcomes = new Map();
191
- for (const wave of waves) {
192
- for (let offset = 0; offset < wave.length; offset += concurrency) {
193
- const chunk = wave.slice(offset, offset + concurrency);
194
- for (const node of chunk)
195
- progress.update(node.id, "running");
196
- await Promise.all(chunk.map(async (node) => {
197
- const failedDependency = (node.dependsOn ?? []).find((id) => outcomes.get(id)?.status !== "completed");
198
- if (failedDependency) {
199
- outcomes.set(node.id, {
200
- id: node.id,
201
- status: "skipped",
202
- error: `Dependency ${failedDependency} did not complete`,
203
- });
204
- progress.update(node.id, "skipped");
205
- return;
206
- }
207
- const result = await runSubagent(dagRequest(node, shared, outcomes, signal));
208
- outcomes.set(node.id, { id: node.id, ...result });
209
- progress.update(node.id, resultProgressStatus(result));
210
- }));
211
- }
249
+ for (const wave of plan.waves) {
250
+ await forEachConcurrent(wave, plan.concurrency, async (item) => {
251
+ const failedDependency = item.dependsOn.find((id) => outcomes.get(id)?.status !== "completed");
252
+ if (failedDependency) {
253
+ outcomes.set(item.id, {
254
+ id: item.id,
255
+ status: "skipped",
256
+ error: `Dependency ${failedDependency} did not complete`,
257
+ });
258
+ progress.update(item.id, "skipped");
259
+ return;
260
+ }
261
+ const release = await globalSlots.acquire();
262
+ let result;
263
+ try {
264
+ progress.update(item.id, "running");
265
+ result = await runSubagent(planRequest(item, shared, outcomes, signal));
266
+ }
267
+ finally {
268
+ release();
269
+ }
270
+ outcomes.set(item.id, { id: item.id, ...result });
271
+ progress.update(item.id, result.status);
272
+ });
212
273
  }
213
- return {
214
- waves: waves.map((wave) => wave.map((node) => node.id)),
215
- results: nodes.map((node) => outcomes.get(node.id)),
216
- };
217
- }
218
- function formatDagOutcome(outcome) {
219
- if (outcome.status === "skipped")
220
- return `Subagent skipped: ${outcome.error}`;
221
- return formatResult(outcome);
274
+ return plan.items.map((item) => outcomes.get(item.id));
222
275
  }
223
- /** Create the normal agent's bounded subagent delegation and DAG tool. */
224
- export function createSubagentTool(runSubagent) {
276
+ /**
277
+ * Create the normal agent's bounded subagent delegation and DAG tool.
278
+ * `globalSlots` is the process-wide fan-out account shared across every
279
+ * conversation's tool instance; omitted, fan-out is bounded per run only.
280
+ */
281
+ export function createSubagentTool(runSubagent, globalSlots = unboundedSlotPool()) {
225
282
  return {
226
283
  name: "subagent",
227
284
  label: "Subagent",
228
- description: "Run fresh isolated subagents. Use task for one subagent, tasks for independent concurrent work, or dag.nodes for a bounded dependency graph. DAG limits: 8 nodes, 16 edges, depth 4, concurrency 4; failed dependencies skip descendants. Subagents have no history or tools unless explicitly provided; nested subagents are not allowed.",
285
+ description: `Run fresh isolated subagents. Use task for one subagent, tasks for independent concurrent work, or dag.nodes for a bounded dependency graph. At most ${MAX_CONCURRENT_SUBAGENTS} subagents run concurrently. DAG limits: ${MAX_DAG_NODES} nodes, ${MAX_DAG_EDGES} edges, depth ${MAX_DAG_DEPTH}; failed dependencies skip descendants, and dependency outputs larger than ${MAX_DEPENDENCY_OUTPUT_CHARS} characters reach downstream nodes as a truncated string. ` +
286
+ "Subagents have no history or tools unless explicitly provided; nested subagents are not allowed.",
229
287
  parameters: subagentSchema,
230
288
  execute: async (_toolCallId, params, signal, onUpdate) => {
231
- if ("dag" in params) {
232
- const progress = new SubagentProgressTracker("dag", params.dag.nodes.map((node) => ({
233
- id: node.id,
234
- label: node.label?.trim() || node.id,
235
- })), onUpdate);
236
- progress.emit();
237
- const result = await runDag(params.dag.nodes, params.dag.maxConcurrency ?? MAX_DAG_CONCURRENCY, params, runSubagent, progress, signal);
238
- return {
239
- content: [
240
- {
241
- type: "text",
242
- text: result.results
243
- .map((outcome) => `[${outcome.id}] ${formatDagOutcome(outcome)}`)
244
- .join("\n\n"),
245
- },
246
- ],
247
- details: { mode: "dag", ...result },
248
- };
249
- }
250
- if ("tasks" in params) {
251
- const progress = new SubagentProgressTracker("parallel", params.tasks.map((task, index) => ({
252
- id: String(index),
253
- label: taskLabel(task, String(index + 1)),
254
- })), onUpdate);
255
- progress.emit();
256
- const results = await Promise.all(params.tasks.map(async (task, index) => {
257
- const id = String(index);
258
- progress.update(id, "running");
259
- const result = await runSubagent(buildRequest(task, params, signal));
260
- progress.update(id, resultProgressStatus(result));
261
- return result;
262
- }));
263
- return {
264
- content: [
265
- {
266
- type: "text",
267
- text: results
268
- .map((result, index) => `[${index + 1}] ${formatResult(result)}`)
269
- .join("\n\n"),
289
+ const plan = buildPlan(params);
290
+ const progress = new SubagentProgressTracker(plan.mode, plan.items.map(({ id, label }) => ({ id, label })), onUpdate);
291
+ progress.emit();
292
+ const ordered = await runWaves(plan, params, runSubagent, progress, globalSlots, signal);
293
+ switch (plan.mode) {
294
+ case "dag":
295
+ return {
296
+ content: [
297
+ {
298
+ type: "text",
299
+ text: ordered
300
+ .map((outcome) => `[${outcome.id}] ${formatOutcome(outcome)}`)
301
+ .join("\n\n"),
302
+ },
303
+ ],
304
+ details: {
305
+ mode: "dag",
306
+ waves: plan.waves.map((wave) => wave.map((item) => item.id)),
307
+ results: ordered,
270
308
  },
271
- ],
272
- details: { mode: "parallel", results },
273
- };
309
+ };
310
+ case "parallel": {
311
+ const results = ordered.map(({ id: _id, ...result }) => result);
312
+ return {
313
+ content: [
314
+ {
315
+ type: "text",
316
+ text: results
317
+ .map((result, index) => `[${index + 1}] ${formatOutcome(result)}`)
318
+ .join("\n\n"),
319
+ },
320
+ ],
321
+ details: { mode: "parallel", results },
322
+ };
323
+ }
324
+ case "single": {
325
+ const { id: _id, ...result } = ordered[0];
326
+ return {
327
+ content: [{ type: "text", text: formatOutcome(result) }],
328
+ details: result,
329
+ };
330
+ }
274
331
  }
275
- const progress = new SubagentProgressTracker("single", [{ id: "0", label: taskLabel(params, "subagent") }], onUpdate);
276
- progress.update("0", "running");
277
- const result = await runSubagent(buildRequest(params, params, signal));
278
- progress.update("0", resultProgressStatus(result));
279
- return {
280
- content: [{ type: "text", text: formatResult(result) }],
281
- details: result,
282
- };
283
332
  },
284
333
  };
285
334
  }