@astralyn/pi 1.3.0 → 1.4.0

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 (206) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/bundle/chunks/anthropic-messages-HWL6AS7T.js +6 -0
  3. package/dist/bundle/chunks/azure-openai-responses-4YYPDYV5.js +2 -0
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +8 -8
  5. package/dist/bundle/chunks/chunk-24FY4C5S.js +2 -0
  6. package/dist/bundle/chunks/chunk-6JS2SOFO.js +11 -0
  7. package/dist/bundle/chunks/chunk-ANCZPKX7.js +2 -0
  8. package/dist/bundle/chunks/{chunk-R2KES7LS.js → chunk-BMTEURL3.js} +102 -87
  9. package/dist/bundle/chunks/chunk-MMNIHCU7.js +2 -0
  10. package/dist/bundle/chunks/{chunk-KSCGI7JW.js → chunk-MZJC45TM.js} +2 -2
  11. package/dist/bundle/chunks/{chunk-J75WV3FL.js → chunk-OV2VMHBX.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-YHRHHXFG.js → chunk-TJIPCBZF.js} +1 -1
  13. package/dist/bundle/chunks/chunk-TPVFPFJP.js +2 -0
  14. package/dist/bundle/chunks/chunk-ZAIGBRV5.js +16 -0
  15. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-7BKATOEJ.js +2 -0
  16. package/dist/bundle/chunks/github-copilot.js +1 -1
  17. package/dist/bundle/chunks/google-generative-ai-HTUSU45F.js +2 -0
  18. package/dist/bundle/chunks/google-vertex-AVQV4P76.js +2 -0
  19. package/dist/bundle/chunks/{llama-cpp-classify-H3IZDR5O.js → llama-cpp-classify-27QYLJZY.js} +2 -2
  20. package/dist/bundle/chunks/{mistral-conversations-6E6SS3WF.js → mistral-conversations-V2JJTMJ5.js} +1 -1
  21. package/dist/bundle/chunks/openai-codex-responses-Q25MHDFX.js +10 -0
  22. package/dist/bundle/chunks/openai-completions-TXZXILJR.js +7 -0
  23. package/dist/bundle/chunks/{openai-decisions-TVCDIPZX.js → openai-decisions-3WYFPGSK.js} +1 -1
  24. package/dist/bundle/chunks/openai-responses-E4BNZIQK.js +4 -0
  25. package/dist/bundle/chunks/openrouter-images-CBP3OPOD.js +2 -0
  26. package/dist/bundle/chunks/pi-messages-LBJQ4NGP.js +8 -0
  27. package/dist/bundle/chunks/typesafe-system-one-BNICP2LS.js +2 -0
  28. package/dist/bundle/chunks/virtual-modules-3CTTTQQN.js +2 -0
  29. package/dist/bundle/cli.js +1 -1
  30. package/dist/bundle/index.js +1 -1
  31. package/dist/bundle/rpc-entry.js +1 -1
  32. package/dist/core/agent-session.d.ts +7 -1
  33. package/dist/core/agent-session.d.ts.map +1 -1
  34. package/dist/core/agent-session.js +61 -15
  35. package/dist/core/agent-session.js.map +1 -1
  36. package/dist/core/client-identity.d.ts +8 -0
  37. package/dist/core/client-identity.d.ts.map +1 -0
  38. package/dist/core/client-identity.js +15 -0
  39. package/dist/core/client-identity.js.map +1 -0
  40. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  41. package/dist/core/compaction/branch-summarization.js +1 -2
  42. package/dist/core/compaction/branch-summarization.js.map +1 -1
  43. package/dist/core/compaction/compaction.d.ts +2 -2
  44. package/dist/core/compaction/compaction.d.ts.map +1 -1
  45. package/dist/core/compaction/compaction.js +20 -15
  46. package/dist/core/compaction/compaction.js.map +1 -1
  47. package/dist/core/export-html/index.d.ts.map +1 -1
  48. package/dist/core/export-html/index.js +2 -0
  49. package/dist/core/export-html/index.js.map +1 -1
  50. package/dist/core/export-html/template.html +1 -0
  51. package/dist/core/export-html/template.js +2 -1
  52. package/dist/core/export-html/vendor/marked-cjk-friendly.min.js +6 -0
  53. package/dist/core/export-html/vendor/marked.min.js +30 -29
  54. package/dist/core/extensions/loader.d.ts.map +1 -1
  55. package/dist/core/extensions/loader.js +3 -0
  56. package/dist/core/extensions/loader.js.map +1 -1
  57. package/dist/core/extensions/runner.d.ts +0 -2
  58. package/dist/core/extensions/runner.d.ts.map +1 -1
  59. package/dist/core/extensions/runner.js +0 -18
  60. package/dist/core/extensions/runner.js.map +1 -1
  61. package/dist/core/extensions/types.d.ts +0 -6
  62. package/dist/core/extensions/types.d.ts.map +1 -1
  63. package/dist/core/extensions/types.js.map +1 -1
  64. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  65. package/dist/core/extensions/virtual-modules.js +3 -0
  66. package/dist/core/extensions/virtual-modules.js.map +1 -1
  67. package/dist/core/model-config.d.ts +915 -0
  68. package/dist/core/model-config.d.ts.map +1 -1
  69. package/dist/core/model-config.js +48 -24
  70. package/dist/core/model-config.js.map +1 -1
  71. package/dist/core/model-resolver.js +7 -7
  72. package/dist/core/model-resolver.js.map +1 -1
  73. package/dist/core/model-runtime.d.ts.map +1 -1
  74. package/dist/core/model-runtime.js +6 -3
  75. package/dist/core/model-runtime.js.map +1 -1
  76. package/dist/core/provider-composer.d.ts +2 -1
  77. package/dist/core/provider-composer.d.ts.map +1 -1
  78. package/dist/core/provider-composer.js +7 -3
  79. package/dist/core/provider-composer.js.map +1 -1
  80. package/dist/core/sdk.d.ts.map +1 -1
  81. package/dist/core/sdk.js +9 -10
  82. package/dist/core/sdk.js.map +1 -1
  83. package/dist/core/settings-manager.d.ts +0 -4
  84. package/dist/core/settings-manager.d.ts.map +1 -1
  85. package/dist/core/settings-manager.js +0 -36
  86. package/dist/core/settings-manager.js.map +1 -1
  87. package/dist/core/settings-schema.d.ts +0 -1
  88. package/dist/core/settings-schema.d.ts.map +1 -1
  89. package/dist/core/settings-schema.js +0 -3
  90. package/dist/core/settings-schema.js.map +1 -1
  91. package/dist/core/tasks/presentation.d.ts.map +1 -1
  92. package/dist/core/tasks/presentation.js +3 -1
  93. package/dist/core/tasks/presentation.js.map +1 -1
  94. package/dist/core/tasks/reminder.d.ts +15 -0
  95. package/dist/core/tasks/reminder.d.ts.map +1 -0
  96. package/dist/core/tasks/reminder.js +54 -0
  97. package/dist/core/tasks/reminder.js.map +1 -0
  98. package/dist/core/tasks/runtime.d.ts +4 -1
  99. package/dist/core/tasks/runtime.d.ts.map +1 -1
  100. package/dist/core/tasks/runtime.js +37 -11
  101. package/dist/core/tasks/runtime.js.map +1 -1
  102. package/dist/core/tasks/session.d.ts +9 -0
  103. package/dist/core/tasks/session.d.ts.map +1 -1
  104. package/dist/core/tasks/session.js +24 -0
  105. package/dist/core/tasks/session.js.map +1 -1
  106. package/dist/core/tasks/types.d.ts +6 -1
  107. package/dist/core/tasks/types.d.ts.map +1 -1
  108. package/dist/core/tasks/types.js.map +1 -1
  109. package/dist/core/tools/grep.d.ts +0 -2
  110. package/dist/core/tools/grep.d.ts.map +1 -1
  111. package/dist/core/tools/grep.js +3 -3
  112. package/dist/core/tools/grep.js.map +1 -1
  113. package/dist/core/tools/shell-tool.js +2 -2
  114. package/dist/core/tools/shell-tool.js.map +1 -1
  115. package/dist/core/tools/tasks/actions.d.ts +1 -1
  116. package/dist/core/tools/tasks/actions.d.ts.map +1 -1
  117. package/dist/core/tools/tasks/actions.js +98 -5
  118. package/dist/core/tools/tasks/actions.js.map +1 -1
  119. package/dist/core/tools/tasks/schema.d.ts +1 -1
  120. package/dist/core/tools/tasks/schema.d.ts.map +1 -1
  121. package/dist/core/tools/tasks/schema.js +9 -6
  122. package/dist/core/tools/tasks/schema.js.map +1 -1
  123. package/dist/core/tools/tasks/types.d.ts +9 -3
  124. package/dist/core/tools/tasks/types.d.ts.map +1 -1
  125. package/dist/core/tools/tasks/types.js.map +1 -1
  126. package/dist/core/tools/tasks.d.ts +1 -1
  127. package/dist/core/tools/tasks.d.ts.map +1 -1
  128. package/dist/core/tools/tasks.js +2 -2
  129. package/dist/core/tools/tasks.js.map +1 -1
  130. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  131. package/dist/extensions/codemode/execute.js +99 -24
  132. package/dist/extensions/codemode/execute.js.map +1 -1
  133. package/dist/extensions/mcp/config.d.ts.map +1 -1
  134. package/dist/extensions/mcp/config.js +3 -2
  135. package/dist/extensions/mcp/config.js.map +1 -1
  136. package/dist/modes/interactive/interactive-mode.d.ts +11 -15
  137. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  138. package/dist/modes/interactive/interactive-mode.js +68 -109
  139. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  140. package/dist/modes/interactive/tasks/render.d.ts.map +1 -1
  141. package/dist/modes/interactive/tasks/render.js +17 -9
  142. package/dist/modes/interactive/tasks/render.js.map +1 -1
  143. package/dist/package-manager-cli.d.ts.map +1 -1
  144. package/dist/package-manager-cli.js +2 -1
  145. package/dist/package-manager-cli.js.map +1 -1
  146. package/dist/utils/clipboard-command.d.ts.map +1 -1
  147. package/dist/utils/clipboard-command.js +3 -0
  148. package/dist/utils/clipboard-command.js.map +1 -1
  149. package/dist/utils/pi-user-agent.d.ts +1 -0
  150. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  151. package/dist/utils/pi-user-agent.js +3 -2
  152. package/dist/utils/pi-user-agent.js.map +1 -1
  153. package/dist/utils/shell.d.ts.map +1 -1
  154. package/dist/utils/shell.js +45 -13
  155. package/dist/utils/shell.js.map +1 -1
  156. package/dist/utils/tools-manager.d.ts.map +1 -1
  157. package/dist/utils/tools-manager.js +4 -3
  158. package/dist/utils/tools-manager.js.map +1 -1
  159. package/docs/bundled/tasks.md +17 -7
  160. package/docs/codemode.md +2 -2
  161. package/docs/compaction.md +4 -2
  162. package/docs/custom-provider.md +53 -1
  163. package/docs/docs.json +4 -0
  164. package/docs/environment-variables.md +1 -0
  165. package/docs/extensions.md +98 -3
  166. package/docs/models-configuration.md +196 -0
  167. package/docs/models.md +9 -5
  168. package/docs/sdk.md +2 -2
  169. package/docs/session-format.md +2 -2
  170. package/docs/settings.md +2 -2
  171. package/docs/tui.md +71 -0
  172. package/docs/windows.md +28 -0
  173. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  174. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  175. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  176. package/examples/extensions/gondolin/package-lock.json +2 -2
  177. package/examples/extensions/gondolin/package.json +1 -1
  178. package/examples/extensions/sandbox/package-lock.json +2 -2
  179. package/examples/extensions/sandbox/package.json +1 -1
  180. package/examples/extensions/with-deps/package-lock.json +2 -2
  181. package/examples/extensions/with-deps/package.json +1 -1
  182. package/npm-shrinkwrap.json +150 -137
  183. package/package.json +7 -6
  184. package/schemas/models.schema.json +83 -29
  185. package/schemas/settings.schema.json +0 -12
  186. package/dist/bundle/chunks/anthropic-messages-MSB6JBS2.js +0 -6
  187. package/dist/bundle/chunks/azure-openai-responses-ATZ757I2.js +0 -2
  188. package/dist/bundle/chunks/chunk-4XZYHGVN.js +0 -11
  189. package/dist/bundle/chunks/chunk-7UBIBLPN.js +0 -2
  190. package/dist/bundle/chunks/chunk-LUYFHZ6W.js +0 -11
  191. package/dist/bundle/chunks/chunk-NM2KGRFS.js +0 -2
  192. package/dist/bundle/chunks/chunk-QDDSFJ35.js +0 -2
  193. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-HGOVFZDC.js +0 -2
  194. package/dist/bundle/chunks/google-generative-ai-QRLQ4MCJ.js +0 -2
  195. package/dist/bundle/chunks/google-vertex-L3T6EGTL.js +0 -2
  196. package/dist/bundle/chunks/openai-codex-responses-4GUO76XJ.js +0 -10
  197. package/dist/bundle/chunks/openai-completions-O4TKZCIM.js +0 -7
  198. package/dist/bundle/chunks/openai-responses-VBQKJFNO.js +0 -3
  199. package/dist/bundle/chunks/openrouter-images-TDLJV5N4.js +0 -2
  200. package/dist/bundle/chunks/pi-messages-3POWZ43C.js +0 -8
  201. package/dist/bundle/chunks/typesafe-system-one-LWPJYTJP.js +0 -2
  202. package/dist/bundle/chunks/virtual-modules-TG53AOL4.js +0 -2
  203. package/dist/core/provider-attribution.d.ts +0 -4
  204. package/dist/core/provider-attribution.d.ts.map +0 -1
  205. package/dist/core/provider-attribution.js +0 -72
  206. package/dist/core/provider-attribution.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/core/tools/tasks/schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `tasks` tool's wire contract: one flat schema whose `action`\n * selects which of the remaining fields apply, plus the model-facing copy.\n *\n * The schema stays flat deliberately: a single tool keeps the model's tool list\n * short. Execution creation belongs to the native tools. Narrowing happens\n * inside actions.ts, not here.\n */\n\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport { TASK_RESULT_BYTES } from \"../../tasks/output.ts\";\nimport { formatSize } from \"../truncate.ts\";\nimport {\n\tTASKS_LOGS_DEFAULT_BYTES,\n\tTASKS_LOGS_MIN_BYTES,\n\tTASKS_WAIT_DEFAULT_MS,\n\tTASKS_WAIT_MAX_MS,\n\tTASKS_WAIT_MIN_MS,\n} from \"./constants.ts\";\n\nexport const tasksSchema = Type.Object({\n\taction: StringEnum([\"read\", \"wait\", \"kill\", \"list\"] as const, {\n\t\tdescription: \"Which task operation to perform\",\n\t}),\n\t// — read / wait / kill —\n\ttaskId: Type.Optional(Type.String({ description: \"Task execution id (read/wait/kill)\" })),\n\t// — read —\n\tmode: Type.Optional(\n\t\tStringEnum([\"tail\", \"head\"] as const, {\n\t\t\tdescription: \"Read from the end (default) or the start of the output (read)\",\n\t\t}),\n\t),\n\tbytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max bytes to return (read, default ${formatSize(TASKS_LOGS_DEFAULT_BYTES)}, max ${formatSize(TASK_RESULT_BYTES)})`,\n\t\t}),\n\t),\n\t// — wait —\n\twaitMs: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max time to wait in ms, default ${TASKS_WAIT_DEFAULT_MS}, max ${TASKS_WAIT_MAX_MS} (wait)`,\n\t\t}),\n\t),\n\tsinceBytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription:\n\t\t\t\t\"Only return output written after this byte offset — use the 'next sinceBytes' value from a previous read or wait (wait)\",\n\t\t}),\n\t),\n});\n\n/** Raw tool arguments. Every per-action field is optional here; actions.ts narrows. */\nexport type TasksInput = Static<typeof tasksSchema>;\n\n// ── reading the contract ──────────────────────────────────────────────────\n// One place per field: required fields throw a message that names the next\n// step, optional ones clamp to their documented range. Callers get plain\n// values, so no action handler needs a cast.\n\nexport function requireTaskId(input: TasksInput): string {\n\tconst taskId = input.taskId;\n\tif (!taskId || taskId.trim().length === 0) {\n\t\tthrow new Error(`action '${input.action}' requires 'taskId' — use action list to find the execution id.`);\n\t}\n\treturn taskId;\n}\n\nexport function clampReadBytes(bytes: number | undefined): number {\n\tconst value = bytes !== undefined && Number.isFinite(bytes) ? bytes : TASKS_LOGS_DEFAULT_BYTES;\n\treturn Math.min(TASK_RESULT_BYTES, Math.max(TASKS_LOGS_MIN_BYTES, Math.floor(value)));\n}\n\n/** Shared with the pending-call renderer so the window it shows is the one that runs. */\nexport function clampWaitMs(waitMs: number | undefined): number {\n\tconst value = waitMs !== undefined && Number.isFinite(waitMs) ? waitMs : TASKS_WAIT_DEFAULT_MS;\n\treturn Math.min(TASKS_WAIT_MAX_MS, Math.max(TASKS_WAIT_MIN_MS, Math.floor(value)));\n}\n\nexport function clampSinceBytes(sinceBytes: number | undefined): number | undefined {\n\treturn sinceBytes === undefined || !Number.isFinite(sinceBytes) ? undefined : Math.max(0, Math.floor(sinceBytes));\n}\n\nexport const TASKS_TOOL_DESCRIPTION =\n\t\"Inspect and control background tasks started by native tools or extensions. \" +\n\t\"Completion is delivered to you automatically as a notification — never poll. \" +\n\t\"list: bounded activity/history listing; find task IDs here. \" +\n\t\"read: bounded output or report slice (head/tail). \" +\n\t\"wait: block up to waitMs for a task to settle; cancelling the wait ends only the wait, never the task. \" +\n\t\"kill: request cancellation of a whole task. \" +\n\t\"tasks cannot start work; submit background work through its owning tool. Each read or wait reports its byte range and the next sinceBytes. Output is capped at 50KB per response.\";\nexport const TASKS_PROMPT_SNIPPET = \"Manage background tasks (list, read, wait, kill)\";\nexport const TASKS_PROMPT_GUIDELINES = [\n\t\"Start background work through its owning tool with background: true; continue independent work while it runs.\",\n\t\"A finished background task delivers its result automatically as a notification; use tasks wait only when your next step is blocked on it, and never sleep-poll with repeated reads.\",\n];\n"]}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/core/tools/tasks/schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `tasks` tool's wire contract: one flat schema whose `action`\n * selects which of the remaining fields apply, plus the model-facing copy.\n *\n * The schema stays flat deliberately: a single tool keeps the model's tool list\n * short. Execution creation belongs to the native tools. Narrowing happens\n * inside actions.ts, not here.\n */\n\nimport { StringEnum } from \"@earendil-works/pi-ai\";\nimport { type Static, Type } from \"typebox\";\nimport { TASK_RESULT_BYTES } from \"../../tasks/output.ts\";\nimport { formatSize } from \"../truncate.ts\";\nimport {\n\tTASKS_LOGS_DEFAULT_BYTES,\n\tTASKS_LOGS_MIN_BYTES,\n\tTASKS_WAIT_DEFAULT_MS,\n\tTASKS_WAIT_MAX_MS,\n\tTASKS_WAIT_MIN_MS,\n} from \"./constants.ts\";\n\nexport const tasksSchema = Type.Object({\n\taction: StringEnum([\"read\", \"wait\", \"kill\", \"list\"] as const, {\n\t\tdescription: \"Which task operation to perform\",\n\t}),\n\t// — read / wait / kill —\n\ttaskId: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: \"Task execution id (read/wait/kill). Omit for wait to wait for any task running at call time.\",\n\t\t}),\n\t),\n\t// — read —\n\tmode: Type.Optional(\n\t\tStringEnum([\"tail\", \"head\"] as const, {\n\t\t\tdescription: \"Read from the end (default) or the start of the output (read)\",\n\t\t}),\n\t),\n\tbytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max bytes to return (read, default ${formatSize(TASKS_LOGS_DEFAULT_BYTES)}, max ${formatSize(TASK_RESULT_BYTES)})`,\n\t\t}),\n\t),\n\t// — wait —\n\twaitMs: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription: `Max time to wait in ms, default ${TASKS_WAIT_DEFAULT_MS}, max ${TASKS_WAIT_MAX_MS} (wait)`,\n\t\t}),\n\t),\n\tsinceBytes: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription:\n\t\t\t\t\"Only return output written after this byte offset — use the 'next sinceBytes' value from a previous read or wait (wait with taskId only)\",\n\t\t}),\n\t),\n});\n\n/** Raw tool arguments. Every per-action field is optional here; actions.ts narrows. */\nexport type TasksInput = Static<typeof tasksSchema>;\n\n// ── reading the contract ──────────────────────────────────────────────────\n// One place per field: required fields throw a message that names the next\n// step, optional ones clamp to their documented range. Callers get plain\n// values, so no action handler needs a cast.\n\nexport function requireTaskId(input: TasksInput): string {\n\tconst taskId = input.taskId;\n\tif (!taskId || taskId.trim().length === 0) {\n\t\tthrow new Error(`action '${input.action}' requires 'taskId' — use action list to find the execution id.`);\n\t}\n\treturn taskId;\n}\n\nexport function clampReadBytes(bytes: number | undefined): number {\n\tconst value = bytes !== undefined && Number.isFinite(bytes) ? bytes : TASKS_LOGS_DEFAULT_BYTES;\n\treturn Math.min(TASK_RESULT_BYTES, Math.max(TASKS_LOGS_MIN_BYTES, Math.floor(value)));\n}\n\n/** Shared with the pending-call renderer so the window it shows is the one that runs. */\nexport function clampWaitMs(waitMs: number | undefined): number {\n\tconst value = waitMs !== undefined && Number.isFinite(waitMs) ? waitMs : TASKS_WAIT_DEFAULT_MS;\n\treturn Math.min(TASKS_WAIT_MAX_MS, Math.max(TASKS_WAIT_MIN_MS, Math.floor(value)));\n}\n\nexport function clampSinceBytes(sinceBytes: number | undefined): number | undefined {\n\treturn sinceBytes === undefined || !Number.isFinite(sinceBytes) ? undefined : Math.max(0, Math.floor(sinceBytes));\n}\n\nexport const TASKS_TOOL_DESCRIPTION =\n\t\"Inspect and control background tasks started by native tools or extensions. \" +\n\t\"Completion is delivered to you automatically as a notification — never poll. \" +\n\t\"list: bounded activity/history listing; find task IDs here. \" +\n\t\"read: bounded output or report slice (head/tail). \" +\n\t\"wait: block up to waitMs for one task to settle, or omit taskId to wait for any task running at call time; no running tasks returns immediately. New steering input ends only the wait with outcome interrupted; it never stops the task. \" +\n\t\"kill: request cancellation of a whole task. \" +\n\t\"tasks cannot start work; submit background work through its owning tool. A wait ends as settled, interrupted, timed_out, or no_tasks. Timeout or cancellation ends only the wait, never execution. Reads and settled waits report byte ranges; use next sinceBytes only with that task's ID. Output is capped at 50KB per response.\";\nexport const TASKS_PROMPT_SNIPPET = \"Manage background tasks; wait for a specific task or any running task\";\nexport const TASKS_PROMPT_GUIDELINES = [\n\t\"Start background work through its owning tool with background: true; continue independent work while it runs.\",\n\t\"A finished background task delivers its result automatically as a notification. Use tasks wait only when your next step is blocked: provide taskId for one task or omit it for any task running at call time; never sleep-poll with repeated reads.\",\n\t\"A new steering message interrupts only an active tasks wait so you can read the new input; it does not cancel execution. A wait timeout is not a task failure.\",\n];\n"]}
