@astralyn/pi 0.85.3 → 0.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/bundle/chunks/anthropic-messages-R2LYJUDD.js +6 -0
  3. package/dist/bundle/chunks/azure-openai-responses-HS35BQV6.js +2 -0
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +36 -32
  5. package/dist/bundle/chunks/{chunk-S2DJQQI2.js → chunk-2IO5GDBS.js} +10 -1
  6. package/dist/bundle/chunks/{chunk-7LO5Z4WE.js → chunk-I5IVW2WS.js} +1 -1
  7. package/dist/bundle/chunks/chunk-JI4WGISU.js +2 -0
  8. package/dist/bundle/chunks/chunk-LPQCB2VJ.js +44 -0
  9. package/dist/bundle/chunks/chunk-M2YWW37K.js +2 -0
  10. package/dist/bundle/chunks/{chunk-LB4P77SH.js → chunk-MSHHFVMD.js} +776 -762
  11. package/dist/bundle/chunks/chunk-NW5FIDD7.js +11 -0
  12. package/dist/bundle/chunks/chunk-PJVFYVHE.js +42 -0
  13. package/dist/bundle/chunks/github-copilot.js +1 -1
  14. package/dist/bundle/chunks/google-generative-ai-NOVAJBFC.js +2 -0
  15. package/dist/bundle/chunks/google-vertex-4VHCZJV5.js +2 -0
  16. package/dist/bundle/chunks/https-proxy-agent-JOOPB4RE.js +16 -0
  17. package/dist/bundle/chunks/jiti-loader-BFSSLU7G.js +21 -0
  18. package/dist/bundle/chunks/jiti-static-loader-CLT3YR3B.js +2 -0
  19. package/dist/bundle/chunks/mistral-conversations-WC6A2WCJ.js +5 -0
  20. package/dist/bundle/chunks/{node-G4XOIDPH.js → node-CXWYTK2I.js} +1 -1
  21. package/dist/bundle/chunks/openai-codex-responses-XCDG75W2.js +10 -0
  22. package/dist/bundle/chunks/openai-completions-WJIA7NEB.js +7 -0
  23. package/dist/bundle/chunks/openai-responses-UT6XFKC7.js +2 -0
  24. package/dist/bundle/chunks/{pi-messages-PE6B42TG.js → pi-messages-MQMPIPNC.js} +1 -1
  25. package/dist/bundle/chunks/virtual-modules-B4BILEXT.js +2 -0
  26. package/dist/bundle/cli.js +1 -1
  27. package/dist/bundle/index.js +1 -1
  28. package/dist/bundle/rpc-entry.js +1 -1
  29. package/dist/cli/session-picker.d.ts +1 -1
  30. package/dist/cli/session-picker.d.ts.map +1 -1
  31. package/dist/cli/session-picker.js +13 -11
  32. package/dist/cli/session-picker.js.map +1 -1
  33. package/dist/config.js +1 -1
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/agent-session.d.ts +56 -14
  36. package/dist/core/agent-session.d.ts.map +1 -1
  37. package/dist/core/agent-session.js +305 -176
  38. package/dist/core/agent-session.js.map +1 -1
  39. package/dist/core/bug-report-upload.d.ts +12 -0
  40. package/dist/core/bug-report-upload.d.ts.map +1 -0
  41. package/dist/core/bug-report-upload.js +22 -0
  42. package/dist/core/bug-report-upload.js.map +1 -0
  43. package/dist/core/bug-report.d.ts +176 -0
  44. package/dist/core/bug-report.d.ts.map +1 -0
  45. package/dist/core/bug-report.js +292 -0
  46. package/dist/core/bug-report.js.map +1 -0
  47. package/dist/core/cache-stats.d.ts.map +1 -1
  48. package/dist/core/cache-stats.js +12 -1
  49. package/dist/core/cache-stats.js.map +1 -1
  50. package/dist/core/cache-warmer.d.ts +102 -0
  51. package/dist/core/cache-warmer.d.ts.map +1 -0
  52. package/dist/core/cache-warmer.js +333 -0
  53. package/dist/core/cache-warmer.js.map +1 -0
  54. package/dist/core/compaction/branch-summarization.js +2 -2
  55. package/dist/core/compaction/branch-summarization.js.map +1 -1
  56. package/dist/core/compaction/compaction.d.ts +14 -9
  57. package/dist/core/compaction/compaction.d.ts.map +1 -1
  58. package/dist/core/compaction/compaction.js +30 -23
  59. package/dist/core/compaction/compaction.js.map +1 -1
  60. package/dist/core/compaction/settings.d.ts +17 -20
  61. package/dist/core/compaction/settings.d.ts.map +1 -1
  62. package/dist/core/compaction/settings.js +19 -26
  63. package/dist/core/compaction/settings.js.map +1 -1
  64. package/dist/core/context-snapshot.d.ts +16 -5
  65. package/dist/core/context-snapshot.d.ts.map +1 -1
  66. package/dist/core/context-snapshot.js +20 -10
  67. package/dist/core/context-snapshot.js.map +1 -1
  68. package/dist/core/crash-log.d.ts +22 -0
  69. package/dist/core/crash-log.d.ts.map +1 -0
  70. package/dist/core/crash-log.js +71 -0
  71. package/dist/core/crash-log.js.map +1 -0
  72. package/dist/core/experimental.d.ts +0 -4
  73. package/dist/core/experimental.d.ts.map +1 -1
  74. package/dist/core/experimental.js +0 -4
  75. package/dist/core/experimental.js.map +1 -1
  76. package/dist/core/extensions/index.d.ts +1 -1
  77. package/dist/core/extensions/index.d.ts.map +1 -1
  78. package/dist/core/extensions/index.js.map +1 -1
  79. package/dist/core/extensions/jiti-loader.d.ts +2 -0
  80. package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
  81. package/dist/core/extensions/jiti-loader.js +4 -0
  82. package/dist/core/extensions/jiti-loader.js.map +1 -0
  83. package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
  84. package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
  85. package/dist/core/extensions/jiti-static-loader.js +4 -0
  86. package/dist/core/extensions/jiti-static-loader.js.map +1 -0
  87. package/dist/core/extensions/loader.d.ts.map +1 -1
  88. package/dist/core/extensions/loader.js +38 -51
  89. package/dist/core/extensions/loader.js.map +1 -1
  90. package/dist/core/extensions/runner.d.ts +10 -7
  91. package/dist/core/extensions/runner.d.ts.map +1 -1
  92. package/dist/core/extensions/runner.js +85 -67
  93. package/dist/core/extensions/runner.js.map +1 -1
  94. package/dist/core/extensions/types.d.ts +60 -50
  95. package/dist/core/extensions/types.d.ts.map +1 -1
  96. package/dist/core/extensions/types.js.map +1 -1
  97. package/dist/core/extensions/virtual-modules.d.ts +3 -0
  98. package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
  99. package/dist/core/extensions/virtual-modules.js +39 -0
  100. package/dist/core/extensions/virtual-modules.js.map +1 -0
  101. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  102. package/dist/core/extensions/wrapper.js +1 -20
  103. package/dist/core/extensions/wrapper.js.map +1 -1
  104. package/dist/core/index.d.ts +2 -1
  105. package/dist/core/index.d.ts.map +1 -1
  106. package/dist/core/index.js.map +1 -1
  107. package/dist/core/keybindings.d.ts +1 -1
  108. package/dist/core/keybindings.js +1 -1
  109. package/dist/core/keybindings.js.map +1 -1
  110. package/dist/core/messages.d.ts.map +1 -1
  111. package/dist/core/messages.js +1 -0
  112. package/dist/core/messages.js.map +1 -1
  113. package/dist/core/model-config.d.ts +101 -20
  114. package/dist/core/model-config.d.ts.map +1 -1
  115. package/dist/core/model-config.js +25 -18
  116. package/dist/core/model-config.js.map +1 -1
  117. package/dist/core/model-registry.d.ts +5 -1
  118. package/dist/core/model-registry.d.ts.map +1 -1
  119. package/dist/core/model-registry.js +8 -0
  120. package/dist/core/model-registry.js.map +1 -1
  121. package/dist/core/model-resolver.js +1 -1
  122. package/dist/core/model-resolver.js.map +1 -1
  123. package/dist/core/model-runtime.d.ts.map +1 -1
  124. package/dist/core/model-runtime.js +5 -3
  125. package/dist/core/model-runtime.js.map +1 -1
  126. package/dist/core/provider-composer.d.ts +3 -2
  127. package/dist/core/provider-composer.d.ts.map +1 -1
  128. package/dist/core/provider-composer.js +2 -0
  129. package/dist/core/provider-composer.js.map +1 -1
  130. package/dist/core/radius.d.ts +3 -0
  131. package/dist/core/radius.d.ts.map +1 -1
  132. package/dist/core/radius.js +6 -0
  133. package/dist/core/radius.js.map +1 -1
  134. package/dist/core/sdk.d.ts.map +1 -1
  135. package/dist/core/sdk.js +46 -18
  136. package/dist/core/sdk.js.map +1 -1
  137. package/dist/core/session-export.d.ts +6 -2
  138. package/dist/core/session-export.d.ts.map +1 -1
  139. package/dist/core/session-export.js +14 -13
  140. package/dist/core/session-export.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +29 -6
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +159 -96
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts +31 -4
  146. package/dist/core/settings-manager.d.ts.map +1 -1
  147. package/dist/core/settings-manager.js +65 -8
  148. package/dist/core/settings-manager.js.map +1 -1
  149. package/dist/core/slash-commands.d.ts.map +1 -1
  150. package/dist/core/slash-commands.js +1 -0
  151. package/dist/core/slash-commands.js.map +1 -1
  152. package/dist/core/system-prompt.d.ts +49 -6
  153. package/dist/core/system-prompt.d.ts.map +1 -1
  154. package/dist/core/system-prompt.js +121 -92
  155. package/dist/core/system-prompt.js.map +1 -1
  156. package/dist/core/tools/bash.d.ts +2 -1
  157. package/dist/core/tools/bash.d.ts.map +1 -1
  158. package/dist/core/tools/bash.js +6 -3
  159. package/dist/core/tools/bash.js.map +1 -1
  160. package/dist/core/tools/edit.d.ts.map +1 -1
  161. package/dist/core/tools/edit.js +1 -2
  162. package/dist/core/tools/edit.js.map +1 -1
  163. package/dist/core/tools/read.d.ts.map +1 -1
  164. package/dist/core/tools/read.js +1 -2
  165. package/dist/core/tools/read.js.map +1 -1
  166. package/dist/core/tools/shell-execution.js +2 -2
  167. package/dist/core/tools/shell-execution.js.map +1 -1
  168. package/dist/core/tools/write.d.ts.map +1 -1
  169. package/dist/core/tools/write.js +1 -2
  170. package/dist/core/tools/write.js.map +1 -1
  171. package/dist/core/usage-totals.d.ts +1 -1
  172. package/dist/core/usage-totals.d.ts.map +1 -1
  173. package/dist/core/usage-totals.js +4 -1
  174. package/dist/core/usage-totals.js.map +1 -1
  175. package/dist/extensions/background/schema.d.ts +1 -1
  176. package/dist/extensions/btw/agent.d.ts.map +1 -1
  177. package/dist/extensions/btw/agent.js +3 -2
  178. package/dist/extensions/btw/agent.js.map +1 -1
  179. package/dist/extensions/llama/client.d.ts +2 -0
  180. package/dist/extensions/llama/client.d.ts.map +1 -1
  181. package/dist/extensions/llama/client.js +7 -3
  182. package/dist/extensions/llama/client.js.map +1 -1
  183. package/dist/extensions/llama/provider.d.ts.map +1 -1
  184. package/dist/extensions/llama/provider.js +20 -5
  185. package/dist/extensions/llama/provider.js.map +1 -1
  186. package/dist/extensions/provider/compat-fields.d.ts.map +1 -1
  187. package/dist/extensions/provider/compat-fields.js +5 -2
  188. package/dist/extensions/provider/compat-fields.js.map +1 -1
  189. package/dist/extensions/provider/ui/app.js +2 -2
  190. package/dist/extensions/provider/ui/app.js.map +1 -1
  191. package/dist/extensions/todo/schema.d.ts +1 -1
  192. package/dist/index.d.ts +3 -2
  193. package/dist/index.d.ts.map +1 -1
  194. package/dist/index.js.map +1 -1
  195. package/dist/main.d.ts.map +1 -1
  196. package/dist/main.js +13 -9
  197. package/dist/main.js.map +1 -1
  198. package/dist/migrations.d.ts.map +1 -1
  199. package/dist/migrations.js +2 -2
  200. package/dist/migrations.js.map +1 -1
  201. package/dist/modes/interactive/bug-report.d.ts +14 -0
  202. package/dist/modes/interactive/bug-report.d.ts.map +1 -0
  203. package/dist/modes/interactive/bug-report.js +209 -0
  204. package/dist/modes/interactive/bug-report.js.map +1 -0
  205. package/dist/modes/interactive/chat-viewport.js +1 -1
  206. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  207. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  208. package/dist/modes/interactive/components/armin.js +0 -5
  209. package/dist/modes/interactive/components/armin.js.map +1 -1
  210. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  211. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  212. package/dist/modes/interactive/components/bash-execution.js +2 -3
  213. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  214. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  215. package/dist/modes/interactive/components/branch-summary-message.js +12 -5
  216. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  217. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  218. package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
  219. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  220. package/dist/modes/interactive/components/countdown-timer.d.ts +6 -13
  221. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  222. package/dist/modes/interactive/components/countdown-timer.js +15 -51
  223. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  224. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  225. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  226. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  227. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  228. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  229. package/dist/modes/interactive/components/extension-input.js +6 -0
  230. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  231. package/dist/modes/interactive/components/extension-selector.d.ts +1 -2
  232. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  233. package/dist/modes/interactive/components/extension-selector.js +4 -2
  234. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  235. package/dist/modes/interactive/components/session-selector.d.ts +5 -8
  236. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  237. package/dist/modes/interactive/components/session-selector.js +72 -95
  238. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  239. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  240. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  241. package/dist/modes/interactive/components/settings-selector.js +11 -0
  242. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  243. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  244. package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
  245. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  246. package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
  247. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  248. package/dist/modes/interactive/components/status-indicator.js +7 -7
  249. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  250. package/dist/modes/interactive/components/tool-chrome.d.ts.map +1 -1
  251. package/dist/modes/interactive/components/tool-chrome.js +4 -1
  252. package/dist/modes/interactive/components/tool-chrome.js.map +1 -1
  253. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  254. package/dist/modes/interactive/components/tool-execution.js +4 -3
  255. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  256. package/dist/modes/interactive/components/tree-selector.d.ts +1 -10
  257. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/tree-selector.js +4 -51
  259. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  260. package/dist/modes/interactive/interactive-mode.d.ts +13 -1
  261. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  262. package/dist/modes/interactive/interactive-mode.js +227 -91
  263. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  264. package/dist/modes/interactive/session-share.d.ts +2 -0
  265. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  266. package/dist/modes/interactive/session-share.js +8 -4
  267. package/dist/modes/interactive/session-share.js.map +1 -1
  268. package/dist/modes/interactive/tui-renderer.js +2 -2
  269. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  270. package/dist/modes/rpc/rpc-mode.js +2 -2
  271. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  272. package/dist/utils/clipboard-command.d.ts +7 -0
  273. package/dist/utils/clipboard-command.d.ts.map +1 -0
  274. package/dist/utils/clipboard-command.js +45 -0
  275. package/dist/utils/clipboard-command.js.map +1 -0
  276. package/dist/utils/clipboard-image.d.ts.map +1 -1
  277. package/dist/utils/clipboard-image.js +52 -69
  278. package/dist/utils/clipboard-image.js.map +1 -1
  279. package/dist/utils/clipboard.d.ts.map +1 -1
  280. package/dist/utils/clipboard.js +61 -125
  281. package/dist/utils/clipboard.js.map +1 -1
  282. package/dist/utils/zip.d.ts +7 -0
  283. package/dist/utils/zip.d.ts.map +1 -0
  284. package/dist/utils/zip.js +60 -0
  285. package/dist/utils/zip.js.map +1 -0
  286. package/docs/compaction.md +32 -11
  287. package/docs/custom-provider.md +19 -8
  288. package/docs/environment-variables.md +1 -0
  289. package/docs/extensions.md +50 -34
  290. package/docs/models.md +38 -3
  291. package/docs/providers.md +1 -1
  292. package/docs/sdk.md +4 -2
  293. package/docs/session-format.md +63 -24
  294. package/docs/sessions.md +28 -1
  295. package/docs/settings.md +58 -4
  296. package/docs/termux.md +0 -1
  297. package/docs/tui.md +2 -0
  298. package/docs/usage.md +1 -0
  299. package/examples/extensions/README.md +0 -1
  300. package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
  301. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  302. package/examples/extensions/prompt-customizer.ts +19 -67
  303. package/npm-shrinkwrap.json +275 -1028
  304. package/package.json +17 -23
  305. package/dist/bundle/chunks/anthropic-messages-IHRRITCV.js +0 -6
  306. package/dist/bundle/chunks/azure-openai-responses-QXBIDYXO.js +0 -2
  307. package/dist/bundle/chunks/chunk-JSJPY26N.js +0 -2
  308. package/dist/bundle/chunks/chunk-KI6LC764.js +0 -42
  309. package/dist/bundle/chunks/chunk-OWESLY5T.js +0 -11
  310. package/dist/bundle/chunks/chunk-RRBI7OUG.js +0 -50
  311. package/dist/bundle/chunks/chunk-YZJWMPUI.js +0 -2
  312. package/dist/bundle/chunks/google-generative-ai-NBOR3IQR.js +0 -2
  313. package/dist/bundle/chunks/google-vertex-VTHX3SUB.js +0 -2
  314. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
  315. package/dist/bundle/chunks/mistral-conversations-NO4ANAA5.js +0 -5
  316. package/dist/bundle/chunks/openai-codex-responses-5S3T3HMA.js +0 -10
  317. package/dist/bundle/chunks/openai-completions-CXRRTRWE.js +0 -7
  318. package/dist/bundle/chunks/openai-responses-CV3MH6VP.js +0 -2
  319. package/dist/utils/clipboard-native.d.ts +0 -11
  320. package/dist/utils/clipboard-native.d.ts.map +0 -1
  321. package/dist/utils/clipboard-native.js +0 -20
  322. package/dist/utils/clipboard-native.js.map +0 -1
  323. package/examples/extensions/kimi-deferred-tools.ts +0 -61
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAY/E,OAAO,EAAE,KAAK,eAAe,EAAiB,MAAM,qBAAqB,CAAC;AAc1E,QAAA,MAAM,UAAU;;;;;;EASf,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;CAQnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAiBtD,MAAM,WAAW,eAAe;IAC/B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4DAA4D;IAC5D,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA0CD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAqEjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAY/E,OAAO,EAAE,KAAK,eAAe,EAAiB,MAAM,qBAAqB,CAAC;AAc1E,QAAA,MAAM,UAAU;;;;;;EASf,CAAC;AAEF,eAAO,MAAM,gCAAgC;;;CAQnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAiBtD,MAAM,WAAW,eAAe;IAC/B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,4DAA4D;IAC5D,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA0CD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,EAAE,eAAe,CAAC,CAqEjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
@@ -2,7 +2,6 @@ import { constants } from "fs";
2
2
  import { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
3
3
  import { Type } from "typebox";
4
4
  import { splitBom } from "../../utils/text.js";
5
- import { getExperimentalToolSampling } from "../experimental.js";
6
5
  import { applyEditsToNormalizedContent, detectLineEnding, generateDiffString, generateUnifiedPatch, normalizeToLF, restoreLineEndings, } from "./edit-diff.js";
7
6
  import { withFileMutationQueue } from "./file-mutation-queue.js";
8
7
  import { resolveToCwd } from "./path-utils.js";
@@ -87,7 +86,7 @@ export function createEditToolDefinition(cwd, options) {
87
86
  promptSnippet: editToolSystemPromptContribution.snippet,
88
87
  promptGuidelines: [...editToolSystemPromptContribution.guidelines],
89
88
  parameters: editSchema,
90
- constrainedSampling: getExperimentalToolSampling(),
89
+ constrainedSampling: { type: "json_schema", strict: "prefer" },
91
90
  prepareArguments: prepareEditArguments,
92
91
  async execute(_toolCallId, input, signal, _onUpdate, ctx) {
93
92
  const { path, edits } = validateEditInput(input);
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { splitBom } from \"../../utils/text.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n} from \"./edit-diff.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { type EditRenderState, editRenderers } from \"./renderers/edit.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst replaceEditSchema = Type.Object(\n\t{\n\t\toldText: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t\t}),\n\t\tnewText: Type.String({ description: \"Replacement text for this targeted edit.\" }),\n\t},\n\t{},\n);\n\nconst editSchema = Type.Object(\n\t{\n\t\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tedits: Type.Array(replaceEditSchema, {\n\t\t\tdescription:\n\t\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t\t}),\n\t},\n\t{},\n);\n\nexport const editToolSystemPromptContribution = {\n\tsnippet: \"Make precise file edits with exact text replacement, including multiple disjoint edits in one call\",\n\tguidelines: [\n\t\t\"Use edit for precise changes (edits[].oldText must match exactly)\",\n\t\t\"When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\",\n\t\t\"Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\",\n\t\t\"Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\",\n\t],\n} as const;\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & {\n\toldText?: unknown;\n\tnewText?: unknown;\n};\n\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn false;\n\t}\n\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\nexport interface EditToolDetails {\n\t/** Display-oriented diff of the changes made */\n\tdiff: string;\n\t/** Standard unified patch of the changes made */\n\tpatch: string;\n\t/** Line number of the first change in the new file (for editor navigation) */\n\tfirstChangedLine?: number;\n}\n\n/**\n * Pluggable operations for the edit tool.\n * Override these to delegate file editing to remote systems (for example SSH).\n */\nexport interface EditOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Check if file is readable and writable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n}\n\nconst defaultEditOperations: EditOperations = {\n\treadFile: (path) => fsReadFile(path),\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\taccess: (path) => fsAccess(path, constants.R_OK | constants.W_OK),\n};\n\nexport interface EditToolOptions {\n\t/** Custom operations for file editing. Default: local filesystem */\n\toperations?: EditOperations;\n}\n\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\") {\n\t\treturn input as EditToolInput;\n\t}\n\n\tconst args = input as Record<string, unknown>;\n\n\t// Some models (Opus 4.6, GLM-5.1) send edits as a JSON string instead of an array.\n\t// Others send a single edit object instead of a one-element edits array.\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") {\n\t\treturn args as EditToolInput;\n\t}\n\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits } as EditToolInput;\n}\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nexport function createEditToolDefinition(\n\tcwd: string,\n\toptions?: EditToolOptions,\n): ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState> {\n\tconst ops = options?.operations ?? defaultEditOperations;\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tpromptSnippet: editToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...editToolSystemPromptContribution.guidelines],\n\t\tparameters: editSchema,\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(_toolCallId, input: EditToolInput, signal?: AbortSignal, _onUpdate?, ctx?: ExtensionContext) {\n\t\t\tconst { path, edits } = validateEditInput(input);\n\t\t\tconst absolutePath = resolveToCwd(path, ctx?.cwd || cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Check if file exists.\n\t\t\t\ttry {\n\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tthrowIfAborted();\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\terror instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. ${errorMessage}.`);\n\t\t\t\t}\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Read the file.\n\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\tconst rawContent = buffer.toString(\"utf-8\");\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Strip BOM before matching. The model will not include an invisible BOM in oldText.\n\t\t\t\tconst { bom, text: content } = splitBom(rawContent);\n\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\tawait ops.writeFile(absolutePath, finalContent);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\n\t\t\t\tconst patch = generateUnifiedPatch(path, baseContent, newContent);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Successfully replaced ${edits.length} block(s) in ${path}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { diff: diffResult.diff, patch, firstChangedLine: diffResult.firstChangedLine },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t...editRenderers,\n\t};\n}\n\nexport function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema> {\n\treturn wrapToolDefinition(createEditToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/core/tools/edit.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { splitBom } from \"../../utils/text.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport {\n\tapplyEditsToNormalizedContent,\n\tdetectLineEnding,\n\ttype Edit,\n\tgenerateDiffString,\n\tgenerateUnifiedPatch,\n\tnormalizeToLF,\n\trestoreLineEndings,\n} from \"./edit-diff.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { type EditRenderState, editRenderers } from \"./renderers/edit.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst replaceEditSchema = Type.Object(\n\t{\n\t\toldText: Type.String({\n\t\t\tdescription:\n\t\t\t\t\"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call.\",\n\t\t}),\n\t\tnewText: Type.String({ description: \"Replacement text for this targeted edit.\" }),\n\t},\n\t{},\n);\n\nconst editSchema = Type.Object(\n\t{\n\t\tpath: Type.String({ description: \"Path to the file to edit (relative or absolute)\" }),\n\t\tedits: Type.Array(replaceEditSchema, {\n\t\t\tdescription:\n\t\t\t\t\"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead.\",\n\t\t}),\n\t},\n\t{},\n);\n\nexport const editToolSystemPromptContribution = {\n\tsnippet: \"Make precise file edits with exact text replacement, including multiple disjoint edits in one call\",\n\tguidelines: [\n\t\t\"Use edit for precise changes (edits[].oldText must match exactly)\",\n\t\t\"When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls\",\n\t\t\"Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.\",\n\t\t\"Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.\",\n\t],\n} as const;\n\nexport type EditToolInput = Static<typeof editSchema>;\ntype LegacyEditToolInput = EditToolInput & {\n\toldText?: unknown;\n\tnewText?: unknown;\n};\n\ntype SingleEditInput = { oldText: string; newText: string };\n\nfunction isSingleEditInput(value: unknown): value is SingleEditInput {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\treturn false;\n\t}\n\n\tconst edit = value as Record<string, unknown>;\n\treturn typeof edit.oldText === \"string\" && typeof edit.newText === \"string\";\n}\n\nexport interface EditToolDetails {\n\t/** Display-oriented diff of the changes made */\n\tdiff: string;\n\t/** Standard unified patch of the changes made */\n\tpatch: string;\n\t/** Line number of the first change in the new file (for editor navigation) */\n\tfirstChangedLine?: number;\n}\n\n/**\n * Pluggable operations for the edit tool.\n * Override these to delegate file editing to remote systems (for example SSH).\n */\nexport interface EditOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Check if file is readable and writable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n}\n\nconst defaultEditOperations: EditOperations = {\n\treadFile: (path) => fsReadFile(path),\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\taccess: (path) => fsAccess(path, constants.R_OK | constants.W_OK),\n};\n\nexport interface EditToolOptions {\n\t/** Custom operations for file editing. Default: local filesystem */\n\toperations?: EditOperations;\n}\n\nfunction prepareEditArguments(input: unknown): EditToolInput {\n\tif (!input || typeof input !== \"object\") {\n\t\treturn input as EditToolInput;\n\t}\n\n\tconst args = input as Record<string, unknown>;\n\n\t// Some models (Opus 4.6, GLM-5.1) send edits as a JSON string instead of an array.\n\t// Others send a single edit object instead of a one-element edits array.\n\tif (typeof args.edits === \"string\") {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(args.edits);\n\t\t\tif (Array.isArray(parsed)) {\n\t\t\t\targs.edits = parsed;\n\t\t\t} else if (isSingleEditInput(parsed)) {\n\t\t\t\targs.edits = [parsed];\n\t\t\t}\n\t\t} catch {}\n\t} else if (isSingleEditInput(args.edits)) {\n\t\targs.edits = [args.edits];\n\t}\n\n\tconst legacy = args as LegacyEditToolInput;\n\tif (typeof legacy.oldText !== \"string\" || typeof legacy.newText !== \"string\") {\n\t\treturn args as EditToolInput;\n\t}\n\n\tconst edits = Array.isArray(legacy.edits) ? [...legacy.edits] : [];\n\tedits.push({ oldText: legacy.oldText, newText: legacy.newText });\n\tconst { oldText: _oldText, newText: _newText, ...rest } = legacy;\n\treturn { ...rest, edits } as EditToolInput;\n}\n\nfunction validateEditInput(input: EditToolInput): { path: string; edits: Edit[] } {\n\tif (!Array.isArray(input.edits) || input.edits.length === 0) {\n\t\tthrow new Error(\"Edit tool input is invalid. edits must contain at least one replacement.\");\n\t}\n\treturn { path: input.path, edits: input.edits };\n}\n\nexport function createEditToolDefinition(\n\tcwd: string,\n\toptions?: EditToolOptions,\n): ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState> {\n\tconst ops = options?.operations ?? defaultEditOperations;\n\treturn {\n\t\tname: \"edit\",\n\t\tlabel: \"edit\",\n\t\tdescription:\n\t\t\t\"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.\",\n\t\tpromptSnippet: editToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...editToolSystemPromptContribution.guidelines],\n\t\tparameters: editSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tprepareArguments: prepareEditArguments,\n\t\tasync execute(_toolCallId, input: EditToolInput, signal?: AbortSignal, _onUpdate?, ctx?: ExtensionContext) {\n\t\t\tconst { path, edits } = validateEditInput(input);\n\t\t\tconst absolutePath = resolveToCwd(path, ctx?.cwd || cwd);\n\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Check if file exists.\n\t\t\t\ttry {\n\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tthrowIfAborted();\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\terror instanceof Error && \"code\" in error ? `Error code: ${error.code}` : String(error);\n\t\t\t\t\tthrow new Error(`Could not edit file: ${path}. ${errorMessage}.`);\n\t\t\t\t}\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Read the file.\n\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\tconst rawContent = buffer.toString(\"utf-8\");\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Strip BOM before matching. The model will not include an invisible BOM in oldText.\n\t\t\t\tconst { bom, text: content } = splitBom(rawContent);\n\t\t\t\tconst originalEnding = detectLineEnding(content);\n\t\t\t\tconst normalizedContent = normalizeToLF(content);\n\t\t\t\tconst { baseContent, newContent } = applyEditsToNormalizedContent(normalizedContent, edits, path);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\tconst finalContent = bom + restoreLineEndings(newContent, originalEnding);\n\t\t\t\tawait ops.writeFile(absolutePath, finalContent);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\tconst diffResult = generateDiffString(baseContent, newContent);\n\t\t\t\tconst patch = generateUnifiedPatch(path, baseContent, newContent);\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Successfully replaced ${edits.length} block(s) in ${path}.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { diff: diffResult.diff, patch, firstChangedLine: diffResult.firstChangedLine },\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t...editRenderers,\n\t};\n}\n\nexport function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema> {\n\treturn wrapToolDefinition(createEditToolDefinition(cwd, options));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI/E,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEtH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+CAA+C;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,sEAAsE;IACtE,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AASD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA+HhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAI/E,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEtH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;CAGnC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+CAA+C;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,sEAAsE;IACtE,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AASD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA+HhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
@@ -3,7 +3,6 @@ import { access as fsAccess, readFile as fsReadFile } from "fs/promises";
3
3
  import { Type } from "typebox";
4
4
  import { processImage } from "../../utils/image-process.js";
5
5
  import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
6
- import { getExperimentalToolSampling } from "../experimental.js";
7
6
  import { resolveReadPathAsync } from "./path-utils.js";
8
7
  import { readRenderers } from "./renderers/read.js";
9
8
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
@@ -39,7 +38,7 @@ export function createReadToolDefinition(cwd, options) {
39
38
  promptGuidelines: [...readToolSystemPromptContribution.guidelines],
40
39
  parameters: readSchema,
41
40
  toolGroup: "explore",
42
- constrainedSampling: getExperimentalToolSampling(),
41
+ constrainedSampling: { type: "json_schema", strict: "prefer" },
43
42
  async execute(_toolCallId, { path, offset, limit }, signal, _onUpdate, ctx) {
44
43
  return new Promise((resolve, reject) => {
45
44
  if (signal?.aborted) {
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { processImage } from \"../../utils/image-process.ts\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.ts\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { resolveReadPathAsync } from \"./path-utils.ts\";\nimport { readRenderers } from \"./renderers/read.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport const readToolSystemPromptContribution = {\n\tsnippet: \"Read file contents\",\n\tguidelines: [\"Use read to examine files instead of cat or sed.\"],\n} as const;\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\n/**\n * Pluggable operations for the read tool.\n * Override these to delegate file reading to remote systems (for example SSH).\n */\nexport interface ReadOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Check if file is readable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n\t/** Detect image MIME type, return null or undefined for non-images */\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\n\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\n\nexport interface ReadToolOptions {\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\n\tautoResizeImages?: boolean;\n\t/** Custom operations for file reading. Default: local filesystem */\n\toperations?: ReadOperations;\n}\n\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined {\n\tif (!model || model.input.includes(\"image\")) {\n\t\treturn undefined;\n\t}\n\treturn \"[Current model does not support images. The image will be omitted from this request.]\";\n}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n\t\tparameters: readSchema,\n\t\ttoolGroup: \"explore\",\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(path, ctx?.cwd || cwd);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\t// Check if file exists and is readable.\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\t\t\t\t\tconst nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read image as binary.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst processed = await processImage(buffer, mimeType, { autoResizeImages });\n\t\t\t\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${mimeType}]\\n${processed.message}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: textNote }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${processed.mimeType}]`;\n\t\t\t\t\t\t\t\t\tif (processed.hints.length > 0) textNote += `\\n${processed.hints.join(\"\\n\")}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read text content.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\t// Apply offset if specified. Convert from 1-indexed input to 0-indexed array access.\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds.\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\t// If limit is specified by the user, honor it first. Otherwise truncateHead decides.\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Apply truncation, respecting both line and byte limits.\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\tlet outputText: string;\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line alone exceeds the byte limit. Point the model at a bash fallback.\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred. Build an actionable continuation notice.\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User-specified limit stopped early, but the file still has more content.\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation and no remaining user-limited content.\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tif (!aborted) reject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\t...readRenderers,\n\t};\n}\n\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\n\treturn wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport { constants } from \"fs\";\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\nimport { type Static, Type } from \"typebox\";\nimport { processImage } from \"../../utils/image-process.ts\";\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { resolveReadPathAsync } from \"./path-utils.ts\";\nimport { readRenderers } from \"./renderers/read.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\n\nconst readSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\n});\n\nexport const readToolSystemPromptContribution = {\n\tsnippet: \"Read file contents\",\n\tguidelines: [\"Use read to examine files instead of cat or sed.\"],\n} as const;\n\nexport type ReadToolInput = Static<typeof readSchema>;\n\nexport interface ReadToolDetails {\n\ttruncation?: TruncationResult;\n}\n\n/**\n * Pluggable operations for the read tool.\n * Override these to delegate file reading to remote systems (for example SSH).\n */\nexport interface ReadOperations {\n\t/** Read file contents as a Buffer */\n\treadFile: (absolutePath: string) => Promise<Buffer>;\n\t/** Check if file is readable (throw if not) */\n\taccess: (absolutePath: string) => Promise<void>;\n\t/** Detect image MIME type, return null or undefined for non-images */\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\n}\n\nconst defaultReadOperations: ReadOperations = {\n\treadFile: (path) => fsReadFile(path),\n\taccess: (path) => fsAccess(path, constants.R_OK),\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\n};\n\nexport interface ReadToolOptions {\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\n\tautoResizeImages?: boolean;\n\t/** Custom operations for file reading. Default: local filesystem */\n\toperations?: ReadOperations;\n}\n\nfunction getNonVisionImageNote(model: Model<Api> | undefined): string | undefined {\n\tif (!model || model.input.includes(\"image\")) {\n\t\treturn undefined;\n\t}\n\treturn \"[Current model does not support images. The image will be omitted from this request.]\";\n}\n\nexport function createReadToolDefinition(\n\tcwd: string,\n\toptions?: ReadToolOptions,\n): ToolDefinition<typeof readSchema, ReadToolDetails | undefined> {\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\n\tconst ops = options?.operations ?? defaultReadOperations;\n\treturn {\n\t\tname: \"read\",\n\t\tlabel: \"read\",\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp, bmp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\n\t\tpromptSnippet: readToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...readToolSystemPromptContribution.guidelines],\n\t\tparameters: readSchema,\n\t\ttoolGroup: \"explore\",\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\n\t\t\t\t(resolve, reject) => {\n\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tlet aborted = false;\n\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\t};\n\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst absolutePath = await resolveReadPathAsync(path, ctx?.cwd || cwd);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\t// Check if file exists and is readable.\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\n\t\t\t\t\t\t\tconst nonVisionImageNote = getNonVisionImageNote(ctx?.model);\n\t\t\t\t\t\t\tif (mimeType) {\n\t\t\t\t\t\t\t\t// Read image as binary.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst processed = await processImage(buffer, mimeType, { autoResizeImages });\n\t\t\t\t\t\t\t\tif (!processed.ok) {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${mimeType}]\\n${processed.message}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: textNote }];\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${processed.mimeType}]`;\n\t\t\t\t\t\t\t\t\tif (processed.hints.length > 0) textNote += `\\n${processed.hints.join(\"\\n\")}`;\n\t\t\t\t\t\t\t\t\tif (nonVisionImageNote) textNote += `\\n${nonVisionImageNote}`;\n\t\t\t\t\t\t\t\t\tcontent = [\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: processed.data, mimeType: processed.mimeType },\n\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// Read text content.\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\n\t\t\t\t\t\t\t\t// Apply offset if specified. Convert from 1-indexed input to 0-indexed array access.\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1;\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds.\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlet selectedContent: string;\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\n\t\t\t\t\t\t\t\t// If limit is specified by the user, honor it first. Otherwise truncateHead decides.\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Apply truncation, respecting both line and byte limits.\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\n\t\t\t\t\t\t\t\tlet outputText: string;\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\t\t\t\t// First line alone exceeds the byte limit. Point the model at a bash fallback.\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\n\t\t\t\t\t\t\t\t\t// Truncation occurred. Build an actionable continuation notice.\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\n\t\t\t\t\t\t\t\t\t// User-specified limit stopped early, but the file still has more content.\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\n\t\t\t\t\t\t\t\t\toutputText = `${truncation.content}\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// No truncation and no remaining user-limited content.\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (aborted) return;\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tresolve({ content, details });\n\t\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tif (!aborted) reject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t})();\n\t\t\t\t},\n\t\t\t);\n\t\t},\n\t\t...readRenderers,\n\t};\n}\n\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\n\treturn wrapToolDefinition(createReadToolDefinition(cwd, options));\n}\n"]}
@@ -168,10 +168,10 @@ export async function runShellCommand(options) {
168
168
  });
169
169
  managed?.control.accept();
170
170
  ({ exitCode } = await execution);
171
- if (exitCode === null && managed) {
171
+ if (exitCode === null) {
172
172
  failure = { status: "failed", error: "Command terminated without an exit code" };
173
173
  }
174
- else if (exitCode !== 0 && exitCode !== null) {
174
+ else if (exitCode !== 0) {
175
175
  failure = { status: "failed", error: `Command exited with code ${exitCode}` };
176
176
  }
177
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAuB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAuB5D,4FAA4F;AAC5F,SAAS,YAAY,CAAC,KAAc;IACnC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACpH,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,2BAA2B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IACvG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,YAAY,CACpB,MAAyB,EACzB,QAAwB,EACxB,OAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,IAAI,IAAI,GAAG,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC;IACzC,IAAI,OAAO,GAAgC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7G,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,GAAG,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC;QACtC,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;YAChC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3D,IAAI,IAAI,qBAAqB,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,YAAY,OAAO,aAAa,YAAY,mBAAmB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC1J,CAAC;aAAM,IAAI,UAAU,CAAC,WAAW,KAAK,OAAO,EAAE,CAAC;YAC/C,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,kBAAkB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC5H,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,yBAAyB,QAAQ,CAAC,cAAc,GAAG,CAAC;QACvK,CAAC;IACF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,OAA8B;IAE9B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9G,IAAI,WAA8B,CAAC;IACnC,IAAI,eAAe,GAAG,IAAI,CAAC;IAC3B,IAAI,WAAqC,CAAC;IAC1C,IAAI,WAAuC,CAAC;IAC5C,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,EAAE;QACrC,IAAI,WAAW;YAAE,OAAO;QACxB,WAAW,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACJ,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACR,uDAAuD;QACxD,CAAC;IACF,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,GAAG,2BAA2B,EAAE,CAAC;YACpG,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE,CACrB,MAAM,CAAC,QAAQ,CAAC;QACf,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;KACxE,CAAC,CAAC;IACJ,MAAM,OAAO,GAAG,CAAC,QAAyB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAiD;YAC5D,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YACnE,OAAO,EAAE,QAAQ;gBAChB,CAAC,CAAC;oBACA,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;oBAC3E,cAAc,EAAE,QAAQ,CAAC,cAAc;iBACvC;gBACF,CAAC,CAAC,SAAS;SACZ,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE;gBAC/B,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO;gBAC5E,KAAK,EAAE;oBACN,IAAI,EAAE,OAAO,CAAC,SAAS;oBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,SAAS,IAAI,KAAK,EAAE;iBAC7F;aACD,CAAC,CAAC;QACJ,CAAC;;YAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC5D,WAAW,GAAG,KAAK,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,WAAW;YAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QAC3C,WAAW,GAAG,SAAS,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QACjC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO;QAC1C,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,KAAK,GAAG,uBAAuB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC;QACpE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,gBAAgB,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACP,WAAW,KAAK,UAAU,CAAC,GAAG,EAAE;gBAC/B,WAAW,GAAG,SAAS,CAAC;gBACxB,gBAAgB,EAAE,CAAC;YACpB,CAAC,EAAE,KAAK,CAAC,CAAC;QACX,CAAC;IACF,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,CAAC,eAAe,IAAI,WAAW;YAAE,OAAO;QAC5C,IAAI,CAAC;YACJ,IACC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY;gBACtC,MAAM,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,2BAA2B,EACjE,CAAC;gBACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;gBACpF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC3C,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAC9E,CAAC;;gBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,oBAAoB,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO;gBAAE,MAAM,KAAK,CAAC;YAC1B,UAAU,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC,CAAC;IAEF,IAAI,CAAC;QACJ,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,cAAe,CAAC;YAC/C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBAC1B,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;oBACzD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;wBAAE,MAAM,KAAK,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC;YACF,IAAI,CAAC;gBACJ,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,OAAO,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC;YACb,CAAC;YACD,mFAAmF;YACnF,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,EAAE,CAAC;QACV,IAAI,OAAiC,CAAC;QACtC,IAAI,QAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC/D,MAAM,EAAE,UAAU;gBAClB,MAAM;gBACN,OAAO;gBACP,GAAG,EAAE,OAAO,CAAC,GAAG;aAChB,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,SAAS,CAAC,CAAC;YACjC,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,EAAE,CAAC;gBAClC,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;YAClF,CAAC;iBAAM,IAAI,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAChD,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,QAAQ,EAAE,EAAE,CAAC;YAC/E,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,IAAI,OAAO;YAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;;YAC5B,gBAAgB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,WAAW;YAAE,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7F,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC/F,OAAO;YACN,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,EAAE;gBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClG,OAAO;aACP;SACD,CAAC;IACH,CAAC;YAAS,CAAC;QACV,eAAe,GAAG,KAAK,CAAC;QACxB,WAAW,EAAE,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../background/output.ts\";\nimport type { BackgroundCompletion, BackgroundContext, BackgroundControl } from \"../background/types.ts\";\nimport type { BashOperations, BashSpawnContext, BashToolDetails } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport { formatSize, truncateTail } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\nexport interface ManagedShellExecution {\n\thost: BackgroundContext;\n\tcontrol: BackgroundControl<BashToolDetails | undefined>;\n}\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tshellName: string;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<BashToolDetails | undefined>) => void;\n\tmanaged?: ManagedShellExecution;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\tmanaged: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = managed ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<BackgroundCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, managed, signal, timeout } = options;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: !!managed });\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tif (managed) managed.host.kill(managed.control.id);\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (managed?.control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: managed?.control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t};\n\t\tif (managed) {\n\t\t\tmanaged.control.publish(result, {\n\t\t\t\ttext: truncateTail(snapshot?.content ?? \"\", { maxBytes: 16 * 1024 }).content,\n\t\t\t\tshell: {\n\t\t\t\t\tname: options.shellName,\n\t\t\t\t\toutput: { text: snapshot?.content ?? \"\", truncated: snapshot?.truncation.truncated ?? false },\n\t\t\t\t},\n\t\t\t});\n\t\t} else options.onUpdate?.(result);\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif ((!managed && !options.onUpdate) || !updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tif (!managed && !options.onUpdate) return;\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (\n\t\t\t\tmanaged?.control.mode === \"background\" &&\n\t\t\t\toutput.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES\n\t\t\t) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tif (!managed) throw error;\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (managed) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tmanaged.control.setOutputPath(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\t\tunsubscribe = managed.host.subscribe(checkOutputLimit);\n\t\t}\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\tlet exitCode: number | null | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tmanaged?.control.accept();\n\t\t\t({ exitCode } = await execution);\n\t\t\tif (exitCode === null && managed) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0 && exitCode !== null) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (managed) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, !!managed, failure ? \"\" : \"(no output)\");\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\t...(exitCode !== undefined ? { exitCode } : {}),\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: failure ? `${text ? `${text}\\n\\n` : \"\"}${failure.error}` : text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
1
+ {"version":3,"file":"shell-execution.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAuB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAuB5D,4FAA4F;AAC5F,SAAS,YAAY,CAAC,KAAc;IACnC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACpH,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,2BAA2B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;IACvG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,YAAY,CACpB,MAAyB,EACzB,QAAwB,EACxB,OAAgB,EAChB,SAAiB;IAEjB,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;IACvC,IAAI,IAAI,GAAG,QAAQ,CAAC,OAAO,IAAI,SAAS,CAAC;IACzC,IAAI,OAAO,GAAgC,OAAO,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7G,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,GAAG,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC;QAClE,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC,WAAW,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC;QACtC,IAAI,UAAU,CAAC,eAAe,EAAE,CAAC;YAChC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3D,IAAI,IAAI,qBAAqB,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,YAAY,OAAO,aAAa,YAAY,mBAAmB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC1J,CAAC;aAAM,IAAI,UAAU,CAAC,WAAW,KAAK,OAAO,EAAE,CAAC;YAC/C,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,kBAAkB,QAAQ,CAAC,cAAc,GAAG,CAAC;QAC5H,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,sBAAsB,SAAS,IAAI,OAAO,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,yBAAyB,QAAQ,CAAC,cAAc,GAAG,CAAC;QACvK,CAAC;IACF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,OAA8B;IAE9B,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9G,IAAI,WAA8B,CAAC;IACnC,IAAI,eAAe,GAAG,IAAI,CAAC;IAC3B,IAAI,WAAqC,CAAC;IAC1C,IAAI,WAAuC,CAAC;IAC5C,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,MAAM,UAAU,GAAG,CAAC,KAAc,EAAE,EAAE;QACrC,IAAI,WAAW;YAAE,OAAO;QACxB,WAAW,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC;YACJ,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACR,uDAAuD;QACxD,CAAC;IACF,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,IAAI,MAAM,CAAC,aAAa,EAAE,GAAG,2BAA2B,EAAE,CAAC;YACpG,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE,CACrB,MAAM,CAAC,QAAQ,CAAC;QACf,kBAAkB,EAAE,IAAI;QACxB,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;KACxE,CAAC,CAAC;IACJ,MAAM,OAAO,GAAG,CAAC,QAAyB,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAiD;YAC5D,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;YACnE,OAAO,EAAE,QAAQ;gBAChB,CAAC,CAAC;oBACA,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;oBAC3E,cAAc,EAAE,QAAQ,CAAC,cAAc;iBACvC;gBACF,CAAC,CAAC,SAAS;SACZ,CAAC;QACF,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE;gBAC/B,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO;gBAC5E,KAAK,EAAE;oBACN,IAAI,EAAE,OAAO,CAAC,SAAS;oBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,SAAS,IAAI,KAAK,EAAE;iBAC7F;aACD,CAAC,CAAC;QACJ,CAAC;;YAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC5D,WAAW,GAAG,KAAK,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC7B,IAAI,WAAW;YAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QAC3C,WAAW,GAAG,SAAS,CAAC;IACzB,CAAC,CAAC;IACF,MAAM,oBAAoB,GAAG,GAAG,EAAE;QACjC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO;QAC1C,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,KAAK,GAAG,uBAAuB,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,CAAC;QACpE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;YACnB,gBAAgB,EAAE,CAAC;QACpB,CAAC;aAAM,CAAC;YACP,WAAW,KAAK,UAAU,CAAC,GAAG,EAAE;gBAC/B,WAAW,GAAG,SAAS,CAAC;gBACxB,gBAAgB,EAAE,CAAC;YACpB,CAAC,EAAE,KAAK,CAAC,CAAC;QACX,CAAC;IACF,CAAC,CAAC;IACF,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QACnC,IAAI,CAAC,eAAe,IAAI,WAAW;YAAE,OAAO;QAC5C,IAAI,CAAC;YACJ,IACC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,YAAY;gBACtC,MAAM,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,2BAA2B,EACjE,CAAC;gBACF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;gBACpF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;gBAC3C,UAAU,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;YAC9E,CAAC;;gBAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3B,oBAAoB,EAAE,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO;gBAAE,MAAM,KAAK,CAAC;YAC1B,UAAU,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACF,CAAC,CAAC;IAEF,IAAI,CAAC;QACJ,IAAI,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,cAAe,CAAC;YAC/C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;gBAC1B,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;oBACzD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;wBAAE,MAAM,KAAK,CAAC;gBAC1C,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC;YACF,IAAI,CAAC;gBACJ,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC9C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,OAAO,EAAE,CAAC;gBAChB,MAAM,KAAK,CAAC;YACb,CAAC;YACD,mFAAmF;YACnF,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,EAAE,CAAC;QACV,IAAI,OAAiC,CAAC;QACtC,IAAI,QAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC/D,MAAM,EAAE,UAAU;gBAClB,MAAM;gBACN,OAAO;gBACP,GAAG,EAAE,OAAO,CAAC,GAAG;aAChB,CAAC,CAAC;YACH,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1B,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,SAAS,CAAC,CAAC;YACjC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;YAClF,CAAC;iBAAM,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC3B,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,QAAQ,EAAE,EAAE,CAAC;YAC/E,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,eAAe,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,IAAI,OAAO;YAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;;YAC5B,gBAAgB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC7B,4EAA4E;QAC5E,sEAAsE;QACtE,IAAI,WAAW;YAAE,OAAO,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7F,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAC/F,OAAO;YACN,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,KAAK,EAAE,OAAO,EAAE,KAAK;YACrB,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,EAAE;gBACP,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClG,OAAO;aACP;SACD,CAAC;IACH,CAAC;YAAS,CAAC;QACV,eAAe,GAAG,KAAK,CAAC;QACxB,WAAW,EAAE,EAAE,CAAC;QAChB,gBAAgB,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { boundText } from \"../background/output.ts\";\nimport type { BackgroundCompletion, BackgroundContext, BackgroundControl } from \"../background/types.ts\";\nimport type { BashOperations, BashSpawnContext, BashToolDetails } from \"./bash.ts\";\nimport { OutputAccumulator, type OutputSnapshot } from \"./output-accumulator.ts\";\nimport { BASH_UPDATE_THROTTLE_MS } from \"./renderers/bash.ts\";\nimport { formatSize, truncateTail } from \"./truncate.ts\";\n\nexport const MAX_BACKGROUND_OUTPUT_BYTES = 20 * 1024 * 1024;\n\nexport interface ManagedShellExecution {\n\thost: BackgroundContext;\n\tcontrol: BackgroundControl<BashToolDetails | undefined>;\n}\n\ninterface ShellExecutionOptions {\n\toperations: BashOperations;\n\tshellName: string;\n\tcontext: BashSpawnContext;\n\ttempFilePrefix: string;\n\ttimeout?: number;\n\tsignal?: AbortSignal;\n\tonUpdate?: (result: AgentToolResult<BashToolDetails | undefined>) => void;\n\tmanaged?: ManagedShellExecution;\n}\n\ninterface ShellFailure {\n\tstatus: \"failed\" | \"cancelled\" | \"timeout\";\n\terror: string;\n}\n\n/** Interpret the documented BashOperations error markers once, before formatting output. */\nfunction shellFailure(error: unknown): ShellFailure {\n\tif (error instanceof Error && error.message === \"aborted\") return { status: \"cancelled\", error: \"Command aborted\" };\n\tif (error instanceof Error && error.message.startsWith(\"timeout:\"))\n\t\treturn { status: \"timeout\", error: `Command timed out after ${error.message.split(\":\")[1]} seconds` };\n\treturn { status: \"failed\", error: boundText(error instanceof Error ? error.message : String(error), 4096) };\n}\n\nfunction formatOutput(\n\toutput: OutputAccumulator,\n\tsnapshot: OutputSnapshot,\n\tmanaged: boolean,\n\temptyText: string,\n): { text: string; details: BashToolDetails | undefined } {\n\tconst truncation = snapshot.truncation;\n\tlet text = snapshot.content || emptyText;\n\tlet details: BashToolDetails | undefined = managed ? { fullOutputPath: snapshot.fullOutputPath } : undefined;\n\tif (truncation.truncated) {\n\t\tdetails = { truncation, fullOutputPath: snapshot.fullOutputPath };\n\t\tconst startLine = truncation.totalLines - truncation.outputLines + 1;\n\t\tconst endLine = truncation.totalLines;\n\t\tif (truncation.lastLinePartial) {\n\t\t\tconst lastLineSize = formatSize(output.getLastLineBytes());\n\t\t\ttext += `\\n\\n[Showing last ${formatSize(truncation.outputBytes)} of line ${endLine} (line is ${lastLineSize}). Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines}. Full output: ${snapshot.fullOutputPath}]`;\n\t\t} else {\n\t\t\ttext += `\\n\\n[Showing lines ${startLine}-${endLine} of ${truncation.totalLines} (${formatSize(truncation.maxBytes)} limit). Full output: ${snapshot.fullOutputPath}]`;\n\t\t}\n\t}\n\treturn { text, details };\n}\n\n/** One process and one output owner across foreground/background handoff. */\nexport async function runShellCommand(\n\toptions: ShellExecutionOptions,\n): Promise<BackgroundCompletion<BashToolDetails | undefined>> {\n\tconst { operations, context, managed, signal, timeout } = options;\n\tconst output = new OutputAccumulator({ tempFilePrefix: options.tempFilePrefix, persistFromStart: !!managed });\n\tlet outputError: Error | undefined;\n\tlet acceptingOutput = true;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet updateTimer: NodeJS.Timeout | undefined;\n\tlet updateDirty = false;\n\tlet lastUpdateAt = 0;\n\n\tconst failOutput = (error: unknown) => {\n\t\tif (outputError) return;\n\t\toutputError = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tif (managed) managed.host.kill(managed.control.id);\n\t\t} catch {\n\t\t\t// Late data must not throw through a process observer.\n\t\t}\n\t};\n\tconst checkOutputLimit = () => {\n\t\tif (managed?.control.mode === \"background\" && output.getTotalBytes() > MAX_BACKGROUND_OUTPUT_BYTES) {\n\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t}\n\t};\n\tconst snapshot = () =>\n\t\toutput.snapshot({\n\t\t\tpersistIfTruncated: true,\n\t\t\tmaxBytes: managed?.control.mode === \"background\" ? 40 * 1024 : undefined,\n\t\t});\n\tconst publish = (snapshot?: OutputSnapshot) => {\n\t\tconst result: AgentToolResult<BashToolDetails | undefined> = {\n\t\t\tcontent: snapshot ? [{ type: \"text\", text: snapshot.content }] : [],\n\t\t\tdetails: snapshot\n\t\t\t\t? {\n\t\t\t\t\t\ttruncation: snapshot.truncation.truncated ? snapshot.truncation : undefined,\n\t\t\t\t\t\tfullOutputPath: snapshot.fullOutputPath,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t};\n\t\tif (managed) {\n\t\t\tmanaged.control.publish(result, {\n\t\t\t\ttext: truncateTail(snapshot?.content ?? \"\", { maxBytes: 16 * 1024 }).content,\n\t\t\t\tshell: {\n\t\t\t\t\tname: options.shellName,\n\t\t\t\t\toutput: { text: snapshot?.content ?? \"\", truncated: snapshot?.truncation.truncated ?? false },\n\t\t\t\t},\n\t\t\t});\n\t\t} else options.onUpdate?.(result);\n\t};\n\tconst emitOutputUpdate = () => {\n\t\tif ((!managed && !options.onUpdate) || !updateDirty) return;\n\t\tupdateDirty = false;\n\t\tlastUpdateAt = Date.now();\n\t\tpublish(snapshot());\n\t};\n\tconst clearUpdateTimer = () => {\n\t\tif (updateTimer) clearTimeout(updateTimer);\n\t\tupdateTimer = undefined;\n\t};\n\tconst scheduleOutputUpdate = () => {\n\t\tif (!managed && !options.onUpdate) return;\n\t\tupdateDirty = true;\n\t\tconst delay = BASH_UPDATE_THROTTLE_MS - (Date.now() - lastUpdateAt);\n\t\tif (delay <= 0) {\n\t\t\tclearUpdateTimer();\n\t\t\temitOutputUpdate();\n\t\t} else {\n\t\t\tupdateTimer ??= setTimeout(() => {\n\t\t\t\tupdateTimer = undefined;\n\t\t\t\temitOutputUpdate();\n\t\t\t}, delay);\n\t\t}\n\t};\n\tconst handleData = (data: Buffer) => {\n\t\tif (!acceptingOutput || outputError) return;\n\t\ttry {\n\t\t\tif (\n\t\t\t\tmanaged?.control.mode === \"background\" &&\n\t\t\t\toutput.getTotalBytes() + data.length > MAX_BACKGROUND_OUTPUT_BYTES\n\t\t\t) {\n\t\t\t\tconst remaining = Math.max(0, MAX_BACKGROUND_OUTPUT_BYTES - output.getTotalBytes());\n\t\t\t\toutput.append(data.subarray(0, remaining));\n\t\t\t\tfailOutput(new Error(\"Background command exceeded the 20 MiB output limit\"));\n\t\t\t} else output.append(data);\n\t\t\tscheduleOutputUpdate();\n\t\t} catch (error) {\n\t\t\tif (!managed) throw error;\n\t\t\tfailOutput(error);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (managed) {\n\t\t\tconst path = output.snapshot().fullOutputPath!;\n\t\t\tconst cleanup = async () => {\n\t\t\t\tawait output.closeTempFile();\n\t\t\t\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\t\tif (error.code !== \"ENOENT\") throw error;\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tmanaged.control.setOutputPath(path, cleanup);\n\t\t\t} catch (error) {\n\t\t\t\tawait cleanup();\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\t// Detach must check a silent foreground log too, preserving bytes already written.\n\t\t\tunsubscribe = managed.host.subscribe(checkOutputLimit);\n\t\t}\n\t\tpublish();\n\t\tlet failure: ShellFailure | undefined;\n\t\tlet exitCode: number | null | undefined;\n\t\ttry {\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst execution = operations.exec(context.command, context.cwd, {\n\t\t\t\tonData: handleData,\n\t\t\t\tsignal,\n\t\t\t\ttimeout,\n\t\t\t\tenv: context.env,\n\t\t\t});\n\t\t\tmanaged?.control.accept();\n\t\t\t({ exitCode } = await execution);\n\t\t\tif (exitCode === null) {\n\t\t\t\tfailure = { status: \"failed\", error: \"Command terminated without an exit code\" };\n\t\t\t} else if (exitCode !== 0) {\n\t\t\t\tfailure = { status: \"failed\", error: `Command exited with code ${exitCode}` };\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tfailure = shellFailure(error);\n\t\t}\n\t\tacceptingOutput = false;\n\t\toutput.finish();\n\t\tclearUpdateTimer();\n\t\tif (managed) publish(snapshot());\n\t\telse emitOutputUpdate();\n\t\tconst final = snapshot();\n\t\tawait output.closeTempFile();\n\t\t// Final progress/cleanup can re-enter handoff. Classify policy cancellation\n\t\t// after those callbacks, independently of the process's abort marker.\n\t\tif (outputError) failure = { status: \"failed\", error: boundText(outputError.message, 4096) };\n\t\tconst { text, details } = formatOutput(output, final, !!managed, failure ? \"\" : \"(no output)\");\n\t\treturn {\n\t\t\tstatus: failure?.status,\n\t\t\terror: failure?.error,\n\t\t\t...(exitCode !== undefined ? { exitCode } : {}),\n\t\t\tresult: {\n\t\t\t\tcontent: [{ type: \"text\", text: failure ? `${text ? `${text}\\n\\n` : \"\"}${failure.error}` : text }],\n\t\t\t\tdetails,\n\t\t\t},\n\t\t};\n\t} finally {\n\t\tacceptingOutput = false;\n\t\tunsubscribe?.();\n\t\tclearUpdateTimer();\n\t\tawait output.closeTempFile();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAM/E,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAOD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,OAAO,WAAW,EAAE,SAAS,CAAC,CA8C/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAoB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAM/E,QAAA,MAAM,WAAW;;;EAGf,CAAC;AAEH,eAAO,MAAM,iCAAiC;;;CAGpC,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,mCAAmC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAOD,MAAM,WAAW,gBAAgB;IAChC,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,wBAAgB,yBAAyB,CACxC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,gBAAgB,GACxB,cAAc,CAAC,OAAO,WAAW,EAAE,SAAS,CAAC,CA8C/C;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,OAAO,WAAW,CAAC,CAEtG"}
@@ -1,7 +1,6 @@
1
1
  import { mkdir as fsMkdir, writeFile as fsWriteFile } from "fs/promises";
2
2
  import { dirname } from "path";
3
3
  import { Type } from "typebox";
4
- import { getExperimentalToolSampling } from "../experimental.js";
5
4
  import { withFileMutationQueue } from "./file-mutation-queue.js";
6
5
  import { resolveToCwd } from "./path-utils.js";
7
6
  import { writeRenderers } from "./renderers/write.js";
@@ -27,7 +26,7 @@ export function createWriteToolDefinition(cwd, options) {
27
26
  promptSnippet: writeToolSystemPromptContribution.snippet,
28
27
  promptGuidelines: [...writeToolSystemPromptContribution.guidelines],
29
28
  parameters: writeSchema,
30
- constrainedSampling: getExperimentalToolSampling(),
29
+ constrainedSampling: { type: "json_schema", strict: "prefer" },
31
30
  async execute(_toolCallId, { path, content }, signal, _onUpdate, ctx) {
32
31
  const absolutePath = resolveToCwd(path, ctx?.cwd || cwd);
33
32
  const dir = dirname(absolutePath);
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { mkdir as fsMkdir, writeFile as fsWriteFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { getExperimentalToolSampling } from \"../experimental.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { writeRenderers } from \"./renderers/write.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeToolSystemPromptContribution = {\n\tsnippet: \"Create or overwrite files\",\n\tguidelines: [\"Use write only for new files or complete rewrites.\"],\n} as const;\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\n/**\n * Pluggable operations for the write tool.\n * Override these to delegate file writing to remote systems (for example SSH).\n */\nexport interface WriteOperations {\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Create directory recursively */\n\tmkdir: (dir: string) => Promise<void>;\n}\n\nconst defaultWriteOperations: WriteOperations = {\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\tmkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => {}),\n};\n\nexport interface WriteToolOptions {\n\t/** Custom operations for file writing. Default: local filesystem */\n\toperations?: WriteOperations;\n}\n\nexport function createWriteToolDefinition(\n\tcwd: string,\n\toptions?: WriteToolOptions,\n): ToolDefinition<typeof writeSchema, undefined> {\n\tconst ops = options?.operations ?? defaultWriteOperations;\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tpromptSnippet: writeToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...writeToolSystemPromptContribution.guidelines],\n\t\tparameters: writeSchema,\n\t\tconstrainedSampling: getExperimentalToolSampling(),\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst absolutePath = resolveToCwd(path, ctx?.cwd || cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\t\t\t\t// Create parent directories if needed.\n\t\t\t\tawait ops.mkdir(dir);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Write the file contents.\n\t\t\t\tawait ops.writeFile(absolutePath, content);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote to ${path}` }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t...writeRenderers,\n\t};\n}\n\nexport function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema> {\n\treturn wrapToolDefinition(createWriteToolDefinition(cwd, options));\n}\n"]}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/tools/write.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kDAAkD,EAAE,CAAC;IACtF,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;CACrE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iCAAiC,GAAG;IAChD,OAAO,EAAE,2BAA2B;IACpC,UAAU,EAAE,CAAC,oDAAoD,CAAC;CACzD,CAAC;AAeX,MAAM,sBAAsB,GAAoB;IAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;IACjE,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;CAChE,CAAC;AAOF,MAAM,UAAU,yBAAyB,CACxC,GAAW,EACX,OAA0B;IAE1B,MAAM,GAAG,GAAG,OAAO,EAAE,UAAU,IAAI,sBAAsB,CAAC;IAC1D,OAAO;QACN,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,iIAAiI;QAClI,aAAa,EAAE,iCAAiC,CAAC,OAAO;QACxD,gBAAgB,EAAE,CAAC,GAAG,iCAAiC,CAAC,UAAU,CAAC;QACnE,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9D,KAAK,CAAC,OAAO,CACZ,WAAW,EACX,EAAE,IAAI,EAAE,OAAO,EAAqC,EACpD,MAAoB,EACpB,SAAU,EACV,GAAsB;YAEtB,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;YACzD,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;YAClC,OAAO,qBAAqB,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;gBACrD,0EAA0E;gBAC1E,2EAA2E;gBAC3E,0EAA0E;gBAC1E,oEAAoE;gBACpE,MAAM,cAAc,GAAG,GAAS,EAAE;oBACjC,IAAI,MAAM,EAAE,OAAO;wBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAC3D,CAAC,CAAC;gBAEF,cAAc,EAAE,CAAC;gBACjB,uCAAuC;gBACvC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACrB,cAAc,EAAE,CAAC;gBAEjB,2BAA2B;gBAC3B,MAAM,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBAC3C,cAAc,EAAE,CAAC;gBAEjB,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,IAAI,EAAE,EAAE,CAAC;oBAClE,OAAO,EAAE,SAAS;iBAClB,CAAC;YACH,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,GAAG,cAAc;KACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,OAA0B;IACtE,OAAO,kBAAkB,CAAC,yBAAyB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AACpE,CAAC","sourcesContent":["import type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { mkdir as fsMkdir, writeFile as fsWriteFile } from \"fs/promises\";\nimport { dirname } from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { withFileMutationQueue } from \"./file-mutation-queue.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { writeRenderers } from \"./renderers/write.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst writeSchema = Type.Object({\n\tpath: Type.String({ description: \"Path to the file to write (relative or absolute)\" }),\n\tcontent: Type.String({ description: \"Content to write to the file\" }),\n});\n\nexport const writeToolSystemPromptContribution = {\n\tsnippet: \"Create or overwrite files\",\n\tguidelines: [\"Use write only for new files or complete rewrites.\"],\n} as const;\n\nexport type WriteToolInput = Static<typeof writeSchema>;\n\n/**\n * Pluggable operations for the write tool.\n * Override these to delegate file writing to remote systems (for example SSH).\n */\nexport interface WriteOperations {\n\t/** Write content to a file */\n\twriteFile: (absolutePath: string, content: string) => Promise<void>;\n\t/** Create directory recursively */\n\tmkdir: (dir: string) => Promise<void>;\n}\n\nconst defaultWriteOperations: WriteOperations = {\n\twriteFile: (path, content) => fsWriteFile(path, content, \"utf-8\"),\n\tmkdir: (dir) => fsMkdir(dir, { recursive: true }).then(() => {}),\n};\n\nexport interface WriteToolOptions {\n\t/** Custom operations for file writing. Default: local filesystem */\n\toperations?: WriteOperations;\n}\n\nexport function createWriteToolDefinition(\n\tcwd: string,\n\toptions?: WriteToolOptions,\n): ToolDefinition<typeof writeSchema, undefined> {\n\tconst ops = options?.operations ?? defaultWriteOperations;\n\treturn {\n\t\tname: \"write\",\n\t\tlabel: \"write\",\n\t\tdescription:\n\t\t\t\"Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.\",\n\t\tpromptSnippet: writeToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: [...writeToolSystemPromptContribution.guidelines],\n\t\tparameters: writeSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{ path, content }: { path: string; content: string },\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst absolutePath = resolveToCwd(path, ctx?.cwd || cwd);\n\t\t\tconst dir = dirname(absolutePath);\n\t\t\treturn withFileMutationQueue(absolutePath, async () => {\n\t\t\t\t// Do not reject from an abort event listener here: that would release the\n\t\t\t\t// mutation queue while an in-flight filesystem operation may still finish.\n\t\t\t\t// Checking signal.aborted after each await observes the same aborts while\n\t\t\t\t// keeping the queue locked until the current operation has settled.\n\t\t\t\tconst throwIfAborted = (): void => {\n\t\t\t\t\tif (signal?.aborted) throw new Error(\"Operation aborted\");\n\t\t\t\t};\n\n\t\t\t\tthrowIfAborted();\n\t\t\t\t// Create parent directories if needed.\n\t\t\t\tawait ops.mkdir(dir);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\t// Write the file contents.\n\t\t\t\tawait ops.writeFile(absolutePath, content);\n\t\t\t\tthrowIfAborted();\n\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Successfully wrote to ${path}` }],\n\t\t\t\t\tdetails: undefined,\n\t\t\t\t};\n\t\t\t});\n\t\t},\n\t\t...writeRenderers,\n\t};\n}\n\nexport function createWriteTool(cwd: string, options?: WriteToolOptions): AgentTool<typeof writeSchema> {\n\treturn wrapToolDefinition(createWriteToolDefinition(cwd, options));\n}\n"]}
@@ -24,6 +24,6 @@ export interface BackgroundUsageRecord {
24
24
  export declare function getBackgroundUsageRecord(entry: SessionEntry): BackgroundUsageRecord | undefined;
25
25
  /** Legacy usage plus the first valid ledger record per task. Managed results omit usage. */
26
26
  export declare function getAccountedUsages(entries: readonly SessionEntry[]): Usage[];
27
- /** Group attributable assistant usage by model and all other usage into a separate bucket. */
27
+ /** Group model-attributed usage by model and all other usage into a separate bucket. */
28
28
  export declare function getUsageCostBreakdown(entries: readonly SessionEntry[]): UsageCostBreakdownEntry[];
29
29
  //# sourceMappingURL=usage-totals.d.ts.map
@@ -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;AAEzD,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,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACb;AAUD,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,qBAAqB,GAAG,SAAS,CA6C/F;AAuBD,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,KAAK,EAAE,CAE5E;AAED,8FAA8F;AAC9F,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;AAEzD,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,MAAM,WAAW,uBAAuB;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;CACb;AAUD,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,qBAAqB,GAAG,SAAS,CA6C/F;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"}
@@ -77,6 +77,9 @@ function* accountedUsageEntries(entries) {
77
77
  usage: entry.message.usage,
78
78
  };
79
79
  }
80
+ else if (entry.type === "usage") {
81
+ yield { key: `${entry.provider}/${entry.model}`, usage: entry.usage };
82
+ }
80
83
  else if (entry.type === "message" && entry.message.role === "toolResult" && entry.message.usage) {
81
84
  yield { key: "Tools/summaries", usage: entry.message.usage };
82
85
  }
@@ -96,7 +99,7 @@ function* accountedUsageEntries(entries) {
96
99
  export function getAccountedUsages(entries) {
97
100
  return Array.from(accountedUsageEntries(entries), ({ usage }) => usage);
98
101
  }
99
- /** Group attributable assistant usage by model and all other usage into a separate bucket. */
102
+ /** Group model-attributed usage by model and all other usage into a separate bucket. */
100
103
  export function getUsageCostBreakdown(entries) {
101
104
  const totalsByKey = new Map();
102
105
  for (const { key, usage } of accountedUsageEntries(entries)) {
@@ -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\";\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\nexport interface UsageCostBreakdownEntry {\n\tkey: string;\n\tcost: number;\n\ttokens: number;\n}\n\nexport const BACKGROUND_USAGE_TYPE = \"background-usage\";\n\nexport interface BackgroundUsageRecord {\n\tversion: 1;\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/** Validate persisted ledger data and return only its serializable accounting fields. */\nexport function getBackgroundUsageRecord(entry: SessionEntry): BackgroundUsageRecord | undefined {\n\tif (entry.type !== \"custom\" || entry.customType !== BACKGROUND_USAGE_TYPE) return undefined;\n\tconst data = entry.data;\n\tif (!isRecord(data) || data.version !== 1 || typeof data.taskId !== \"string\" || !data.taskId.trim()) {\n\t\treturn undefined;\n\t}\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\tversion: 1,\n\t\ttaskId: data.taskId,\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 === \"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 = getBackgroundUsageRecord(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 attributable assistant 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\";\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\nexport interface UsageCostBreakdownEntry {\n\tkey: string;\n\tcost: number;\n\ttokens: number;\n}\n\nexport const BACKGROUND_USAGE_TYPE = \"background-usage\";\n\nexport interface BackgroundUsageRecord {\n\tversion: 1;\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/** Validate persisted ledger data and return only its serializable accounting fields. */\nexport function getBackgroundUsageRecord(entry: SessionEntry): BackgroundUsageRecord | undefined {\n\tif (entry.type !== \"custom\" || entry.customType !== BACKGROUND_USAGE_TYPE) return undefined;\n\tconst data = entry.data;\n\tif (!isRecord(data) || data.version !== 1 || typeof data.taskId !== \"string\" || !data.taskId.trim()) {\n\t\treturn undefined;\n\t}\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\tversion: 1,\n\t\ttaskId: data.taskId,\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 = getBackgroundUsageRecord(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"]}
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { type Static, Type } from "typebox";
10
10
  export declare const bgSchema: Type.TObject<{
11
- action: Type.TUnsafe<"list" | "read" | "wait" | "kill">;
11
+ action: Type.TUnsafe<"read" | "list" | "wait" | "kill">;
12
12
  taskId: Type.TOptional<Type.TString>;
13
13
  mode: Type.TOptional<Type.TUnsafe<"head" | "tail">>;
14
14
  bytes: Type.TOptional<Type.TNumber>;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA6B,MAAM,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEtF,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;AAiBD,+FAA+F;AAC/F,qBAAa,QAAQ;IACpB,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,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,aAAa,CAAK;gBAEd,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAwDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAapC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCtC,MAAM,IAAI,IAAI;IAQd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAaZ,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,YAAY;CAiBpB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/agent.ts"],"names":[],"mappings":"AACA,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;AAiBD,+FAA+F;AAC/F,qBAAa,QAAQ;IACpB,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,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,aAAa,CAAK;gBAEd,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI;IAwDlG,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAapC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoCtC,MAAM,IAAI,IAAI;IAQd,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,YAAY;CAiBpB"}
@@ -1,4 +1,5 @@
1
1
  import { Agent } from "@earendil-works/pi-agent-core";
2
+ import { normalizeContext } from "@earendil-works/pi-ai";
2
3
  import { estimateContextTokens } from "@earendil-works/pi-ai/utils/estimate";
3
4
  import { MAX_DISPLAY_CHARS, MAX_MODEL_STEPS, MAX_OUTPUT_RESERVE_TOKENS, MAX_QUESTION_CHARS, MAX_QUESTIONS, MAX_RESPONSE_CHARS, TOOL_DENIAL, } from "./constants.js";
4
5
  import { createBtwMessages } from "./snapshot.js";
@@ -159,11 +160,11 @@ export class BtwAgent {
159
160
  // sessionId is cache affinity shared with main. Never clean up its provider resources here.
160
161
  }
161
162
  fits(messages) {
162
- return (estimateContextTokens({
163
+ return (estimateContextTokens(normalizeContext({
163
164
  systemPrompt: this.agent.state.systemPrompt,
164
165
  tools: this.agent.state.tools,
165
166
  messages: messages.filter((message) => message.role === "user" || message.role === "assistant" || message.role === "toolResult"),
166
- }).tokens < this.inputBudget);
167
+ })).tokens < this.inputBudget);
167
168
  }
168
169
  handleEvent(event) {
169
170
  if (this.disposed)