@astralyn/pi 1.4.6 → 1.4.7

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 (242) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/bundle/chunks/{chunk-KDO6L76C.js → chunk-FODCTZXW.js} +4 -4
  3. package/dist/bundle/chunks/{chunk-EYKC6ESU.js → chunk-FYKNSJG6.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-AXFWZIHH.js → chunk-MG5XDTXV.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-ALHAFUHP.js → chunk-PU2IWWXV.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-5M3YJ54Z.js → chunk-RO2VH6UZ.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-RBTJBQWX.js → chunk-YJTSOLP2.js} +73 -74
  8. package/dist/bundle/chunks/{cli-FH77R7JR.js → cli-MEL7SGJD.js} +1 -1
  9. package/dist/bundle/chunks/{execute-5ZQUS52M.js → execute-4CWRNHPO.js} +1 -1
  10. package/dist/bundle/chunks/{runtime-R5CMHJ5P.js → runtime-R3X67XMR.js} +1 -1
  11. package/dist/bundle/chunks/{virtual-modules-KCQU7LOC.js → virtual-modules-PKEOKGYI.js} +1 -1
  12. package/dist/bundle/cli.js +1 -1
  13. package/dist/bundle/index.js +1 -1
  14. package/dist/bundle/rpc-entry.js +1 -1
  15. package/dist/core/agent-session.d.ts +0 -3
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +0 -4
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/extensions/index.d.ts +1 -1
  20. package/dist/core/extensions/index.d.ts.map +1 -1
  21. package/dist/core/extensions/index.js.map +1 -1
  22. package/dist/core/package-manager.d.ts +7 -1
  23. package/dist/core/package-manager.d.ts.map +1 -1
  24. package/dist/core/package-manager.js +72 -1
  25. package/dist/core/package-manager.js.map +1 -1
  26. package/dist/core/resource-loader.d.ts +1 -0
  27. package/dist/core/resource-loader.d.ts.map +1 -1
  28. package/dist/core/resource-loader.js +23 -7
  29. package/dist/core/resource-loader.js.map +1 -1
  30. package/dist/core/settings-manager.d.ts +4 -2
  31. package/dist/core/settings-manager.d.ts.map +1 -1
  32. package/dist/core/settings-manager.js +11 -0
  33. package/dist/core/settings-manager.js.map +1 -1
  34. package/dist/core/settings-schema.d.ts +7 -0
  35. package/dist/core/settings-schema.d.ts.map +1 -1
  36. package/dist/core/settings-schema.js +6 -0
  37. package/dist/core/settings-schema.js.map +1 -1
  38. package/dist/core/skills.d.ts +10 -0
  39. package/dist/core/skills.d.ts.map +1 -1
  40. package/dist/core/skills.js +23 -0
  41. package/dist/core/skills.js.map +1 -1
  42. package/dist/core/tasks/delivery.d.ts +11 -4
  43. package/dist/core/tasks/delivery.d.ts.map +1 -1
  44. package/dist/core/tasks/delivery.js +9 -9
  45. package/dist/core/tasks/delivery.js.map +1 -1
  46. package/dist/core/tasks/execution.d.ts +10 -3
  47. package/dist/core/tasks/execution.d.ts.map +1 -1
  48. package/dist/core/tasks/execution.js +72 -52
  49. package/dist/core/tasks/execution.js.map +1 -1
  50. package/dist/core/tasks/format.d.ts +0 -2
  51. package/dist/core/tasks/format.d.ts.map +1 -1
  52. package/dist/core/tasks/format.js +1 -16
  53. package/dist/core/tasks/format.js.map +1 -1
  54. package/dist/core/tasks/limits.d.ts +12 -1
  55. package/dist/core/tasks/limits.d.ts.map +1 -1
  56. package/dist/core/tasks/limits.js +20 -1
  57. package/dist/core/tasks/limits.js.map +1 -1
  58. package/dist/core/tasks/output.d.ts +6 -12
  59. package/dist/core/tasks/output.d.ts.map +1 -1
  60. package/dist/core/tasks/output.js +35 -32
  61. package/dist/core/tasks/output.js.map +1 -1
  62. package/dist/core/tasks/record.d.ts +45 -0
  63. package/dist/core/tasks/record.d.ts.map +1 -0
  64. package/dist/core/tasks/record.js +80 -0
  65. package/dist/core/tasks/record.js.map +1 -0
  66. package/dist/core/tasks/runtime.d.ts +14 -14
  67. package/dist/core/tasks/runtime.d.ts.map +1 -1
  68. package/dist/core/tasks/runtime.js +111 -93
  69. package/dist/core/tasks/runtime.js.map +1 -1
  70. package/dist/core/tasks/session.d.ts +0 -1
  71. package/dist/core/tasks/session.d.ts.map +1 -1
  72. package/dist/core/tasks/session.js +7 -8
  73. package/dist/core/tasks/session.js.map +1 -1
  74. package/dist/core/tasks/store.d.ts +18 -25
  75. package/dist/core/tasks/store.d.ts.map +1 -1
  76. package/dist/core/tasks/store.js +42 -40
  77. package/dist/core/tasks/store.js.map +1 -1
  78. package/dist/core/tasks/types.d.ts +96 -17
  79. package/dist/core/tasks/types.d.ts.map +1 -1
  80. package/dist/core/tasks/types.js.map +1 -1
  81. package/dist/core/tools/shell-execution.d.ts +8 -7
  82. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  83. package/dist/core/tools/shell-execution.js +18 -26
  84. package/dist/core/tools/shell-execution.js.map +1 -1
  85. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  86. package/dist/core/tools/shell-tool.js +31 -29
  87. package/dist/core/tools/shell-tool.js.map +1 -1
  88. package/dist/core/usage-totals.d.ts +3 -0
  89. package/dist/core/usage-totals.d.ts.map +1 -1
  90. package/dist/core/usage-totals.js +15 -0
  91. package/dist/core/usage-totals.js.map +1 -1
  92. package/dist/extensions/agent/progress.d.ts.map +1 -1
  93. package/dist/extensions/agent/progress.js +1 -11
  94. package/dist/extensions/agent/progress.js.map +1 -1
  95. package/dist/extensions/agent/tool.d.ts.map +1 -1
  96. package/dist/extensions/agent/tool.js +9 -5
  97. package/dist/extensions/agent/tool.js.map +1 -1
  98. package/dist/extensions/agent/worker.d.ts.map +1 -1
  99. package/dist/extensions/agent/worker.js +3 -5
  100. package/dist/extensions/agent/worker.js.map +1 -1
  101. package/dist/extensions/btw/agent.d.ts +1 -1
  102. package/dist/extensions/btw/agent.d.ts.map +1 -1
  103. package/dist/extensions/btw/agent.js +3 -20
  104. package/dist/extensions/btw/agent.js.map +1 -1
  105. package/dist/extensions/cached-compaction/index.d.ts.map +1 -1
  106. package/dist/extensions/cached-compaction/index.js +3 -22
  107. package/dist/extensions/cached-compaction/index.js.map +1 -1
  108. package/dist/extensions/cached-compaction/render.d.ts +1 -0
  109. package/dist/extensions/cached-compaction/render.d.ts.map +1 -1
  110. package/dist/extensions/cached-compaction/render.js +42 -14
  111. package/dist/extensions/cached-compaction/render.js.map +1 -1
  112. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  113. package/dist/extensions/deepwiki/client.js +6 -78
  114. package/dist/extensions/deepwiki/client.js.map +1 -1
  115. package/dist/extensions/deepwiki/transport.d.ts +3 -0
  116. package/dist/extensions/deepwiki/transport.d.ts.map +1 -0
  117. package/dist/extensions/deepwiki/transport.js +96 -0
  118. package/dist/extensions/deepwiki/transport.js.map +1 -0
  119. package/dist/extensions/provider/ui/builtin-data.d.ts +3 -3
  120. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  121. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  122. package/dist/extensions/provider/ui/compat.d.ts +3 -3
  123. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  124. package/dist/extensions/provider/ui/compat.js.map +1 -1
  125. package/dist/extensions/provider/ui/controls.d.ts +2 -2
  126. package/dist/extensions/provider/ui/controls.d.ts.map +1 -1
  127. package/dist/extensions/provider/ui/controls.js.map +1 -1
  128. package/dist/extensions/provider/ui/dialogs.d.ts +3 -3
  129. package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -1
  130. package/dist/extensions/provider/ui/dialogs.js.map +1 -1
  131. package/dist/extensions/provider/ui/dictionary.d.ts +2 -2
  132. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  133. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  134. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  135. package/dist/extensions/provider/ui/editor.js +1 -3
  136. package/dist/extensions/provider/ui/editor.js.map +1 -1
  137. package/dist/extensions/provider/ui/fetch-models.d.ts +2 -2
  138. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  139. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  140. package/dist/extensions/provider/ui/model-fields.d.ts +2 -2
  141. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  142. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  143. package/dist/extensions/provider/ui/model-options.d.ts +6 -6
  144. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  145. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  146. package/dist/extensions/provider/ui/pane.d.ts +21 -12
  147. package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
  148. package/dist/extensions/provider/ui/pane.js.map +1 -1
  149. package/dist/extensions/provider/ui/provider-fields.d.ts +3 -3
  150. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  151. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  152. package/dist/extensions/provider/ui/thinking-map.d.ts +2 -2
  153. package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
  154. package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
  155. package/dist/extensions/run-summary/format.js +1 -1
  156. package/dist/extensions/run-summary/format.js.map +1 -1
  157. package/dist/extensions/statusline/usage.d.ts.map +1 -1
  158. package/dist/extensions/statusline/usage.js +2 -6
  159. package/dist/extensions/statusline/usage.js.map +1 -1
  160. package/dist/extensions/tasks/tool/actions.d.ts +1 -1
  161. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  162. package/dist/extensions/tasks/tool/actions.js +49 -106
  163. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  164. package/dist/extensions/tasks/tool/constants.d.ts +1 -6
  165. package/dist/extensions/tasks/tool/constants.d.ts.map +1 -1
  166. package/dist/extensions/tasks/tool/constants.js +1 -6
  167. package/dist/extensions/tasks/tool/constants.js.map +1 -1
  168. package/dist/extensions/tasks/tool/schema.d.ts +0 -3
  169. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  170. package/dist/extensions/tasks/tool/schema.js +4 -13
  171. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  172. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  173. package/dist/extensions/tasks/tool.js +2 -2
  174. package/dist/extensions/tasks/tool.js.map +1 -1
  175. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  176. package/dist/extensions/tasks/ui/completion-render.js +31 -33
  177. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  178. package/dist/extensions/tasks/ui/layout.d.ts +7 -7
  179. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  180. package/dist/extensions/tasks/ui/layout.js +17 -19
  181. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  182. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  183. package/dist/extensions/tasks/ui/list.js +2 -3
  184. package/dist/extensions/tasks/ui/list.js.map +1 -1
  185. package/dist/extensions/tasks/ui/manager.d.ts +16 -7
  186. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  187. package/dist/extensions/tasks/ui/manager.js +163 -131
  188. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  189. package/dist/extensions/tasks/ui/model.d.ts +25 -0
  190. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  191. package/dist/extensions/tasks/ui/model.js +4 -0
  192. package/dist/extensions/tasks/ui/model.js.map +1 -1
  193. package/dist/extensions/tasks/ui/render.d.ts +1 -1
  194. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  195. package/dist/extensions/tasks/ui/render.js +11 -7
  196. package/dist/extensions/tasks/ui/render.js.map +1 -1
  197. package/dist/extensions/tasks/ui/status.d.ts +15 -0
  198. package/dist/extensions/tasks/ui/status.d.ts.map +1 -0
  199. package/dist/extensions/tasks/ui/status.js +16 -0
  200. package/dist/extensions/tasks/ui/status.js.map +1 -0
  201. package/dist/index.d.ts +1 -1
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js.map +1 -1
  204. package/dist/modes/interactive/components/config-selector.d.ts +14 -1
  205. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  206. package/dist/modes/interactive/components/config-selector.js +258 -7
  207. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  208. package/dist/modes/interactive/components/status-marker.d.ts +2 -1
  209. package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
  210. package/dist/modes/interactive/components/status-marker.js +0 -1
  211. package/dist/modes/interactive/components/status-marker.js.map +1 -1
  212. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  213. package/dist/modes/interactive/interactive-mode.js +7 -1
  214. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  215. package/dist/utils/duration.d.ts +3 -0
  216. package/dist/utils/duration.d.ts.map +1 -0
  217. package/dist/utils/duration.js +17 -0
  218. package/dist/utils/duration.js.map +1 -0
  219. package/dist/utils/number.d.ts +3 -0
  220. package/dist/utils/number.d.ts.map +1 -0
  221. package/dist/utils/number.js +5 -0
  222. package/dist/utils/number.js.map +1 -0
  223. package/docs/bundled/extensions/agent.md +3 -3
  224. package/docs/bundled/extensions/cached-compaction.md +13 -4
  225. package/docs/bundled/extensions/deepwiki.md +3 -1
  226. package/docs/extensions.md +5 -5
  227. package/docs/packages.md +5 -3
  228. package/docs/sdk.md +1 -1
  229. package/docs/session-format.md +1 -1
  230. package/docs/settings.md +11 -0
  231. package/docs/skills.md +23 -0
  232. package/npm-shrinkwrap.json +2 -2
  233. package/package.json +1 -1
  234. package/schemas/settings.schema.json +36 -0
  235. package/dist/extensions/deepwiki/http.d.ts +0 -13
  236. package/dist/extensions/deepwiki/http.d.ts.map +0 -1
  237. package/dist/extensions/deepwiki/http.js +0 -88
  238. package/dist/extensions/deepwiki/http.js.map +0 -1
  239. package/dist/extensions/tasks/ui/task-view.d.ts +0 -8
  240. package/dist/extensions/tasks/ui/task-view.d.ts.map +0 -1
  241. package/dist/extensions/tasks/ui/task-view.js +0 -13
  242. package/dist/extensions/tasks/ui/task-view.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"shell-tool.js","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport type { TaskCompletion } from \"../tasks/types.ts\";\nimport {\n\ttype BashOperations,\n\ttype BashToolOptions,\n\tresolveSpawnContext,\n\tresolveTimeoutMs,\n\ttype ShellToolConfig,\n} from \"./bash.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { type ManagedShellExecution, runShellCommand } from \"./shell-execution.ts\";\nimport { createLocalBashOperations } from \"./shell-operations.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background, and you are notified when it completes — do not poll for its result; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nconst bashOutputSchema = Type.Union([\n\tType.Object({\n\t\toutput: Type.String({\n\t\t\tdescription: \"Combined stdout and stderr, up to 1 MiB, keeping head and tail when truncated.\",\n\t\t}),\n\t\ttruncated: Type.Boolean(),\n\t\tfull_output_path: Type.Optional(Type.String()),\n\t\texit_code: Type.Number(),\n\t\twall_time_seconds: Type.Number(),\n\t}),\n\tType.Object({ task_id: Type.String(), status: Type.String() }),\n]);\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: string };\n}\n\nexport type BashRenderState = {\n\tdispose?: () => void;\n};\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: TaskCompletion<BashToolDetails | undefined>) {\n\tconst status = completion.status;\n\tif (completion.result.structuredContent) return completion.result;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions: BashToolOptions & { operations: BashOperations },\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options.operations;\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use tasks read to inspect output, tasks wait with an ID for one task or without one for any running task, and tasks kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired tasks wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\toutputSchema: bashOutputSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst host = ctx?.tasks;\n\t\t\tif (host?.closed) throw new Error(\"Task service is closed\");\n\t\t\tconst run = async (managed?: ManagedShellExecution): Promise<TaskCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tconst signal = managed?.control.signal ?? parentSignal;\n\t\t\t\tif (managed) {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Command aborted\");\n\t\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\t}\n\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\tresolvedCommand,\n\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\tspawnHook,\n\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\tctx,\n\t\t\t\t);\n\t\t\t\t// A setup throw settles a managed task as failed, or cancelled once its signal fired.\n\t\t\t\treturn await runShellCommand({\n\t\t\t\t\toperations: ops,\n\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\ttimeout,\n\t\t\t\t\tsignal,\n\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\tmanaged,\n\t\t\t\t});\n\t\t\t};\n\t\t\tif (!host) {\n\t\t\t\tif (background)\n\t\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t\treturn shellToolResult(await run());\n\t\t\t}\n\t\t\tconst outcome = await host.execute<BashToolDetails | undefined>({\n\t\t\t\tkind: config.name,\n\t\t\t\tlabel: config.shellName[0]!.toUpperCase() + config.shellName.slice(1),\n\t\t\t\ttitle: command,\n\t\t\t\tinput: { label: \"Command\", text: command, truncated: false, language: config.name },\n\t\t\t\tfacts: [[\"Directory\", ctx?.cwd || cwd]],\n\t\t\t\ttoolCallId,\n\t\t\t\tbackground,\n\t\t\t\tsignal: parentSignal,\n\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\trun: (control) => run({ control }),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome);\n\t\t\tconst tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use tasks read to inspect output, tasks wait only when your next step is blocked on a result (one ID or any running task; prefer foreground next time in that case), or tasks kill to stop it.`;\n\t\t\t// Shell execution can become background work in two ways, and the model has to know which\n\t\t\t// one it got: a submitted background command starts from an empty log, while a detached\n\t\t\t// one already holds output and keeps its original timeout.\n\t\t\tconst handoff =\n\t\t\t\tbackground === true\n\t\t\t\t\t? `Command handed to background. ${tail}`\n\t\t\t\t\t: `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so tasks read now returns partial output, not a fresh start. ${tail}`;\n\t\t\treturn {\n\t\t\t\tstructuredContent: { task_id: outcome.task.id, status: outcome.task.status },\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `${handoff}${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"pi-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ReturnType<typeof createShellToolDefinition> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, {\n\t\t...options,\n\t\toperations: options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath }),\n\t});\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions) {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
1
+ {"version":3,"file":"shell-tool.js","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { TaskRuntime } from \"../tasks/runtime.ts\";\nimport type { TaskCompletion, TaskControl, TaskToolOutcome } from \"../tasks/types.ts\";\nimport {\n\ttype BashOperations,\n\ttype BashToolOptions,\n\tresolveSpawnContext,\n\tresolveTimeoutMs,\n\ttype ShellToolConfig,\n} from \"./bash.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { runShellCommand } from \"./shell-execution.ts\";\nimport { createLocalBashOperations } from \"./shell-operations.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background, and you are notified when it completes — do not poll for its result; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nconst bashOutputSchema = Type.Union([\n\tType.Object({\n\t\toutput: Type.String({\n\t\t\tdescription: \"Combined stdout and stderr, up to 1 MiB, keeping head and tail when truncated.\",\n\t\t}),\n\t\ttruncated: Type.Boolean(),\n\t\tfull_output_path: Type.Optional(Type.String()),\n\t\texit_code: Type.Number(),\n\t\twall_time_seconds: Type.Number(),\n\t}),\n\tType.Object({ task_id: Type.String(), status: Type.String() }),\n]);\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: string };\n}\n\nexport type BashRenderState = {\n\tdispose?: () => void;\n};\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: TaskCompletion<BashToolDetails | undefined>) {\n\tconst status = completion.status;\n\tif (completion.result.structuredContent) return completion.result;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions: BashToolOptions & { operations: BashOperations },\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options.operations;\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use tasks read to inspect output, tasks wait with an ID for one task or without one for any running task, and tasks kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired tasks wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\toutputSchema: bashOutputSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst sessionTasks = ctx?.tasks;\n\t\t\tif (sessionTasks?.closed) throw new Error(\"Task service is closed\");\n\t\t\tif (!sessionTasks && background)\n\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t// Without a session the command still runs as a task, on a throwaway runtime that never backgrounds.\n\t\t\tconst standalone = sessionTasks ? undefined : new TaskRuntime();\n\t\t\tconst run = async (\n\t\t\t\tcontrol: TaskControl<BashToolDetails | undefined>,\n\t\t\t): Promise<TaskCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tif (control.signal.aborted) throw new Error(\"Command aborted\");\n\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\tresolvedCommand,\n\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\tspawnHook,\n\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\tctx,\n\t\t\t\t);\n\t\t\t\t// A setup throw settles the task as failed, or cancelled once its signal fired.\n\t\t\t\treturn await runShellCommand({\n\t\t\t\t\toperations: ops,\n\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\ttimeout,\n\t\t\t\t\tcontrol,\n\t\t\t\t\ttaskLog: sessionTasks !== undefined,\n\t\t\t\t});\n\t\t\t};\n\t\t\tlet outcome: TaskToolOutcome<BashToolDetails | undefined>;\n\t\t\ttry {\n\t\t\t\toutcome = await (sessionTasks ?? standalone!).execute<BashToolDetails | undefined>({\n\t\t\t\t\tkind: config.name,\n\t\t\t\t\tlabel: config.shellName[0]!.toUpperCase() + config.shellName.slice(1),\n\t\t\t\t\ttitle: command,\n\t\t\t\t\tinput: { label: \"Command\", text: command, truncated: false, language: config.name },\n\t\t\t\t\tfacts: [[\"Directory\", ctx?.cwd || cwd]],\n\t\t\t\t\ttoolCallId,\n\t\t\t\t\tbackground,\n\t\t\t\t\tsignal: parentSignal,\n\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\trun,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tstandalone?.close();\n\t\t\t}\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome);\n\t\t\tconst tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use tasks read to inspect output, tasks wait only when your next step is blocked on a result (one ID or any running task; prefer foreground next time in that case), or tasks kill to stop it.`;\n\t\t\t// Shell execution can become background work in two ways, and the model has to know which\n\t\t\t// one it got: a submitted background command starts from an empty log, while a detached\n\t\t\t// one already holds output and keeps its original timeout.\n\t\t\tconst handoff =\n\t\t\t\tbackground === true\n\t\t\t\t\t? `Command handed to background. ${tail}`\n\t\t\t\t\t: `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so tasks read now returns partial output, not a fresh start. ${tail}`;\n\t\t\treturn {\n\t\t\t\tstructuredContent: { task_id: outcome.task.id, status: outcome.task.status },\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `${handoff}${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"pi-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ReturnType<typeof createShellToolDefinition> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, {\n\t\t...options,\n\t\toperations: options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath }),\n\t});\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions) {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
@@ -11,6 +11,9 @@ export declare function createUsageTotals(): UsageTotals;
11
11
  export declare function addUsageToTotals(totals: UsageTotals, usage: Usage): void;
12
12
  /** Sum of two usages, keeping the optional token splits when either side reports them. */
13
13
  export declare function combineUsage(first: Usage, second: Usage): Usage;
14
+ export declare function emptyUsage(): Usage;
15
+ /** Share of one request's prompt served from cache, or undefined when it reported no cache activity. */
16
+ export declare function cacheHitPercent({ input, cacheRead, cacheWrite, }: Pick<Usage, "input" | "cacheRead" | "cacheWrite">): number | undefined;
14
17
  export interface UsageCostBreakdownEntry {
15
18
  key: string;
16
19
  cost: number;
@@ -1 +1 @@
1
- {"version":3,"file":"usage-totals.d.ts","sourceRoot":"","sources":["../../src/core/usage-totals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAQ/C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAMxE;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,KAAK,CAqB/D;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACb;AAsBD,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,GAAG,SAAS,CA0CnF;AAyBD,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,KAAK,EAAE,CAE5E;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,uBAAuB,EAAE,CAmBjG"}
1
+ {"version":3,"file":"usage-totals.d.ts","sourceRoot":"","sources":["../../src/core/usage-totals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAQ/C;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAMxE;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,KAAK,CAqB/D;AAED,wBAAgB,UAAU,IAAI,KAAK,CASlC;AAED,wGAAwG;AACxG,wBAAgB,eAAe,CAAC,EAC/B,KAAK,EACL,SAAS,EACT,UAAU,GACV,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG,MAAM,GAAG,SAAS,CAGxE;AAED,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACb;AAsBD,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,eAAe,GAAG,SAAS,CA0CnF;AAyBD,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,KAAK,EAAE,CAE5E;AAED,wFAAwF;AACxF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,uBAAuB,EAAE,CAmBjG"}
@@ -38,6 +38,21 @@ export function combineUsage(first, second) {
38
38
  },
39
39
  };
40
40
  }
41
+ export function emptyUsage() {
42
+ return {
43
+ input: 0,
44
+ output: 0,
45
+ cacheRead: 0,
46
+ cacheWrite: 0,
47
+ totalTokens: 0,
48
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
49
+ };
50
+ }
51
+ /** Share of one request's prompt served from cache, or undefined when it reported no cache activity. */
52
+ export function cacheHitPercent({ input, cacheRead, cacheWrite, }) {
53
+ const promptTokens = input + cacheRead + cacheWrite;
54
+ return (cacheRead > 0 || cacheWrite > 0) && promptTokens > 0 ? (cacheRead / promptTokens) * 100 : undefined;
55
+ }
41
56
  function isRecord(value) {
42
57
  return typeof value === "object" && value !== null && !Array.isArray(value);
43
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"usage-totals.js","sourceRoot":"","sources":["../../src/core/usage-totals.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport type { SessionEntry } from \"./session-manager.ts\";\nimport { TASK_RECORD_TYPE, TASK_SNAPSHOT_VERSION } from \"./tasks/codec.ts\";\n\nexport interface UsageTotals {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\tcost: number;\n}\n\nexport function createUsageTotals(): UsageTotals {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\tcost: 0,\n\t};\n}\n\nexport function addUsageToTotals(totals: UsageTotals, usage: Usage): void {\n\ttotals.input += usage.input;\n\ttotals.output += usage.output;\n\ttotals.cacheRead += usage.cacheRead;\n\ttotals.cacheWrite += usage.cacheWrite;\n\ttotals.cost += usage.cost.total;\n}\n\n/** Sum of two usages, keeping the optional token splits when either side reports them. */\nexport function combineUsage(first: Usage, second: Usage): Usage {\n\treturn {\n\t\tinput: first.input + second.input,\n\t\toutput: first.output + second.output,\n\t\tcacheRead: first.cacheRead + second.cacheRead,\n\t\tcacheWrite: first.cacheWrite + second.cacheWrite,\n\t\t...(first.cacheWrite1h !== undefined || second.cacheWrite1h !== undefined\n\t\t\t? { cacheWrite1h: (first.cacheWrite1h ?? 0) + (second.cacheWrite1h ?? 0) }\n\t\t\t: {}),\n\t\t...(first.reasoning !== undefined || second.reasoning !== undefined\n\t\t\t? { reasoning: (first.reasoning ?? 0) + (second.reasoning ?? 0) }\n\t\t\t: {}),\n\t\ttotalTokens: first.totalTokens + second.totalTokens,\n\t\tcost: {\n\t\t\tinput: first.cost.input + second.cost.input,\n\t\t\toutput: first.cost.output + second.cost.output,\n\t\t\tcacheRead: first.cost.cacheRead + second.cost.cacheRead,\n\t\t\tcacheWrite: first.cost.cacheWrite + second.cost.cacheWrite,\n\t\t\ttotal: first.cost.total + second.cost.total,\n\t\t},\n\t};\n}\n\nexport interface UsageCostBreakdownEntry {\n\tkey: string;\n\tcost: number;\n\ttokens: number;\n}\n\nexport interface TaskUsageRecord {\n\ttaskId: string;\n\tusage: Usage;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isUsageValue(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\n/** Released sessions settled usage in separate entries; their billing still counts. */\nconst LEGACY_TASK_USAGE_TYPE = \"task-usage\";\n\nfunction settledTaskId(entry: SessionEntry): unknown {\n\tif (entry.type !== \"custom\" || !isRecord(entry.data)) return undefined;\n\tconst data = entry.data;\n\tif (entry.customType === TASK_RECORD_TYPE)\n\t\treturn data.version === TASK_SNAPSHOT_VERSION && isRecord(data.task) ? data.task.id : undefined;\n\tif (entry.customType === LEGACY_TASK_USAGE_TYPE) return data.version === 1 ? data.taskId : undefined;\n\treturn undefined;\n}\n\n/** Validate a task record's usage settlement and return only its serializable accounting fields. */\nexport function getTaskUsageRecord(entry: SessionEntry): TaskUsageRecord | undefined {\n\tconst taskId = settledTaskId(entry);\n\tif (typeof taskId !== \"string\" || !taskId.trim() || entry.type !== \"custom\") return undefined;\n\tconst data = entry.data as Record<string, unknown>;\n\tconst usage = data.usage;\n\tif (!isRecord(usage) || !isRecord(usage.cost)) return undefined;\n\tconst { input, output, cacheRead, cacheWrite, totalTokens, reasoning, cacheWrite1h } = usage;\n\tconst cost = usage.cost;\n\tif (\n\t\t!isUsageValue(input) ||\n\t\t!isUsageValue(output) ||\n\t\t!isUsageValue(cacheRead) ||\n\t\t!isUsageValue(cacheWrite) ||\n\t\t!isUsageValue(totalTokens) ||\n\t\t!isUsageValue(cost.input) ||\n\t\t!isUsageValue(cost.output) ||\n\t\t!isUsageValue(cost.cacheRead) ||\n\t\t!isUsageValue(cost.cacheWrite) ||\n\t\t!isUsageValue(cost.total) ||\n\t\t(reasoning !== undefined && !isUsageValue(reasoning)) ||\n\t\t(cacheWrite1h !== undefined && !isUsageValue(cacheWrite1h))\n\t)\n\t\treturn undefined;\n\treturn {\n\t\ttaskId,\n\t\tusage: {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcacheRead,\n\t\t\tcacheWrite,\n\t\t\ttotalTokens,\n\t\t\t...(reasoning === undefined ? {} : { reasoning }),\n\t\t\t...(cacheWrite1h === undefined ? {} : { cacheWrite1h }),\n\t\t\tcost: {\n\t\t\t\tinput: cost.input,\n\t\t\t\toutput: cost.output,\n\t\t\t\tcacheRead: cost.cacheRead,\n\t\t\t\tcacheWrite: cost.cacheWrite,\n\t\t\t\ttotal: cost.total,\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction* accountedUsageEntries(entries: readonly SessionEntry[]): Generator<{ key: string; usage: Usage }> {\n\tconst backgroundTasks = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tyield {\n\t\t\t\tkey: `${entry.message.provider}/${entry.message.responseModel ?? entry.message.model}`,\n\t\t\t\tusage: entry.message.usage,\n\t\t\t};\n\t\t} else if (entry.type === \"usage\") {\n\t\t\tyield { key: `${entry.provider}/${entry.model}`, usage: entry.usage };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\tyield { key: \"Tools/summaries\", usage: entry.message.usage };\n\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\tyield { key: \"Tools/summaries\", usage: entry.usage };\n\t\t} else {\n\t\t\tconst record = getTaskUsageRecord(entry);\n\t\t\tif (!record || backgroundTasks.has(record.taskId)) continue;\n\t\t\tbackgroundTasks.add(record.taskId);\n\t\t\tyield { key: \"Tools/summaries\", usage: record.usage };\n\t\t}\n\t}\n}\n\n/** Legacy usage plus the first valid ledger record per task. Managed results omit usage. */\nexport function getAccountedUsages(entries: readonly SessionEntry[]): Usage[] {\n\treturn Array.from(accountedUsageEntries(entries), ({ usage }) => usage);\n}\n\n/** Group model-attributed usage by model and all other usage into a separate bucket. */\nexport function getUsageCostBreakdown(entries: readonly SessionEntry[]): UsageCostBreakdownEntry[] {\n\tconst totalsByKey = new Map<string, UsageTotals>();\n\n\tfor (const { key, usage } of accountedUsageEntries(entries)) {\n\t\tlet totals = totalsByKey.get(key);\n\t\tif (!totals) {\n\t\t\ttotals = createUsageTotals();\n\t\t\ttotalsByKey.set(key, totals);\n\t\t}\n\t\taddUsageToTotals(totals, usage);\n\t}\n\n\treturn Array.from(totalsByKey, ([key, totals]) => ({\n\t\tkey,\n\t\tcost: totals.cost,\n\t\ttokens: totals.input + totals.output + totals.cacheRead + totals.cacheWrite,\n\t}))\n\t\t.filter((entry) => entry.cost > 0 || entry.tokens > 0)\n\t\t.sort((a, b) => b.cost - a.cost);\n}\n"]}
1
+ {"version":3,"file":"usage-totals.js","sourceRoot":"","sources":["../../src/core/usage-totals.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport type { SessionEntry } from \"./session-manager.ts\";\nimport { TASK_RECORD_TYPE, TASK_SNAPSHOT_VERSION } from \"./tasks/codec.ts\";\n\nexport interface UsageTotals {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\tcost: number;\n}\n\nexport function createUsageTotals(): UsageTotals {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\tcost: 0,\n\t};\n}\n\nexport function addUsageToTotals(totals: UsageTotals, usage: Usage): void {\n\ttotals.input += usage.input;\n\ttotals.output += usage.output;\n\ttotals.cacheRead += usage.cacheRead;\n\ttotals.cacheWrite += usage.cacheWrite;\n\ttotals.cost += usage.cost.total;\n}\n\n/** Sum of two usages, keeping the optional token splits when either side reports them. */\nexport function combineUsage(first: Usage, second: Usage): Usage {\n\treturn {\n\t\tinput: first.input + second.input,\n\t\toutput: first.output + second.output,\n\t\tcacheRead: first.cacheRead + second.cacheRead,\n\t\tcacheWrite: first.cacheWrite + second.cacheWrite,\n\t\t...(first.cacheWrite1h !== undefined || second.cacheWrite1h !== undefined\n\t\t\t? { cacheWrite1h: (first.cacheWrite1h ?? 0) + (second.cacheWrite1h ?? 0) }\n\t\t\t: {}),\n\t\t...(first.reasoning !== undefined || second.reasoning !== undefined\n\t\t\t? { reasoning: (first.reasoning ?? 0) + (second.reasoning ?? 0) }\n\t\t\t: {}),\n\t\ttotalTokens: first.totalTokens + second.totalTokens,\n\t\tcost: {\n\t\t\tinput: first.cost.input + second.cost.input,\n\t\t\toutput: first.cost.output + second.cost.output,\n\t\t\tcacheRead: first.cost.cacheRead + second.cost.cacheRead,\n\t\t\tcacheWrite: first.cost.cacheWrite + second.cost.cacheWrite,\n\t\t\ttotal: first.cost.total + second.cost.total,\n\t\t},\n\t};\n}\n\nexport function emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\n/** Share of one request's prompt served from cache, or undefined when it reported no cache activity. */\nexport function cacheHitPercent({\n\tinput,\n\tcacheRead,\n\tcacheWrite,\n}: Pick<Usage, \"input\" | \"cacheRead\" | \"cacheWrite\">): number | undefined {\n\tconst promptTokens = input + cacheRead + cacheWrite;\n\treturn (cacheRead > 0 || cacheWrite > 0) && promptTokens > 0 ? (cacheRead / promptTokens) * 100 : undefined;\n}\n\nexport interface UsageCostBreakdownEntry {\n\tkey: string;\n\tcost: number;\n\ttokens: number;\n}\n\nexport interface TaskUsageRecord {\n\ttaskId: string;\n\tusage: Usage;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isUsageValue(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\n/** Released sessions settled usage in separate entries; their billing still counts. */\nconst LEGACY_TASK_USAGE_TYPE = \"task-usage\";\n\nfunction settledTaskId(entry: SessionEntry): unknown {\n\tif (entry.type !== \"custom\" || !isRecord(entry.data)) return undefined;\n\tconst data = entry.data;\n\tif (entry.customType === TASK_RECORD_TYPE)\n\t\treturn data.version === TASK_SNAPSHOT_VERSION && isRecord(data.task) ? data.task.id : undefined;\n\tif (entry.customType === LEGACY_TASK_USAGE_TYPE) return data.version === 1 ? data.taskId : undefined;\n\treturn undefined;\n}\n\n/** Validate a task record's usage settlement and return only its serializable accounting fields. */\nexport function getTaskUsageRecord(entry: SessionEntry): TaskUsageRecord | undefined {\n\tconst taskId = settledTaskId(entry);\n\tif (typeof taskId !== \"string\" || !taskId.trim() || entry.type !== \"custom\") return undefined;\n\tconst data = entry.data as Record<string, unknown>;\n\tconst usage = data.usage;\n\tif (!isRecord(usage) || !isRecord(usage.cost)) return undefined;\n\tconst { input, output, cacheRead, cacheWrite, totalTokens, reasoning, cacheWrite1h } = usage;\n\tconst cost = usage.cost;\n\tif (\n\t\t!isUsageValue(input) ||\n\t\t!isUsageValue(output) ||\n\t\t!isUsageValue(cacheRead) ||\n\t\t!isUsageValue(cacheWrite) ||\n\t\t!isUsageValue(totalTokens) ||\n\t\t!isUsageValue(cost.input) ||\n\t\t!isUsageValue(cost.output) ||\n\t\t!isUsageValue(cost.cacheRead) ||\n\t\t!isUsageValue(cost.cacheWrite) ||\n\t\t!isUsageValue(cost.total) ||\n\t\t(reasoning !== undefined && !isUsageValue(reasoning)) ||\n\t\t(cacheWrite1h !== undefined && !isUsageValue(cacheWrite1h))\n\t)\n\t\treturn undefined;\n\treturn {\n\t\ttaskId,\n\t\tusage: {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcacheRead,\n\t\t\tcacheWrite,\n\t\t\ttotalTokens,\n\t\t\t...(reasoning === undefined ? {} : { reasoning }),\n\t\t\t...(cacheWrite1h === undefined ? {} : { cacheWrite1h }),\n\t\t\tcost: {\n\t\t\t\tinput: cost.input,\n\t\t\t\toutput: cost.output,\n\t\t\t\tcacheRead: cost.cacheRead,\n\t\t\t\tcacheWrite: cost.cacheWrite,\n\t\t\t\ttotal: cost.total,\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction* accountedUsageEntries(entries: readonly SessionEntry[]): Generator<{ key: string; usage: Usage }> {\n\tconst backgroundTasks = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tyield {\n\t\t\t\tkey: `${entry.message.provider}/${entry.message.responseModel ?? entry.message.model}`,\n\t\t\t\tusage: entry.message.usage,\n\t\t\t};\n\t\t} else if (entry.type === \"usage\") {\n\t\t\tyield { key: `${entry.provider}/${entry.model}`, usage: entry.usage };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\" && entry.message.usage) {\n\t\t\tyield { key: \"Tools/summaries\", usage: entry.message.usage };\n\t\t} else if ((entry.type === \"branch_summary\" || entry.type === \"compaction\") && entry.usage) {\n\t\t\tyield { key: \"Tools/summaries\", usage: entry.usage };\n\t\t} else {\n\t\t\tconst record = getTaskUsageRecord(entry);\n\t\t\tif (!record || backgroundTasks.has(record.taskId)) continue;\n\t\t\tbackgroundTasks.add(record.taskId);\n\t\t\tyield { key: \"Tools/summaries\", usage: record.usage };\n\t\t}\n\t}\n}\n\n/** Legacy usage plus the first valid ledger record per task. Managed results omit usage. */\nexport function getAccountedUsages(entries: readonly SessionEntry[]): Usage[] {\n\treturn Array.from(accountedUsageEntries(entries), ({ usage }) => usage);\n}\n\n/** Group model-attributed usage by model and all other usage into a separate bucket. */\nexport function getUsageCostBreakdown(entries: readonly SessionEntry[]): UsageCostBreakdownEntry[] {\n\tconst totalsByKey = new Map<string, UsageTotals>();\n\n\tfor (const { key, usage } of accountedUsageEntries(entries)) {\n\t\tlet totals = totalsByKey.get(key);\n\t\tif (!totals) {\n\t\t\ttotals = createUsageTotals();\n\t\t\ttotalsByKey.set(key, totals);\n\t\t}\n\t\taddUsageToTotals(totals, usage);\n\t}\n\n\treturn Array.from(totalsByKey, ([key, totals]) => ({\n\t\tkey,\n\t\tcost: totals.cost,\n\t\ttokens: totals.input + totals.output + totals.cacheRead + totals.cacheWrite,\n\t}))\n\t\t.filter((entry) => entry.cost > 0 || entry.tokens > 0)\n\t\t.sort((a, b) => b.cost - a.cost);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGjG,OAAO,EAA4C,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAuB7F,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAM5E;AAWD;;;GAGG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,IAAI,CAAC,CAAmB;gBAEpB,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC;IAIlD,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAsCtC,OAAO,IAAI,IAAI;IAgBf,+DAA+D;IAC/D,OAAO,IAAI;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAYzD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,gBAAgB,CAAC;IAcjH,yGAAyG;IACzG,OAAO,CAAC,MAAM;IAOd,sEAAsE;IACtE,OAAO,CAAC,OAAO;CAGf"}
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/progress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGjG,OAAO,EAA4C,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAY7F,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAM5E;AAWD;;;GAGG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,IAAI,CAAC,CAAmB;gBAEpB,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC;IAIlD,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAsCtC,OAAO,IAAI,IAAI;IAgBf,+DAA+D;IAC/D,OAAO,IAAI;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAYzD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,gBAAgB,CAAC;IAcjH,yGAAyG;IACzG,OAAO,CAAC,MAAM;IAOd,sEAAsE;IACtE,OAAO,CAAC,OAAO;CAGf"}
@@ -1,16 +1,6 @@
1
- import { combineUsage } from "../../core/usage-totals.js";
1
+ import { combineUsage, emptyUsage } from "../../core/usage-totals.js";
2
2
  import { activitiesText, activityTarget, clipText, compactArguments } from "./activity.js";
3
3
  import { AGENT_MAX_ACTIVITIES } from "./types.js";
4
- function emptyUsage() {
5
- return {
6
- input: 0,
7
- output: 0,
8
- cacheRead: 0,
9
- cacheWrite: 0,
10
- totalTokens: 0,
11
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
12
- };
13
- }
14
4
  function assistantText(message) {
15
5
  if (message.role !== "assistant")
16
6
  return "";
@@ -1 +1 @@
1
- {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/extensions/agent/progress.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,oBAAoB,EAA6C,MAAM,YAAY,CAAC;AAI7F,SAAS,UAAU;IAClB,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KACpE,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAqB;IAC3C,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IAC5C,OAAO,OAAO,CAAC,OAAO;SACpB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SACxC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,CAAC,IAAI,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAiC;IACnE,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAE,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,aAAa,CAAC,MAAe;IACrC,MAAM,OAAO,GAAI,MAA+D,CAAC,OAAO,CAAC;IACzF,MAAM,IAAI,GAAG,OAAO;QACnB,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SACzC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;SAChC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,QAAQ,CAAC,IAAI,IAAI,mBAAmB,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,aAAa;IAQzB,YAAY,OAAsC;QANjC,eAAU,GAAoB,EAAE,CAAC;QACjC,YAAO,GAAG,IAAI,OAAO,EAAgB,CAAC;QAC/C,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAU,UAAU,EAAE,CAAC;QAInC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,KAAwB;QAC9B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,aAAa;gBACjB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;oBAAE,OAAO;gBAC/C,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC;gBAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;oBAChC,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5D,CAAC;gBACD,OAAO;YACR,KAAK,gBAAgB;gBACpB,IAAI,KAAK,CAAC,MAAM,EAAE,KAAK;oBAAE,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACnF,OAAO;YACR,KAAK,sBAAsB;gBAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;oBACpB,EAAE,EAAE,KAAK,CAAC,UAAU;oBACpB,IAAI,EAAE,KAAK,CAAC,QAAQ;oBACpB,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC;oBAClC,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;oBAClD,MAAM,EAAE,SAAS;iBACjB,CAAC,CAAC;gBACH,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,oBAAoB;oBAAE,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBAC3E,MAAM;YACP,KAAK,oBAAoB,CAAC,CAAC,CAAC;gBAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,UAAU,CAAC,CAAC;gBAClF,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBACtB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC7F,QAAQ,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;gBACvC,IAAI,KAAK,CAAC,OAAO;oBAAE,QAAQ,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAChE,MAAM;YACP,CAAC;YACD;gBACC,OAAO;QACT,CAAC;QACD,IAAI,CAAC,OAAO,EAAE,CAAC;IAChB,CAAC;IAED,OAAO;QACN,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YACpB,MAAM,EAAE;gBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;gBAChD,OAAO,EAAE;oBACR,OAAO,EAAE,CAAC;oBACV,KAAK,EAAE,SAAS;oBAChB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE;oBACvB,UAAU,EAAE,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC;iBAC5C;aACD;YACD,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;SACjB,CAAC,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,OAAO;QACN,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,EAAE,UAAU,KAAK,SAAS;YAChE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC;QAC3D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ;YACvE,OAAO;gBACN,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,IAAI,wCAAwC,EAAE,IAAI,CAAC;aACrF,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAChC,CAAC;IAED,QAAQ,CAAC,MAA0B,EAAE,KAAyB,EAAE,MAAc;QAC7E,OAAO;YACN,MAAM;YACN,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE;YACvB,MAAM,EAAE;gBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gBACzC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;gBAC5F,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;aACpD;SACD,CAAC;IACH,CAAC;IAED,yGAAyG;IACjG,MAAM;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,mCAAmC,CAAC;QACxD,MAAM,KAAK,GAAG,GAAG,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1E,OAAO,mBAAmB,KAAK,cAAc,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACvG,CAAC;IAED,sEAAsE;IAC9D,OAAO;QACd,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,CAAC;CACD","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSessionEvent } from \"../../core/agent-session.ts\";\nimport type { TaskCompletion, TaskControl, TaskTerminalStatus } from \"../../core/tasks/types.ts\";\nimport { combineUsage } from \"../../core/usage-totals.ts\";\nimport { activitiesText, activityTarget, clipText, compactArguments } from \"./activity.ts\";\nimport { AGENT_MAX_ACTIVITIES, type AgentActivity, type AgentToolDetails } from \"./types.ts\";\n\ntype AssistantMessage = Extract<AgentMessage, { role: \"assistant\" }>;\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction assistantText(message: AgentMessage): string {\n\tif (message.role !== \"assistant\") return \"\";\n\treturn message.content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\nexport function finalAssistantText(messages: readonly AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst text = assistantText(messages[index]!);\n\t\tif (text.trim()) return text;\n\t}\n\treturn \"\";\n}\n\nfunction toolErrorText(result: unknown): string {\n\tconst content = (result as { content?: Array<{ type: string; text?: string }> }).content;\n\tconst text = content\n\t\t?.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text ?? \"\")\n\t\t.join(\"\\n\");\n\treturn clipText(text || \"Tool call failed.\", 1000);\n}\n\n/**\n * One worker session translated into task progress: a one-line status for the model,\n * tool activity for humans, and cumulative usage for the ledger.\n */\nexport class AgentProgress {\n\tprivate readonly control: TaskControl<AgentToolDetails>;\n\tprivate readonly activities: AgentActivity[] = [];\n\tprivate readonly counted = new WeakSet<AgentMessage>();\n\tprivate calls = 0;\n\tprivate usage: Usage = emptyUsage();\n\tprivate last?: AssistantMessage;\n\n\tconstructor(control: TaskControl<AgentToolDetails>) {\n\t\tthis.control = control;\n\t}\n\n\thandle(event: AgentSessionEvent): void {\n\t\tswitch (event.type) {\n\t\t\tcase \"message_end\":\n\t\t\t\tif (event.message.role !== \"assistant\") return;\n\t\t\t\tthis.last = event.message;\n\t\t\t\tif (!this.counted.has(event.message)) {\n\t\t\t\t\tthis.counted.add(event.message);\n\t\t\t\t\tthis.usage = combineUsage(this.usage, event.message.usage);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase \"compaction_end\":\n\t\t\t\tif (event.result?.usage) this.usage = combineUsage(this.usage, event.result.usage);\n\t\t\t\treturn;\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis.calls++;\n\t\t\t\tthis.activities.push({\n\t\t\t\t\tid: event.toolCallId,\n\t\t\t\t\tname: event.toolName,\n\t\t\t\t\targs: compactArguments(event.args),\n\t\t\t\t\ttarget: activityTarget(event.toolName, event.args),\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t});\n\t\t\t\tif (this.activities.length > AGENT_MAX_ACTIVITIES) this.activities.shift();\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst activity = this.activities.findLast((item) => item.id === event.toolCallId);\n\t\t\t\tif (!activity) return;\n\t\t\t\tactivity.status = this.control.signal.aborted ? \"cancelled\" : event.isError ? \"error\" : \"ok\";\n\t\t\t\tactivity.durationMs = event.durationMs;\n\t\t\t\tif (event.isError) activity.error = toolErrorText(event.result);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t}\n\t\tthis.publish();\n\t}\n\n\tpublish(): void {\n\t\tthis.control.publish({\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: this.status() }],\n\t\t\t\tdetails: {\n\t\t\t\t\tversion: 2,\n\t\t\t\t\tstate: \"running\",\n\t\t\t\t\ttaskId: this.control.id,\n\t\t\t\t\tactivities: structuredClone(this.activities),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdisplay: this.display(),\n\t\t\tusage: this.usage,\n\t\t});\n\t}\n\n\t/** Classify a finished run from its last assistant message. */\n\toutcome(): { status: TaskTerminalStatus; error?: string } {\n\t\tconst last = this.last;\n\t\tif (this.control.signal.aborted || last?.stopReason === \"aborted\")\n\t\t\treturn { status: \"cancelled\", error: \"Agent cancelled.\" };\n\t\tif (!last || last.stopReason === \"error\" || last.stopReason === \"length\")\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: clipText(last?.errorMessage || \"Agent ended without a complete report.\", 4096),\n\t\t\t};\n\t\treturn { status: \"completed\" };\n\t}\n\n\tcomplete(status: TaskTerminalStatus, error: string | undefined, report: string): TaskCompletion<AgentToolDetails> {\n\t\treturn {\n\t\t\tstatus,\n\t\t\terror,\n\t\t\tusage: this.usage,\n\t\t\tdisplay: this.display(),\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: report }],\n\t\t\t\tdetails: { version: 2, state: status, taskId: this.control.id, ...(error ? { error } : {}) },\n\t\t\t\t...(status === \"completed\" ? {} : { isError: true }),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Model-readable progress: the report is the contract, so intermediate text never leaves the worker. */\n\tprivate status(): string {\n\t\tconst latest = this.activities.at(-1);\n\t\tif (!latest) return \"Agent running; no tool calls yet.\";\n\t\tconst calls = `${this.calls} tool ${this.calls === 1 ? \"call\" : \"calls\"}`;\n\t\treturn `Agent running · ${calls} · latest: ${latest.name}${latest.target ? ` ${latest.target}` : \"\"}`;\n\t}\n\n\t/** Human-only Output: compact tool calls, never sent to the model. */\n\tprivate display(): string {\n\t\treturn this.activities.length ? `Tool calls\\n${activitiesText(this.activities)}` : \"\";\n\t}\n}\n"]}
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/extensions/agent/progress.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSessionEvent } from \"../../core/agent-session.ts\";\nimport type { TaskCompletion, TaskControl, TaskTerminalStatus } from \"../../core/tasks/types.ts\";\nimport { combineUsage, emptyUsage } from \"../../core/usage-totals.ts\";\nimport { activitiesText, activityTarget, clipText, compactArguments } from \"./activity.ts\";\nimport { AGENT_MAX_ACTIVITIES, type AgentActivity, type AgentToolDetails } from \"./types.ts\";\n\ntype AssistantMessage = Extract<AgentMessage, { role: \"assistant\" }>;\n\nfunction assistantText(message: AgentMessage): string {\n\tif (message.role !== \"assistant\") return \"\";\n\treturn message.content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(\"\\n\");\n}\n\nexport function finalAssistantText(messages: readonly AgentMessage[]): string {\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst text = assistantText(messages[index]!);\n\t\tif (text.trim()) return text;\n\t}\n\treturn \"\";\n}\n\nfunction toolErrorText(result: unknown): string {\n\tconst content = (result as { content?: Array<{ type: string; text?: string }> }).content;\n\tconst text = content\n\t\t?.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text ?? \"\")\n\t\t.join(\"\\n\");\n\treturn clipText(text || \"Tool call failed.\", 1000);\n}\n\n/**\n * One worker session translated into task progress: a one-line status for the model,\n * tool activity for humans, and cumulative usage for the ledger.\n */\nexport class AgentProgress {\n\tprivate readonly control: TaskControl<AgentToolDetails>;\n\tprivate readonly activities: AgentActivity[] = [];\n\tprivate readonly counted = new WeakSet<AgentMessage>();\n\tprivate calls = 0;\n\tprivate usage: Usage = emptyUsage();\n\tprivate last?: AssistantMessage;\n\n\tconstructor(control: TaskControl<AgentToolDetails>) {\n\t\tthis.control = control;\n\t}\n\n\thandle(event: AgentSessionEvent): void {\n\t\tswitch (event.type) {\n\t\t\tcase \"message_end\":\n\t\t\t\tif (event.message.role !== \"assistant\") return;\n\t\t\t\tthis.last = event.message;\n\t\t\t\tif (!this.counted.has(event.message)) {\n\t\t\t\t\tthis.counted.add(event.message);\n\t\t\t\t\tthis.usage = combineUsage(this.usage, event.message.usage);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\tcase \"compaction_end\":\n\t\t\t\tif (event.result?.usage) this.usage = combineUsage(this.usage, event.result.usage);\n\t\t\t\treturn;\n\t\t\tcase \"tool_execution_start\":\n\t\t\t\tthis.calls++;\n\t\t\t\tthis.activities.push({\n\t\t\t\t\tid: event.toolCallId,\n\t\t\t\t\tname: event.toolName,\n\t\t\t\t\targs: compactArguments(event.args),\n\t\t\t\t\ttarget: activityTarget(event.toolName, event.args),\n\t\t\t\t\tstatus: \"running\",\n\t\t\t\t});\n\t\t\t\tif (this.activities.length > AGENT_MAX_ACTIVITIES) this.activities.shift();\n\t\t\t\tbreak;\n\t\t\tcase \"tool_execution_end\": {\n\t\t\t\tconst activity = this.activities.findLast((item) => item.id === event.toolCallId);\n\t\t\t\tif (!activity) return;\n\t\t\t\tactivity.status = this.control.signal.aborted ? \"cancelled\" : event.isError ? \"error\" : \"ok\";\n\t\t\t\tactivity.durationMs = event.durationMs;\n\t\t\t\tif (event.isError) activity.error = toolErrorText(event.result);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn;\n\t\t}\n\t\tthis.publish();\n\t}\n\n\tpublish(): void {\n\t\tthis.control.publish({\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: this.status() }],\n\t\t\t\tdetails: {\n\t\t\t\t\tversion: 2,\n\t\t\t\t\tstate: \"running\",\n\t\t\t\t\ttaskId: this.control.id,\n\t\t\t\t\tactivities: structuredClone(this.activities),\n\t\t\t\t},\n\t\t\t},\n\t\t\tdisplay: this.display(),\n\t\t\tusage: this.usage,\n\t\t});\n\t}\n\n\t/** Classify a finished run from its last assistant message. */\n\toutcome(): { status: TaskTerminalStatus; error?: string } {\n\t\tconst last = this.last;\n\t\tif (this.control.signal.aborted || last?.stopReason === \"aborted\")\n\t\t\treturn { status: \"cancelled\", error: \"Agent cancelled.\" };\n\t\tif (!last || last.stopReason === \"error\" || last.stopReason === \"length\")\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror: clipText(last?.errorMessage || \"Agent ended without a complete report.\", 4096),\n\t\t\t};\n\t\treturn { status: \"completed\" };\n\t}\n\n\tcomplete(status: TaskTerminalStatus, error: string | undefined, report: string): TaskCompletion<AgentToolDetails> {\n\t\treturn {\n\t\t\tstatus,\n\t\t\terror,\n\t\t\tusage: this.usage,\n\t\t\tdisplay: this.display(),\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: report }],\n\t\t\t\tdetails: { version: 2, state: status, taskId: this.control.id, ...(error ? { error } : {}) },\n\t\t\t\t...(status === \"completed\" ? {} : { isError: true }),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** Model-readable progress: the report is the contract, so intermediate text never leaves the worker. */\n\tprivate status(): string {\n\t\tconst latest = this.activities.at(-1);\n\t\tif (!latest) return \"Agent running; no tool calls yet.\";\n\t\tconst calls = `${this.calls} tool ${this.calls === 1 ? \"call\" : \"calls\"}`;\n\t\treturn `Agent running · ${calls} · latest: ${latest.name}${latest.target ? ` ${latest.target}` : \"\"}`;\n\t}\n\n\t/** Human-only Output: compact tool calls, never sent to the model. */\n\tprivate display(): string {\n\t\treturn this.activities.length ? `Tool calls\\n${activitiesText(this.activities)}` : \"\";\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAMtF,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG1F,QAAA,MAAM,WAAW;;;;EAYhB,CAAC;AAmBF,wBAAgB,eAAe,CAC9B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACpC,cAAc,CAAC,OAAO,WAAW,EAAE,gBAAgB,CAAC,CAmDtD"}
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAMtF,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG1F,QAAA,MAAM,WAAW;;;;EAehB,CAAC;AAmBF,wBAAgB,eAAe,CAC9B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACpC,cAAc,CAAC,OAAO,WAAW,EAAE,gBAAgB,CAAC,CAuDtD"}
@@ -8,9 +8,9 @@ import { runWorker } from "./worker.js";
8
8
  const agentSchema = Type.Object({
9
9
  prompt: Type.String({
10
10
  minLength: 1,
11
- description: "Complete, self-contained task briefing; the Agent cannot see this conversation",
11
+ description: "Complete, self-contained task briefing: goal, relevant context and paths, constraints, whether to edit or only investigate, and expected verification and report. The Agent cannot see this conversation.",
12
12
  }),
13
- description: Type.Optional(Type.String({ description: "Short task label for the transcript and Tasks panel" })),
13
+ description: Type.Optional(Type.String({ description: "Short (3–5 word) task label for the transcript and Tasks panel" })),
14
14
  background: Type.Optional(Type.Boolean({ description: "Return a task ID and deliver the final report asynchronously" })),
15
15
  }, { additionalProperties: false });