@@ -19,19 +19,25 @@ export interface TasksReadDetails {
19
19
  totalBytes: number;
20
20
  outputPath: string;
21
21
  }
22
+ export type TasksWaitOutcome = "settled" | "interrupted" | "timed_out" | "no_tasks";
22
23
  export interface TasksWaitDetails {
23
24
  kind?: TaskKind;
24
25
  action: "wait";
25
- taskId: string;
26
- /** True when the wait window expired and the task is still running. */
26
+ /** Absent only in historical results; new calls always record the reason the wait ended. */
27
+ outcome?: TasksWaitOutcome;
28
+ /** Undefined for waitAny with no selected task, or when no tasks were running. */
29
+ taskId?: string;
30
+ /** Retained for compatibility with historical details; true only for a wait-window expiry. */
27
31
  timedOut: boolean;
28
- status: TaskStatus;
32
+ status?: TaskStatus;
29
33
  exitCode: number | null | undefined;
30
34
  waitedMs: number;
31
35
  deltaBytes: number;
32
36
  totalBytes: number;
33
37
  deltaTruncated: boolean;
34
38
  outputPath: string;
39
+ /** Initial waitAny cohort members still running when the wait ended. */
40
+ running?: number;
35
41
  }
36
42
  export interface TasksKillDetails {
37
43
  requested?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAEpF,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,gBAAgB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/tools/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG","sourcesContent":["/**\n * The `tasks` tool's structured `details` payloads.\n *\n * Every shape here is JSON-serialized verbatim into the session file and read back\n * by the renderers on `/reload`, `/tree`, and session resume. Adding an optional\n * field is free; renaming or repurposing an existing one degrades historical\n * transcripts.\n *\n * `exitCode` is three-state: `null` for signal-reaped tasks.\n */\n\nimport type { TaskKind, TaskStatus } from \"../../tasks/types.ts\";\n\nexport interface TasksReadDetails {\n\tkind?: TaskKind;\n\tstatus?: TaskStatus;\n\taction: \"read\";\n\ttaskId: string;\n\tmode: \"head\" | \"tail\";\n\tsliceBytes: number;\n\ttotalBytes: number;\n\toutputPath: string;\n}\n\nexport interface TasksWaitDetails {\n\tkind?: TaskKind;\n\taction: \"wait\";\n\ttaskId: string;\n\t/** True when the wait window expired and the task is still running. */\n\ttimedOut: boolean;\n\tstatus: TaskStatus;\n\texitCode: number | null | undefined;\n\twaitedMs: number;\n\tdeltaBytes: number;\n\ttotalBytes: number;\n\tdeltaTruncated: boolean;\n\toutputPath: string;\n}\n\nexport interface TasksKillDetails {\n\trequested?: boolean;\n\tstatus?: TaskStatus;\n\taction: \"kill\";\n\ttaskId: string;\n\tcommand: string;\n}\n\nexport interface TasksListDetails {\n\taction: \"list\";\n\trunning: number;\n\tfinished: number;\n\tshown: number;\n\thidden: number;\n\t/** Foreground executions omitted from the listing; they deliver inline in the transcript. */\n\tforegroundOmitted?: number;\n}\n\nexport type TasksDetails = TasksReadDetails | TasksKillDetails | TasksListDetails | TasksWaitDetails;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/tools/tasks/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG","sourcesContent":["/**\n * The `tasks` tool's structured `details` payloads.\n *\n * Every shape here is JSON-serialized verbatim into the session file and read back\n * by the renderers on `/reload`, `/tree`, and session resume. Adding an optional\n * field is free; renaming or repurposing an existing one degrades historical\n * transcripts.\n *\n * `exitCode` is three-state: `null` for signal-reaped tasks.\n */\n\nimport type { TaskKind, TaskStatus } from \"../../tasks/types.ts\";\n\nexport interface TasksReadDetails {\n\tkind?: TaskKind;\n\tstatus?: TaskStatus;\n\taction: \"read\";\n\ttaskId: string;\n\tmode: \"head\" | \"tail\";\n\tsliceBytes: number;\n\ttotalBytes: number;\n\toutputPath: string;\n}\n\nexport type TasksWaitOutcome = \"settled\" | \"interrupted\" | \"timed_out\" | \"no_tasks\";\n\nexport interface TasksWaitDetails {\n\tkind?: TaskKind;\n\taction: \"wait\";\n\t/** Absent only in historical results; new calls always record the reason the wait ended. */\n\toutcome?: TasksWaitOutcome;\n\t/** Undefined for waitAny with no selected task, or when no tasks were running. */\n\ttaskId?: string;\n\t/** Retained for compatibility with historical details; true only for a wait-window expiry. */\n\ttimedOut: boolean;\n\tstatus?: TaskStatus;\n\texitCode: number | null | undefined;\n\twaitedMs: number;\n\tdeltaBytes: number;\n\ttotalBytes: number;\n\tdeltaTruncated: boolean;\n\toutputPath: string;\n\t/** Initial waitAny cohort members still running when the wait ended. */\n\trunning?: number;\n}\n\nexport interface TasksKillDetails {\n\trequested?: boolean;\n\tstatus?: TaskStatus;\n\taction: \"kill\";\n\ttaskId: string;\n\tcommand: string;\n}\n\nexport interface TasksListDetails {\n\taction: \"list\";\n\trunning: number;\n\tfinished: number;\n\tshown: number;\n\thidden: number;\n\t/** Foreground executions omitted from the listing; they deliver inline in the transcript. */\n\tforegroundOmitted?: number;\n}\n\nexport type TasksDetails = TasksReadDetails | TasksKillDetails | TasksListDetails | TasksWaitDetails;\n"]}
