@xopcai/xopc 0.0.113 → 0.0.114

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 (327) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-Fp-p7bP1.js} +1 -1
  4. package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +6 -0
  5. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-DJWG26Si.js +71 -0
  7. package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-v24i25Oj.js} +1 -1
  8. package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-ycbdJRuZ.js} +1 -1
  9. package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +1 -0
  10. package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CJzSADJo.js} +1 -1
  11. package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BTAB4zGS.js} +1 -1
  12. package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-DXR1-mct.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-CzQri9h2.js} +44 -44
  14. package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +1 -0
  15. package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-DRqjEvAx.js} +1 -1
  16. package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +2 -0
  17. package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-BXaZXv1o.js} +1 -1
  18. package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +3 -0
  19. package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +1 -0
  20. package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-DSkqMYo7.js} +1 -1
  21. package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-h2dGDbMN.js} +1 -1
  22. package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-hN99RhOi.js} +1 -1
  23. package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D9QqUtzZ.js} +1 -1
  24. package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-D6E687rG.js} +1 -1
  25. package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-CLt_SKTC.js} +1 -1
  26. package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-1PDi4lI0.js} +1 -1
  27. package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-N7Z_sz7p.js} +1 -1
  28. package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +1 -0
  29. package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +2 -0
  30. package/dist/gateway/static/root/assets/{goals-settings-ceEBjnfc.js → goals-settings-LFlwtIKE.js} +1 -1
  31. package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-DGPadTw-.js} +1 -1
  32. package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-BHHAs8ZX.js} +1 -1
  33. package/dist/gateway/static/root/assets/index-DefIdW9q.js +122 -0
  34. package/dist/gateway/static/root/assets/index-DzmWBkq-.css +1 -0
  35. package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-CEklPQ_r.js} +1 -1
  36. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-Ce_aQ8Iv.js} +1 -1
  37. package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +2 -0
  38. package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-BMz3xPXO.js} +1 -1
  39. package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-BalOSoz9.js} +1 -1
  40. package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +3 -0
  41. package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +2 -0
  42. package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +2 -0
  43. package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-C5D1Q5mY.js} +1 -1
  44. package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +1 -0
  45. package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CYFR5U9l.js} +1 -1
  46. package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +1 -0
  47. package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-BQ79Z5IP.js} +1 -1
  48. package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-Bgk6Emue.js} +1 -1
  49. package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DzS36TMa.js} +1 -1
  50. package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +1 -0
  51. package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +1 -0
  52. package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CdjFnSAy.js} +1 -1
  53. package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-DZLy_exu.js} +1 -1
  54. package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +1 -0
  55. package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +1 -0
  56. package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-_qRDr4g_.js} +1 -1
  57. package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +1 -0
  58. package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +1 -0
  59. package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +2 -0
  60. package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-hqaBF5aG.js} +1 -1
  61. package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-zbVIQLOA.js} +1 -1
  62. package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CbXq97rT.js} +1 -1
  63. package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-DwS3drWK.js} +1 -1
  64. package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +1 -0
  65. package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DSuOd9zy.js} +1 -1
  66. package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +1 -0
  67. package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.js +18 -0
  68. package/dist/gateway/static/root/index.html +5 -5
  69. package/dist/package.js +1 -1
  70. package/dist/src/agent/agent-manager.d.ts +8 -0
  71. package/dist/src/agent/agent-manager.js +57 -22
  72. package/dist/src/agent/agent-manager.js.map +1 -1
  73. package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
  74. package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
  75. package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
  76. package/dist/src/agent/goals/persistent-goal-service.js +2 -4
  77. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  78. package/dist/src/agent/inbound/inbound-loop.js +5 -1
  79. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  80. package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
  81. package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
  82. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  83. package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
  84. package/dist/src/agent/mcp/bundle-mcp-materialize.js +49 -1
  85. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  86. package/dist/src/agent/mcp/bundle-mcp-runtime.js +78 -3
  87. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  88. package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
  89. package/dist/src/agent/service/btw-query.js +11 -3
  90. package/dist/src/agent/service/btw-query.js.map +1 -1
  91. package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
  92. package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
  93. package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
  94. package/dist/src/agent/service/process-direct-one-shot.js +1 -1
  95. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  96. package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
  97. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  98. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  99. package/dist/src/agent/service.d.ts +1 -1
  100. package/dist/src/agent/service.js +9 -5
  101. package/dist/src/agent/service.js.map +1 -1
  102. package/dist/src/agent/service.types.d.ts +5 -0
  103. package/dist/src/agent/skills/filesystem-watcher.js +4 -3
  104. package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
  105. package/dist/src/agent/skills/index.js +2 -1
  106. package/dist/src/agent/skills/index.js.map +1 -1
  107. package/dist/src/agent/skills/skill-manage-ops.js +2 -1
  108. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  109. package/dist/src/agent/skills/types.d.ts +1 -1
  110. package/dist/src/agent/skills/watcher.js +2 -5
  111. package/dist/src/agent/skills/watcher.js.map +1 -1
  112. package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
  113. package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
  114. package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
  115. package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
  116. package/dist/src/agent/tool-manuals/browser.js +62 -3
  117. package/dist/src/agent/tool-manuals/browser.js.map +1 -1
  118. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
  119. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
  120. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  121. package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
  122. package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
  123. package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
  124. package/dist/src/agent/tools/factory.js +1 -10
  125. package/dist/src/agent/tools/factory.js.map +1 -1
  126. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  127. package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
  128. package/dist/src/agent/workflow/subagent-runner.js +18 -1
  129. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  130. package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
  131. package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
  132. package/dist/src/browser/actions/registry.js +383 -7
  133. package/dist/src/browser/actions/registry.js.map +1 -1
  134. package/dist/src/browser/actions/types.d.ts +11 -3
  135. package/dist/src/browser/index.js +2 -2
  136. package/dist/src/browser/pipeline/output.d.ts +18 -16
  137. package/dist/src/browser/pipeline/output.js +28 -20
  138. package/dist/src/browser/pipeline/output.js.map +1 -1
  139. package/dist/src/browser/pipeline/runner.d.ts +7 -14
  140. package/dist/src/browser/pipeline/runner.js +349 -102
  141. package/dist/src/browser/pipeline/runner.js.map +1 -1
  142. package/dist/src/browser/pipeline/schema.d.ts +1 -0
  143. package/dist/src/browser/pipeline/schema.js +35 -58
  144. package/dist/src/browser/pipeline/schema.js.map +1 -1
  145. package/dist/src/browser/pipeline/source.d.ts +2 -0
  146. package/dist/src/browser/pipeline/source.js +10 -1
  147. package/dist/src/browser/pipeline/source.js.map +1 -1
  148. package/dist/src/browser/pipeline/template.d.ts +10 -2
  149. package/dist/src/browser/pipeline/template.js +50 -8
  150. package/dist/src/browser/pipeline/template.js.map +1 -1
  151. package/dist/src/chat-commands/builtins/config.js +3 -5
  152. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  153. package/dist/src/chat-commands/context.d.ts +5 -0
  154. package/dist/src/chat-commands/context.js +18 -9
  155. package/dist/src/chat-commands/context.js.map +1 -1
  156. package/dist/src/chat-commands/index.d.ts +1 -1
  157. package/dist/src/chat-commands/index.js +2 -2
  158. package/dist/src/chat-commands/index.js.map +1 -1
  159. package/dist/src/chat-commands/processor.js +22 -21
  160. package/dist/src/chat-commands/processor.js.map +1 -1
  161. package/dist/src/chat-commands/session-key.d.ts +3 -15
  162. package/dist/src/chat-commands/session-key.js +3 -49
  163. package/dist/src/chat-commands/session-key.js.map +1 -1
  164. package/dist/src/chat-commands/types.d.ts +4 -0
  165. package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
  166. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  167. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  168. package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
  169. package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
  170. package/dist/src/config/rules.js +5 -0
  171. package/dist/src/config/rules.js.map +1 -1
  172. package/dist/src/connectors/builtin-catalog.js +180 -1
  173. package/dist/src/connectors/builtin-catalog.js.map +1 -1
  174. package/dist/src/connectors/health.js +18 -9
  175. package/dist/src/connectors/health.js.map +1 -1
  176. package/dist/src/connectors/types.d.ts +19 -0
  177. package/dist/src/connectors/usage.js +12 -4
  178. package/dist/src/connectors/usage.js.map +1 -1
  179. package/dist/src/extensions/types/tui.d.ts +2 -0
  180. package/dist/src/gateway/heartbeat/service.js +13 -1
  181. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  182. package/dist/src/gateway/hono/app.js +13 -4
  183. package/dist/src/gateway/hono/app.js.map +1 -1
  184. package/dist/src/gateway/hono/oauth-async.js +1 -1
  185. package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
  186. package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
  187. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
  188. package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
  189. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  190. package/dist/src/gateway/hono/routes/goals.js +16 -3
  191. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  192. package/dist/src/gateway/hono/routes/logs.js +1 -0
  193. package/dist/src/gateway/hono/routes/logs.js.map +1 -1
  194. package/dist/src/gateway/hono/routes/mcp.js +27 -8
  195. package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
  196. package/dist/src/gateway/hono/routes/notes.js +14 -2
  197. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  198. package/dist/src/gateway/hono/routes/sessions.js +62 -4
  199. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  200. package/dist/src/gateway/hono/routes/workspace.js +3 -66
  201. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  202. package/dist/src/gateway/hono/sse.d.ts +2 -2
  203. package/dist/src/gateway/hono/sse.js +7 -15
  204. package/dist/src/gateway/hono/sse.js.map +1 -1
  205. package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
  206. package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
  207. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
  208. package/dist/src/gateway/service/agent-runner.d.ts +2 -3
  209. package/dist/src/gateway/service/agent-runner.js +9 -22
  210. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  211. package/dist/src/gateway/service/run-gateway-agent.js +9 -7
  212. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  213. package/dist/src/gateway/service/sessions-api.d.ts +9 -0
  214. package/dist/src/gateway/service/sessions-api.js +11 -0
  215. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  216. package/dist/src/gateway/service.d.ts +1 -1
  217. package/dist/src/gateway/service.js +19 -5
  218. package/dist/src/gateway/service.js.map +1 -1
  219. package/dist/src/gateway/workspace-file-search.d.ts +9 -0
  220. package/dist/src/gateway/workspace-file-search.js +76 -0
  221. package/dist/src/gateway/workspace-file-search.js.map +1 -0
  222. package/dist/src/goals/goal-notifications.d.ts +2 -0
  223. package/dist/src/goals/goal-notifications.js +16 -11
  224. package/dist/src/goals/goal-notifications.js.map +1 -1
  225. package/dist/src/goals/goal-service.js +1 -6
  226. package/dist/src/goals/goal-service.js.map +1 -1
  227. package/dist/src/project-trust/trust-store.js +2 -0
  228. package/dist/src/project-trust/trust-store.js.map +1 -1
  229. package/dist/src/session/index.d.ts +1 -1
  230. package/dist/src/session/index.js +2 -2
  231. package/dist/src/session/init-session-turn.js +6 -9
  232. package/dist/src/session/init-session-turn.js.map +1 -1
  233. package/dist/src/session/manager.d.ts +5 -1
  234. package/dist/src/session/manager.js +5 -2
  235. package/dist/src/session/manager.js.map +1 -1
  236. package/dist/src/session/reset-type.d.ts +0 -2
  237. package/dist/src/session/reset-type.js +3 -9
  238. package/dist/src/session/reset-type.js.map +1 -1
  239. package/dist/src/session/resolve-session.js +9 -20
  240. package/dist/src/session/resolve-session.js.map +1 -1
  241. package/dist/src/session/store.d.ts +11 -3
  242. package/dist/src/session/store.js +29 -13
  243. package/dist/src/session/store.js.map +1 -1
  244. package/dist/src/session/types.d.ts +2 -4
  245. package/dist/src/session/types.js.map +1 -1
  246. package/dist/src/storage/sqlite/index.d.ts +2 -2
  247. package/dist/src/storage/sqlite/index.js +3 -3
  248. package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
  249. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  250. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  251. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  252. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  253. package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
  254. package/dist/src/storage/sqlite/row-mappers.js +11 -14
  255. package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
  256. package/dist/src/storage/sqlite/schema.js +3 -3
  257. package/dist/src/storage/sqlite/schema.js.map +1 -1
  258. package/dist/src/storage/sqlite/schema.sql +37 -10
  259. package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
  260. package/dist/src/storage/sqlite/session-metadata.js +18 -72
  261. package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
  262. package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
  263. package/dist/src/storage/sqlite/session-repository.js +34 -40
  264. package/dist/src/storage/sqlite/session-repository.js.map +1 -1
  265. package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
  266. package/dist/src/storage/sqlite/transcript-repository.js +52 -52
  267. package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
  268. package/dist/src/tui/backends/embedded-backend.d.ts +11 -4
  269. package/dist/src/tui/backends/embedded-backend.js +27 -1
  270. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  271. package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -1
  272. package/dist/src/tui/backends/gateway-sse-backend.js +21 -2
  273. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  274. package/dist/src/tui/extension-host/autocomplete.js +13 -10
  275. package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
  276. package/dist/src/tui/extension-host/runtime.d.ts +7 -0
  277. package/dist/src/tui/extension-host/runtime.js +6 -4
  278. package/dist/src/tui/extension-host/runtime.js.map +1 -1
  279. package/dist/src/tui/tui-backend.d.ts +9 -0
  280. package/dist/src/tui/tui-commands.js +85 -6
  281. package/dist/src/tui/tui-commands.js.map +1 -1
  282. package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
  283. package/dist/src/tui/tui-file-autocomplete.js +26 -0
  284. package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
  285. package/dist/src/tui/tui-picker-overlay.js +1 -1
  286. package/dist/src/tui/tui.js +29 -11
  287. package/dist/src/tui/tui.js.map +1 -1
  288. package/dist/src/utils/logger/context.d.ts +2 -2
  289. package/dist/src/utils/logger/context.js +2 -1
  290. package/dist/src/utils/logger/context.js.map +1 -1
  291. package/dist/src/utils/logger/log-store.js +1 -0
  292. package/dist/src/utils/logger/log-store.js.map +1 -1
  293. package/dist/src/utils/logger/pino-record.js +3 -0
  294. package/dist/src/utils/logger/pino-record.js.map +1 -1
  295. package/dist/src/utils/logger/types.d.ts +5 -0
  296. package/dist/src/utils/logger/types.js.map +1 -1
  297. package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
  298. package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
  299. package/package.json +1 -1
  300. package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
  301. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
  302. package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
  303. package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
  304. package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
  305. package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
  306. package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
  307. package/dist/gateway/static/root/assets/dreaming-settings-6UZE1FSK.js +0 -1
  308. package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
  309. package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
  310. package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
  311. package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
  312. package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
  313. package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
  314. package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
  315. package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
  316. package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
  317. package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
  318. package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
  319. package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
  320. package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
  321. package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
  322. package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
  323. package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
  324. package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
  325. package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
  326. package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
  327. package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"browser-use-tool.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/browser-use-tool.ts"],"sourcesContent":["/**\n * browser_use — unified browser AgentTool.\n *\n * Modes: command | pipeline | inspect | close.\n * Replaces the 14 fine-grained browser_* tools with a single entry point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport { createLogger } from '../../../../utils/logger.js';\nimport type { Config } from '../../../../config/schema.js';\nimport type { BrowserManager } from '../../../../browser/manager.js';\nimport type { CdpSupervisor } from '../../../../browser/cdp-supervisor.js';\nimport type { Page } from 'playwright-core';\n\nimport { BrowserUseSchema } from './schemas.js';\nimport { createBrowserActionRegistry } from '../../../../browser/actions/registry.js';\nimport type { BrowserActionContext, BrowserActionResult } from '../../../../browser/actions/types.js';\nimport { loadBrowserPipelineSource } from '../../../../browser/pipeline/source.js';\nimport type { BrowserNotReadyError, BrowserSetupHint } from '../../../../browser/readiness.js';\n\nconst log = createLogger('Agent:BrowserUse');\n\nexport interface CreateBrowserUseToolDeps {\n getManager: () => BrowserManager;\n getPageForTask: () => Promise<Page>;\n getTaskId: () => string;\n getConfig: () => Config | undefined;\n getSupervisor?: () => CdpSupervisor | undefined;\n notifyBrowserPageClosed?: (taskId: string) => void;\n /**\n * Preflight readiness check. Returns `null` when the configured backend is\n * usable, otherwise a structured hint the chat surface renders as a setup\n * card. Cache the result upstream (~30s) so back-to-back calls don't reprobe.\n */\n getReadiness?: () => Promise<BrowserNotReadyError | null>;\n /** Pipeline runner (injected to avoid circular deps; lazy-loaded if not provided). */\n runPipeline?: (yaml: string, args: Record<string, unknown>, ctx: BrowserActionContext, dryRun: boolean) => Promise<BrowserActionResult>;\n}\n\nexport function createBrowserUseTool(deps: CreateBrowserUseToolDeps): AgentTool<any, any> {\n const registry = createBrowserActionRegistry();\n\n function buildContext(page: Page, signal?: AbortSignal): BrowserActionContext {\n return {\n page,\n manager: deps.getManager(),\n config: deps.getConfig(),\n taskId: deps.getTaskId(),\n supervisor: deps.getSupervisor?.(),\n signal,\n };\n }\n\n /**\n * Render a {@link BrowserSetupHint} as a tool result. The text body is a\n * JSON envelope (`kind: 'browser_setup_required'`) so the chat surface can\n * detect it and render a Setup card; the embedded `message` keeps the\n * payload human-readable for the LLM so it stops the browser attempt and\n * tells the user to finish setup.\n */\n function formatNotReady(hint: BrowserSetupHint): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n const message =\n `⚠ Browser is not ready (backend=${hint.backend}, reason=${hint.reason}). ` +\n `Do NOT retry. Tell the user to open Settings → Browser to finish setup, ` +\n `then ask them to confirm before running any browser action again.`;\n const payload = {\n kind: 'browser_setup_required' as const,\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n detail: hint.detail,\n message,\n };\n return {\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n details: {\n ok: false,\n kind: 'browser_setup_required',\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n },\n };\n }\n\n function formatResult(result: BrowserActionResult): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n if (result.ok) {\n const parts: string[] = [];\n if (result.text) parts.push(result.text);\n if (result.data && !result.text) parts.push(JSON.stringify(result.data, null, 2));\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'OK' }],\n details: { ok: true, action: result.action, ...(result.artifacts?.length ? { artifacts: result.artifacts.length } : {}) },\n };\n }\n const parts: string[] = [];\n if (result.error) parts.push(`[${result.error.code}] ${result.error.message}`);\n if (result.diagnostics?.url) parts.push(`URL: ${result.diagnostics.url}`);\n if (result.diagnostics?.snapshot) parts.push(`Snapshot: ${result.diagnostics.snapshot.slice(0, 2000)}`);\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'Failed' }],\n details: { ok: false, action: result.action, error: result.error },\n };\n }\n\n const tool: any = {\n name: 'browser_use',\n label: '🌐 Browser',\n description:\n 'Use a persistent browser for web navigation, page inspection, interaction, screenshots, network capture, and scripted browser pipelines. For non-trivial browser tasks, load the built-in manual first with tool_manual({ tool: \"browser_use\" }).',\n parameters: BrowserUseSchema,\n\n async execute(_toolCallId, params: any, signal, _onUpdate) {\n const { mode, command, args: cmdArgs, pipeline: pipelineParams, options: _options } = params as {\n mode: string;\n command?: string;\n args?: Record<string, unknown>;\n pipeline?: { yaml?: string; script?: string; path?: string; args?: Record<string, unknown>; dryRun?: boolean };\n options?: { timeout?: number; headless?: boolean };\n };\n\n // ─── readiness preflight ────────────────────────────────────────────\n // Probes the configured backend (doctor + WS bridge / CDP / cloud key)\n // before any launch attempt. On failure we short-circuit with a setup\n // hint the chat renders as a card — the agent should stop and ask the\n // user to finish setup instead of looping on launch errors.\n if (deps.getReadiness) {\n try {\n const notReady = await deps.getReadiness();\n if (notReady) {\n return formatNotReady(notReady.hint);\n }\n } catch (e) {\n log.warn({ err: e }, 'Readiness preflight threw; continuing with launch attempt');\n }\n }\n\n // ─── inspect ────────────────────────────────────────────────────────\n if (mode === 'inspect') {\n const mgr = deps.getManager();\n await mgr.ensureConnected();\n const ext = mgr.getExtensionProvider();\n if (ext) {\n const timeout = deps.getConfig?.()?.agents?.defaults?.browser?.commandTimeout;\n const timeoutMs =\n typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0\n ? Math.floor(timeout * 1000)\n : 30_000;\n const urlRes = await ext.sendCommand('get_url', {}, { timeout: timeoutMs });\n const titleRes = await ext.sendCommand('get_title', {}, { timeout: timeoutMs });\n const snapRes = await ext.sendCommand('snapshot', {}, { timeout: timeoutMs });\n const url = urlRes.ok && urlRes.data ? String((urlRes.data as { url?: string }).url ?? '') : '';\n const title =\n titleRes.ok && titleRes.data ? String((titleRes.data as { title?: string }).title ?? '') : '';\n let snapText = '';\n if (snapRes.ok && snapRes.data) {\n const nodes = (snapRes.data as { nodes?: Array<{ role?: string; name?: string }> }).nodes ?? [];\n snapText = nodes.map((n) => `${n.role ?? '?'}: ${n.name ?? ''}`).join('\\n');\n if (snapText.length > 8000) snapText = `${snapText.slice(0, 8000)}\\n... (truncated)`;\n }\n const text = `URL: ${url}\\nTitle: ${title}\\n${snapText ? `--- Page Snapshot ---\\n${snapText}` : ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const result = await registry.execute('state', ctx, {});\n // Augment with URL / title\n const url = page.url();\n const title = await page.title().catch(() => '');\n const text = `URL: ${url}\\nTitle: ${title}\\n${result.text ?? ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n\n // ─── close ──────────────────────────────────────────────────────────\n if (mode === 'close') {\n const taskId = deps.getTaskId();\n await deps.getManager().ensureConnected();\n await deps.getManager().closePage(taskId);\n deps.notifyBrowserPageClosed?.(taskId);\n return {\n content: [{ type: 'text', text: 'Browser page closed.' }],\n details: { ok: true, mode: 'close' },\n };\n }\n\n // ─── command ────────────────────────────────────────────────────────\n if (mode === 'command') {\n if (!command) {\n return {\n content: [{ type: 'text', text: 'Missing `command` parameter for command mode.' }],\n details: { ok: false, mode: 'command' },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const args = cmdArgs ?? {};\n const result = await registry.execute(command, ctx, args);\n return formatResult(result);\n }\n\n // ─── pipeline ──────────────────────────────────────────────────────\n if (mode === 'pipeline') {\n if (!pipelineParams) {\n return {\n content: [{ type: 'text', text: 'Missing `pipeline` parameter for pipeline mode.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n // Resolve YAML source\n let yamlSource = pipelineParams.yaml ?? pipelineParams.script ?? '';\n\n if (!yamlSource && pipelineParams.path) {\n try {\n yamlSource = (await loadBrowserPipelineSource(pipelineParams.path)).source;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [{ type: 'text', text: `Failed to read pipeline source: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n if (!yamlSource) {\n return {\n content: [{ type: 'text', text: 'Pipeline mode requires `yaml`, `script`, or `path`.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n const pipelineArgs = (pipelineParams.args as Record<string, unknown>) ?? {};\n const dryRun = pipelineParams.dryRun === true;\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n\n // Use injected runner or lazy-load\n if (deps.runPipeline) {\n const result = await deps.runPipeline(yamlSource, pipelineArgs, ctx, dryRun);\n return formatResult(result);\n }\n\n // Lazy import pipeline runner\n try {\n const { runBrowserPipeline } = await import('../../../../browser/pipeline/runner.js');\n const result = await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, dryRun);\n return formatResult(result);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.error({ err: e }, `Pipeline execution failed: ${msg}`);\n return {\n content: [{ type: 'text', text: `Pipeline failed: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n return {\n content: [{ type: 'text', text: `Unknown mode: ${mode}` }],\n details: { ok: false },\n };\n },\n };\n return tool;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"browser-use-tool.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/browser-use-tool.ts"],"sourcesContent":["/**\n * browser_use — unified browser AgentTool.\n *\n * Modes: command | pipeline | inspect | close.\n * Replaces the 14 fine-grained browser_* tools with a single entry point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\n\nimport { createLogger } from '../../../../utils/logger.js';\nimport type { Config } from '../../../../config/schema.js';\nimport type { BrowserManager } from '../../../../browser/manager.js';\nimport type { CdpSupervisor } from '../../../../browser/cdp-supervisor.js';\nimport type { Page } from 'playwright-core';\n\nimport { BrowserUseSchema } from './schemas.js';\nimport { createBrowserActionRegistry } from '../../../../browser/actions/registry.js';\nimport type { BrowserActionContext, BrowserActionResult } from '../../../../browser/actions/types.js';\nimport { loadBrowserPipelineSource } from '../../../../browser/pipeline/source.js';\nimport type { BrowserNotReadyError, BrowserSetupHint } from '../../../../browser/readiness.js';\n\nconst log = createLogger('Agent:BrowserUse');\n\nexport interface CreateBrowserUseToolDeps {\n getManager: () => BrowserManager;\n getPageForTask: () => Promise<Page>;\n getTaskId: () => string;\n getConfig: () => Config | undefined;\n getSupervisor?: () => CdpSupervisor | undefined;\n notifyBrowserPageClosed?: (taskId: string) => void;\n /**\n * Preflight readiness check. Returns `null` when the configured backend is\n * usable, otherwise a structured hint the chat surface renders as a setup\n * card. Cache the result upstream (~30s) so back-to-back calls don't reprobe.\n */\n getReadiness?: () => Promise<BrowserNotReadyError | null>;\n /** Pipeline runner (injected to avoid circular deps; lazy-loaded if not provided). */\n runPipeline?: (\n yaml: string,\n args: Record<string, unknown>,\n ctx: BrowserActionContext,\n options: { dryRun?: boolean; sourceLocation?: string },\n ) => Promise<BrowserActionResult>;\n}\n\nexport function createBrowserUseTool(deps: CreateBrowserUseToolDeps): AgentTool<any, any> {\n const registry = createBrowserActionRegistry();\n\n function buildContext(page: Page, signal?: AbortSignal): BrowserActionContext {\n return {\n page,\n manager: deps.getManager(),\n config: deps.getConfig(),\n taskId: deps.getTaskId(),\n supervisor: deps.getSupervisor?.(),\n signal,\n };\n }\n\n /**\n * Render a {@link BrowserSetupHint} as a tool result. The text body is a\n * JSON envelope (`kind: 'browser_setup_required'`) so the chat surface can\n * detect it and render a Setup card; the embedded `message` keeps the\n * payload human-readable for the LLM so it stops the browser attempt and\n * tells the user to finish setup.\n */\n function formatNotReady(hint: BrowserSetupHint): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n const message =\n `⚠ Browser is not ready (backend=${hint.backend}, reason=${hint.reason}). ` +\n `Do NOT retry. Tell the user to open Settings → Browser to finish setup, ` +\n `then ask them to confirm before running any browser action again.`;\n const payload = {\n kind: 'browser_setup_required' as const,\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n detail: hint.detail,\n message,\n };\n return {\n content: [{ type: 'text', text: JSON.stringify(payload) }],\n details: {\n ok: false,\n kind: 'browser_setup_required',\n backend: hint.backend,\n reason: hint.reason,\n deepLink: hint.deepLink,\n },\n };\n }\n\n function formatResult(result: BrowserActionResult): { content: { type: 'text'; text: string }[]; details: Record<string, unknown> } {\n if (result.ok) {\n const parts: string[] = [];\n if (result.text) parts.push(result.text);\n if (result.data && !result.text) parts.push(JSON.stringify(result.data, null, 2));\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'OK' }],\n details: { ok: true, action: result.action, ...(result.artifacts?.length ? { artifacts: result.artifacts.length } : {}) },\n };\n }\n const parts: string[] = [];\n if (result.error) parts.push(`[${result.error.code}] ${result.error.message}`);\n if (result.diagnostics?.url) parts.push(`URL: ${result.diagnostics.url}`);\n if (result.diagnostics?.snapshot) parts.push(`Snapshot: ${result.diagnostics.snapshot.slice(0, 2000)}`);\n return {\n content: [{ type: 'text', text: parts.join('\\n') || 'Failed' }],\n details: { ok: false, action: result.action, error: result.error },\n };\n }\n\n const tool: any = {\n name: 'browser_use',\n label: '🌐 Browser',\n description:\n 'Use a persistent browser for web navigation, page inspection, interaction, screenshots, network capture, and scripted browser pipelines. For non-trivial browser tasks, load the built-in manual first with tool_manual({ tool: \"browser_use\" }).',\n parameters: BrowserUseSchema,\n\n async execute(_toolCallId, params: any, signal, _onUpdate) {\n const { mode, command, args: cmdArgs, pipeline: pipelineParams, options: _options } = params as {\n mode: string;\n command?: string;\n args?: Record<string, unknown>;\n pipeline?: { yaml?: string; path?: string; args?: Record<string, unknown>; dryRun?: boolean };\n options?: { timeout?: number; headless?: boolean };\n };\n\n // ─── readiness preflight ────────────────────────────────────────────\n // Probes the configured backend (doctor + WS bridge / CDP / cloud key)\n // before any launch attempt. On failure we short-circuit with a setup\n // hint the chat renders as a card — the agent should stop and ask the\n // user to finish setup instead of looping on launch errors.\n if (deps.getReadiness) {\n try {\n const notReady = await deps.getReadiness();\n if (notReady) {\n return formatNotReady(notReady.hint);\n }\n } catch (e) {\n log.warn({ err: e }, 'Readiness preflight threw; continuing with launch attempt');\n }\n }\n\n // ─── inspect ────────────────────────────────────────────────────────\n if (mode === 'inspect') {\n const mgr = deps.getManager();\n await mgr.ensureConnected();\n const ext = mgr.getExtensionProvider();\n if (ext) {\n const timeout = deps.getConfig?.()?.agents?.defaults?.browser?.commandTimeout;\n const timeoutMs =\n typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0\n ? Math.floor(timeout * 1000)\n : 30_000;\n const urlRes = await ext.sendCommand('get_url', {}, { timeout: timeoutMs });\n const titleRes = await ext.sendCommand('get_title', {}, { timeout: timeoutMs });\n const snapRes = await ext.sendCommand('snapshot', {}, { timeout: timeoutMs });\n const url = urlRes.ok && urlRes.data ? String((urlRes.data as { url?: string }).url ?? '') : '';\n const title =\n titleRes.ok && titleRes.data ? String((titleRes.data as { title?: string }).title ?? '') : '';\n let snapText = '';\n if (snapRes.ok && snapRes.data) {\n const nodes = (snapRes.data as { nodes?: Array<{ role?: string; name?: string }> }).nodes ?? [];\n snapText = nodes.map((n) => `${n.role ?? '?'}: ${n.name ?? ''}`).join('\\n');\n if (snapText.length > 8000) snapText = `${snapText.slice(0, 8000)}\\n... (truncated)`;\n }\n const text = `URL: ${url}\\nTitle: ${title}\\n${snapText ? `--- Page Snapshot ---\\n${snapText}` : ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const result = await registry.execute('state', ctx, {});\n // Augment with URL / title\n const url = page.url();\n const title = await page.title().catch(() => '');\n const text = `URL: ${url}\\nTitle: ${title}\\n${result.text ?? ''}`;\n return {\n content: [{ type: 'text', text }],\n details: { ok: true, mode: 'inspect', url, title },\n };\n }\n\n // ─── close ──────────────────────────────────────────────────────────\n if (mode === 'close') {\n const taskId = deps.getTaskId();\n await deps.getManager().ensureConnected();\n await deps.getManager().closePage(taskId);\n deps.notifyBrowserPageClosed?.(taskId);\n return {\n content: [{ type: 'text', text: 'Browser page closed.' }],\n details: { ok: true, mode: 'close' },\n };\n }\n\n // ─── command ────────────────────────────────────────────────────────\n if (mode === 'command') {\n if (!command) {\n return {\n content: [{ type: 'text', text: 'Missing `command` parameter for command mode.' }],\n details: { ok: false, mode: 'command' },\n };\n }\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n const args = cmdArgs ?? {};\n const result = await registry.execute(command, ctx, args);\n return formatResult(result);\n }\n\n // ─── pipeline ──────────────────────────────────────────────────────\n if (mode === 'pipeline') {\n if (!pipelineParams) {\n return {\n content: [{ type: 'text', text: 'Missing `pipeline` parameter for pipeline mode.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n let yamlSource = pipelineParams.yaml ?? '';\n let sourceLocation: string | undefined;\n\n if (!yamlSource && pipelineParams.path) {\n try {\n const loaded = await loadBrowserPipelineSource(pipelineParams.path);\n yamlSource = loaded.source;\n sourceLocation = loaded.location;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return {\n content: [{ type: 'text', text: `Failed to read pipeline source: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n if (!yamlSource) {\n return {\n content: [{ type: 'text', text: 'Pipeline mode requires `yaml`, `script`, or `path`.' }],\n details: { ok: false, mode: 'pipeline' },\n };\n }\n\n const pipelineArgs = (pipelineParams.args as Record<string, unknown>) ?? {};\n const dryRun = pipelineParams.dryRun === true;\n const page = await deps.getPageForTask();\n const ctx = buildContext(page, signal);\n\n // Use injected runner or lazy-load\n if (deps.runPipeline) {\n const result = await deps.runPipeline(yamlSource, pipelineArgs, ctx, { dryRun, sourceLocation });\n return formatResult(result);\n }\n\n // Lazy import pipeline runner\n try {\n const { runBrowserPipeline } = await import('../../../../browser/pipeline/runner.js');\n const result = await runBrowserPipeline(yamlSource, pipelineArgs, ctx, registry, { dryRun, sourceLocation });\n return formatResult(result);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n log.error({ err: e }, `Pipeline execution failed: ${msg}`);\n return {\n content: [{ type: 'text', text: `Pipeline failed: ${msg}` }],\n details: { ok: false, mode: 'pipeline', error: msg },\n };\n }\n }\n\n return {\n content: [{ type: 'text', text: `Unknown mode: ${mode}` }],\n details: { ok: false },\n };\n },\n };\n return tool;\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@
3
3
  */
4
4
  export declare const BrowserUsePipelineSchema: import("@sinclair/typebox/build/cjs").TObject<{
5
5
  yaml: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
6
- script: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
7
6
  path: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
8
7
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
9
8
  dryRun: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TBoolean>;
@@ -18,7 +17,6 @@ export declare const BrowserUseSchema: import("@sinclair/typebox/build/cjs").TOb
18
17
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
19
18
  pipeline: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TObject<{
20
19
  yaml: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
21
- script: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
22
20
  path: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TString>;
23
21
  args: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TRecord<import("@sinclair/typebox/build/cjs").TString, import("@sinclair/typebox/build/cjs").TUnknown>>;
24
22
  dryRun: import("@sinclair/typebox/build/cjs").TOptional<import("@sinclair/typebox/build/cjs").TBoolean>;
@@ -4,8 +4,7 @@ import { Type } from "@sinclair/typebox";
4
4
  * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.
5
5
  */
6
6
  const BrowserUsePipelineSchema = Type.Object({
7
- yaml: Type.Optional(Type.String({ description: "Inline YAML pipeline (brocli-style DSL)." })),
8
- script: Type.Optional(Type.String({ description: "Alias for `yaml` — inline brocli YAML script." })),
7
+ yaml: Type.Optional(Type.String({ description: "Inline YAML browser pipeline." })),
9
8
  path: Type.Optional(Type.String({ description: "Path or http(s) URL to a .yaml pipeline file." })),
10
9
  args: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Override pipeline arg defaults." })),
11
10
  dryRun: Type.Optional(Type.Boolean({ description: "Only parse & validate, do not execute." }))
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/schemas.ts"],"sourcesContent":["/**\n * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.\n */\n\nimport { Type } from '@sinclair/typebox';\n\nexport const BrowserUsePipelineSchema = Type.Object({\n yaml: Type.Optional(Type.String({ description: 'Inline YAML pipeline (brocli-style DSL).' })),\n script: Type.Optional(Type.String({ description: 'Alias for `yaml` — inline brocli YAML script.' })),\n path: Type.Optional(Type.String({ description: 'Path or http(s) URL to a .yaml pipeline file.' })),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Override pipeline arg defaults.' }),\n ),\n dryRun: Type.Optional(Type.Boolean({ description: 'Only parse & validate, do not execute.' })),\n});\n\nexport const BrowserUseOptionsSchema = Type.Object({\n timeout: Type.Optional(Type.Number({ description: 'Action timeout override (ms).' })),\n headless: Type.Optional(Type.Boolean({ description: 'Override headless mode for this call.' })),\n});\n\nexport const BrowserUseSchema = Type.Object({\n mode: Type.Union(\n [\n Type.Literal('command'),\n Type.Literal('pipeline'),\n Type.Literal('inspect'),\n Type.Literal('close'),\n ],\n { description: 'Execution mode.' },\n ),\n command: Type.Optional(\n Type.String({ description: 'Browser action name (command mode). E.g. open, click, type, screenshot.' }),\n ),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Action arguments (command mode).' }),\n ),\n pipeline: Type.Optional(BrowserUsePipelineSchema),\n options: Type.Optional(BrowserUseOptionsSchema),\n});\n"],"mappings":";;;;;AAMA,MAAa,2BAA2B,KAAK,OAAO;CAClD,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,4CAA4C,CAAC,CAAC;CAC7F,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CACpG,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CAClG,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,mCAAmC,CAAC,CAC/F;CACD,QAAQ,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,0CAA0C,CAAC,CAAC;CAC/F,CAAC;AAEF,MAAa,0BAA0B,KAAK,OAAO;CACjD,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CACrF,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,yCAAyC,CAAC,CAAC;CAChG,CAAC;AAEF,MAAa,mBAAmB,KAAK,OAAO;CAC1C,MAAM,KAAK,MACT;EACE,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,WAAW;EACxB,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,QAAQ;EACtB,EACD,EAAE,aAAa,mBAAmB,CACnC;CACD,SAAS,KAAK,SACZ,KAAK,OAAO,EAAE,aAAa,2EAA2E,CAAC,CACxG;CACD,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,oCAAoC,CAAC,CAChG;CACD,UAAU,KAAK,SAAS,yBAAyB;CACjD,SAAS,KAAK,SAAS,wBAAwB;CAChD,CAAC"}
1
+ {"version":3,"file":"schemas.js","names":[],"sources":["../../../../../../src/agent/tools/browser/tool/schemas.ts"],"sourcesContent":["/**\n * BrowserUseSchema — Typebox schema for the unified `browser_use` AgentTool.\n */\n\nimport { Type } from '@sinclair/typebox';\n\nexport const BrowserUsePipelineSchema = Type.Object({\n yaml: Type.Optional(Type.String({ description: 'Inline YAML browser pipeline.' })),\n path: Type.Optional(Type.String({ description: 'Path or http(s) URL to a .yaml pipeline file.' })),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Override pipeline arg defaults.' }),\n ),\n dryRun: Type.Optional(Type.Boolean({ description: 'Only parse & validate, do not execute.' })),\n});\n\nexport const BrowserUseOptionsSchema = Type.Object({\n timeout: Type.Optional(Type.Number({ description: 'Action timeout override (ms).' })),\n headless: Type.Optional(Type.Boolean({ description: 'Override headless mode for this call.' })),\n});\n\nexport const BrowserUseSchema = Type.Object({\n mode: Type.Union(\n [\n Type.Literal('command'),\n Type.Literal('pipeline'),\n Type.Literal('inspect'),\n Type.Literal('close'),\n ],\n { description: 'Execution mode.' },\n ),\n command: Type.Optional(\n Type.String({ description: 'Browser action name (command mode). E.g. open, click, type, screenshot.' }),\n ),\n args: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), { description: 'Action arguments (command mode).' }),\n ),\n pipeline: Type.Optional(BrowserUsePipelineSchema),\n options: Type.Optional(BrowserUseOptionsSchema),\n});\n"],"mappings":";;;;;AAMA,MAAa,2BAA2B,KAAK,OAAO;CAClD,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CAClF,MAAM,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAiD,CAAC,CAAC;CAClG,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,mCAAmC,CAAC,CAC/F;CACD,QAAQ,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,0CAA0C,CAAC,CAAC;CAC/F,CAAC;AAEF,MAAa,0BAA0B,KAAK,OAAO;CACjD,SAAS,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iCAAiC,CAAC,CAAC;CACrF,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,yCAAyC,CAAC,CAAC;CAChG,CAAC;AAEF,MAAa,mBAAmB,KAAK,OAAO;CAC1C,MAAM,KAAK,MACT;EACE,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,WAAW;EACxB,KAAK,QAAQ,UAAU;EACvB,KAAK,QAAQ,QAAQ;EACtB,EACD,EAAE,aAAa,mBAAmB,CACnC;CACD,SAAS,KAAK,SACZ,KAAK,OAAO,EAAE,aAAa,2EAA2E,CAAC,CACxG;CACD,MAAM,KAAK,SACT,KAAK,OAAO,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,EAAE,aAAa,oCAAoC,CAAC,CAChG;CACD,UAAU,KAAK,SAAS,yBAAyB;CACjD,SAAS,KAAK,SAAS,wBAAwB;CAChD,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
4
3
  import { createReadFileTool } from "./read.js";
5
4
  import { createWriteFileTool } from "./write.js";
6
5
  import { createEditFileTool } from "./edit.js";
@@ -45,7 +44,6 @@ import { mergeTtsConfigFromAppConfig } from "../../voice/tts/merge-config.js";
45
44
  import { createTextToSpeechTool } from "./tts-tool.js";
46
45
  import { createGoalEvidenceRecorder } from "./goal-evidence-recorder.js";
47
46
  //#region src/agent/tools/factory.ts
48
- init_session_key();
49
47
  init_logger();
50
48
  const log = createLogger("AgentToolsFactory");
51
49
  /** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */
@@ -54,12 +52,6 @@ const CLARIFY_SUPPORTED_CHANNELS = new Set([
54
52
  "telegram",
55
53
  "cli"
56
54
  ]);
57
- function clarifyTransportSource(sessionKey) {
58
- const parsed = parseSessionKey(sessionKey);
59
- if (parsed) return parsed.source;
60
- const first = sessionKey.split(":").filter(Boolean)[0] ?? "";
61
- if (first === "cli" || first === "webchat") return first;
62
- }
63
55
  var AgentToolsFactory = class AgentToolsFactory {
64
56
  browserManager = null;
65
57
  /** One dialog/console supervisor per chat session (browser tab). */
@@ -195,8 +187,7 @@ var AgentToolsFactory = class AgentToolsFactory {
195
187
  if (!req) return null;
196
188
  const ctx = this.deps.getCurrentContext();
197
189
  if (!ctx?.sessionKey) return null;
198
- const source = clarifyTransportSource(ctx.sessionKey);
199
- if (!source || !CLARIFY_SUPPORTED_CHANNELS.has(source)) return null;
190
+ if (!CLARIFY_SUPPORTED_CHANNELS.has(ctx.channel)) return null;
200
191
  return (r) => req(ctx.sessionKey, r);
201
192
  } }),
202
193
  createTodoTool({ getSessionKey: () => this.deps.getCurrentContext()?.sessionKey }),
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","names":["parseRoutingSessionKey"],"sources":["../../../../src/agent/tools/factory.ts"],"sourcesContent":["/**\n * Agent Tools Factory - Creates and configures agent tools\n *\n * Centralizes tool creation logic to keep service.ts focused on orchestration.\n *\n * TTS: auto TTS is applied at the ChannelManager via maybeApplyTtsToPayload().\n * Optional \\`text_to_speech\\` tool sends explicit voice when TTS is enabled.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { Page } from 'playwright-core';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport {\n createReadFileTool,\n createWriteFileTool,\n createEditFileTool,\n createListDirTool,\n createGrepTool,\n createFindTool,\n createShellTool,\n createWebSearchTool,\n createWebFetchTool,\n createWebExtractTool,\n createMessageTool,\n createSendMediaTool,\n createReadMediaTool,\n createCreateShareTool,\n isShareToolAvailable,\n createMemorySearchTool,\n createMemoryGetTool,\n createTodoTool,\n createSessionStatusTool,\n createDreamingTool,\n createClarifyTool,\n createToolManualTool,\n createGoalTool,\n} from './index.js';\nimport { createCuratedMemoryTool } from './curated-memory-tool.js';\nimport { createSessionSearchTool } from './session-search-tool.js';\nimport type { BuiltinMemoryStore } from '../memory/builtin-memory-store.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport { shouldRegisterCuratedMemoryTool } from '../memory/memory-config.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { parseSessionKey as parseRoutingSessionKey } from '../../routing/session-key.js';\nimport type { GatewayClarifyRequestFn } from './clarify-tool.js';\nimport { createImageTool } from './image-tool.js';\nimport { createImageGenerateTool } from './image-generate-tool.js';\nimport {\n BrowserManager,\n BrowserNotReadyError,\n CdpSupervisor,\n checkBrowserReadiness,\n resolveBrowserBackendFromConfig,\n} from '../../browser/index.js';\nimport { createBrowserUseTool } from './browser/tool/browser-use-tool.js';\nimport { createDelegateTool } from './delegate-tool.js';\nimport { createWorkflowTool } from './workflow-tool.js';\nimport { createWorkflowCatalog } from '../workflow/catalog.js';\nimport { buildSandboxToolMap, createExecuteCodeTool } from './execute-code-tool.js';\nimport { createCronjobTool } from './cronjob-tool.js';\nimport type { CronService } from '../../cron/index.js';\nimport type { WorkflowRunServiceLike } from '../../workflows/service/workflow-run-service.types.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { wrapToolsWithProtection, type ToolExecutorConfig } from './executor.js';\nimport { createSkillsListTool, createSkillViewTool } from './skills-tools.js';\nimport { createSkillManageTool } from './skill-manage-tool.js';\nimport { createTextToSpeechTool } from './tts-tool.js';\nimport { mergeTtsConfigFromAppConfig } from '../../voice/tts/merge-config.js';\nimport { createGoalEvidenceRecorder } from './goal-evidence-recorder.js';\n\nconst log = createLogger('AgentToolsFactory');\n\n/** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */\nconst CLARIFY_SUPPORTED_CHANNELS = new Set(['webchat', 'telegram', 'cli']);\n\nfunction clarifyTransportSource(sessionKey: string): string | undefined {\n const parsed = parseRoutingSessionKey(sessionKey);\n if (parsed) return parsed.source;\n // Fallback for simple `<channel>:<chatId>` keys used by webchat and CLI.\n const first = sessionKey.split(':').filter(Boolean)[0] ?? '';\n if (first === 'cli' || first === 'webchat') return first;\n return undefined;\n}\n\nexport interface ToolFactoryDeps {\n workspace: string;\n extensionRegistry?: any;\n getCurrentContext: () => { channel: string; chatId: string; sessionKey: string } | null;\n hookRunner?: import('../../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /** Agent defaults (image tools, etc.); use getter so hot-reloaded config applies. */\n getConfig?: () => Config | undefined;\n /** Session / default chat model for vision tool description. */\n getPrimaryModel?: () => Model<Api>;\n /** Built-in curated memory store (agent home `memories/`). */\n getBuiltinMemoryStore?: () => BuiltinMemoryStore;\n /** Memory orchestration (prefetch/sync + external tools). */\n getMemoryManager?: () => MemoryManager;\n /** Session store for `session_search`. */\n getSessionStore?: () => SessionStore;\n /** When set (gateway webchat), enables the `clarify` tool. */\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: enables the `cronjob` tool. */\n getCronService?: () => CronService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => WorkflowRunServiceLike | undefined;\n /** Current session skill indexing (tool gating + allowlist); used by skills_list / skill_view. */\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** After skill_manage mutates disk, reload skills + refresh agent prompts (optional). */\n onSkillsFilesystemMutate?: () => void;\n /** Names registered via skill_view for shell env passthrough. */\n getSkillPassthroughEnvVarNames?: () => string[];\n /** Add declared env names for the current session (no values stored). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nexport interface CreateCoreToolsOptions {\n /** Workspace root for file/shell tools (defaults to factory workspace). */\n workspace?: string;\n /** Canonical `agents/<id>/profile/`: bare SOUL.md / IDENTITY.md resolve here after the workspace. */\n profileMarkdownRoot?: string;\n /** Tool `name` values to omit (e.g. `shell`, `extensions` for extension tools). */\n disabledTools?: Set<string>;\n /** Optional primary model for image tool heuristics. */\n getPrimaryModel?: () => Model<Api>;\n getBuiltinMemoryStore?: () => BuiltinMemoryStore;\n getMemoryManager?: () => MemoryManager;\n /** When set, registers `skills_list` and `skill_view` bound to this workspace\\'s skills. */\n getSkillManager?: () => SkillManager;\n}\n\nexport class AgentToolsFactory {\n private browserManager: BrowserManager | null = null;\n /** One dialog/console supervisor per chat session (browser tab). */\n private readonly browserTaskSupervisors = new Map<string, CdpSupervisor>();\n /** Cached readiness probe — keyed by backend mode + extension host:port. */\n private browserReadinessCache: {\n key: string;\n expiresAt: number;\n inflight?: Promise<BrowserNotReadyError | null>;\n result?: BrowserNotReadyError | null;\n } | null = null;\n\n constructor(private deps: ToolFactoryDeps) {}\n\n private browserReadinessKey(): string {\n const cfg = this.deps.getConfig?.();\n const backend = resolveBrowserBackendFromConfig(cfg);\n const ext = cfg?.agents?.defaults?.browser?.extension;\n const host = typeof ext?.host === 'string' && ext.host.trim() ? ext.host.trim() : '127.0.0.1';\n const port = typeof ext?.port === 'number' ? ext.port : 19820;\n const cdpUrl = backend.mode === 'cdp' ? backend.config.wsEndpoint : '';\n const cloudKind = backend.mode === 'cloud' ? backend.config.type : '';\n return `${backend.mode}@${host}:${port}|${cdpUrl}|${cloudKind}`;\n }\n\n private async checkBrowserReadinessCached(): Promise<BrowserNotReadyError | null> {\n const key = this.browserReadinessKey();\n const now = Date.now();\n const cached = this.browserReadinessCache;\n if (cached && cached.key === key && cached.expiresAt > now && cached.inflight === undefined) {\n return cached.result ?? null;\n }\n if (cached && cached.key === key && cached.inflight) {\n return cached.inflight;\n }\n const inflight = checkBrowserReadiness(this.deps.getConfig?.());\n this.browserReadinessCache = { key, expiresAt: now + 30_000, inflight };\n try {\n const result = await inflight;\n this.browserReadinessCache = { key, expiresAt: Date.now() + 30_000, result };\n return result;\n } catch (e) {\n // Probe should never throw, but if it does we just bypass the cache.\n this.browserReadinessCache = null;\n log.warn({ err: e }, 'browserReadiness probe failed');\n return null;\n }\n }\n\n /** Invalidate the readiness cache (config hot-reload, settings-page save, etc.). */\n invalidateBrowserReadinessCache(): void {\n this.browserReadinessCache = null;\n }\n\n private browserSupervisorForTask(taskId: string): CdpSupervisor {\n let s = this.browserTaskSupervisors.get(taskId);\n if (!s) {\n const b = this.deps.getConfig?.()?.agents?.defaults?.browser;\n const dialogPolicy =\n b?.dialogPolicy === 'must_respond' || b?.dialogPolicy === 'auto_accept' || b?.dialogPolicy === 'auto_dismiss'\n ? b.dialogPolicy\n : 'auto_dismiss';\n const dialogTimeoutSeconds =\n typeof b?.dialogTimeoutSeconds === 'number' &&\n Number.isFinite(b.dialogTimeoutSeconds) &&\n b.dialogTimeoutSeconds >= 1\n ? Math.floor(b.dialogTimeoutSeconds)\n : 300;\n s = new CdpSupervisor({ dialogPolicy, dialogTimeoutSeconds });\n this.browserTaskSupervisors.set(taskId, s);\n }\n return s;\n }\n\n private async acquireBrowserPage(): Promise<Page> {\n const taskId = this.deps.getCurrentContext()?.sessionKey ?? 'default';\n const mgr = this.ensureBrowserManager();\n await mgr.ensureConnected();\n if (mgr.getExtensionProvider()) {\n return null as unknown as Page;\n }\n const page = await mgr.getPage(taskId);\n this.browserSupervisorForTask(taskId).attach(page);\n return page;\n }\n\n private ensureBrowserManager(): BrowserManager {\n if (!this.browserManager) {\n this.browserManager = new BrowserManager({\n getHeadless: () => this.deps.getConfig?.()?.agents?.defaults?.browser?.headless === true,\n getBackend: () => resolveBrowserBackendFromConfig(this.deps.getConfig?.()),\n });\n }\n return this.browserManager;\n }\n\n /** Close Playwright and all pages (gateway stop, agent manager dispose, or config hot-reload). */\n async shutdownBrowser(): Promise<void> {\n this.browserReadinessCache = null;\n if (!this.browserManager) {\n return;\n }\n await this.browserManager.shutdown();\n this.browserManager = null;\n this.browserTaskSupervisors.clear();\n }\n\n /** Drop the tab for a session when its agent instance is removed. */\n async closeBrowserPageForSession(sessionKey: string): Promise<void> {\n this.browserTaskSupervisors.delete(sessionKey);\n await this.browserManager?.closePage(sessionKey);\n }\n\n createCoreTools(options?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const workspace = options?.workspace ?? this.deps.workspace;\n const { bus } = this.deps;\n const getPrimary = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const getBuiltin = options?.getBuiltinMemoryStore ?? this.deps.getBuiltinMemoryStore;\n const builtinStore = getBuiltin?.();\n const memoriesDir = builtinStore?.memoriesDir;\n const getMemMgr = options?.getMemoryManager ?? this.deps.getMemoryManager;\n const getSkillMgr = options?.getSkillManager;\n const disabled = options?.disabledTools;\n\n const primary = getPrimary?.();\n const modelHasVision = primary?.input?.includes('image') ?? false;\n const cfg = this.deps.getConfig?.();\n const recordGoalEvidence = createGoalEvidenceRecorder({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n });\n const imageTool = createImageTool({\n config: cfg,\n workspace,\n modelHasVision,\n });\n const imageGenerateTool = createImageGenerateTool({\n config: cfg,\n workspace,\n });\n\n const optionalTools = [imageTool, imageGenerateTool].filter((t) => t != null) as any[];\n\n const readTool = createReadFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n });\n const writeTool = createWriteFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const editTool = createEditFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const listDir = createListDirTool(workspace);\n const grep = createGrepTool(workspace);\n const find = createFindTool(workspace);\n\n const core: AgentTool<any, any>[] = [\n createSessionStatusTool(),\n createDreamingTool({\n getWorkspace: () => workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n createToolManualTool(),\n createClarifyTool({\n resolveAskUser: () => {\n const req = this.deps.gatewayClarify?.requestClarification;\n if (!req) return null;\n const ctx = this.deps.getCurrentContext();\n if (!ctx?.sessionKey) return null;\n const source = clarifyTransportSource(ctx.sessionKey);\n if (!source || !CLARIFY_SUPPORTED_CHANNELS.has(source)) return null;\n return (r) => req(ctx.sessionKey, r);\n },\n }),\n createTodoTool({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ...(getSkillMgr\n ? [\n createSkillsListTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n }),\n createSkillViewTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n registerSkillEnvPassthrough: this.deps.registerSkillEnvPassthrough,\n }),\n createSkillManageTool({\n getSkillManager: getSkillMgr,\n getWorkspace: () => workspace,\n onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate,\n }),\n ]\n : []),\n readTool,\n writeTool,\n editTool,\n listDir,\n grep,\n find,\n createShellTool(workspace, {\n getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames,\n recordGoalEvidence,\n }),\n createWebSearchTool(() => this.deps.getConfig?.()),\n createWebFetchTool(() => this.deps.getConfig?.()),\n createWebExtractTool({ getConfig: () => this.deps.getConfig?.() }),\n // Note: TTS is NOT handled by send_message tool anymore\n // TTS is applied at the ChannelManager dispatch layer\n createMessageTool(bus, () => this.deps.getCurrentContext()),\n ...(mergeTtsConfigFromAppConfig(cfg?.messages?.tts).enabled\n ? [\n createTextToSpeechTool({\n bus,\n getContext: () => this.deps.getCurrentContext(),\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createSendMediaTool(workspace, bus, () => this.deps.getCurrentContext()),\n createReadMediaTool(),\n ...(isShareToolAvailable(cfg)\n ? [\n createCreateShareTool({\n workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createMemorySearchTool({ workspaceDir: workspace, memoriesDir }),\n createMemoryGetTool({ workspaceDir: workspace, memoriesDir }),\n ...(getBuiltin && shouldRegisterCuratedMemoryTool(this.deps.getConfig?.())\n ? [\n createCuratedMemoryTool(getBuiltin, {\n onMemoryWrite: (action, target, content) => {\n getMemMgr?.().onMemoryWrite(action, target, content);\n },\n }),\n ]\n : []),\n ...(getMemMgr?.().getAdditionalTools() ?? []),\n ...(this.deps.getSessionStore\n ? [\n createSessionSearchTool({\n getSessionStore: this.deps.getSessionStore,\n getConfig: this.deps.getConfig,\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ]\n : []),\n ...(this.deps.getCronService\n ? [\n createCronjobTool({\n getCronService: this.deps.getCronService,\n }),\n ]\n : []),\n createGoalTool(),\n ...(cfg?.agents?.defaults?.browser?.enabled !== false\n ? [\n createBrowserUseTool({\n getManager: () => this.ensureBrowserManager(),\n getPageForTask: () => this.acquireBrowserPage(),\n getTaskId: () => this.deps.getCurrentContext()?.sessionKey ?? 'default',\n getConfig: () => this.deps.getConfig?.(),\n getReadiness: () => this.checkBrowserReadinessCached(),\n getSupervisor: () =>\n this.browserSupervisorForTask(this.deps.getCurrentContext()?.sessionKey ?? 'default'),\n notifyBrowserPageClosed: (taskId) => {\n this.browserTaskSupervisors.delete(taskId);\n },\n }),\n ]\n : []),\n ...(cfg?.agents?.defaults?.workflow?.enabled !== false && primary\n ? [\n createWorkflowTool({\n catalog: createWorkflowCatalog(),\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n getConfig: () => this.deps.getConfig?.(),\n startWorkflowRun: this.deps.getWorkflowRunService\n ? (params) => this.deps.getWorkflowRunService!().startWorkflowRun(params)\n : undefined,\n }),\n ]\n : []),\n ...(cfg?.agents?.defaults?.delegate?.enabled === true && primary\n ? [\n createDelegateTool({\n workspace,\n getSubagentModel: () => {\n const gp = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const m = gp?.();\n if (!m) {\n throw new Error('No primary model configured for delegate_task');\n }\n return m;\n },\n bus: this.deps.bus,\n getConfig: () => this.deps.getConfig?.(),\n getCurrentContext: () => this.deps.getCurrentContext?.() ?? null,\n hookRunner: this.deps.hookRunner,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n // Injected so `child-agent-factory.ts` does not need to import\n // `AgentToolsFactory` directly (which would form a cycle).\n buildChildTools: (childOpts) => {\n const childFactory = new AgentToolsFactory({\n workspace: childOpts.workspace,\n bus: childOpts.bus,\n getCurrentContext: () => null,\n getConfig: childOpts.getConfig,\n getPrimaryModel: () => childOpts.model,\n toolExecutorConfig: childOpts.toolExecutorConfig,\n });\n return childFactory.createAllTools({\n workspace: childOpts.workspace,\n getPrimaryModel: () => childOpts.model,\n disabledTools: new Set(['extensions']),\n });\n },\n }),\n ]\n : []),\n ...optionalTools,\n ];\n\n return filterToolsByDisabledSet(core, disabled);\n }\n\n createAllTools(coreOptions?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const coreTools = this.createCoreTools(coreOptions);\n const disableExtensions = coreOptions?.disabledTools?.has('extensions');\n const cfg = this.deps.getConfig?.();\n\n let bundled: AgentTool<any, any>[];\n if (!this.deps.extensionRegistry || disableExtensions) {\n bundled = coreTools;\n } else {\n const extensionTools = this.deps.extensionRegistry.getAllTools();\n log.info({ count: extensionTools.length }, 'Loaded extension tools');\n bundled = [...coreTools, ...extensionTools];\n }\n\n const wrapped = wrapToolsWithProtection(bundled, this.deps.toolExecutorConfig);\n\n const executeEnabled =\n cfg?.agents?.defaults?.executeCode?.enabled === true &&\n !coreOptions?.disabledTools?.has('execute_code');\n\n if (executeEnabled) {\n const sandboxMap = buildSandboxToolMap(wrapped);\n const executeTool = createExecuteCodeTool({ getSandboxToolMap: () => sandboxMap });\n const wrappedExecute = wrapToolsWithProtection([executeTool as any], this.deps.toolExecutorConfig);\n return [...wrapped, ...wrappedExecute];\n }\n\n return wrapped;\n }\n}\n\nfunction filterToolsByDisabledSet(\n tools: any[],\n disabled: Set<string> | undefined,\n): any[] {\n if (!disabled || disabled.size === 0) {\n return tools;\n }\n return tools.filter((t) => !disabled.has(t.name));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"factory.js","names":[],"sources":["../../../../src/agent/tools/factory.ts"],"sourcesContent":["/**\n * Agent Tools Factory - Creates and configures agent tools\n *\n * Centralizes tool creation logic to keep service.ts focused on orchestration.\n *\n * TTS: auto TTS is applied at the ChannelManager via maybeApplyTtsToPayload().\n * Optional \\`text_to_speech\\` tool sends explicit voice when TTS is enabled.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { Page } from 'playwright-core';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport {\n createReadFileTool,\n createWriteFileTool,\n createEditFileTool,\n createListDirTool,\n createGrepTool,\n createFindTool,\n createShellTool,\n createWebSearchTool,\n createWebFetchTool,\n createWebExtractTool,\n createMessageTool,\n createSendMediaTool,\n createReadMediaTool,\n createCreateShareTool,\n isShareToolAvailable,\n createMemorySearchTool,\n createMemoryGetTool,\n createTodoTool,\n createSessionStatusTool,\n createDreamingTool,\n createClarifyTool,\n createToolManualTool,\n createGoalTool,\n} from './index.js';\nimport { createCuratedMemoryTool } from './curated-memory-tool.js';\nimport { createSessionSearchTool } from './session-search-tool.js';\nimport type { BuiltinMemoryStore } from '../memory/builtin-memory-store.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport { shouldRegisterCuratedMemoryTool } from '../memory/memory-config.js';\nimport type { SessionStore } from '../../session/store.js';\nimport type { GatewayClarifyRequestFn } from './clarify-tool.js';\nimport { createImageTool } from './image-tool.js';\nimport { createImageGenerateTool } from './image-generate-tool.js';\nimport {\n BrowserManager,\n BrowserNotReadyError,\n CdpSupervisor,\n checkBrowserReadiness,\n resolveBrowserBackendFromConfig,\n} from '../../browser/index.js';\nimport { createBrowserUseTool } from './browser/tool/browser-use-tool.js';\nimport { createDelegateTool } from './delegate-tool.js';\nimport { createWorkflowTool } from './workflow-tool.js';\nimport { createWorkflowCatalog } from '../workflow/catalog.js';\nimport { buildSandboxToolMap, createExecuteCodeTool } from './execute-code-tool.js';\nimport { createCronjobTool } from './cronjob-tool.js';\nimport type { CronService } from '../../cron/index.js';\nimport type { WorkflowRunServiceLike } from '../../workflows/service/workflow-run-service.types.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport { wrapToolsWithProtection, type ToolExecutorConfig } from './executor.js';\nimport { createSkillsListTool, createSkillViewTool } from './skills-tools.js';\nimport { createSkillManageTool } from './skill-manage-tool.js';\nimport { createTextToSpeechTool } from './tts-tool.js';\nimport { mergeTtsConfigFromAppConfig } from '../../voice/tts/merge-config.js';\nimport { createGoalEvidenceRecorder } from './goal-evidence-recorder.js';\n\nconst log = createLogger('AgentToolsFactory');\n\n/** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */\nconst CLARIFY_SUPPORTED_CHANNELS = new Set(['webchat', 'telegram', 'cli']);\n\nexport interface ToolFactoryDeps {\n workspace: string;\n extensionRegistry?: any;\n getCurrentContext: () => { channel: string; chatId: string; sessionKey: string } | null;\n hookRunner?: import('../../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n /** Agent defaults (image tools, etc.); use getter so hot-reloaded config applies. */\n getConfig?: () => Config | undefined;\n /** Session / default chat model for vision tool description. */\n getPrimaryModel?: () => Model<Api>;\n /** Built-in curated memory store (agent home `memories/`). */\n getBuiltinMemoryStore?: () => BuiltinMemoryStore;\n /** Memory orchestration (prefetch/sync + external tools). */\n getMemoryManager?: () => MemoryManager;\n /** Session store for `session_search`. */\n getSessionStore?: () => SessionStore;\n /** When set (gateway webchat), enables the `clarify` tool. */\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: enables the `cronjob` tool. */\n getCronService?: () => CronService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => WorkflowRunServiceLike | undefined;\n /** Current session skill indexing (tool gating + allowlist); used by skills_list / skill_view. */\n getSkillIndexingContext?: () =>\n | { registeredToolNames: string[]; skillAllowlist?: string[] }\n | undefined;\n /** After skill_manage mutates disk, reload skills + refresh agent prompts (optional). */\n onSkillsFilesystemMutate?: () => void;\n /** Names registered via skill_view for shell env passthrough. */\n getSkillPassthroughEnvVarNames?: () => string[];\n /** Add declared env names for the current session (no values stored). */\n registerSkillEnvPassthrough?: (names: string[]) => void;\n}\n\nexport interface CreateCoreToolsOptions {\n /** Workspace root for file/shell tools (defaults to factory workspace). */\n workspace?: string;\n /** Canonical `agents/<id>/profile/`: bare SOUL.md / IDENTITY.md resolve here after the workspace. */\n profileMarkdownRoot?: string;\n /** Tool `name` values to omit (e.g. `shell`, `extensions` for extension tools). */\n disabledTools?: Set<string>;\n /** Optional primary model for image tool heuristics. */\n getPrimaryModel?: () => Model<Api>;\n getBuiltinMemoryStore?: () => BuiltinMemoryStore;\n getMemoryManager?: () => MemoryManager;\n /** When set, registers `skills_list` and `skill_view` bound to this workspace\\'s skills. */\n getSkillManager?: () => SkillManager;\n}\n\nexport class AgentToolsFactory {\n private browserManager: BrowserManager | null = null;\n /** One dialog/console supervisor per chat session (browser tab). */\n private readonly browserTaskSupervisors = new Map<string, CdpSupervisor>();\n /** Cached readiness probe — keyed by backend mode + extension host:port. */\n private browserReadinessCache: {\n key: string;\n expiresAt: number;\n inflight?: Promise<BrowserNotReadyError | null>;\n result?: BrowserNotReadyError | null;\n } | null = null;\n\n constructor(private deps: ToolFactoryDeps) {}\n\n private browserReadinessKey(): string {\n const cfg = this.deps.getConfig?.();\n const backend = resolveBrowserBackendFromConfig(cfg);\n const ext = cfg?.agents?.defaults?.browser?.extension;\n const host = typeof ext?.host === 'string' && ext.host.trim() ? ext.host.trim() : '127.0.0.1';\n const port = typeof ext?.port === 'number' ? ext.port : 19820;\n const cdpUrl = backend.mode === 'cdp' ? backend.config.wsEndpoint : '';\n const cloudKind = backend.mode === 'cloud' ? backend.config.type : '';\n return `${backend.mode}@${host}:${port}|${cdpUrl}|${cloudKind}`;\n }\n\n private async checkBrowserReadinessCached(): Promise<BrowserNotReadyError | null> {\n const key = this.browserReadinessKey();\n const now = Date.now();\n const cached = this.browserReadinessCache;\n if (cached && cached.key === key && cached.expiresAt > now && cached.inflight === undefined) {\n return cached.result ?? null;\n }\n if (cached && cached.key === key && cached.inflight) {\n return cached.inflight;\n }\n const inflight = checkBrowserReadiness(this.deps.getConfig?.());\n this.browserReadinessCache = { key, expiresAt: now + 30_000, inflight };\n try {\n const result = await inflight;\n this.browserReadinessCache = { key, expiresAt: Date.now() + 30_000, result };\n return result;\n } catch (e) {\n // Probe should never throw, but if it does we just bypass the cache.\n this.browserReadinessCache = null;\n log.warn({ err: e }, 'browserReadiness probe failed');\n return null;\n }\n }\n\n /** Invalidate the readiness cache (config hot-reload, settings-page save, etc.). */\n invalidateBrowserReadinessCache(): void {\n this.browserReadinessCache = null;\n }\n\n private browserSupervisorForTask(taskId: string): CdpSupervisor {\n let s = this.browserTaskSupervisors.get(taskId);\n if (!s) {\n const b = this.deps.getConfig?.()?.agents?.defaults?.browser;\n const dialogPolicy =\n b?.dialogPolicy === 'must_respond' || b?.dialogPolicy === 'auto_accept' || b?.dialogPolicy === 'auto_dismiss'\n ? b.dialogPolicy\n : 'auto_dismiss';\n const dialogTimeoutSeconds =\n typeof b?.dialogTimeoutSeconds === 'number' &&\n Number.isFinite(b.dialogTimeoutSeconds) &&\n b.dialogTimeoutSeconds >= 1\n ? Math.floor(b.dialogTimeoutSeconds)\n : 300;\n s = new CdpSupervisor({ dialogPolicy, dialogTimeoutSeconds });\n this.browserTaskSupervisors.set(taskId, s);\n }\n return s;\n }\n\n private async acquireBrowserPage(): Promise<Page> {\n const taskId = this.deps.getCurrentContext()?.sessionKey ?? 'default';\n const mgr = this.ensureBrowserManager();\n await mgr.ensureConnected();\n if (mgr.getExtensionProvider()) {\n return null as unknown as Page;\n }\n const page = await mgr.getPage(taskId);\n this.browserSupervisorForTask(taskId).attach(page);\n return page;\n }\n\n private ensureBrowserManager(): BrowserManager {\n if (!this.browserManager) {\n this.browserManager = new BrowserManager({\n getHeadless: () => this.deps.getConfig?.()?.agents?.defaults?.browser?.headless === true,\n getBackend: () => resolveBrowserBackendFromConfig(this.deps.getConfig?.()),\n });\n }\n return this.browserManager;\n }\n\n /** Close Playwright and all pages (gateway stop, agent manager dispose, or config hot-reload). */\n async shutdownBrowser(): Promise<void> {\n this.browserReadinessCache = null;\n if (!this.browserManager) {\n return;\n }\n await this.browserManager.shutdown();\n this.browserManager = null;\n this.browserTaskSupervisors.clear();\n }\n\n /** Drop the tab for a session when its agent instance is removed. */\n async closeBrowserPageForSession(sessionKey: string): Promise<void> {\n this.browserTaskSupervisors.delete(sessionKey);\n await this.browserManager?.closePage(sessionKey);\n }\n\n createCoreTools(options?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const workspace = options?.workspace ?? this.deps.workspace;\n const { bus } = this.deps;\n const getPrimary = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const getBuiltin = options?.getBuiltinMemoryStore ?? this.deps.getBuiltinMemoryStore;\n const builtinStore = getBuiltin?.();\n const memoriesDir = builtinStore?.memoriesDir;\n const getMemMgr = options?.getMemoryManager ?? this.deps.getMemoryManager;\n const getSkillMgr = options?.getSkillManager;\n const disabled = options?.disabledTools;\n\n const primary = getPrimary?.();\n const modelHasVision = primary?.input?.includes('image') ?? false;\n const cfg = this.deps.getConfig?.();\n const recordGoalEvidence = createGoalEvidenceRecorder({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n });\n const imageTool = createImageTool({\n config: cfg,\n workspace,\n modelHasVision,\n });\n const imageGenerateTool = createImageGenerateTool({\n config: cfg,\n workspace,\n });\n\n const optionalTools = [imageTool, imageGenerateTool].filter((t) => t != null) as any[];\n\n const readTool = createReadFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n });\n const writeTool = createWriteFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const editTool = createEditFileTool(workspace, {\n profileMarkdownRoot: options?.profileMarkdownRoot,\n recordGoalEvidence,\n });\n const listDir = createListDirTool(workspace);\n const grep = createGrepTool(workspace);\n const find = createFindTool(workspace);\n\n const core: AgentTool<any, any>[] = [\n createSessionStatusTool(),\n createDreamingTool({\n getWorkspace: () => workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n createToolManualTool(),\n createClarifyTool({\n resolveAskUser: () => {\n const req = this.deps.gatewayClarify?.requestClarification;\n if (!req) return null;\n const ctx = this.deps.getCurrentContext();\n if (!ctx?.sessionKey) return null;\n if (!CLARIFY_SUPPORTED_CHANNELS.has(ctx.channel)) return null;\n return (r) => req(ctx.sessionKey, r);\n },\n }),\n createTodoTool({\n getSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ...(getSkillMgr\n ? [\n createSkillsListTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n }),\n createSkillViewTool({\n getSkillManager: getSkillMgr,\n getSkillIndexingContext: this.deps.getSkillIndexingContext,\n registerSkillEnvPassthrough: this.deps.registerSkillEnvPassthrough,\n }),\n createSkillManageTool({\n getSkillManager: getSkillMgr,\n getWorkspace: () => workspace,\n onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate,\n }),\n ]\n : []),\n readTool,\n writeTool,\n editTool,\n listDir,\n grep,\n find,\n createShellTool(workspace, {\n getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames,\n recordGoalEvidence,\n }),\n createWebSearchTool(() => this.deps.getConfig?.()),\n createWebFetchTool(() => this.deps.getConfig?.()),\n createWebExtractTool({ getConfig: () => this.deps.getConfig?.() }),\n // Note: TTS is NOT handled by send_message tool anymore\n // TTS is applied at the ChannelManager dispatch layer\n createMessageTool(bus, () => this.deps.getCurrentContext()),\n ...(mergeTtsConfigFromAppConfig(cfg?.messages?.tts).enabled\n ? [\n createTextToSpeechTool({\n bus,\n getContext: () => this.deps.getCurrentContext(),\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createSendMediaTool(workspace, bus, () => this.deps.getCurrentContext()),\n createReadMediaTool(),\n ...(isShareToolAvailable(cfg)\n ? [\n createCreateShareTool({\n workspace,\n getConfig: () => this.deps.getConfig?.(),\n }),\n ]\n : []),\n createMemorySearchTool({ workspaceDir: workspace, memoriesDir }),\n createMemoryGetTool({ workspaceDir: workspace, memoriesDir }),\n ...(getBuiltin && shouldRegisterCuratedMemoryTool(this.deps.getConfig?.())\n ? [\n createCuratedMemoryTool(getBuiltin, {\n onMemoryWrite: (action, target, content) => {\n getMemMgr?.().onMemoryWrite(action, target, content);\n },\n }),\n ]\n : []),\n ...(getMemMgr?.().getAdditionalTools() ?? []),\n ...(this.deps.getSessionStore\n ? [\n createSessionSearchTool({\n getSessionStore: this.deps.getSessionStore,\n getConfig: this.deps.getConfig,\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n }),\n ]\n : []),\n ...(this.deps.getCronService\n ? [\n createCronjobTool({\n getCronService: this.deps.getCronService,\n }),\n ]\n : []),\n createGoalTool(),\n ...(cfg?.agents?.defaults?.browser?.enabled !== false\n ? [\n createBrowserUseTool({\n getManager: () => this.ensureBrowserManager(),\n getPageForTask: () => this.acquireBrowserPage(),\n getTaskId: () => this.deps.getCurrentContext()?.sessionKey ?? 'default',\n getConfig: () => this.deps.getConfig?.(),\n getReadiness: () => this.checkBrowserReadinessCached(),\n getSupervisor: () =>\n this.browserSupervisorForTask(this.deps.getCurrentContext()?.sessionKey ?? 'default'),\n notifyBrowserPageClosed: (taskId) => {\n this.browserTaskSupervisors.delete(taskId);\n },\n }),\n ]\n : []),\n ...(cfg?.agents?.defaults?.workflow?.enabled !== false && primary\n ? [\n createWorkflowTool({\n catalog: createWorkflowCatalog(),\n getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,\n getConfig: () => this.deps.getConfig?.(),\n startWorkflowRun: this.deps.getWorkflowRunService\n ? (params) => this.deps.getWorkflowRunService!().startWorkflowRun(params)\n : undefined,\n }),\n ]\n : []),\n ...(cfg?.agents?.defaults?.delegate?.enabled === true && primary\n ? [\n createDelegateTool({\n workspace,\n getSubagentModel: () => {\n const gp = options?.getPrimaryModel ?? this.deps.getPrimaryModel;\n const m = gp?.();\n if (!m) {\n throw new Error('No primary model configured for delegate_task');\n }\n return m;\n },\n bus: this.deps.bus,\n getConfig: () => this.deps.getConfig?.(),\n getCurrentContext: () => this.deps.getCurrentContext?.() ?? null,\n hookRunner: this.deps.hookRunner,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n // Injected so `child-agent-factory.ts` does not need to import\n // `AgentToolsFactory` directly (which would form a cycle).\n buildChildTools: (childOpts) => {\n const childFactory = new AgentToolsFactory({\n workspace: childOpts.workspace,\n bus: childOpts.bus,\n getCurrentContext: () => null,\n getConfig: childOpts.getConfig,\n getPrimaryModel: () => childOpts.model,\n toolExecutorConfig: childOpts.toolExecutorConfig,\n });\n return childFactory.createAllTools({\n workspace: childOpts.workspace,\n getPrimaryModel: () => childOpts.model,\n disabledTools: new Set(['extensions']),\n });\n },\n }),\n ]\n : []),\n ...optionalTools,\n ];\n\n return filterToolsByDisabledSet(core, disabled);\n }\n\n createAllTools(coreOptions?: CreateCoreToolsOptions): AgentTool<any, any>[] {\n const coreTools = this.createCoreTools(coreOptions);\n const disableExtensions = coreOptions?.disabledTools?.has('extensions');\n const cfg = this.deps.getConfig?.();\n\n let bundled: AgentTool<any, any>[];\n if (!this.deps.extensionRegistry || disableExtensions) {\n bundled = coreTools;\n } else {\n const extensionTools = this.deps.extensionRegistry.getAllTools();\n log.info({ count: extensionTools.length }, 'Loaded extension tools');\n bundled = [...coreTools, ...extensionTools];\n }\n\n const wrapped = wrapToolsWithProtection(bundled, this.deps.toolExecutorConfig);\n\n const executeEnabled =\n cfg?.agents?.defaults?.executeCode?.enabled === true &&\n !coreOptions?.disabledTools?.has('execute_code');\n\n if (executeEnabled) {\n const sandboxMap = buildSandboxToolMap(wrapped);\n const executeTool = createExecuteCodeTool({ getSandboxToolMap: () => sandboxMap });\n const wrappedExecute = wrapToolsWithProtection([executeTool as any], this.deps.toolExecutorConfig);\n return [...wrapped, ...wrappedExecute];\n }\n\n return wrapped;\n }\n}\n\nfunction filterToolsByDisabledSet(\n tools: any[],\n disabled: Set<string> | undefined,\n): any[] {\n if (!disabled || disabled.size === 0) {\n return tools;\n }\n return tools.filter((t) => !disabled.has(t.name));\n}\n"],"mappings":"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"}
@@ -40,7 +40,7 @@ function createSkillManageTool(deps) {
40
40
  return {
41
41
  name: "skill_manage",
42
42
  label: "🛠️ Skill",
43
- description: "Create, edit, patch, or delete user skills under ~/.xopc/skills and/or workspace skills/ (see skills.agentWritePolicy). Also write_file / remove_file under references/, templates/, scripts/, assets/. Bundled and extra-dir skills cannot be modified. Runs a security scan after writes.",
43
+ description: "Create, edit, patch, or delete user skills under ~/.xopc/skills and/or workspace .xopc/skills/ (see skills.agentWritePolicy). Also write_file / remove_file under references/, templates/, scripts/, assets/. Bundled and extra-dir skills cannot be modified. Runs a security scan after writes.",
44
44
  parameters: SkillManageSchema,
45
45
  async execute(_toolCallId, params) {
46
46
  const mgr = deps.getSkillManager();
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manage-tool.js","names":[],"sources":["../../../../src/agent/tools/skill-manage-tool.ts"],"sourcesContent":["import { Type, type Static } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { existsSync, rmSync } from 'fs';\nimport { join } from 'path';\nimport { readFile, rm } from 'fs/promises';\n\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createSkillConfigManager } from '../skills/config.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport {\n applyPatchToContent,\n atomicWriteUtf8,\n effectiveAgentWritePolicy,\n ensureCategorySegment,\n maxSkillMdChars,\n maxSupportFileBytes,\n mutatableSkillOrNull,\n isPathInsideDir,\n resolveCreateSkillDir,\n scanSkillDirOrError,\n validateSkillMdContent,\n validateSkillNameSegment,\n validateSupportingRelativePath,\n} from '../skills/skill-manage-ops.js';\n\nconst SkillManageSchema = Type.Object({\n action: Type.Union([\n Type.Literal('create'),\n Type.Literal('edit'),\n Type.Literal('patch'),\n Type.Literal('delete'),\n Type.Literal('write_file'),\n Type.Literal('remove_file'),\n ]),\n name: Type.Optional(Type.String({ description: 'Skill name (directory id / frontmatter name)' })),\n content: Type.Optional(Type.String({ description: 'Full SKILL.md for create or edit' })),\n category: Type.Optional(Type.String({ description: 'Optional single-segment category folder under skills root' })),\n write_target: Type.Optional(\n Type.Union([Type.Literal('global'), Type.Literal('workspace')], {\n description: 'Where to create the skill (default global). Respects skills.agentWritePolicy.',\n }),\n ),\n old_string: Type.Optional(Type.String()),\n new_string: Type.Optional(Type.String()),\n replace_all: Type.Optional(Type.Boolean({ default: false })),\n file_path: Type.Optional(\n Type.String({\n description: 'Relative path under skill dir (references/, templates/, scripts/, assets/)',\n }),\n ),\n file_content: Type.Optional(Type.String({ description: 'For write_file' })),\n});\n\nexport interface SkillManageToolDeps {\n getSkillManager: () => SkillManager | undefined;\n getWorkspace: () => string;\n onSkillsFilesystemMutate?: () => void;\n}\n\nfunction jsonResult(obj: Record<string, unknown>): AgentToolResult<{}> {\n return { content: [{ type: 'text', text: JSON.stringify(obj, null, 2) }], details: {} };\n}\n\nexport function createSkillManageTool(deps: SkillManageToolDeps): AgentTool {\n return {\n name: 'skill_manage',\n label: '🛠️ Skill',\n description:\n 'Create, edit, patch, or delete user skills under ~/.xopc/skills and/or workspace skills/ (see skills.agentWritePolicy). ' +\n 'Also write_file / remove_file under references/, templates/, scripts/, assets/. ' +\n 'Bundled and extra-dir skills cannot be modified. Runs a security scan after writes.',\n parameters: SkillManageSchema,\n async execute(\n _toolCallId: string,\n params: Static<typeof SkillManageSchema>,\n ): Promise<AgentToolResult<{}>> {\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return jsonResult({ success: false, error: 'Skill manager not available in this context.' });\n }\n\n const workspace = deps.getWorkspace();\n const skillsCfg = createSkillConfigManager(resolveStateDir()).load();\n const policy = effectiveAgentWritePolicy(skillsCfg);\n const mdMax = maxSkillMdChars(skillsCfg);\n const supMax = maxSupportFileBytes(skillsCfg);\n\n const notify = () => deps.onSkillsFilesystemMutate?.();\n\n try {\n switch (params.action) {\n case 'create': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const catErr = ensureCategorySegment(params.category);\n if (catErr) return jsonResult({ success: false, error: catErr });\n\n const md = validateSkillMdContent(params.content ?? '', name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: md.error });\n\n if (mgr.hasSkill(name)) {\n return jsonResult({\n success: false,\n error: `A skill named \"${name}\" already exists. Use edit or choose another name.`,\n });\n }\n\n const target = params.write_target ?? 'global';\n const dirRes = resolveCreateSkillDir(name, params.category?.trim(), target, workspace, policy);\n if (dirRes.ok === false) return jsonResult({ success: false, error: dirRes.error });\n\n if (existsSync(dirRes.dir)) {\n return jsonResult({ success: false, error: `Directory already exists: ${dirRes.dir}` });\n }\n\n const skillMdPath = join(dirRes.dir, 'SKILL.md');\n try {\n await atomicWriteUtf8(skillMdPath, params.content!);\n const scanErr = await scanSkillDirOrError(dirRes.dir, name);\n if (scanErr) {\n rmSync(dirRes.dir, { recursive: true, force: true });\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n rmSync(dirRes.dir, { recursive: true, force: true });\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Skill \"${name}\" created.`,\n path: dirRes.dir,\n });\n }\n\n case 'edit': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable (bundled/extra or policy).`,\n });\n }\n\n const md = validateSkillMdContent(params.content ?? '', name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: md.error });\n\n const skillMdPath = join(sk.baseDir, 'SKILL.md');\n let previous: string;\n try {\n previous = await readFile(skillMdPath, 'utf-8');\n } catch {\n return jsonResult({ success: false, error: 'SKILL.md could not be read.' });\n }\n\n try {\n await atomicWriteUtf8(skillMdPath, params.content!);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n await atomicWriteUtf8(skillMdPath, previous);\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n await atomicWriteUtf8(skillMdPath, previous).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({ success: true, message: `Skill \"${name}\" updated.`, path: sk.baseDir });\n }\n\n case 'patch': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n let relPath: string | undefined;\n if (params.file_path?.trim()) {\n const pErr = validateSupportingRelativePath(params.file_path.trim());\n if (pErr) return jsonResult({ success: false, error: pErr });\n relPath = params.file_path.trim().replace(/\\\\/g, '/');\n }\n\n const targetPath = relPath ? join(sk.baseDir, relPath) : join(sk.baseDir, 'SKILL.md');\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n let previous: string;\n try {\n previous = await readFile(targetPath, 'utf-8');\n } catch {\n return jsonResult({ success: false, error: `File not found: ${relPath ?? 'SKILL.md'}` });\n }\n\n const patched = applyPatchToContent(\n previous,\n params.old_string ?? '',\n params.new_string ?? '',\n params.replace_all === true,\n );\n if (patched.ok === false) return jsonResult({ success: false, error: patched.error });\n\n if (!relPath) {\n const md = validateSkillMdContent(patched.next, name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: `Patch rejected: ${md.error}` });\n } else if (Buffer.byteLength(patched.next, 'utf-8') > supMax) {\n return jsonResult({ success: false, error: `File exceeds size limit (${supMax} bytes).` });\n }\n\n try {\n await atomicWriteUtf8(targetPath, patched.next);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n await atomicWriteUtf8(targetPath, previous);\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n await atomicWriteUtf8(targetPath, previous).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Patched ${relPath ?? 'SKILL.md'} (${patched.replacements} replacement(s)).`,\n });\n }\n\n case 'delete': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n rmSync(sk.baseDir, { recursive: true, force: true });\n notify();\n return jsonResult({ success: true, message: `Skill \"${name}\" removed.`, path: sk.baseDir });\n }\n\n case 'write_file': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n const pErr = validateSupportingRelativePath(params.file_path ?? '');\n if (pErr) return jsonResult({ success: false, error: pErr });\n const rel = params.file_path!.trim().replace(/\\\\/g, '/');\n const targetPath = join(sk.baseDir, rel);\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n const body = params.file_content ?? '';\n if (Buffer.byteLength(body, 'utf-8') > supMax) {\n return jsonResult({ success: false, error: `File exceeds size limit (${supMax} bytes).` });\n }\n\n const existed = existsSync(targetPath);\n let previous: string | null = null;\n if (existed) {\n try {\n previous = await readFile(targetPath, 'utf-8');\n } catch {\n previous = null;\n }\n }\n\n try {\n await atomicWriteUtf8(targetPath, body);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n if (previous !== null) await atomicWriteUtf8(targetPath, previous);\n else await rm(targetPath, { force: true });\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n if (previous !== null) await atomicWriteUtf8(targetPath, previous).catch(() => {});\n else await rm(targetPath, { force: true }).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Wrote ${rel}.`,\n });\n }\n\n case 'remove_file': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n const pErr = validateSupportingRelativePath(params.file_path ?? '');\n if (pErr) return jsonResult({ success: false, error: pErr });\n const rel = params.file_path!.trim().replace(/\\\\/g, '/');\n const targetPath = join(sk.baseDir, rel);\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n if (!existsSync(targetPath)) {\n return jsonResult({ success: false, error: `File not found: ${rel}` });\n }\n\n await rm(targetPath, { force: true });\n await scanSkillDirOrError(sk.baseDir, name);\n notify();\n return jsonResult({ success: true, message: `Removed ${rel}.` });\n }\n\n default:\n return jsonResult({ success: false, error: 'Unknown action.' });\n }\n } catch (e) {\n return jsonResult({\n success: false,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n },\n } as any;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skill-manage-tool.js","names":[],"sources":["../../../../src/agent/tools/skill-manage-tool.ts"],"sourcesContent":["import { Type, type Static } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { existsSync, rmSync } from 'fs';\nimport { join } from 'path';\nimport { readFile, rm } from 'fs/promises';\n\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createSkillConfigManager } from '../skills/config.js';\nimport type { SkillManager } from '../skills/skill-manager.js';\nimport {\n applyPatchToContent,\n atomicWriteUtf8,\n effectiveAgentWritePolicy,\n ensureCategorySegment,\n maxSkillMdChars,\n maxSupportFileBytes,\n mutatableSkillOrNull,\n isPathInsideDir,\n resolveCreateSkillDir,\n scanSkillDirOrError,\n validateSkillMdContent,\n validateSkillNameSegment,\n validateSupportingRelativePath,\n} from '../skills/skill-manage-ops.js';\n\nconst SkillManageSchema = Type.Object({\n action: Type.Union([\n Type.Literal('create'),\n Type.Literal('edit'),\n Type.Literal('patch'),\n Type.Literal('delete'),\n Type.Literal('write_file'),\n Type.Literal('remove_file'),\n ]),\n name: Type.Optional(Type.String({ description: 'Skill name (directory id / frontmatter name)' })),\n content: Type.Optional(Type.String({ description: 'Full SKILL.md for create or edit' })),\n category: Type.Optional(Type.String({ description: 'Optional single-segment category folder under skills root' })),\n write_target: Type.Optional(\n Type.Union([Type.Literal('global'), Type.Literal('workspace')], {\n description: 'Where to create the skill (default global). Respects skills.agentWritePolicy.',\n }),\n ),\n old_string: Type.Optional(Type.String()),\n new_string: Type.Optional(Type.String()),\n replace_all: Type.Optional(Type.Boolean({ default: false })),\n file_path: Type.Optional(\n Type.String({\n description: 'Relative path under skill dir (references/, templates/, scripts/, assets/)',\n }),\n ),\n file_content: Type.Optional(Type.String({ description: 'For write_file' })),\n});\n\nexport interface SkillManageToolDeps {\n getSkillManager: () => SkillManager | undefined;\n getWorkspace: () => string;\n onSkillsFilesystemMutate?: () => void;\n}\n\nfunction jsonResult(obj: Record<string, unknown>): AgentToolResult<{}> {\n return { content: [{ type: 'text', text: JSON.stringify(obj, null, 2) }], details: {} };\n}\n\nexport function createSkillManageTool(deps: SkillManageToolDeps): AgentTool {\n return {\n name: 'skill_manage',\n label: '🛠️ Skill',\n description:\n 'Create, edit, patch, or delete user skills under ~/.xopc/skills and/or workspace .xopc/skills/ (see skills.agentWritePolicy). ' +\n 'Also write_file / remove_file under references/, templates/, scripts/, assets/. ' +\n 'Bundled and extra-dir skills cannot be modified. Runs a security scan after writes.',\n parameters: SkillManageSchema,\n async execute(\n _toolCallId: string,\n params: Static<typeof SkillManageSchema>,\n ): Promise<AgentToolResult<{}>> {\n const mgr = deps.getSkillManager();\n if (!mgr) {\n return jsonResult({ success: false, error: 'Skill manager not available in this context.' });\n }\n\n const workspace = deps.getWorkspace();\n const skillsCfg = createSkillConfigManager(resolveStateDir()).load();\n const policy = effectiveAgentWritePolicy(skillsCfg);\n const mdMax = maxSkillMdChars(skillsCfg);\n const supMax = maxSupportFileBytes(skillsCfg);\n\n const notify = () => deps.onSkillsFilesystemMutate?.();\n\n try {\n switch (params.action) {\n case 'create': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const catErr = ensureCategorySegment(params.category);\n if (catErr) return jsonResult({ success: false, error: catErr });\n\n const md = validateSkillMdContent(params.content ?? '', name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: md.error });\n\n if (mgr.hasSkill(name)) {\n return jsonResult({\n success: false,\n error: `A skill named \"${name}\" already exists. Use edit or choose another name.`,\n });\n }\n\n const target = params.write_target ?? 'global';\n const dirRes = resolveCreateSkillDir(name, params.category?.trim(), target, workspace, policy);\n if (dirRes.ok === false) return jsonResult({ success: false, error: dirRes.error });\n\n if (existsSync(dirRes.dir)) {\n return jsonResult({ success: false, error: `Directory already exists: ${dirRes.dir}` });\n }\n\n const skillMdPath = join(dirRes.dir, 'SKILL.md');\n try {\n await atomicWriteUtf8(skillMdPath, params.content!);\n const scanErr = await scanSkillDirOrError(dirRes.dir, name);\n if (scanErr) {\n rmSync(dirRes.dir, { recursive: true, force: true });\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n rmSync(dirRes.dir, { recursive: true, force: true });\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Skill \"${name}\" created.`,\n path: dirRes.dir,\n });\n }\n\n case 'edit': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable (bundled/extra or policy).`,\n });\n }\n\n const md = validateSkillMdContent(params.content ?? '', name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: md.error });\n\n const skillMdPath = join(sk.baseDir, 'SKILL.md');\n let previous: string;\n try {\n previous = await readFile(skillMdPath, 'utf-8');\n } catch {\n return jsonResult({ success: false, error: 'SKILL.md could not be read.' });\n }\n\n try {\n await atomicWriteUtf8(skillMdPath, params.content!);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n await atomicWriteUtf8(skillMdPath, previous);\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n await atomicWriteUtf8(skillMdPath, previous).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({ success: true, message: `Skill \"${name}\" updated.`, path: sk.baseDir });\n }\n\n case 'patch': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n let relPath: string | undefined;\n if (params.file_path?.trim()) {\n const pErr = validateSupportingRelativePath(params.file_path.trim());\n if (pErr) return jsonResult({ success: false, error: pErr });\n relPath = params.file_path.trim().replace(/\\\\/g, '/');\n }\n\n const targetPath = relPath ? join(sk.baseDir, relPath) : join(sk.baseDir, 'SKILL.md');\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n let previous: string;\n try {\n previous = await readFile(targetPath, 'utf-8');\n } catch {\n return jsonResult({ success: false, error: `File not found: ${relPath ?? 'SKILL.md'}` });\n }\n\n const patched = applyPatchToContent(\n previous,\n params.old_string ?? '',\n params.new_string ?? '',\n params.replace_all === true,\n );\n if (patched.ok === false) return jsonResult({ success: false, error: patched.error });\n\n if (!relPath) {\n const md = validateSkillMdContent(patched.next, name, mdMax);\n if (md.ok === false) return jsonResult({ success: false, error: `Patch rejected: ${md.error}` });\n } else if (Buffer.byteLength(patched.next, 'utf-8') > supMax) {\n return jsonResult({ success: false, error: `File exceeds size limit (${supMax} bytes).` });\n }\n\n try {\n await atomicWriteUtf8(targetPath, patched.next);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n await atomicWriteUtf8(targetPath, previous);\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n await atomicWriteUtf8(targetPath, previous).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Patched ${relPath ?? 'SKILL.md'} (${patched.replacements} replacement(s)).`,\n });\n }\n\n case 'delete': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n rmSync(sk.baseDir, { recursive: true, force: true });\n notify();\n return jsonResult({ success: true, message: `Skill \"${name}\" removed.`, path: sk.baseDir });\n }\n\n case 'write_file': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n const pErr = validateSupportingRelativePath(params.file_path ?? '');\n if (pErr) return jsonResult({ success: false, error: pErr });\n const rel = params.file_path!.trim().replace(/\\\\/g, '/');\n const targetPath = join(sk.baseDir, rel);\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n const body = params.file_content ?? '';\n if (Buffer.byteLength(body, 'utf-8') > supMax) {\n return jsonResult({ success: false, error: `File exceeds size limit (${supMax} bytes).` });\n }\n\n const existed = existsSync(targetPath);\n let previous: string | null = null;\n if (existed) {\n try {\n previous = await readFile(targetPath, 'utf-8');\n } catch {\n previous = null;\n }\n }\n\n try {\n await atomicWriteUtf8(targetPath, body);\n const scanErr = await scanSkillDirOrError(sk.baseDir, name);\n if (scanErr) {\n if (previous !== null) await atomicWriteUtf8(targetPath, previous);\n else await rm(targetPath, { force: true });\n return jsonResult({ success: false, error: scanErr });\n }\n } catch (e) {\n if (previous !== null) await atomicWriteUtf8(targetPath, previous).catch(() => {});\n else await rm(targetPath, { force: true }).catch(() => {});\n throw e;\n }\n\n notify();\n return jsonResult({\n success: true,\n message: `Wrote ${rel}.`,\n });\n }\n\n case 'remove_file': {\n const nameErr = validateSkillNameSegment(params.name ?? '', 'name');\n if (nameErr) return jsonResult({ success: false, error: nameErr });\n const name = params.name!.trim();\n\n const sk = mutatableSkillOrNull(mgr.findSkill(name), workspace, policy);\n if (!sk) {\n return jsonResult({\n success: false,\n error: `Skill \"${name}\" not found or not writable.`,\n });\n }\n\n const pErr = validateSupportingRelativePath(params.file_path ?? '');\n if (pErr) return jsonResult({ success: false, error: pErr });\n const rel = params.file_path!.trim().replace(/\\\\/g, '/');\n const targetPath = join(sk.baseDir, rel);\n if (!isPathInsideDir(sk.baseDir, targetPath)) {\n return jsonResult({ success: false, error: 'Resolved path escapes skill directory.' });\n }\n\n if (!existsSync(targetPath)) {\n return jsonResult({ success: false, error: `File not found: ${rel}` });\n }\n\n await rm(targetPath, { force: true });\n await scanSkillDirOrError(sk.baseDir, name);\n notify();\n return jsonResult({ success: true, message: `Removed ${rel}.` });\n }\n\n default:\n return jsonResult({ success: false, error: 'Unknown action.' });\n }\n } catch (e) {\n return jsonResult({\n success: false,\n error: e instanceof Error ? e.message : String(e),\n });\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -106,7 +106,24 @@ var DelegateSubagentRunner = class {
106
106
  async preparePersistentSubagentSession(sessionKey, metadata) {
107
107
  const store = this.deps.sessionStore;
108
108
  if (!store) return;
109
- await store.resolveTranscriptPath(sessionKey);
109
+ await store.resolveTranscriptPath(sessionKey, { metadata: {
110
+ sessionType: "workflow-subagent",
111
+ hiddenFromSessionList: true,
112
+ parentSessionKey: metadata.parentSessionKey,
113
+ workflowRunId: metadata.workflowRunId,
114
+ workflowDefinitionId: metadata.workflowDefinitionId,
115
+ workflowAgentId: metadata.workflowAgentId,
116
+ workflowAgentLabel: metadata.workflowAgentLabel,
117
+ sourceChannel: "workflow",
118
+ sourceChatId: metadata.workflowRunId,
119
+ routing: {
120
+ agentId: metadata.workflowAgentId || "main",
121
+ source: "workflow",
122
+ accountId: "default",
123
+ peerKind: "subagent",
124
+ peerId: metadata.workflowRunId
125
+ }
126
+ } });
110
127
  await store.updateMetadata(sessionKey, {
111
128
  sessionType: "workflow-subagent",
112
129
  hiddenFromSessionList: true,
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner, SubagentProgressEvent } from './types.js';\n\nconst log = createLogger('Agent:WorkflowSubagent');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n sessionStore?: SessionStore;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n const streamMode = resolveSubagentStreamMode(this.deps.getConfig);\n\n let transcriptPersistQueue: Promise<void> = Promise.resolve();\n const persistTranscriptSnapshot = opts.sessionKey && this.deps.sessionStore\n ? (messages: Parameters<SessionStore['saveMessages']>[1]) => {\n const store = this.deps.sessionStore;\n const key = opts.sessionKey;\n if (!store || !key) return;\n const snapshot = cloneAgentMessages(messages);\n transcriptPersistQueue = transcriptPersistQueue\n .then(async () => {\n await store.saveMessages(key, snapshot);\n emitSessionTranscriptUpdate({ sessionKey: key });\n })\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, sessionKey: key, errorMessage: msg },\n `Failed to persist workflow subagent transcript snapshot: ${msg}`,\n );\n });\n }\n : undefined;\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n progressHooks:\n opts.onProgress && streamMode !== 'off'\n ? {\n mode: streamMode === 'full' ? 'full' : 'steps',\n onProgress: (event) => {\n opts.onProgress?.(mapChildProgressEvent(event));\n },\n }\n : undefined,\n onTranscriptSnapshot: persistTranscriptSnapshot,\n };\n\n if (opts.sessionKey && opts.sessionMetadata && this.deps.sessionStore) {\n await this.preparePersistentSubagentSession(opts.sessionKey, opts.sessionMetadata);\n }\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary, messages } = await handle.run();\n await transcriptPersistQueue;\n if (opts.sessionKey && this.deps.sessionStore) {\n await this.deps.sessionStore.saveMessages(opts.sessionKey, messages);\n emitSessionTranscriptUpdate({ sessionKey: opts.sessionKey });\n }\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n private async preparePersistentSubagentSession(\n sessionKey: string,\n metadata: NonNullable<SubagentRunOptions['sessionMetadata']>,\n ): Promise<void> {\n const store = this.deps.sessionStore;\n if (!store) return;\n await store.resolveTranscriptPath(sessionKey);\n await store.updateMetadata(sessionKey, {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n name: metadata.workflowAgentLabel,\n tags: ['workflow-subagent', metadata.workflowDefinitionId],\n });\n }\n}\n\nfunction cloneAgentMessages(messages: Parameters<SessionStore['saveMessages']>[1]): Parameters<SessionStore['saveMessages']>[1] {\n return messages.map((message) => structuredClone(message));\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n\nfunction resolveSubagentStreamMode(\n getConfig: () => Config | undefined,\n): 'off' | 'steps' | 'full' {\n const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;\n if (mode === 'off' || mode === 'steps' || mode === 'full') return mode;\n return 'steps';\n}\n\nfunction mapChildProgressEvent(event: {\n type: 'tool_start' | 'tool_end' | 'iteration' | 'text_delta' | 'thinking_delta';\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n isError?: boolean;\n resultPreview?: string;\n error?: string;\n count?: number;\n max?: number;\n delta?: string;\n}): SubagentProgressEvent {\n switch (event.type) {\n case 'tool_start':\n return {\n type: 'tool_start',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n args: event.args ?? {},\n };\n case 'tool_end':\n return {\n type: 'tool_end',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n isError: Boolean(event.isError),\n resultPreview: event.resultPreview,\n error: event.error,\n };\n case 'iteration':\n return {\n type: 'iteration',\n count: event.count ?? 0,\n max: event.max ?? 0,\n };\n case 'text_delta':\n return { type: 'text_delta', delta: event.delta ?? '' };\n case 'thinking_delta':\n return { type: 'thinking_delta', delta: event.delta ?? '' };\n default:\n return { type: 'text_delta', delta: '' };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner, SubagentProgressEvent } from './types.js';\n\nconst log = createLogger('Agent:WorkflowSubagent');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n sessionStore?: SessionStore;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n const streamMode = resolveSubagentStreamMode(this.deps.getConfig);\n\n let transcriptPersistQueue: Promise<void> = Promise.resolve();\n const persistTranscriptSnapshot = opts.sessionKey && this.deps.sessionStore\n ? (messages: Parameters<SessionStore['saveMessages']>[1]) => {\n const store = this.deps.sessionStore;\n const key = opts.sessionKey;\n if (!store || !key) return;\n const snapshot = cloneAgentMessages(messages);\n transcriptPersistQueue = transcriptPersistQueue\n .then(async () => {\n await store.saveMessages(key, snapshot);\n emitSessionTranscriptUpdate({ sessionKey: key });\n })\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, sessionKey: key, errorMessage: msg },\n `Failed to persist workflow subagent transcript snapshot: ${msg}`,\n );\n });\n }\n : undefined;\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n progressHooks:\n opts.onProgress && streamMode !== 'off'\n ? {\n mode: streamMode === 'full' ? 'full' : 'steps',\n onProgress: (event) => {\n opts.onProgress?.(mapChildProgressEvent(event));\n },\n }\n : undefined,\n onTranscriptSnapshot: persistTranscriptSnapshot,\n };\n\n if (opts.sessionKey && opts.sessionMetadata && this.deps.sessionStore) {\n await this.preparePersistentSubagentSession(opts.sessionKey, opts.sessionMetadata);\n }\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary, messages } = await handle.run();\n await transcriptPersistQueue;\n if (opts.sessionKey && this.deps.sessionStore) {\n await this.deps.sessionStore.saveMessages(opts.sessionKey, messages);\n emitSessionTranscriptUpdate({ sessionKey: opts.sessionKey });\n }\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n private async preparePersistentSubagentSession(\n sessionKey: string,\n metadata: NonNullable<SubagentRunOptions['sessionMetadata']>,\n ): Promise<void> {\n const store = this.deps.sessionStore;\n if (!store) return;\n await store.resolveTranscriptPath(sessionKey, {\n metadata: {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n sourceChannel: 'workflow',\n sourceChatId: metadata.workflowRunId,\n routing: {\n agentId: metadata.workflowAgentId || 'main',\n source: 'workflow',\n accountId: 'default',\n peerKind: 'subagent',\n peerId: metadata.workflowRunId,\n },\n },\n });\n await store.updateMetadata(sessionKey, {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n name: metadata.workflowAgentLabel,\n tags: ['workflow-subagent', metadata.workflowDefinitionId],\n });\n }\n}\n\nfunction cloneAgentMessages(messages: Parameters<SessionStore['saveMessages']>[1]): Parameters<SessionStore['saveMessages']>[1] {\n return messages.map((message) => structuredClone(message));\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n\nfunction resolveSubagentStreamMode(\n getConfig: () => Config | undefined,\n): 'off' | 'steps' | 'full' {\n const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;\n if (mode === 'off' || mode === 'steps' || mode === 'full') return mode;\n return 'steps';\n}\n\nfunction mapChildProgressEvent(event: {\n type: 'tool_start' | 'tool_end' | 'iteration' | 'text_delta' | 'thinking_delta';\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n isError?: boolean;\n resultPreview?: string;\n error?: string;\n count?: number;\n max?: number;\n delta?: string;\n}): SubagentProgressEvent {\n switch (event.type) {\n case 'tool_start':\n return {\n type: 'tool_start',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n args: event.args ?? {},\n };\n case 'tool_end':\n return {\n type: 'tool_end',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n isError: Boolean(event.isError),\n resultPreview: event.resultPreview,\n error: event.error,\n };\n case 'iteration':\n return {\n type: 'iteration',\n count: event.count ?? 0,\n max: event.max ?? 0,\n };\n case 'text_delta':\n return { type: 'text_delta', delta: event.delta ?? '' };\n case 'thinking_delta':\n return { type: 'thinking_delta', delta: event.delta ?? '' };\n default:\n return { type: 'text_delta', delta: '' };\n }\n}\n"],"mappings":"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"}