16
16
  /** The model-facing handoff: who moved the Agent, whether it waits for a slot, and how to follow it. */
@@ -34,10 +34,14 @@ export function createAgentTool(options = {}) {
34
34
  return defineTool({
35
35
  name: "Agent",
36
36
  label: "Agent",
37
- description: "Delegate independent work to a temporary isolated Agent when separate context or parallel execution offers a clear benefit. Use sparingly; handle known-path reads and small edits directly. The Agent cannot see the parent conversation, so include all necessary context and desired verification in prompt. Foreground returns the final report; background returns a task ID and delivers it automatically.",
38
- promptSnippet: "Delegate an independent task",
37
+ description: "Run one self-contained task in a fresh Agent session and get back only its final report. Use Agent when separate context or parallel execution clearly helps; handle known-path reads and small edits directly. The Agent cannot see this conversation, but shares your working directory and applicable project instructions, with read, bash, edit, and write. Foreground returns the report; background returns a task ID and delivers the report automatically.",
38
+ promptSnippet: "Delegate a self-contained task and receive only its final report",
39
39
  promptGuidelines: [
40
- "Give Agent a complete, self-contained briefing with relevant paths, constraints and expected verification; use parallel calls only for independent, non-overlapping work.",
40
+ "Use Agent primarily for independent research, verification, or well-specified, self-contained implementation when separate context or parallel execution clearly helps. Keep design and substantial coding in the main session; handle known-path reads and small edits directly. “Multiple angles” or “be thorough” alone does not justify an Agent.",
41
+ "Give Agent a self-contained briefing: the goal and why it matters, prior findings or ruled-out options, relevant paths and constraints, whether to investigate or edit, and expected verification. For open investigations, hand over the question rather than a fragile step-by-step procedure; state any report-length limit.",
42
+ "Keep ownership of synthesis when using Agent—never delegate understanding. For edits, supply your conclusions, target behavior, relevant files, and acceptance checks rather than “based on your findings, fix it.” Verify actual edits and test evidence before calling the work done.",
43
+ "Run parallel Agents only on independent work; concurrent writers must not touch the same files or shared state. Do not duplicate delegated work or repeatedly poll a background Agent. Continue independent work, or wait when its result is needed.",
44
+ "An Agent report is not automatically presented to the user. Relay the important outcome, verification result, and remaining risks concisely.",
41
45
  ],
42
46
  parameters: agentSchema,
43
47
  constrainedSampling: { type: "json_schema", strict: "prefer" },
@@ -1 +1 @@
1
- {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type } from \"typebox\";\nimport type { AgentToolResult, ToolDefinition } from \"../../core/extensions/types.ts\";\nimport { defineTool } from \"../../core/extensions/types.ts\";\nimport type { TaskSnapshot } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { agentRenderers } from \"./render.ts\";\nimport { resolveAgentConfiguration } from \"./settings.ts\";\nimport { AGENT_CONCURRENCY, AGENT_PROMPT_BYTES, type AgentToolDetails } from \"./types.ts\";\nimport { runWorker } from \"./worker.ts\";\n\nconst agentSchema = Type.Object(\n\t{\n\t\tprompt: Type.String({\n\t\t\tminLength: 1,\n\t\t\tdescription: \"Complete, self-contained task briefing; the Agent cannot see this conversation\",\n\t\t}),\n\t\tdescription: Type.Optional(Type.String({ description: \"Short task label for the transcript and Tasks panel\" })),\n\t\tbackground: Type.Optional(\n\t\t\tType.Boolean({ description: \"Return a task ID and deliver the final report asynchronously\" }),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\n/** The model-facing handoff: who moved the Agent, whether it waits for a slot, and how to follow it. */\nfunction handoffResult(task: TaskSnapshot, byUser: boolean): AgentToolResult<AgentToolDetails> {\n\tconst moved = byUser\n\t\t? `The user moved this Agent to the background while it was running: ${task.id}. It continues unchanged.`\n\t\t: `Agent running in background: ${task.id}.`;\n\tconst queued = task.status === \"queued\" ? \" It is queued until an Agent slot frees.\" : \"\";\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `${moved}${queued} The report will be delivered automatically. Use tasks read/wait/kill to inspect, wait or stop.`,\n\t\t\t},\n\t\t],\n\t\tdetails: { version: 2, state: \"background\", taskId: task.id, byUser },\n\t};\n}\n\nexport function createAgentTool(\n\toptions: { concurrency?: number } = {},\n): ToolDefinition<typeof agentSchema, AgentToolDetails> {\n\tconst limit = options.concurrency ?? AGENT_CONCURRENCY;\n\treturn defineTool({\n\t\tname: \"Agent\",\n\t\tlabel: \"Agent\",\n\t\tdescription:\n\t\t\t\"Delegate independent work to a temporary isolated Agent when separate context or parallel execution offers a clear benefit. Use sparingly; handle known-path reads and small edits directly. The Agent cannot see the parent conversation, so include all necessary context and desired verification in prompt. Foreground returns the final report; background returns a task ID and delivers it automatically.\",\n\t\tpromptSnippet: \"Delegate an independent task\",\n\t\tpromptGuidelines: [\n\t\t\t\"Give Agent a complete, self-contained briefing with relevant paths, constraints and expected verification; use parallel calls only for independent, non-overlapping work.\",\n\t\t],\n\t\tparameters: agentSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx) {\n\t\t\tif (!params.prompt.trim() || Buffer.byteLength(params.prompt) > AGENT_PROMPT_BYTES)\n\t\t\t\tthrow new Error(\"Agent prompt must contain text and fit within 16 KiB.\");\n\t\t\tconst { model, thinking } = resolveAgentConfiguration(ctx);\n\t\t\tconst auth = await ctx.modelRuntime.getAuth(model, { signal });\n\t\t\tif (!auth) throw new Error(`No authentication for Agent model ${model.provider}/${model.id}`);\n\t\t\tconst outcome = await ctx.tasks.execute<AgentToolDetails>({\n\t\t\t\tkind: \"agent\",\n\t\t\t\tlabel: \"Agent\",\n\t\t\t\ttitle: clipText((params.description?.trim() || params.prompt).replace(/\\s+/gu, \" \").trim(), 160),\n\t\t\t\toutput: \"report\",\n\t\t\t\tinput: { label: \"Prompt\", text: params.prompt, truncated: false },\n\t\t\t\tfacts: [\n\t\t\t\t\t[\"Model\", `${model.provider}/${model.id}`],\n\t\t\t\t\t[\"Thinking\", thinking],\n\t\t\t\t\t[\"Directory\", ctx.cwd],\n\t\t\t\t],\n\t\t\t\tconcurrency: { key: \"agent\", limit },\n\t\t\t\ttoolCallId,\n\t\t\t\tbackground: params.background,\n\t\t\t\tsignal,\n\t\t\t\tonUpdate,\n\t\t\t\trun: (control) =>\n\t\t\t\t\trunWorker(control, {\n\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinking,\n\t\t\t\t\t\tmodelRuntime: ctx.modelRuntime,\n\t\t\t\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t\t\t\t}),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return outcome.result;\n\t\t\treturn handoffResult(outcome.task, params.background !== true);\n\t\t},\n\t\t...agentRenderers,\n\t});\n}\n"]}
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type } from \"typebox\";\nimport type { AgentToolResult, ToolDefinition } from \"../../core/extensions/types.ts\";\nimport { defineTool } from \"../../core/extensions/types.ts\";\nimport type { TaskSnapshot } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { agentRenderers } from \"./render.ts\";\nimport { resolveAgentConfiguration } from \"./settings.ts\";\nimport { AGENT_CONCURRENCY, AGENT_PROMPT_BYTES, type AgentToolDetails } from \"./types.ts\";\nimport { runWorker } from \"./worker.ts\";\n\nconst agentSchema = Type.Object(\n\t{\n\t\tprompt: Type.String({\n\t\t\tminLength: 1,\n\t\t\tdescription:\n\t\t\t\t\"Complete, self-contained task briefing: goal, relevant context and paths, constraints, whether to edit or only investigate, and expected verification and report. The Agent cannot see this conversation.\",\n\t\t}),\n\t\tdescription: Type.Optional(\n\t\t\tType.String({ description: \"Short (3–5 word) task label for the transcript and Tasks panel\" }),\n\t\t),\n\t\tbackground: Type.Optional(\n\t\t\tType.Boolean({ description: \"Return a task ID and deliver the final report asynchronously\" }),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\n/** The model-facing handoff: who moved the Agent, whether it waits for a slot, and how to follow it. */\nfunction handoffResult(task: TaskSnapshot, byUser: boolean): AgentToolResult<AgentToolDetails> {\n\tconst moved = byUser\n\t\t? `The user moved this Agent to the background while it was running: ${task.id}. It continues unchanged.`\n\t\t: `Agent running in background: ${task.id}.`;\n\tconst queued = task.status === \"queued\" ? \" It is queued until an Agent slot frees.\" : \"\";\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `${moved}${queued} The report will be delivered automatically. Use tasks read/wait/kill to inspect, wait or stop.`,\n\t\t\t},\n\t\t],\n\t\tdetails: { version: 2, state: \"background\", taskId: task.id, byUser },\n\t};\n}\n\nexport function createAgentTool(\n\toptions: { concurrency?: number } = {},\n): ToolDefinition<typeof agentSchema, AgentToolDetails> {\n\tconst limit = options.concurrency ?? AGENT_CONCURRENCY;\n\treturn defineTool({\n\t\tname: \"Agent\",\n\t\tlabel: \"Agent\",\n\t\tdescription:\n\t\t\t\"Run one self-contained task in a fresh Agent session and get back only its final report. Use Agent when separate context or parallel execution clearly helps; handle known-path reads and small edits directly. The Agent cannot see this conversation, but shares your working directory and applicable project instructions, with read, bash, edit, and write. Foreground returns the report; background returns a task ID and delivers the report automatically.\",\n\t\tpromptSnippet: \"Delegate a self-contained task and receive only its final report\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use Agent primarily for independent research, verification, or well-specified, self-contained implementation when separate context or parallel execution clearly helps. Keep design and substantial coding in the main session; handle known-path reads and small edits directly. “Multiple angles” or “be thorough” alone does not justify an Agent.\",\n\t\t\t\"Give Agent a self-contained briefing: the goal and why it matters, prior findings or ruled-out options, relevant paths and constraints, whether to investigate or edit, and expected verification. For open investigations, hand over the question rather than a fragile step-by-step procedure; state any report-length limit.\",\n\t\t\t\"Keep ownership of synthesis when using Agent—never delegate understanding. For edits, supply your conclusions, target behavior, relevant files, and acceptance checks rather than “based on your findings, fix it.” Verify actual edits and test evidence before calling the work done.\",\n\t\t\t\"Run parallel Agents only on independent work; concurrent writers must not touch the same files or shared state. Do not duplicate delegated work or repeatedly poll a background Agent. Continue independent work, or wait when its result is needed.\",\n\t\t\t\"An Agent report is not automatically presented to the user. Relay the important outcome, verification result, and remaining risks concisely.\",\n\t\t],\n\t\tparameters: agentSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx) {\n\t\t\tif (!params.prompt.trim() || Buffer.byteLength(params.prompt) > AGENT_PROMPT_BYTES)\n\t\t\t\tthrow new Error(\"Agent prompt must contain text and fit within 16 KiB.\");\n\t\t\tconst { model, thinking } = resolveAgentConfiguration(ctx);\n\t\t\tconst auth = await ctx.modelRuntime.getAuth(model, { signal });\n\t\t\tif (!auth) throw new Error(`No authentication for Agent model ${model.provider}/${model.id}`);\n\t\t\tconst outcome = await ctx.tasks.execute<AgentToolDetails>({\n\t\t\t\tkind: \"agent\",\n\t\t\t\tlabel: \"Agent\",\n\t\t\t\ttitle: clipText((params.description?.trim() || params.prompt).replace(/\\s+/gu, \" \").trim(), 160),\n\t\t\t\toutput: \"report\",\n\t\t\t\tinput: { label: \"Prompt\", text: params.prompt, truncated: false },\n\t\t\t\tfacts: [\n\t\t\t\t\t[\"Model\", `${model.provider}/${model.id}`],\n\t\t\t\t\t[\"Thinking\", thinking],\n\t\t\t\t\t[\"Directory\", ctx.cwd],\n\t\t\t\t],\n\t\t\t\tconcurrency: { key: \"agent\", limit },\n\t\t\t\ttoolCallId,\n\t\t\t\tbackground: params.background,\n\t\t\t\tsignal,\n\t\t\t\tonUpdate,\n\t\t\t\trun: (control) =>\n\t\t\t\t\trunWorker(control, {\n\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinking,\n\t\t\t\t\t\tmodelRuntime: ctx.modelRuntime,\n\t\t\t\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t\t\t\t}),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return outcome.result;\n\t\t\treturn handoffResult(outcome.task, params.background !== true);\n\t\t},\n\t\t...agentRenderers,\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAG1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;CACxB;AAeD,gGAAgG;AAChG,wBAAsB,SAAS,CAC9B,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC,EACtC,OAAO,EAAE,YAAY,GACnB,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CA6C3C"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAG1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;CACxB;AAaD,gGAAgG;AAChG,wBAAsB,SAAS,CAC9B,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC,EACtC,OAAO,EAAE,YAAY,GACnB,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CA6C3C"}
@@ -6,11 +6,9 @@ const WORKER_TOOLS = ["read", "bash", "edit", "write"];
6
6
  function workerPrompt(base) {
7
7
  return [
8
8
  base,
9
- "You are an Agent working independently on one delegated task.",
10
- "You cannot see the parent conversation. Treat the parent Agent as your caller, rely on the task briefing and available workspace context, and do not ask the end user questions. If anything is unclear, explain the ambiguity in your final report.",
11
- "Work in the assigned directory and stay within the requested scope. Use read for known-path file reads and bash for file discovery, search, and shell commands.",
12
- "Do not delegate or start background work. Run required commands in the foreground and wait for them.",
13
- "Only your final report returns to the caller. Make it self-contained: include essential findings or changes, verification when applicable, blockers, and unresolved risks; omit process narration.",
9
+ "You are an Agent completing one delegated task in an isolated session. The first user message is the complete briefing from your caller. You cannot see the caller's conversation or ask it questions. If the briefing is ambiguous, choose a reasonable interpretation within scope and report it; stop only when ambiguity blocks meaningful progress.",
10
+ "Use the assigned working directory and stay within the requested scope. Complete the task fully without expanding it. If the briefing asks only for investigation, do not modify files. Use read for known paths and bash for discovery, search, and shell commands. Prefer editing existing files; create new files only when the task requires them, and never create documentation or report files unless explicitly requested. Do not delegate or start background work. Run required commands in the foreground and wait for them.",
11
+ "Your final message is the only output returned to the caller. Lead with the outcome, then include essential findings, files changed if any, verification actually run and its result, and blockers or remaining risks. Cite workspace-relative paths with line numbers when useful. Respect any length limit in the briefing and omit process narration.",
14
12
  ]
15
13
  .filter((part) => Boolean(part?.trim()))
16
14
  .join("\n\n");
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport { createIsolatedSession } from \"../../core/isolated-session.ts\";\nimport type { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport type { TaskCompletion, TaskControl } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { AgentProgress, finalAssistantText } from \"./progress.ts\";\nimport { finalReport } from \"./report.ts\";\nimport type { AgentToolDetails } from \"./types.ts\";\n\nconst WORKER_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\nexport interface AgentRequest {\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<any>;\n\tthinking: ThinkingLevel;\n\tmodelRuntime: ModelRuntime;\n\tprojectTrusted: boolean;\n}\n\nfunction workerPrompt(base: string | undefined): string {\n\treturn [\n\t\tbase,\n\t\t\"You are an Agent working independently on one delegated task.\",\n\t\t\"You cannot see the parent conversation. Treat the parent Agent as your caller, rely on the task briefing and available workspace context, and do not ask the end user questions. If anything is unclear, explain the ambiguity in your final report.\",\n\t\t\"Work in the assigned directory and stay within the requested scope. Use read for known-path file reads and bash for file discovery, search, and shell commands.\",\n\t\t\"Do not delegate or start background work. Run required commands in the foreground and wait for them.\",\n\t\t\"Only your final report returns to the caller. Make it self-contained: include essential findings or changes, verification when applicable, blockers, and unresolved risks; omit process narration.\",\n\t]\n\t\t.filter((part): part is string => Boolean(part?.trim()))\n\t\t.join(\"\\n\\n\");\n}\n\n/** Run one delegated task in an isolated session and settle it with a self-contained report. */\nexport async function runWorker(\n\tcontrol: TaskControl<AgentToolDetails>,\n\trequest: AgentRequest,\n): Promise<TaskCompletion<AgentToolDetails>> {\n\tconst { signal } = control;\n\tconst progress = new AgentProgress(control);\n\tlet session: AgentSession | undefined;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst abort = () => {\n\t\tvoid session?.abort().catch(() => {});\n\t};\n\tsignal.addEventListener(\"abort\", abort, { once: true });\n\ttry {\n\t\tsession = await createIsolatedSession({\n\t\t\tcwd: request.cwd,\n\t\t\tmodel: request.model,\n\t\t\tthinkingLevel: request.thinking,\n\t\t\tmodelRuntime: request.modelRuntime,\n\t\t\tprojectTrusted: request.projectTrusted,\n\t\t\tsystemPrompt: workerPrompt,\n\t\t\ttools: WORKER_TOOLS,\n\t\t\tsignal,\n\t\t});\n\t\tconst worker = session;\n\t\tunsubscribe = worker.subscribe((event) => {\n\t\t\t// Cancellation during prompt preflight can precede the run's own abort controller.\n\t\t\tif (event.type === \"agent_start\" && signal.aborted) abort();\n\t\t\telse progress.handle(event);\n\t\t});\n\t\tprogress.publish();\n\t\tcontrol.accept();\n\t\tsignal.throwIfAborted();\n\t\tawait worker.prompt(request.prompt, { expandPromptTemplates: false });\n\t\tconst { status, error } = progress.outcome();\n\t\treturn progress.complete(status, error, await finalReport(control, finalAssistantText(worker.messages), error));\n\t} catch (error) {\n\t\tconst status = signal.aborted ? \"cancelled\" : \"failed\";\n\t\tconst reason =\n\t\t\tstatus === \"cancelled\"\n\t\t\t\t? \"Agent cancelled.\"\n\t\t\t\t: clipText(error instanceof Error ? error.message : String(error), 4096);\n\t\tconst report = session ? finalAssistantText(session.messages) : \"\";\n\t\treturn progress.complete(status, reason, await finalReport(control, report, reason));\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", abort);\n\t\tunsubscribe?.();\n\t\tsession?.dispose();\n\t}\n}\n"]}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport { createIsolatedSession } from \"../../core/isolated-session.ts\";\nimport type { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport type { TaskCompletion, TaskControl } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { AgentProgress, finalAssistantText } from \"./progress.ts\";\nimport { finalReport } from \"./report.ts\";\nimport type { AgentToolDetails } from \"./types.ts\";\n\nconst WORKER_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\nexport interface AgentRequest {\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<any>;\n\tthinking: ThinkingLevel;\n\tmodelRuntime: ModelRuntime;\n\tprojectTrusted: boolean;\n}\n\nfunction workerPrompt(base: string | undefined): string {\n\treturn [\n\t\tbase,\n\t\t\"You are an Agent completing one delegated task in an isolated session. The first user message is the complete briefing from your caller. You cannot see the caller's conversation or ask it questions. If the briefing is ambiguous, choose a reasonable interpretation within scope and report it; stop only when ambiguity blocks meaningful progress.\",\n\t\t\"Use the assigned working directory and stay within the requested scope. Complete the task fully without expanding it. If the briefing asks only for investigation, do not modify files. Use read for known paths and bash for discovery, search, and shell commands. Prefer editing existing files; create new files only when the task requires them, and never create documentation or report files unless explicitly requested. Do not delegate or start background work. Run required commands in the foreground and wait for them.\",\n\t\t\"Your final message is the only output returned to the caller. Lead with the outcome, then include essential findings, files changed if any, verification actually run and its result, and blockers or remaining risks. Cite workspace-relative paths with line numbers when useful. Respect any length limit in the briefing and omit process narration.\",\n\t]\n\t\t.filter((part): part is string => Boolean(part?.trim()))\n\t\t.join(\"\\n\\n\");\n}\n\n/** Run one delegated task in an isolated session and settle it with a self-contained report. */\nexport async function runWorker(\n\tcontrol: TaskControl<AgentToolDetails>,\n\trequest: AgentRequest,\n): Promise<TaskCompletion<AgentToolDetails>> {\n\tconst { signal } = control;\n\tconst progress = new AgentProgress(control);\n\tlet session: AgentSession | undefined;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst abort = () => {\n\t\tvoid session?.abort().catch(() => {});\n\t};\n\tsignal.addEventListener(\"abort\", abort, { once: true });\n\ttry {\n\t\tsession = await createIsolatedSession({\n\t\t\tcwd: request.cwd,\n\t\t\tmodel: request.model,\n\t\t\tthinkingLevel: request.thinking,\n\t\t\tmodelRuntime: request.modelRuntime,\n\t\t\tprojectTrusted: request.projectTrusted,\n\t\t\tsystemPrompt: workerPrompt,\n\t\t\ttools: WORKER_TOOLS,\n\t\t\tsignal,\n\t\t});\n\t\tconst worker = session;\n\t\tunsubscribe = worker.subscribe((event) => {\n\t\t\t// Cancellation during prompt preflight can precede the run's own abort controller.\n\t\t\tif (event.type === \"agent_start\" && signal.aborted) abort();\n\t\t\telse progress.handle(event);\n\t\t});\n\t\tprogress.publish();\n\t\tcontrol.accept();\n\t\tsignal.throwIfAborted();\n\t\tawait worker.prompt(request.prompt, { expandPromptTemplates: false });\n\t\tconst { status, error } = progress.outcome();\n\t\treturn progress.complete(status, error, await finalReport(control, finalAssistantText(worker.messages), error));\n\t} catch (error) {\n\t\tconst status = signal.aborted ? \"cancelled\" : \"failed\";\n\t\tconst reason =\n\t\t\tstatus === \"cancelled\"\n\t\t\t\t? \"Agent cancelled.\"\n\t\t\t\t: clipText(error instanceof Error ? error.message : String(error), 4096);\n\t\tconst report = session ? finalAssistantText(session.messages) : \"\";\n\t\treturn progress.complete(status, reason, await finalReport(control, report, reason));\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", abort);\n\t\tunsubscribe?.();\n\t\tsession?.dispose();\n\t}\n}\n"]}
@@ -20,7 +20,7 @@ export interface BtwConversationState {
20
20
  /** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */
21
21
  export declare class BtwAgent implements BtwConversationState {
22
22
  readonly turns: BtwTurn[];
23
- readonly usage: Usage;
23
+ usage: Usage;
24
24
  latestCacheHitPercent: number | undefined;
25
25
  blockedTools: number;
26
26
  private readonly agent;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAYtE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACrB;AAwBD,+FAA+F;AAC/F,qBAAa,QAAS,YAAW,oBAAoB;IACpD,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAM;IAC/B,QAAQ,CAAC,KAAK,QAAgB;IAC9B,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,SAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAC,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAyDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,CAAC,QAAQ;IAahB,oGAAoG;IACpG,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;YAqBhE,WAAW;IAsBzB,MAAM,IAAI,IAAI;IAOd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IA8CnB,OAAO,CAAC,YAAY;CAkBpB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAatE,MAAM,WAAW,OAAO;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,EAAE,MAAM,CAAC;CACrB;AAaD,+FAA+F;AAC/F,qBAAa,QAAS,YAAW,oBAAoB;IACpD,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAM;IAC/B,KAAK,QAAgB;IACrB,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,YAAY,SAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAC,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAyDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,OAAO,CAAC,QAAQ;IAahB,oGAAoG;IACpG,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE;YAqBhE,WAAW;IAsBzB,MAAM,IAAI,IAAI;IAOd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IAsCnB,OAAO,CAAC,YAAY;CAkBpB"}
@@ -1,18 +1,9 @@
1
1
  import { Agent, } from "@earendil-works/pi-agent-core";
2
2
  import { normalizeContext } from "@earendil-works/pi-ai";
3
3
  import { estimateContextTokens } from "@earendil-works/pi-ai/utils/estimate";
4
+ import { cacheHitPercent, combineUsage, emptyUsage } from "../../core/usage-totals.js";
4
5
  import { MAX_DISPLAY_CHARS, MAX_MODEL_STEPS, MAX_OUTPUT_RESERVE_TOKENS, MAX_QUESTION_CHARS, MAX_QUESTIONS, MAX_RESPONSE_CHARS, TOOL_DENIAL, } from "./constants.js";
5
6
  import { createBtwMessages } from "./snapshot.js";
6
- function emptyUsage() {
7
- return {
8
- input: 0,
9
- output: 0,
10
- cacheRead: 0,
11
- cacheWrite: 0,
12
- totalTokens: 0,
13
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
14
- };
15
- }
16
7
  function displayText(text) {
17
8
  return text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\n\n[Display truncated]`;
18
9
  }
@@ -186,16 +177,8 @@ export class BtwAgent {
186
177
  ? part.thinking.length
187
178
  : JSON.stringify(part.arguments).length), 0);
188
179
  this.blockedTools += message.content.filter((part) => part.type === "toolCall").length;
189
- const usage = message.usage;
190
- const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
191
- this.latestCacheHitPercent =
192
- (usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0
193
- ? (usage.cacheRead / promptTokens) * 100
194
- : undefined;
195
- for (const key of ["input", "output", "cacheRead", "cacheWrite", "totalTokens"])
196
- this.usage[key] += usage[key];
197
- for (const key of ["input", "output", "cacheRead", "cacheWrite", "total"])
198
- this.usage.cost[key] += usage.cost[key];
180
+ this.latestCacheHitPercent = cacheHitPercent(message.usage);
181
+ this.usage = combineUsage(this.usage, message.usage);
199
182
  if (message.stopReason === "error" || message.stopReason === "aborted") {
200
183
  turn.status = message.stopReason === "aborted" ? "cancelled" : "error";
201
184
  turn.notice ??=
@@ -1 +1 @@
1
- {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAKL,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,EACN,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,WAAW,GACX,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AA4BlD,SAAS,UAAU;IAClB,OAAO;QACN,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KACpE,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,yBAAyB,CAAC;AAC/G,CAAC;AAED,+FAA+F;AAC/F,MAAM,OAAO,QAAQ;IAYpB,YAAY,QAAyB,EAAE,OAAqC,EAAE,QAAoB;QAXzF,UAAK,GAAc,EAAE,CAAC;QACtB,UAAK,GAAG,UAAU,EAAE,CAAC;QAE9B,iBAAY,GAAG,CAAC,CAAC;QAMT,aAAQ,GAAG,KAAK,CAAC;QAGxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAC7B,yBAAyB,EACzB,QAAQ,CAAC,KAAK,CAAC,SAAS,EACxB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,CAC5D,CAAC;QACF,mFAAmF;QACnF,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,GAAG,aAAa,GAAG,IAAI,CAAC;QACvE,MAAM,KAAK,GAAgB,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACxD,GAAG,eAAe,CAAC,IAAI,CAAC;YACxB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,IAAI,EAAE;gBACnB,8EAA8E;gBAC9E,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;YAC9B,CAAC;SACD,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC;YACtB,YAAY,EAAE;gBACb,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,aAAa,EAAE,QAAQ,CAAC,aAAa;gBACrC,YAAY,EAAE,QAAQ,CAAC,YAAY;gBACnC,KAAK;gBACL,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,CAAC;aACrC;YACD,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS;YACjE,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS;YAC3C,eAAe,EAAE,QAAQ,CAAC,aAAa,CAAC,eAAe;YACvD,eAAe,EAAE,QAAQ,CAAC,aAAa,CAAC,eAAe;YACvD,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,SAAS;YAC3C,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,UAAU;YAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACrC,uEAAuE;YACvE,oFAAoF;YACpF,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,CAAC,aAAa,EAAE,GAAG,OAAO,EAAE,CAAC;YAChF,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YAClE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,EAAiC,EAAE;gBAChF,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC7B,0FAA0F;gBAC1F,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;oBACnG,OAAO,SAAS,CAAC;gBAClB,QAAQ,CAAC,KAAK,EAAE,CAAC;gBACjB,IAAI,CAAC,WAAW,CAAC,MAAM;oBAAE,OAAO,SAAS,CAAC;gBAC1C,IAAI,QAAQ,CAAC,KAAK,IAAI,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACvE,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;oBAC/B,QAAQ,CAAC,IAAI,CAAC,MAAM;wBACnB,QAAQ,CAAC,KAAK,IAAI,eAAe;4BAChC,CAAC,CAAC,8EAA8E;4BAChF,CAAC,CAAC,4DAA4D,CAAC;oBACjE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;gBAC1B,CAAC;gBACD,OAAO,SAAS,CAAC;YAClB,CAAC;SACD,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,IAAI;QACP,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;IAClC,CAAC;IAEO,QAAQ,CAAC,IAAY;QAC5B,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,kCAAkC,CAAC;QAC7D,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,8DAA8D,CAAC;QACrF,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,aAAa;YAAE,OAAO,iEAAiE,CAAC;QACjH,IAAI,IAAI,CAAC,MAAM,GAAG,kBAAkB;YACnC,OAAO,gCAAgC,kBAAkB,CAAC,cAAc,EAAE,cAAc,CAAC;QAC1F,MAAM,QAAQ,GAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACtF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1D,OAAO,kGAAkG,CAAC;QAC3G,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,oGAAoG;IACpG,aAAa,CAAC,IAAY;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAmB;YAChC,IAAI,EAAE;gBACL,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,EAAE;gBACV,QAAQ,EAAE,EAAE;gBACZ,MAAM,EAAE,WAAW;gBACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,SAAS,EAAE,CAAC;aACZ;YACD,KAAK,EAAE,CAAC;YACR,eAAe,EAAE,EAAE;YACnB,aAAa,EAAE,CAAC;SAChB,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,EAAkB;QACjD,IAAI,CAAC;YACJ,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,IAAI,CAAC,MAAM,GAAG,oCAAoC,CAAC;YACtE,CAAC;iBAAM,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACzC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;YAC3B,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;YACtB,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACnF,CAAC;gBAAS,CAAC;YACV,sEAAsE;YACtE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;YACxB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;YAC7C,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;;gBACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,CAAC;IACF,CAAC;IAED,MAAM;QACL,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnC,4FAA4F;IAC7F,CAAC;IAEO,IAAI,CAAC,QAAwB;QACpC,OAAO,CACN,qBAAqB,CACpB,gBAAgB,CAAC;YAChB,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;YAC3C,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK;YAC7B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CACxB,CAAC,OAAO,EAAsB,EAAE,CAC/B,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY,CACzF;SACD,CAAC,CACF,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAC3B,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,KAAiB;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,IACC,IAAI,CAAC,QAAQ;YACb,CAAC,QAAQ;YACT,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;YACjE,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;YAElC,OAAO;QACR,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QAC1B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClC,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC,MAAM,CAAC;YACvC,QAAQ,CAAC,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAC/C,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CACb,GAAG;gBACH,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM;oBACpB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;oBAClB,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU;wBACzB,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM;wBACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAC3C,CAAC,CACD,CAAC;YACF,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;YACvF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC;YACtE,IAAI,CAAC,qBAAqB;gBACzB,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,IAAI,YAAY,GAAG,CAAC;oBAChE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,GAAG,GAAG;oBACxC,CAAC,CAAC,SAAS,CAAC;YACd,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,CAAU;gBACvF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAU;gBACjF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,OAAO,CAAC,UAAU,KAAK,OAAO,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;gBACxE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;gBACvE,IAAI,CAAC,MAAM;oBACV,OAAO,CAAC,UAAU,KAAK,SAAS;wBAC/B,CAAC,CAAC,wCAAwC;wBAC1C,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC,CAAC;YAChE,CAAC;QACF,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC;IAEO,YAAY,CAAC,QAAwB,EAAE,OAAyB;QACvE,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;aACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACxB,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO;aAC9B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;aAC1C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;aAC5B,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,IAAI,IAAI,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC/F,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACzF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YAC1F,IAAI,CAAC,MAAM,GAAG,0EAA0E,CAAC;YACzF,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACF,CAAC;CACD","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nexport interface BtwConversationState {\n\tbusy: boolean;\n\tturns: readonly BtwTurn[];\n\tusage: Usage;\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools: number;\n}\n\ninterface ActiveQuestion {\n\tturn: BtwTurn;\n\tsteps: number;\n\tcompletedAnswer: string;\n\tresponseChars: number;\n}\n\nfunction emptyUsage(): Usage {\n\treturn {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\ttotalTokens: 0,\n\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t};\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent implements BtwConversationState {\n\treadonly turns: BtwTurn[] = [];\n\treadonly usage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate active?: ActiveQuestion;\n\tprivate disposed = false;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\tconst question = this.active;\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (!question || this.disposed || message.stopReason === \"error\" || message.stopReason === \"aborted\")\n\t\t\t\t\treturn undefined;\n\t\t\t\tquestion.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tquestion.turn.status = \"error\";\n\t\t\t\t\tquestion.turn.notice =\n\t\t\t\t\t\tquestion.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.active !== undefined;\n\t}\n\n\tprivate validate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */\n\tstartQuestion(text: string): { error: string } | { completion: Promise<void> } {\n\t\tconst error = this.validate(text);\n\t\tif (error) return { error };\n\t\tconst question: ActiveQuestion = {\n\t\t\tturn: {\n\t\t\t\tquestion: text,\n\t\t\t\tanswer: \"\",\n\t\t\t\tthinking: \"\",\n\t\t\t\tstatus: \"streaming\",\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\telapsedMs: 0,\n\t\t\t},\n\t\t\tsteps: 0,\n\t\t\tcompletedAnswer: \"\",\n\t\t\tresponseChars: 0,\n\t\t};\n\t\tthis.active = question;\n\t\tthis.turns.push(question.turn);\n\t\treturn { completion: this.runQuestion(question) };\n\t}\n\n\tprivate async runQuestion({ turn }: ActiveQuestion): Promise<void> {\n\t\ttry {\n\t\t\tthis.onChange();\n\t\t\tawait this.agent.prompt(turn.question);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\t// Cancellation remains busy until the native Agent has fully settled.\n\t\t\tthis.active = undefined;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.active || this.disposed) return;\n\t\tthis.active.turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tconst question = this.active;\n\t\tif (\n\t\t\tthis.disposed ||\n\t\t\t!question ||\n\t\t\t(event.type !== \"message_update\" && event.type !== \"message_end\") ||\n\t\t\tevent.message.role !== \"assistant\"\n\t\t)\n\t\t\treturn;\n\t\tconst { turn } = question;\n\t\tconst message = event.message;\n\t\tthis.updateAnswer(question, message);\n\t\tif (event.type === \"message_end\") {\n\t\t\tquestion.completedAnswer = turn.answer;\n\t\t\tquestion.responseChars += message.content.reduce(\n\t\t\t\t(sum, part) =>\n\t\t\t\t\tsum +\n\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t0,\n\t\t\t);\n\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\tconst usage = message.usage;\n\t\t\tconst promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;\n\t\t\tthis.latestCacheHitPercent =\n\t\t\t\t(usage.cacheRead > 0 || usage.cacheWrite > 0) && promptTokens > 0\n\t\t\t\t\t? (usage.cacheRead / promptTokens) * 100\n\t\t\t\t\t: undefined;\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"totalTokens\"] as const)\n\t\t\t\tthis.usage[key] += usage[key];\n\t\t\tfor (const key of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\", \"total\"] as const)\n\t\t\t\tthis.usage.cost[key] += usage.cost[key];\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\tturn.notice ??=\n\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t}\n\t\t}\n\t\tthis.onChange();\n\t}\n\n\tprivate updateAnswer(question: ActiveQuestion, message: AssistantMessage): void {\n\t\tconst { turn } = question;\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([question.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tAgent,\n\ttype AgentEvent,\n\ttype AgentMessage,\n\ttype AgentTool,\n\ttype AgentTurnDecision,\n} from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage, Message, Models, Usage } from \"@earendil-works/pi-ai\";\nimport { normalizeContext } from \"@earendil-works/pi-ai\";\nimport { estimateContextTokens } from \"@earendil-works/pi-ai/utils/estimate\";\nimport type { ContextSnapshot } from \"../../core/extensions/index.ts\";\nimport { cacheHitPercent, combineUsage, emptyUsage } from \"../../core/usage-totals.ts\";\nimport {\n\tMAX_DISPLAY_CHARS,\n\tMAX_MODEL_STEPS,\n\tMAX_OUTPUT_RESERVE_TOKENS,\n\tMAX_QUESTION_CHARS,\n\tMAX_QUESTIONS,\n\tMAX_RESPONSE_CHARS,\n\tTOOL_DENIAL,\n} from \"./constants.ts\";\nimport { createBtwMessages } from \"./snapshot.ts\";\n\nexport interface BtwTurn {\n\tquestion: string;\n\tanswer: string;\n\tthinking: string;\n\tstatus: \"streaming\" | \"cancelling\" | \"done\" | \"cancelled\" | \"error\";\n\tnotice?: string;\n\tstartedAt: number;\n\telapsedMs: number;\n\tfirstAnswerMs?: number;\n}\n\nexport interface BtwConversationState {\n\tbusy: boolean;\n\tturns: readonly BtwTurn[];\n\tusage: Usage;\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools: number;\n}\n\ninterface ActiveQuestion {\n\tturn: BtwTurn;\n\tsteps: number;\n\tcompletedAnswer: string;\n\tresponseChars: number;\n}\n\nfunction displayText(text: string): string {\n\treturn text.length <= MAX_DISPLAY_CHARS ? text : `${text.slice(0, MAX_DISPLAY_CHARS)}\\n\\n[Display truncated]`;\n}\n\n/** An in-memory native Agent. No SessionManager, real tool executors, or main-agent signal. */\nexport class BtwAgent implements BtwConversationState {\n\treadonly turns: BtwTurn[] = [];\n\tusage = emptyUsage();\n\tlatestCacheHitPercent: number | undefined;\n\tblockedTools = 0;\n\tprivate readonly agent: Agent;\n\tprivate readonly unsubscribe: () => void;\n\tprivate readonly onChange: () => void;\n\tprivate readonly inputBudget: number;\n\tprivate active?: ActiveQuestion;\n\tprivate disposed = false;\n\n\tconstructor(snapshot: ContextSnapshot, runtime: Pick<Models, \"streamSimple\">, onChange: () => void) {\n\t\tthis.onChange = onChange;\n\t\tconst outputReserve = Math.min(\n\t\t\tMAX_OUTPUT_RESERVE_TOKENS,\n\t\t\tsnapshot.model.maxTokens,\n\t\t\tMath.max(1024, Math.floor(snapshot.model.contextWindow / 8)),\n\t\t);\n\t\t// Leave room for the answer and estimation error; never trim the inherited prefix.\n\t\tthis.inputBudget = snapshot.model.contextWindow - outputReserve - 4096;\n\t\tconst tools: AgentTool[] = snapshot.tools.map((tool) => ({\n\t\t\t...structuredClone(tool),\n\t\t\tlabel: tool.name,\n\t\t\texecute: async () => {\n\t\t\t\t// Defense in depth: these objects never receive an original execute function.\n\t\t\t\tthrow new Error(TOOL_DENIAL);\n\t\t\t},\n\t\t}));\n\t\tthis.agent = new Agent({\n\t\t\tinitialState: {\n\t\t\t\tmodel: snapshot.model,\n\t\t\t\tthinkingLevel: snapshot.thinkingLevel,\n\t\t\t\tsystemPrompt: snapshot.systemPrompt,\n\t\t\t\ttools,\n\t\t\t\tmessages: createBtwMessages(snapshot),\n\t\t\t},\n\t\t\tsessionId: snapshot.streamOptions.sessionId ?? snapshot.sessionId,\n\t\t\ttransport: snapshot.streamOptions.transport,\n\t\t\tthinkingBudgets: snapshot.streamOptions.thinkingBudgets,\n\t\t\tmaxRetryDelayMs: snapshot.streamOptions.maxRetryDelayMs,\n\t\t\tonPayload: snapshot.streamOptions.onPayload,\n\t\t\tonResponse: snapshot.streamOptions.onResponse,\n\t\t\tstreamFn: (model, context, options) =>\n\t\t\t\t// Keep the parent's generation settings as well as its message prefix.\n\t\t\t\t// The model's native output ceiling and our response-size guard still bound output.\n\t\t\t\truntime.streamSimple(model, context, { ...snapshot.streamOptions, ...options }),\n\t\t\tbeforeToolCall: async () => ({ block: true, reason: TOOL_DENIAL }),\n\t\t\tfinishTurn: ({ message, toolResults, context }): AgentTurnDecision | undefined => {\n\t\t\t\tconst question = this.active;\n\t\t\t\t// Error and aborted responses are hard exits; the step budget only counts answered turns.\n\t\t\t\tif (!question || this.disposed || message.stopReason === \"error\" || message.stopReason === \"aborted\")\n\t\t\t\t\treturn undefined;\n\t\t\t\tquestion.steps++;\n\t\t\t\tif (!toolResults.length) return undefined;\n\t\t\t\tif (question.steps >= MAX_MODEL_STEPS || !this.fits(context.messages)) {\n\t\t\t\t\tquestion.turn.status = \"error\";\n\t\t\t\t\tquestion.turn.notice =\n\t\t\t\t\t\tquestion.steps >= MAX_MODEL_STEPS\n\t\t\t\t\t\t\t? \"Stopped after repeated tool requests. BTW can only answer from its snapshot.\"\n\t\t\t\t\t\t\t: \"Context limit reached. Reopen /btw for a new conversation.\";\n\t\t\t\t\treturn { action: \"end\" };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t});\n\t\tthis.unsubscribe = this.agent.subscribe((event) => this.handleEvent(event));\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.active !== undefined;\n\t}\n\n\tprivate validate(text: string): string | undefined {\n\t\tif (this.disposed) return \"This BTW conversation is closed.\";\n\t\tif (this.busy) return \"BTW is still answering. Your question is kept in the editor.\";\n\t\tif (this.turns.length >= MAX_QUESTIONS) return \"BTW conversation limit reached. Reopen /btw to start a new one.\";\n\t\tif (text.length > MAX_QUESTION_CHARS)\n\t\t\treturn `BTW questions are limited to ${MAX_QUESTION_CHARS.toLocaleString()} characters.`;\n\t\tconst question: AgentMessage = { role: \"user\", content: text, timestamp: Date.now() };\n\t\tif (!this.fits([...this.agent.state.messages, question])) {\n\t\t\treturn \"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw.\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Accept synchronously so a rejected question stays in the editor, outside both agents' queues. */\n\tstartQuestion(text: string): { error: string } | { completion: Promise<void> } {\n\t\tconst error = this.validate(text);\n\t\tif (error) return { error };\n\t\tconst question: ActiveQuestion = {\n\t\t\tturn: {\n\t\t\t\tquestion: text,\n\t\t\t\tanswer: \"\",\n\t\t\t\tthinking: \"\",\n\t\t\t\tstatus: \"streaming\",\n\t\t\t\tstartedAt: Date.now(),\n\t\t\t\telapsedMs: 0,\n\t\t\t},\n\t\t\tsteps: 0,\n\t\t\tcompletedAnswer: \"\",\n\t\t\tresponseChars: 0,\n\t\t};\n\t\tthis.active = question;\n\t\tthis.turns.push(question.turn);\n\t\treturn { completion: this.runQuestion(question) };\n\t}\n\n\tprivate async runQuestion({ turn }: ActiveQuestion): Promise<void> {\n\t\ttry {\n\t\t\tthis.onChange();\n\t\t\tawait this.agent.prompt(turn.question);\n\t\t\tif (turn.status === \"streaming\") {\n\t\t\t\tturn.status = \"done\";\n\t\t\t\tif (!turn.answer) turn.notice = \"The model returned no answer text.\";\n\t\t\t} else if (turn.status === \"cancelling\") {\n\t\t\t\tturn.status = \"cancelled\";\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tturn.status = \"error\";\n\t\t\tturn.notice = displayText(error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\t// Cancellation remains busy until the native Agent has fully settled.\n\t\t\tthis.active = undefined;\n\t\t\tturn.elapsedMs = Date.now() - turn.startedAt;\n\t\t\tif (this.disposed) this.agent.reset();\n\t\t\telse this.onChange();\n\t\t}\n\t}\n\n\tcancel(): void {\n\t\tif (!this.active || this.disposed) return;\n\t\tthis.active.turn.status = \"cancelling\";\n\t\tthis.agent.abort();\n\t\tthis.onChange();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.unsubscribe();\n\t\tthis.agent.abort();\n\t\tthis.turns.length = 0;\n\t\tif (!this.busy) this.agent.reset();\n\t\t// sessionId is cache affinity shared with main. Never clean up its provider resources here.\n\t}\n\n\tprivate fits(messages: AgentMessage[]): boolean {\n\t\treturn (\n\t\t\testimateContextTokens(\n\t\t\t\tnormalizeContext({\n\t\t\t\t\tsystemPrompt: this.agent.state.systemPrompt,\n\t\t\t\t\ttools: this.agent.state.tools,\n\t\t\t\t\tmessages: messages.filter(\n\t\t\t\t\t\t(message): message is Message =>\n\t\t\t\t\t\t\tmessage.role === \"user\" || message.role === \"assistant\" || message.role === \"toolResult\",\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t).tokens < this.inputBudget\n\t\t);\n\t}\n\n\tprivate handleEvent(event: AgentEvent): void {\n\t\tconst question = this.active;\n\t\tif (\n\t\t\tthis.disposed ||\n\t\t\t!question ||\n\t\t\t(event.type !== \"message_update\" && event.type !== \"message_end\") ||\n\t\t\tevent.message.role !== \"assistant\"\n\t\t)\n\t\t\treturn;\n\t\tconst { turn } = question;\n\t\tconst message = event.message;\n\t\tthis.updateAnswer(question, message);\n\t\tif (event.type === \"message_end\") {\n\t\t\tquestion.completedAnswer = turn.answer;\n\t\t\tquestion.responseChars += message.content.reduce(\n\t\t\t\t(sum, part) =>\n\t\t\t\t\tsum +\n\t\t\t\t\t(part.type === \"text\"\n\t\t\t\t\t\t? part.text.length\n\t\t\t\t\t\t: part.type === \"thinking\"\n\t\t\t\t\t\t\t? part.thinking.length\n\t\t\t\t\t\t\t: JSON.stringify(part.arguments).length),\n\t\t\t\t0,\n\t\t\t);\n\t\t\tthis.blockedTools += message.content.filter((part) => part.type === \"toolCall\").length;\n\t\t\tthis.latestCacheHitPercent = cacheHitPercent(message.usage);\n\t\t\tthis.usage = combineUsage(this.usage, message.usage);\n\t\t\tif (message.stopReason === \"error\" || message.stopReason === \"aborted\") {\n\t\t\t\tturn.status = message.stopReason === \"aborted\" ? \"cancelled\" : \"error\";\n\t\t\t\tturn.notice ??=\n\t\t\t\t\tmessage.stopReason === \"aborted\"\n\t\t\t\t\t\t? \"Stopped. You can ask another question.\"\n\t\t\t\t\t\t: displayText(message.errorMessage ?? \"The request failed.\");\n\t\t\t}\n\t\t}\n\t\tthis.onChange();\n\t}\n\n\tprivate updateAnswer(question: ActiveQuestion, message: AssistantMessage): void {\n\t\tconst { turn } = question;\n\t\tconst text = message.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\");\n\t\tconst thinking = message.content\n\t\t\t.filter((part) => part.type === \"thinking\")\n\t\t\t.map((part) => part.thinking)\n\t\t\t.join(\"\");\n\t\tif (text && turn.firstAnswerMs === undefined) turn.firstAnswerMs = Date.now() - turn.startedAt;\n\t\tturn.answer = displayText([question.completedAnswer, text].filter(Boolean).join(\"\\n\\n\"));\n\t\tturn.thinking = thinking.slice(-2000);\n\t\tif (question.responseChars + JSON.stringify(message.content).length > MAX_RESPONSE_CHARS) {\n\t\t\tturn.notice = \"Stopped at the BTW response size limit. You can ask a shorter follow-up.\";\n\t\t\tthis.agent.abort();\n\t\t}\n\t}\n}\n"]}