@@ -2,7 +2,7 @@ import { type TasksRenderState } from "../../modes/interactive/tasks/render.ts";
2
2
  import type { ToolDefinition } from "../extensions/types.ts";
3
3
  import { tasksSchema } from "./tasks/schema.ts";
4
4
  import type { TasksDetails } from "./tasks/types.ts";
5
- export declare function createTasksToolDefinition(onWaitResult?: (toolCallId: string, taskId: string) => void): ToolDefinition<typeof tasksSchema, TasksDetails, TasksRenderState>;
5
+ export declare function createTasksToolDefinition(onWaitResult?: (toolCallId: string, taskId: string) => void, waitInterruptSignal?: () => AbortSignal | undefined): ToolDefinition<typeof tasksSchema, TasksDetails, TasksRenderState>;
6
6
  export declare function createTasksTool(): import("@earendil-works/pi-agent-core").AgentTool<import("typebox").TObject<{
7
7
  action: import("typebox").TUnsafe<"read" | "list" | "wait" | "kill">;
8
8
  taskId: import("typebox").TOptional<import("typebox").TString>;
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../../src/core/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AACpH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAyE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,wBAAgB,yBAAyB,CACxC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GACzD,cAAc,CAAC,OAAO,WAAW,EAAE,YAAY,EAAE,gBAAgB,CAAC,CA8BpE;AAED,wBAAgB,eAAe;;;;;;;kBAE9B"}
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../../src/core/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AACpH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAyE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,wBAAgB,yBAAyB,CACxC,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,EAC3D,mBAAmB,CAAC,EAAE,MAAM,WAAW,GAAG,SAAS,GACjD,cAAc,CAAC,OAAO,WAAW,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAoCpE;AAED,wBAAgB,eAAe;;;;;;;kBAE9B"}
@@ -2,7 +2,7 @@ import { renderTasksCall, renderTasksResult } from "../../modes/interactive/task
2
2
  import { boundedText, runKill, runList, runRead, runWait } from "./tasks/actions.js";
3
3
  import { TASKS_PROMPT_GUIDELINES, TASKS_PROMPT_SNIPPET, TASKS_TOOL_DESCRIPTION, tasksSchema } from "./tasks/schema.js";
4
4
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
5
- export function createTasksToolDefinition(onWaitResult) {
5
+ export function createTasksToolDefinition(onWaitResult, waitInterruptSignal) {
6
6
  return {
7
7
  name: "tasks",
8
8
  label: "tasks",
@@ -17,7 +17,7 @@ export function createTasksToolDefinition(onWaitResult) {
17
17
  case "read":
18
18
  return await runRead(ctx.tasks, params);
19
19
  case "wait":
20
- return await runWait(ctx.tasks, params, signal, (taskId) => onWaitResult?.(_id, taskId));
20
+ return await runWait(ctx.tasks, params, signal, (taskId) => onWaitResult?.(_id, taskId), waitInterruptSignal?.());
21
21
  case "kill":
22
22
  return runKill(ctx.tasks, params);
23
23
  case "list":
@@ -1 +1 @@
1
- {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../../src/core/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAyB,MAAM,yCAAyC,CAAC;AAEpH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvH,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,yBAAyB,CACxC,YAA2D;IAE3D,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,sBAAsB;QACnC,aAAa,EAAE,oBAAoB;QACnC,gBAAgB,EAAE,uBAAuB;QACzC,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9D,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;YAChD,IAAI,CAAC;gBACJ,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;oBACvB,KAAK,MAAM;wBACV,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACzC,KAAK,MAAM;wBACV,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;oBAC1F,KAAK,MAAM;wBACV,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACnC,KAAK,MAAM;wBACV,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC5B,CAAC;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,uEAAuE;gBACvE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;YACvC,CAAC;QACF,CAAC;QACD,UAAU,EAAE,eAAe;QAC3B,YAAY,EAAE,iBAAiB;KAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,kBAAkB,CAAC,yBAAyB,EAAE,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import { renderTasksCall, renderTasksResult, type TasksRenderState } from \"../../modes/interactive/tasks/render.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { boundedText, runKill, runList, runRead, runWait } from \"./tasks/actions.ts\";\nimport { TASKS_PROMPT_GUIDELINES, TASKS_PROMPT_SNIPPET, TASKS_TOOL_DESCRIPTION, tasksSchema } from \"./tasks/schema.ts\";\nimport type { TasksDetails } from \"./tasks/types.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nexport function createTasksToolDefinition(\n\tonWaitResult?: (toolCallId: string, taskId: string) => void,\n): ToolDefinition<typeof tasksSchema, TasksDetails, TasksRenderState> {\n\treturn {\n\t\tname: \"tasks\",\n\t\tlabel: \"tasks\",\n\t\tdescription: TASKS_TOOL_DESCRIPTION,\n\t\tpromptSnippet: TASKS_PROMPT_SNIPPET,\n\t\tpromptGuidelines: TASKS_PROMPT_GUIDELINES,\n\t\tparameters: tasksSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(_id, params, signal, _onUpdate, ctx) {\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"read\":\n\t\t\t\t\t\treturn await runRead(ctx.tasks, params);\n\t\t\t\t\tcase \"wait\":\n\t\t\t\t\t\treturn await runWait(ctx.tasks, params, signal, (taskId) => onWaitResult?.(_id, taskId));\n\t\t\t\t\tcase \"kill\":\n\t\t\t\t\t\treturn runKill(ctx.tasks, params);\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\treturn runList(ctx.tasks);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Lookup failures already carry the current task list from actions.ts.\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(boundedText(message));\n\t\t\t}\n\t\t},\n\t\trenderCall: renderTasksCall,\n\t\trenderResult: renderTasksResult,\n\t};\n}\n\nexport function createTasksTool() {\n\treturn wrapToolDefinition(createTasksToolDefinition());\n}\n"]}
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../../src/core/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAyB,MAAM,yCAAyC,CAAC;AAEpH,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvH,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,yBAAyB,CACxC,YAA2D,EAC3D,mBAAmD;IAEnD,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EAAE,sBAAsB;QACnC,aAAa,EAAE,oBAAoB;QACnC,gBAAgB,EAAE,uBAAuB;QACzC,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9D,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;YAChD,IAAI,CAAC;gBACJ,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;oBACvB,KAAK,MAAM;wBACV,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACzC,KAAK,MAAM;wBACV,OAAO,MAAM,OAAO,CACnB,GAAG,CAAC,KAAK,EACT,MAAM,EACN,MAAM,EACN,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,EACvC,mBAAmB,EAAE,EAAE,CACvB,CAAC;oBACH,KAAK,MAAM;wBACV,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACnC,KAAK,MAAM;wBACV,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC5B,CAAC;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,uEAAuE;gBACvE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;YACvC,CAAC;QACF,CAAC;QACD,UAAU,EAAE,eAAe;QAC3B,YAAY,EAAE,iBAAiB;KAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,kBAAkB,CAAC,yBAAyB,EAAE,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import { renderTasksCall, renderTasksResult, type TasksRenderState } from \"../../modes/interactive/tasks/render.ts\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport { boundedText, runKill, runList, runRead, runWait } from \"./tasks/actions.ts\";\nimport { TASKS_PROMPT_GUIDELINES, TASKS_PROMPT_SNIPPET, TASKS_TOOL_DESCRIPTION, tasksSchema } from \"./tasks/schema.ts\";\nimport type { TasksDetails } from \"./tasks/types.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nexport function createTasksToolDefinition(\n\tonWaitResult?: (toolCallId: string, taskId: string) => void,\n\twaitInterruptSignal?: () => AbortSignal | undefined,\n): ToolDefinition<typeof tasksSchema, TasksDetails, TasksRenderState> {\n\treturn {\n\t\tname: \"tasks\",\n\t\tlabel: \"tasks\",\n\t\tdescription: TASKS_TOOL_DESCRIPTION,\n\t\tpromptSnippet: TASKS_PROMPT_SNIPPET,\n\t\tpromptGuidelines: TASKS_PROMPT_GUIDELINES,\n\t\tparameters: tasksSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(_id, params, signal, _onUpdate, ctx) {\n\t\t\ttry {\n\t\t\t\tswitch (params.action) {\n\t\t\t\t\tcase \"read\":\n\t\t\t\t\t\treturn await runRead(ctx.tasks, params);\n\t\t\t\t\tcase \"wait\":\n\t\t\t\t\t\treturn await runWait(\n\t\t\t\t\t\t\tctx.tasks,\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t(taskId) => onWaitResult?.(_id, taskId),\n\t\t\t\t\t\t\twaitInterruptSignal?.(),\n\t\t\t\t\t\t);\n\t\t\t\t\tcase \"kill\":\n\t\t\t\t\t\treturn runKill(ctx.tasks, params);\n\t\t\t\t\tcase \"list\":\n\t\t\t\t\t\treturn runList(ctx.tasks);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Lookup failures already carry the current task list from actions.ts.\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(boundedText(message));\n\t\t\t}\n\t\t},\n\t\trenderCall: renderTasksCall,\n\t\trenderResult: renderTasksResult,\n\t};\n}\n\nexport function createTasksTool() {\n\treturn wrapToolDefinition(createTasksToolDefinition());\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/execute.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsBtG,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,gCAAgC,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,OAAO,EAMN,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGxB,MAAM,WAAW,CAAC;AAmMnB,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAU1F;AAyLD;;;GAGG;AACH,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAC9E,GAAG,EAAE,oBAAoB,GAAG,SAAS,EACrC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CA+H/C"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/execute.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsBtG,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,gCAAgC,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,OAAO,EAMN,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGxB,MAAM,WAAW,CAAC;AAuPnB,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAU1F;AAyLD;;;GAGG;AACH,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAC9E,GAAG,EAAE,oBAAoB,GAAG,SAAS,EACrC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAyJ/C"}
@@ -20,8 +20,55 @@ const MAX_CONCURRENT_MODEL_CALLS = 4;
20
20
  */
21
21
  const CODEMODE_MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;
22
22
  // Shared across calls and sessions. Allow one replacement while a cancelled worker is still exiting.
23
- const MAX_CONCURRENT_CODEMODE_WORKERS = 2;
23
+ const DEFAULT_MAX_CODEMODE_WORKERS = 2;
24
+ /** `PI_CODEMODE_MAX_WORKERS` if it is a positive integer. Read per call so SDK hosts can set it at runtime. */
25
+ function maxCodemodeWorkers() {
26
+ const value = Number(process.env.PI_CODEMODE_MAX_WORKERS);
27
+ return Number.isInteger(value) && value > 0 ? value : DEFAULT_MAX_CODEMODE_WORKERS;
28
+ }
29
+ /**
30
+ * How long a script waits for a free worker before failing. Bounds the wait when every worker is
31
+ * held by a script that waits on another script, for example an in-process subagent that uses codemode.
32
+ */
33
+ const CODEMODE_WORKER_WAIT_MS = 60_000;
24
34
  let activeCodemodeWorkers = 0;
35
+ /** Scripts waiting for a worker, in arrival order. */
36
+ const codemodeWorkerWaiters = [];
37
+ /**
38
+ * Reserve one worker slot, waiting in arrival order while all are taken. Resolves with why it could
39
+ * not reserve one: the signal aborted, or `timeoutMs` passed.
40
+ */
41
+ function reserveCodemodeWorker(signal, timeoutMs) {
42
+ if (signal?.aborted)
43
+ return Promise.resolve("aborted");
44
+ return new Promise((resolve) => {
45
+ const settle = (outcome) => {
46
+ clearTimeout(timer);
47
+ signal?.removeEventListener("abort", onAbort);
48
+ const index = codemodeWorkerWaiters.indexOf(grant);
49
+ if (index >= 0)
50
+ codemodeWorkerWaiters.splice(index, 1);
51
+ resolve(outcome);
52
+ };
53
+ const grant = () => settle("reserved");
54
+ const onAbort = () => settle("aborted");
55
+ const timer = setTimeout(() => settle("timeout"), timeoutMs);
56
+ codemodeWorkerWaiters.push(grant);
57
+ signal?.addEventListener("abort", onAbort, { once: true });
58
+ admitCodemodeWorkers();
59
+ });
60
+ }
61
+ /** Give free slots to waiting scripts in arrival order. */
62
+ function admitCodemodeWorkers() {
63
+ while (codemodeWorkerWaiters.length > 0 && activeCodemodeWorkers < maxCodemodeWorkers()) {
64
+ activeCodemodeWorkers++;
65
+ codemodeWorkerWaiters.shift()?.();
66
+ }
67
+ }
68
+ function releaseCodemodeWorker() {
69
+ activeCodemodeWorkers--;
70
+ admitCodemodeWorkers();
71
+ }
25
72
  const MODEL_TYPES = new Set(["chat", "image", "classifier"]);
26
73
  function truncateText(text, maxChars) {
27
74
  return text.length > maxChars ? `${text.slice(0, maxChars - 3)}...` : text;
@@ -432,35 +479,63 @@ export async function executeCodemode(toolCallId, input, signal, onUpdate, ctx,
432
479
  return toScriptValue(tool, outcome);
433
480
  },
434
481
  }));
435
- const sandbox = new CodemodeSandbox({
436
- tools: sandboxTools,
437
- globals: [
438
- ...createDiscoveryGlobals(callable, samples, options),
439
- ...(options.models && ctx
440
- ? createModelGlobals(ctx.modelRegistry, toolCallId, calls, publish, addModelUsage, addGeneratedImages)
441
- : []),
442
- ],
443
- timeoutMs: sourceOptions.timeoutMs ?? Number.POSITIVE_INFINITY,
444
- memoryLimitBytes: CODEMODE_MEMORY_LIMIT_BYTES,
445
- wasm: loadQuickJSWasm(getQuickJSWasmPath()),
446
- workerUrl: getCodemodeWorkerSpecifier(),
447
- acquireWorker: () => {
448
- if (activeCodemodeWorkers >= MAX_CONCURRENT_CODEMODE_WORKERS) {
449
- throw new Error(`Codemode worker limit reached (${MAX_CONCURRENT_CODEMODE_WORKERS} workers are still running or shutting down). Retry after they exit.`);
450
- }
451
- activeCodemodeWorkers++;
452
- return () => {
453
- activeCodemodeWorkers--;
454
- };
455
- },
456
- });
482
+ // The wait for a worker counts toward the script's deadline.
483
+ const deadline = sourceOptions.timeoutMs ?? Number.POSITIVE_INFINITY;
484
+ const waitStartedAt = performance.now();
485
+ const admission = await reserveCodemodeWorker(signal, Math.min(deadline, CODEMODE_WORKER_WAIT_MS));
486
+ const waitedMs = performance.now() - waitStartedAt;
487
+ if (admission !== "reserved") {
488
+ const waited = ((performance.now() - startedAt) / 1000).toFixed(1);
489
+ const reason = signal?.reason;
490
+ const error = admission === "aborted"
491
+ ? `Script aborted: ${reason instanceof Error ? reason.message : "Execution aborted"}`
492
+ : deadline <= CODEMODE_WORKER_WAIT_MS
493
+ ? `Script timed out: Execution timed out after ${deadline} ms while waiting for a free codemode worker`
494
+ : `No codemode worker became free within ${CODEMODE_WORKER_WAIT_MS / 1000} seconds. All ${maxCodemodeWorkers()} workers, shared by every session in this process, are held by other scripts. Retry after they finish.`;
495
+ return {
496
+ content: [
497
+ { type: "text", text: `Script failed\nWall time ${waited} seconds\nOutput:\n` },
498
+ { type: "text", text: `Script error:\n${error}\n\nThe script did not start.` },
499
+ ],
500
+ details: snapshot(),
501
+ isError: true,
502
+ };
503
+ }
504
+ // The reservation covers the one worker this script starts. A launch that resumes after the result
505
+ // settled finds it released and starts no worker.
506
+ let reserved = true;
507
+ let sandbox;
457
508
  let result;
458
509
  try {
510
+ sandbox = new CodemodeSandbox({
511
+ tools: sandboxTools,
512
+ globals: [
513
+ ...createDiscoveryGlobals(callable, samples, options),
514
+ ...(options.models && ctx
515
+ ? createModelGlobals(ctx.modelRegistry, toolCallId, calls, publish, addModelUsage, addGeneratedImages)
516
+ : []),
517
+ ],
518
+ timeoutMs: Math.max(1, Math.round(deadline - waitedMs)),
519
+ memoryLimitBytes: CODEMODE_MEMORY_LIMIT_BYTES,
520
+ wasm: loadQuickJSWasm(getQuickJSWasmPath()),
521
+ workerUrl: getCodemodeWorkerSpecifier(),
522
+ acquireWorker: () => {
523
+ if (!reserved)
524
+ throw new Error("The script already settled");
525
+ // From here the sandbox releases the slot when the worker actually exits.
526
+ reserved = false;
527
+ return releaseCodemodeWorker;
528
+ },
529
+ });
459
530
  const store = ctx ? readCodemodeStore(ctx.sessionManager.getBranch()) : {};
460
531
  result = await sandbox.execute(code, { signal, store });
461
532
  }
462
533
  finally {
463
- await sandbox.close();
534
+ await sandbox?.close();
535
+ if (reserved) {
536
+ reserved = false;
537
+ releaseCodemodeWorker();
538
+ }
464
539
  }
465
540
  // Calls still marked running were cut off by the script ending, a timeout, or an abort.
466
541
  for (const call of calls) {