@xopcai/xopc 0.0.114 → 0.0.116

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 (328) hide show
  1. package/README.md +5 -4
  2. package/README.zh-CN.md +5 -4
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Fp-p7bP1.js → agent-avatar-dicebear-CWM1UU5P.js} +1 -1
  6. package/dist/gateway/static/root/assets/agent-browser-settings-page-D1SyFYeh.js +6 -0
  7. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-C9YxgvuI.js +1 -0
  8. package/dist/gateway/static/root/assets/agents-CteVs3UO.js +71 -0
  9. package/dist/gateway/static/root/assets/app-management-settings-panel-yXSXY_bu.js +1 -0
  10. package/dist/gateway/static/root/assets/{appearance-settings-ycbdJRuZ.js → appearance-settings-DjY1P_ug.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-CVQ1M8Ax.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-CJzSADJo.js → archive-plugin-CytE5j-e.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-BTAB4zGS.js → attachment-load-BvvrN6rF.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-DXR1-mct.js → binary-plugins-IBWSitnj.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-CzQri9h2.js → block-editor-C-wDpsf-.js} +44 -44
  16. package/dist/gateway/static/root/assets/channels-settings-Cd3JbeQ1.js +1 -0
  17. package/dist/gateway/static/root/assets/{config-api-DRqjEvAx.js → config-api-C4RAtTKW.js} +1 -1
  18. package/dist/gateway/static/root/assets/connectors-page-MsMa5qBr.js +2 -0
  19. package/dist/gateway/static/root/assets/{cron-api-BXaZXv1o.js → cron-api-sJNMqB6P.js} +1 -1
  20. package/dist/gateway/static/root/assets/cron-page-D30CSwkn.js +3 -0
  21. package/dist/gateway/static/root/assets/dreaming-settings-6fCUWRQf.js +1 -0
  22. package/dist/gateway/static/root/assets/{extension-debug-page-DSkqMYo7.js → extension-debug-page-BAIyjDlq.js} +1 -1
  23. package/dist/gateway/static/root/assets/{extension-page-h2dGDbMN.js → extension-page-DEhv2GpC.js} +1 -1
  24. package/dist/gateway/static/root/assets/{extension-settings-page-hN99RhOi.js → extension-settings-page-DOuAxTDW.js} +1 -1
  25. package/dist/gateway/static/root/assets/{fetch-D9QqUtzZ.js → fetch-CTsREQIe.js} +1 -1
  26. package/dist/gateway/static/root/assets/{format-interval-label-D6E687rG.js → format-interval-label-D35Bfhtx.js} +1 -1
  27. package/dist/gateway/static/root/assets/{gateway-config-api-CLt_SKTC.js → gateway-config-api-C6989a-W.js} +1 -1
  28. package/dist/gateway/static/root/assets/gateway-settings-BpF26t91.js +1 -0
  29. package/dist/gateway/static/root/assets/{gateway-startup-retry-N7Z_sz7p.js → gateway-startup-retry-C1KAHrd2.js} +1 -1
  30. package/dist/gateway/static/root/assets/goal-detail-page-DOjhmRyf.js +1 -0
  31. package/dist/gateway/static/root/assets/goals-config-api-KnLGpu6h.js +1 -0
  32. package/dist/gateway/static/root/assets/goals-page-Xl9_wrFc.js +2 -0
  33. package/dist/gateway/static/root/assets/goals-settings-DtPtqZi8.js +1 -0
  34. package/dist/gateway/static/root/assets/{heartbeat-config-api-DGPadTw-.js → heartbeat-config-api-uKw1f0IG.js} +1 -1
  35. package/dist/gateway/static/root/assets/heartbeat-settings-DN9vEj9P.js +1 -0
  36. package/dist/gateway/static/root/assets/index-C8ytlAF2.js +122 -0
  37. package/dist/gateway/static/root/assets/index-CVpJW2NS.css +1 -0
  38. package/dist/gateway/static/root/assets/{interval-presets-CEklPQ_r.js → interval-presets-Dq0FXJ65.js} +1 -1
  39. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Ce_aQ8Iv.js → keyboard-shortcuts-settings-C9_t4m7t.js} +1 -1
  40. package/dist/gateway/static/root/assets/logs-page-SNkWzidV.js +2 -0
  41. package/dist/gateway/static/root/assets/{markdown-split-BMz3xPXO.js → markdown-split-Ca87W8-h.js} +1 -1
  42. package/dist/gateway/static/root/assets/{media-plugins-BalOSoz9.js → media-plugins-BAcUjPRJ.js} +1 -1
  43. package/dist/gateway/static/root/assets/messages-BqzIDrlr.js +3 -0
  44. package/dist/gateway/static/root/assets/models-hub-panel-BO4o-GmO.js +2 -0
  45. package/dist/gateway/static/root/assets/note-detail-page-DLV_XDmT.js +2 -0
  46. package/dist/gateway/static/root/assets/{note-image-lightbox-C5D1Q5mY.js → note-image-lightbox-hnSX5SSn.js} +1 -1
  47. package/dist/gateway/static/root/assets/notes-page-ycsDlkFA.js +1 -0
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CYFR5U9l.js → preview-open-alternatives-CNgM20H5.js} +1 -1
  49. package/dist/gateway/static/root/assets/remote-access-hub-DQpnE8K9.js +1 -0
  50. package/dist/gateway/static/root/assets/{save-bar-controls-BQ79Z5IP.js → save-bar-controls-CcdjGcfT.js} +1 -1
  51. package/dist/gateway/static/root/assets/{schedule-field-Bgk6Emue.js → schedule-field-CYr39z76.js} +1 -1
  52. package/dist/gateway/static/root/assets/{schema-form-DzS36TMa.js → schema-form-BRAJgZQ2.js} +1 -1
  53. package/dist/gateway/static/root/assets/sessions-page-BZui7iAY.js +1 -0
  54. package/dist/gateway/static/root/assets/settings-advanced-gate-DEfzZ1ax.js +1 -0
  55. package/dist/gateway/static/root/assets/{settings-collapsible-section-CdjFnSAy.js → settings-collapsible-section-BhzjeGWi.js} +1 -1
  56. package/dist/gateway/static/root/assets/{settings-form-section-DZLy_exu.js → settings-form-section-Cz3Pcr9b.js} +1 -1
  57. package/dist/gateway/static/root/assets/settings-page-CLuSsu1-.js +1 -0
  58. package/dist/gateway/static/root/assets/setup-status-panel-Cq4qpXLi.js +1 -0
  59. package/dist/gateway/static/root/assets/{share-preview-page-_qRDr4g_.js → share-preview-page-DL4y9K5e.js} +1 -1
  60. package/dist/gateway/static/root/assets/shares-settings-B9F3HyYQ.js +1 -0
  61. package/dist/gateway/static/root/assets/skill-reload-api-Bp9UPPwm.js +1 -0
  62. package/dist/gateway/static/root/assets/skills-page-BIoBsfSV.js +2 -0
  63. package/dist/gateway/static/root/assets/system-settings-panel-FD2jxRZ3.js +1 -0
  64. package/dist/gateway/static/root/assets/use-agent-defaults-form-Cz2_pPzu.js +1 -0
  65. package/dist/gateway/static/root/assets/{use-channel-catalog-CbXq97rT.js → use-channel-catalog-BInPrfR5.js} +1 -1
  66. package/dist/gateway/static/root/assets/{use-settings-tab-guard-DwS3drWK.js → use-settings-tab-guard-nuHMmZQv.js} +1 -1
  67. package/dist/gateway/static/root/assets/voice-api-key-field-BUIrKb8s.js +1 -0
  68. package/dist/gateway/static/root/assets/{voice-player-store-DSuOd9zy.js → voice-player-store-1U3vFppm.js} +1 -1
  69. package/dist/gateway/static/root/assets/workflows-page-qE3SexnO.js +18 -0
  70. package/dist/gateway/static/root/index.html +5 -5
  71. package/dist/gateway/static/root/logo.svg +4 -3
  72. package/dist/package.js +1 -1
  73. package/dist/src/agent/embedded/session-tool-result-guard.js +8 -1
  74. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  75. package/dist/src/agent/goals/checklist-judge.d.ts +2 -0
  76. package/dist/src/agent/goals/checklist-judge.js +4 -3
  77. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  78. package/dist/src/agent/goals/evaluate-turn.d.ts +2 -1
  79. package/dist/src/agent/goals/evaluate-turn.js +2 -0
  80. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  81. package/dist/src/agent/goals/post-turn.d.ts +6 -1
  82. package/dist/src/agent/goals/post-turn.js +20 -4
  83. package/dist/src/agent/goals/post-turn.js.map +1 -1
  84. package/dist/src/agent/image/understanding/pi-ai-provider.js +5 -2
  85. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  86. package/dist/src/agent/image/understanding/provider-registry.d.ts +1 -0
  87. package/dist/src/agent/image/understanding/provider-registry.js +16 -2
  88. package/dist/src/agent/image/understanding/provider-registry.js.map +1 -1
  89. package/dist/src/agent/tools/composio-tool.d.ts +8 -0
  90. package/dist/src/agent/tools/composio-tool.js +46 -0
  91. package/dist/src/agent/tools/composio-tool.js.map +1 -0
  92. package/dist/src/agent/tools/factory.js +13 -8
  93. package/dist/src/agent/tools/factory.js.map +1 -1
  94. package/dist/src/agent/tools/index.d.ts +1 -0
  95. package/dist/src/agent/tools/index.js +2 -1
  96. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  97. package/dist/src/agent/workflow/builtins/audit-repo.js +15 -2
  98. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  99. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +1 -1
  100. package/dist/src/agent/workflow/builtins/client-proposal.js +10 -1
  101. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -1
  102. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +1 -1
  103. package/dist/src/agent/workflow/builtins/competitor-scan.js +16 -2
  104. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -1
  105. package/dist/src/agent/workflow/builtins/content-draft.d.ts +1 -1
  106. package/dist/src/agent/workflow/builtins/content-draft.js +15 -2
  107. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -1
  108. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +1 -1
  109. package/dist/src/agent/workflow/builtins/content-repurpose.js +10 -1
  110. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -1
  111. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  112. package/dist/src/agent/workflow/builtins/debug-incident.js +9 -1
  113. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  114. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +1 -1
  115. package/dist/src/agent/workflow/builtins/decision-compare.js +16 -2
  116. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -1
  117. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +1 -1
  118. package/dist/src/agent/workflow/builtins/implementation-plan.js +11 -1
  119. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -1
  120. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +1 -1
  121. package/dist/src/agent/workflow/builtins/inbox-triage.js +11 -1
  122. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -1
  123. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +1 -1
  124. package/dist/src/agent/workflow/builtins/meeting-prep.js +9 -1
  125. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -1
  126. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  127. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +9 -1
  128. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  129. package/dist/src/agent/workflow/builtins/offer-design.d.ts +1 -1
  130. package/dist/src/agent/workflow/builtins/offer-design.js +10 -1
  131. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -1
  132. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  133. package/dist/src/agent/workflow/builtins/pr-review.js +9 -1
  134. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  135. package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
  136. package/dist/src/agent/workflow/builtins/release-check.js +10 -1
  137. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
  138. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  139. package/dist/src/agent/workflow/builtins/research.js +16 -2
  140. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  141. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +1 -1
  142. package/dist/src/agent/workflow/builtins/weekly-review.js +9 -1
  143. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -1
  144. package/dist/src/agent/workflow/snapshot.d.ts +10 -0
  145. package/dist/src/agent/workflow/snapshot.js +136 -1
  146. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  147. package/dist/src/channels/catalog/channel-catalog-service.d.ts +2 -1
  148. package/dist/src/channels/catalog/channel-catalog-service.js +133 -16
  149. package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
  150. package/dist/src/channels/catalog/channel-catalog-types.d.ts +13 -0
  151. package/dist/src/cli/commands/doctor/checks/channel-config.js +14 -1
  152. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  153. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  154. package/dist/src/config/index.js +2 -2
  155. package/dist/src/config/schema.d.ts +15 -0
  156. package/dist/src/config/schema.js +12 -3
  157. package/dist/src/config/schema.js.map +1 -1
  158. package/dist/src/config/web-patch.d.ts +1 -0
  159. package/dist/src/config/web-patch.js +1 -0
  160. package/dist/src/config/web-patch.js.map +1 -1
  161. package/dist/src/connectors/composio-triggers.d.ts +10 -0
  162. package/dist/src/connectors/composio-triggers.js +32 -0
  163. package/dist/src/connectors/composio-triggers.js.map +1 -0
  164. package/dist/src/connectors/composio.d.ts +54 -0
  165. package/dist/src/connectors/composio.js +334 -0
  166. package/dist/src/connectors/composio.js.map +1 -0
  167. package/dist/src/connectors/health.js +16 -1
  168. package/dist/src/connectors/health.js.map +1 -1
  169. package/dist/src/connectors/install.d.ts +2 -1
  170. package/dist/src/connectors/install.js +50 -13
  171. package/dist/src/connectors/install.js.map +1 -1
  172. package/dist/src/connectors/instances.js +57 -6
  173. package/dist/src/connectors/instances.js.map +1 -1
  174. package/dist/src/connectors/lifecycle.d.ts +3 -0
  175. package/dist/src/connectors/lifecycle.js +23 -0
  176. package/dist/src/connectors/lifecycle.js.map +1 -0
  177. package/dist/src/connectors/materialize.js +2 -1
  178. package/dist/src/connectors/materialize.js.map +1 -1
  179. package/dist/src/connectors/providers.d.ts +1 -0
  180. package/dist/src/connectors/providers.js +10 -2
  181. package/dist/src/connectors/providers.js.map +1 -1
  182. package/dist/src/connectors/registries/modelscope.d.ts +2 -0
  183. package/dist/src/connectors/registries/modelscope.js +205 -0
  184. package/dist/src/connectors/registries/modelscope.js.map +1 -0
  185. package/dist/src/connectors/registries/official-mcp.d.ts +2 -0
  186. package/dist/src/connectors/registries/official-mcp.js +142 -0
  187. package/dist/src/connectors/registries/official-mcp.js.map +1 -0
  188. package/dist/src/connectors/registries/search.d.ts +12 -0
  189. package/dist/src/connectors/registries/search.js +89 -0
  190. package/dist/src/connectors/registries/search.js.map +1 -0
  191. package/dist/src/connectors/registries/smithery.d.ts +2 -0
  192. package/dist/src/connectors/registries/smithery.js +98 -0
  193. package/dist/src/connectors/registries/smithery.js.map +1 -0
  194. package/dist/src/connectors/registries/types.d.ts +20 -0
  195. package/dist/src/connectors/registries/types.js +1 -0
  196. package/dist/src/connectors/secret-store.js +4 -2
  197. package/dist/src/connectors/secret-store.js.map +1 -1
  198. package/dist/src/connectors/setup-secrets.d.ts +15 -0
  199. package/dist/src/connectors/setup-secrets.js +64 -0
  200. package/dist/src/connectors/setup-secrets.js.map +1 -0
  201. package/dist/src/connectors/supervisor.d.ts +15 -0
  202. package/dist/src/connectors/supervisor.js +73 -0
  203. package/dist/src/connectors/supervisor.js.map +1 -0
  204. package/dist/src/connectors/types.d.ts +27 -3
  205. package/dist/src/connectors/usage.js +6 -1
  206. package/dist/src/connectors/usage.js.map +1 -1
  207. package/dist/src/gateway/hono/app.js +5 -1
  208. package/dist/src/gateway/hono/app.js.map +1 -1
  209. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
  210. package/dist/src/gateway/hono/lib/config-payload.js +7 -4
  211. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  212. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
  213. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +19 -5
  214. package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -1
  215. package/dist/src/gateway/hono/routes/channels.js +18 -14
  216. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  217. package/dist/src/gateway/hono/routes/connectors.js +230 -3
  218. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  219. package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
  220. package/dist/src/gateway/hono/routes/goals.js +52 -5
  221. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  222. package/dist/src/gateway/hono/routes/voice.js +14 -1
  223. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  224. package/dist/src/gateway/hono/sse.js.map +1 -1
  225. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  226. package/dist/src/gateway/rate-limit/buckets.js +12 -0
  227. package/dist/src/gateway/rate-limit/buckets.js.map +1 -1
  228. package/dist/src/gateway/service/agent-runner.d.ts +5 -12
  229. package/dist/src/gateway/service/agent-runner.js +8 -8
  230. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  231. package/dist/src/gateway/service/run-gateway-agent.d.ts +2 -10
  232. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  233. package/dist/src/gateway/service.d.ts +1 -1
  234. package/dist/src/gateway/service.js +9 -4
  235. package/dist/src/gateway/service.js.map +1 -1
  236. package/dist/src/gateway/user-turn-input.d.ts +18 -0
  237. package/dist/src/gateway/user-turn-input.js +16 -0
  238. package/dist/src/gateway/user-turn-input.js.map +1 -0
  239. package/dist/src/goals/goal-queue-store.d.ts +2 -1
  240. package/dist/src/goals/goal-queue-store.js +2 -2
  241. package/dist/src/goals/goal-queue-store.js.map +1 -1
  242. package/dist/src/goals/goal-queue-types.d.ts +4 -3
  243. package/dist/src/goals/goal-runner.js +25 -3
  244. package/dist/src/goals/goal-runner.js.map +1 -1
  245. package/dist/src/goals/goal-service.d.ts +6 -1
  246. package/dist/src/goals/goal-service.js +9 -2
  247. package/dist/src/goals/goal-service.js.map +1 -1
  248. package/dist/src/goals/goal-store.d.ts +7 -1
  249. package/dist/src/goals/goal-store.js +42 -0
  250. package/dist/src/goals/goal-store.js.map +1 -1
  251. package/dist/src/goals/types.d.ts +10 -0
  252. package/dist/src/storage/sqlite/migrations/011_goal_context_messages.sql +8 -0
  253. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  254. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  255. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  256. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  257. package/dist/src/storage/sqlite/schema.js +3 -3
  258. package/dist/src/storage/sqlite/schema.sql +9 -0
  259. package/dist/src/tui/backends/embedded-backend.d.ts +8 -1
  260. package/dist/src/tui/backends/embedded-backend.js +73 -0
  261. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  262. package/dist/src/tui/backends/gateway-sse-backend.d.ts +2 -1
  263. package/dist/src/tui/backends/gateway-sse-backend.js +24 -0
  264. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  265. package/dist/src/tui/components/chat-log.d.ts +2 -0
  266. package/dist/src/tui/components/chat-log.js +19 -0
  267. package/dist/src/tui/components/chat-log.js.map +1 -1
  268. package/dist/src/tui/extension-host/autocomplete.d.ts +3 -2
  269. package/dist/src/tui/extension-host/autocomplete.js +17 -3
  270. package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
  271. package/dist/src/tui/extension-host/runtime.d.ts +5 -0
  272. package/dist/src/tui/extension-host/runtime.js +1 -1
  273. package/dist/src/tui/extension-host/runtime.js.map +1 -1
  274. package/dist/src/tui/tui-backend.d.ts +14 -0
  275. package/dist/src/tui/tui-commands.d.ts +16 -3
  276. package/dist/src/tui/tui-commands.js +47 -19
  277. package/dist/src/tui/tui-commands.js.map +1 -1
  278. package/dist/src/tui/tui-startup-text.js +1 -1
  279. package/dist/src/tui/tui-startup-text.js.map +1 -1
  280. package/dist/src/tui/tui.js +72 -1
  281. package/dist/src/tui/tui.js.map +1 -1
  282. package/dist/src/voice/tts/openai-compatible-speech.d.ts +1 -1
  283. package/dist/src/voice/tts/openai-compatible-speech.js.map +1 -1
  284. package/dist/src/voice/tts/providers/edge-speech.js +14 -2
  285. package/dist/src/voice/tts/providers/edge-speech.js.map +1 -1
  286. package/dist/src/voice/tts/speak-core.js +3 -3
  287. package/dist/src/voice/tts/speak-core.js.map +1 -1
  288. package/dist/src/voice/tts/speech-provider-types.d.ts +2 -2
  289. package/dist/src/voice/tts/types.js +1 -1
  290. package/dist/src/voice/tts/types.js.map +1 -1
  291. package/dist/src/workflows/domain/result.d.ts +0 -1
  292. package/dist/src/workflows/engine/workflow-engine.js +7 -23
  293. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  294. package/package.json +2 -2
  295. package/dist/gateway/static/root/assets/agent-browser-settings-page-CWh7trjd.js +0 -6
  296. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-kC8OuLoj.js +0 -1
  297. package/dist/gateway/static/root/assets/agents-DJWG26Si.js +0 -71
  298. package/dist/gateway/static/root/assets/app-management-settings-panel-v24i25Oj.js +0 -1
  299. package/dist/gateway/static/root/assets/apps-page-0V3DXZ7J.js +0 -1
  300. package/dist/gateway/static/root/assets/channels-settings-CIKOkYdO.js +0 -1
  301. package/dist/gateway/static/root/assets/connectors-settings-ClrDS5jH.js +0 -2
  302. package/dist/gateway/static/root/assets/cron-page-Chi_4u4P.js +0 -3
  303. package/dist/gateway/static/root/assets/dreaming-settings-B0_rs2tj.js +0 -1
  304. package/dist/gateway/static/root/assets/gateway-settings-1PDi4lI0.js +0 -1
  305. package/dist/gateway/static/root/assets/goal-detail-page-D_wwXL-t.js +0 -1
  306. package/dist/gateway/static/root/assets/goals-page-DZ2toZ8y.js +0 -2
  307. package/dist/gateway/static/root/assets/goals-settings-LFlwtIKE.js +0 -1
  308. package/dist/gateway/static/root/assets/heartbeat-settings-BHHAs8ZX.js +0 -1
  309. package/dist/gateway/static/root/assets/index-DefIdW9q.js +0 -122
  310. package/dist/gateway/static/root/assets/index-DzmWBkq-.css +0 -1
  311. package/dist/gateway/static/root/assets/logs-page-j_D2QTuQ.js +0 -2
  312. package/dist/gateway/static/root/assets/messages-BN_WiUg0.js +0 -3
  313. package/dist/gateway/static/root/assets/models-hub-panel-CMH_TmZz.js +0 -2
  314. package/dist/gateway/static/root/assets/note-detail-page-O18BrQPq.js +0 -2
  315. package/dist/gateway/static/root/assets/notes-page-B_ZYCmY9.js +0 -1
  316. package/dist/gateway/static/root/assets/remote-access-hub-CwKgWixY.js +0 -1
  317. package/dist/gateway/static/root/assets/sessions-page-C4fcD-7B.js +0 -1
  318. package/dist/gateway/static/root/assets/settings-advanced-gate-Ad2OJ86w.js +0 -1
  319. package/dist/gateway/static/root/assets/settings-page-D2BMY5wo.js +0 -1
  320. package/dist/gateway/static/root/assets/setup-status-panel-aWwxl_E1.js +0 -1
  321. package/dist/gateway/static/root/assets/shares-settings-DUE83uIf.js +0 -1
  322. package/dist/gateway/static/root/assets/skill-reload-api-mWKJcrog.js +0 -1
  323. package/dist/gateway/static/root/assets/skills-page-0Sx1Q58n.js +0 -2
  324. package/dist/gateway/static/root/assets/system-settings-panel-hqaBF5aG.js +0 -1
  325. package/dist/gateway/static/root/assets/use-agent-defaults-form-zbVIQLOA.js +0 -1
  326. package/dist/gateway/static/root/assets/voice-api-key-field-D6HR0hR2.js +0 -1
  327. package/dist/gateway/static/root/assets/workflow-page.utils-C0Uq3xyq.js +0 -1
  328. package/dist/gateway/static/root/assets/workflows-page-DW0fmWhQ.js +0 -18
@@ -1 +1 @@
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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"}
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 createComposioExecuteTool,\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 composioTool = createComposioExecuteTool(() => this.deps.getConfig?.());\n const optionalTools = [imageTool, imageGenerateTool, composioTool].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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"}
@@ -11,6 +11,7 @@ export { findTool, createFindTool, type FindToolInput, type FindToolDetails, } f
11
11
  export { createWebSearchTool, createWebFetchTool } from './web.js';
12
12
  export { createWebExtractTool, stripHtmlBoilerplate, DEFAULT_WEB_EXTRACT_MAX_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, } from './web-extract.js';
13
13
  export { createMessageTool } from './communication.js';
14
+ export { createComposioExecuteTool } from './composio-tool.js';
14
15
  export { createSendMediaTool } from './send-media.js';
15
16
  export { createReadMediaTool } from './media-read-tool.js';
16
17
  export { createCreateShareTool, isShareToolAvailable, type CreateShareToolDeps, } from './create-share-tool.js';
@@ -13,6 +13,7 @@ import { createFindTool, findTool } from "./find.js";
13
13
  import { createWebFetchTool, createWebSearchTool } from "./web.js";
14
14
  import { DEFAULT_WEB_EXTRACT_MAX_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, createWebExtractTool, stripHtmlBoilerplate } from "./web-extract.js";
15
15
  import { createMessageTool } from "./communication.js";
16
+ import { createComposioExecuteTool } from "./composio-tool.js";
16
17
  import { createSendMediaTool } from "./send-media.js";
17
18
  import { createReadMediaTool } from "./media-read-tool.js";
18
19
  import { createCreateShareTool, isShareToolAvailable } from "./create-share-tool.js";
@@ -34,4 +35,4 @@ import { createToolManualTool } from "./tool-manual-tool.js";
34
35
  import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
35
36
  import { createImageTool } from "./image-tool.js";
36
37
  import { createImageGenerateTool, resolveImageGenerationModelConfigForTool } from "./image-generate-tool.js";
37
- export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, assertBrowserUrlAllowed, buildSandboxToolMap, createClarifyTool, createCreateShareTool, createCronjobTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createEditFileTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createShellTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, editFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, restoreLineEndings, scanCronPrompt, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
38
+ export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, assertBrowserUrlAllowed, buildSandboxToolMap, createClarifyTool, createComposioExecuteTool, createCreateShareTool, createCronjobTool, createCuratedMemoryTool, createDelegateTool, createDreamingTool, createEditFileTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createShellTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, editFileTool, findTool, formatSize, fuzzyFindText, generateDiffString, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, restoreLineEndings, scanCronPrompt, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
@@ -10,4 +10,4 @@
10
10
  * - scope: subdirectory to focus on (default '.')
11
11
  * - dimensions: subset of dimension keys, e.g. ['security', 'bugs']
12
12
  */
13
- export declare const AUDIT_REPO_SCRIPT = "export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n examplePrompts: [\n { field: 'goal', text: 'Run a thorough audit of this repository' },\n { field: 'goal', text: 'Review code quality across the whole codebase' },\n ],\n i18n: {\n zh: {\n description: '\u591A\u7EF4\u5EA6\u5E76\u884C\u5BA1\u67E5\u6574\u4E2A\u4ED3\u5E93\uFF0C\u5E76\u6C47\u603B\u4E3A\u7ED3\u6784\u5316\u62A5\u544A\u3002',\n whenToUse: '\u7528\u6237\u9700\u8981\u5BF9\u6574\u5E93\u6216\u4E3B\u8981\u5B50\u7CFB\u7EDF\u505A\u5168\u9762\u3001\u591A\u7EF4\u5EA6\u7684\u4EE3\u7801\u5BA1\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'goal', text: '\u5BF9\u6574\u4E2A\u4ED3\u5E93\u505A\u4E00\u6B21\u5168\u9762\u5BA1\u67E5' },\n { field: 'goal', text: '\u4ECE\u4EE3\u7801\u8D28\u91CF\u7EF4\u5EA6\u5BA1\u67E5\u6574\u4E2A\u4EE3\u7801\u5E93' },\n ],\n },\n },\n tags: ['code-review', 'audit'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir']\n\nconst scope = args && typeof args === 'object' && args.scope\n ? String(args.scope)\n : '.'\n\nconst ALL_DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nlet dimensions = ALL_DIMENSIONS\nif (args && typeof args === 'object' && Array.isArray(args.dimensions) && args.dimensions.length) {\n const keys = new Set(args.dimensions.map((d) => String(d)))\n dimensions = ALL_DIMENSIONS.filter((d) => keys.has(d.key))\n if (!dimensions.length) dimensions = ALL_DIMENSIONS\n}\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository scope: ' + scope + '. ' +\n 'Cover layout, main modules, the 5\u201310 most important files, and obvious entry points. Be terse and structured.',\n { label: 'repo inventory', toolset: READ_ONLY_TOOLS },\n)\n\nphase('Review')\nconst findings = await parallel(\n dimensions.map((d) => () =>\n agent(\n 'Review scope \"' + scope + '\" through the ' + d.key + ' lens.\\n' +\n 'Focus: ' + d.focus + '\\n\\n' +\n 'Inventory for orientation:\\n' + inventory + '\\n\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n return { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }\n}\nconst byDimension = {}\nfor (let i = 0; i < dimensions.length; i++) {\n byDimension[dimensions[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high \u2192 low). Cap topFindings at 20. ' +\n 'Also return priorityActions: the top 5 fixes ranked by impact, each with effort (S|M|L).\\n\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n priorityActions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n effort: { type: 'string', enum: ['S', 'M', 'L'] },\n },\n required: ['file', 'severity', 'title', 'effort'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'priorityActions', 'summary'],\n },\n },\n)\n\nreturn {\n ok: true,\n scope,\n dimensions: dimensions.map((d) => d.key),\n ...(summary ?? { topFindings: [], priorityActions: [], summary: 'synthesis failed' }),\n byDimension,\n}\n";
13
+ export declare const AUDIT_REPO_SCRIPT = "export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n examplePrompts: [\n { field: 'goal', text: 'Run a thorough audit of this repository' },\n { field: 'goal', text: 'Review code quality across the whole codebase' },\n ],\n i18n: {\n zh: {\n description: '\u591A\u7EF4\u5EA6\u5E76\u884C\u5BA1\u67E5\u6574\u4E2A\u4ED3\u5E93\uFF0C\u5E76\u6C47\u603B\u4E3A\u7ED3\u6784\u5316\u62A5\u544A\u3002',\n whenToUse: '\u7528\u6237\u9700\u8981\u5BF9\u6574\u5E93\u6216\u4E3B\u8981\u5B50\u7CFB\u7EDF\u505A\u5168\u9762\u3001\u591A\u7EF4\u5EA6\u7684\u4EE3\u7801\u5BA1\u67E5\u65F6\u3002',\n examplePrompts: [\n { field: 'goal', text: '\u5BF9\u6574\u4E2A\u4ED3\u5E93\u505A\u4E00\u6B21\u5168\u9762\u5BA1\u67E5' },\n { field: 'goal', text: '\u4ECE\u4EE3\u7801\u8D28\u91CF\u7EF4\u5EA6\u5BA1\u67E5\u6574\u4E2A\u4EE3\u7801\u5E93' },\n ],\n },\n },\n tags: ['code-review', 'audit'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir']\n\nconst scope = args && typeof args === 'object' && args.scope\n ? String(args.scope)\n : '.'\n\nconst ALL_DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nlet dimensions = ALL_DIMENSIONS\nif (args && typeof args === 'object' && Array.isArray(args.dimensions) && args.dimensions.length) {\n const keys = new Set(args.dimensions.map((d) => String(d)))\n dimensions = ALL_DIMENSIONS.filter((d) => keys.has(d.key))\n if (!dimensions.length) dimensions = ALL_DIMENSIONS\n}\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository scope: ' + scope + '. ' +\n 'Cover layout, main modules, the 5\u201310 most important files, and obvious entry points. Be terse and structured.',\n { label: 'repo inventory', toolset: READ_ONLY_TOOLS },\n)\n\nphase('Review')\nconst findings = await parallel(\n dimensions.map((d) => () =>\n agent(\n 'Review scope \"' + scope + '\" through the ' + d.key + ' lens.\\n' +\n 'Focus: ' + d.focus + '\\n\\n' +\n 'Inventory for orientation:\\n' + inventory + '\\n\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n const output = { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }\n return {\n summary: output.summary,\n sections: [{ kind: 'json', title: 'Audit result', value: output }],\n structuredOutput: output,\n }\n}\nconst byDimension = {}\nfor (let i = 0; i < dimensions.length; i++) {\n byDimension[dimensions[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high \u2192 low). Cap topFindings at 20. ' +\n 'Also return priorityActions: the top 5 fixes ranked by impact, each with effort (S|M|L).\\n\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n priorityActions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n effort: { type: 'string', enum: ['S', 'M', 'L'] },\n },\n required: ['file', 'severity', 'title', 'effort'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'priorityActions', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n scope,\n dimensions: dimensions.map((d) => d.key),\n ...(summary ?? { topFindings: [], priorityActions: [], summary: 'synthesis failed' }),\n byDimension,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Top findings', items: output.topFindings.map((item) => ({ title: item.title, severity: item.severity, file: item.file, detail: item.fix })) },\n { kind: 'json', title: 'Priority actions', value: output.priorityActions },\n ],\n structuredOutput: output,\n}\n";
@@ -105,7 +105,12 @@ const findings = await parallel(
105
105
  phase('Synthesize')
106
106
  const live = findings.filter(Boolean)
107
107
  if (!live.length) {
108
- return { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }
108
+ const output = { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }
109
+ return {
110
+ summary: output.summary,
111
+ sections: [{ kind: 'json', title: 'Audit result', value: output }],
112
+ structuredOutput: output,
113
+ }
109
114
  }
110
115
  const byDimension = {}
111
116
  for (let i = 0; i < dimensions.length; i++) {
@@ -156,13 +161,21 @@ const summary = await agent(
156
161
  },
157
162
  )
158
163
 
159
- return {
164
+ const output = {
160
165
  ok: true,
161
166
  scope,
162
167
  dimensions: dimensions.map((d) => d.key),
163
168
  ...(summary ?? { topFindings: [], priorityActions: [], summary: 'synthesis failed' }),
164
169
  byDimension,
165
170
  }
171
+ return {
172
+ summary: output.summary,
173
+ sections: [
174
+ { kind: 'findings', title: 'Top findings', items: output.topFindings.map((item) => ({ title: item.title, severity: item.severity, file: item.file, detail: item.fix })) },
175
+ { kind: 'json', title: 'Priority actions', value: output.priorityActions },
176
+ ],
177
+ structuredOutput: output,
178
+ }
166
179
  `;
167
180
  //#endregion
168
181
  export { AUDIT_REPO_SCRIPT };
@@ -1 +1 @@
1
- {"version":3,"file":"audit-repo.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/audit-repo.ts"],"sourcesContent":["/**\n * Built-in workflow: `audit_repo`\n *\n * Fan-out repo audit. Phase 1 inventories the repo; phase 2 spawns N reviewers\n * in parallel, one per dimension (bugs / perf / security / tests / style);\n * phase 3 synthesises into a structured report. The script is kept readable so\n * users can copy it into `~/.xopc/workflows/` as a starting point.\n *\n * Args:\n * - scope: subdirectory to focus on (default '.')\n * - dimensions: subset of dimension keys, e.g. ['security', 'bugs']\n */\n\nexport const AUDIT_REPO_SCRIPT = `export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n examplePrompts: [\n { field: 'goal', text: 'Run a thorough audit of this repository' },\n { field: 'goal', text: 'Review code quality across the whole codebase' },\n ],\n i18n: {\n zh: {\n description: '多维度并行审查整个仓库,并汇总为结构化报告。',\n whenToUse: '用户需要对整库或主要子系统做全面、多维度的代码审查时。',\n examplePrompts: [\n { field: 'goal', text: '对整个仓库做一次全面审查' },\n { field: 'goal', text: '从代码质量维度审查整个代码库' },\n ],\n },\n },\n tags: ['code-review', 'audit'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir']\n\nconst scope = args && typeof args === 'object' && args.scope\n ? String(args.scope)\n : '.'\n\nconst ALL_DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nlet dimensions = ALL_DIMENSIONS\nif (args && typeof args === 'object' && Array.isArray(args.dimensions) && args.dimensions.length) {\n const keys = new Set(args.dimensions.map((d) => String(d)))\n dimensions = ALL_DIMENSIONS.filter((d) => keys.has(d.key))\n if (!dimensions.length) dimensions = ALL_DIMENSIONS\n}\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository scope: ' + scope + '. ' +\n 'Cover layout, main modules, the 5–10 most important files, and obvious entry points. Be terse and structured.',\n { label: 'repo inventory', toolset: READ_ONLY_TOOLS },\n)\n\nphase('Review')\nconst findings = await parallel(\n dimensions.map((d) => () =>\n agent(\n 'Review scope \"' + scope + '\" through the ' + d.key + ' lens.\\\\n' +\n 'Focus: ' + d.focus + '\\\\n\\\\n' +\n 'Inventory for orientation:\\\\n' + inventory + '\\\\n\\\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n return { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }\n}\nconst byDimension = {}\nfor (let i = 0; i < dimensions.length; i++) {\n byDimension[dimensions[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high → low). Cap topFindings at 20. ' +\n 'Also return priorityActions: the top 5 fixes ranked by impact, each with effort (S|M|L).\\\\n\\\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n priorityActions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n effort: { type: 'string', enum: ['S', 'M', 'L'] },\n },\n required: ['file', 'severity', 'title', 'effort'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'priorityActions', 'summary'],\n },\n },\n)\n\nreturn {\n ok: true,\n scope,\n dimensions: dimensions.map((d) => d.key),\n ...(summary ?? { topFindings: [], priorityActions: [], summary: 'synthesis failed' }),\n byDimension,\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,oBAAoB"}
1
+ {"version":3,"file":"audit-repo.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/audit-repo.ts"],"sourcesContent":["/**\n * Built-in workflow: `audit_repo`\n *\n * Fan-out repo audit. Phase 1 inventories the repo; phase 2 spawns N reviewers\n * in parallel, one per dimension (bugs / perf / security / tests / style);\n * phase 3 synthesises into a structured report. The script is kept readable so\n * users can copy it into `~/.xopc/workflows/` as a starting point.\n *\n * Args:\n * - scope: subdirectory to focus on (default '.')\n * - dimensions: subset of dimension keys, e.g. ['security', 'bugs']\n */\n\nexport const AUDIT_REPO_SCRIPT = `export const meta = {\n name: 'audit_repo',\n description: 'Fan-out repository audit across multiple dimensions, then synthesize a structured report.',\n whenToUse: 'User asks for a thorough / multi-dimension code review of the whole repo or a major subsystem.',\n examplePrompts: [\n { field: 'goal', text: 'Run a thorough audit of this repository' },\n { field: 'goal', text: 'Review code quality across the whole codebase' },\n ],\n i18n: {\n zh: {\n description: '多维度并行审查整个仓库,并汇总为结构化报告。',\n whenToUse: '用户需要对整库或主要子系统做全面、多维度的代码审查时。',\n examplePrompts: [\n { field: 'goal', text: '对整个仓库做一次全面审查' },\n { field: 'goal', text: '从代码质量维度审查整个代码库' },\n ],\n },\n },\n tags: ['code-review', 'audit'],\n estimatedAgents: { min: 7, max: 7 },\n phases: [\n { title: 'Inventory' },\n { title: 'Review' },\n { title: 'Synthesize' },\n ],\n}\n\nconst READ_ONLY_TOOLS = ['read_file', 'grep', 'find', 'list_dir']\n\nconst scope = args && typeof args === 'object' && args.scope\n ? String(args.scope)\n : '.'\n\nconst ALL_DIMENSIONS = [\n { key: 'bugs', focus: 'Correctness bugs, null-safety, error handling, race conditions, off-by-one, dead code.' },\n { key: 'perf', focus: 'Performance issues, hot paths, N+1 patterns, accidental quadratic loops, sync I/O, missing caching.' },\n { key: 'security', focus: 'Auth/authz, input validation, secret handling, injection sinks, unsafe deserialization, SSRF.' },\n { key: 'tests', focus: 'Test coverage gaps, brittle tests, integration vs unit gaps, missing regression cases.' },\n { key: 'style', focus: 'Inconsistent conventions, naming, unused exports, duplication, layering violations.' },\n]\n\nlet dimensions = ALL_DIMENSIONS\nif (args && typeof args === 'object' && Array.isArray(args.dimensions) && args.dimensions.length) {\n const keys = new Set(args.dimensions.map((d) => String(d)))\n dimensions = ALL_DIMENSIONS.filter((d) => keys.has(d.key))\n if (!dimensions.length) dimensions = ALL_DIMENSIONS\n}\n\nphase('Inventory')\nconst inventory = await agent(\n 'Produce a compact map of this repository scope: ' + scope + '. ' +\n 'Cover layout, main modules, the 5–10 most important files, and obvious entry points. Be terse and structured.',\n { label: 'repo inventory', toolset: READ_ONLY_TOOLS },\n)\n\nphase('Review')\nconst findings = await parallel(\n dimensions.map((d) => () =>\n agent(\n 'Review scope \"' + scope + '\" through the ' + d.key + ' lens.\\\\n' +\n 'Focus: ' + d.focus + '\\\\n\\\\n' +\n 'Inventory for orientation:\\\\n' + inventory + '\\\\n\\\\n' +\n 'Return findings: file paths, line numbers when known, severity (low/med/high), a one-sentence why, a one-sentence fix.',\n {\n label: d.key + ' review',\n toolset: READ_ONLY_TOOLS,\n schema: {\n type: 'object',\n properties: {\n findings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n line: { type: ['number', 'string'] },\n severity: { type: 'string', enum: ['low', 'med', 'high'] },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['file', 'severity', 'title', 'fix'],\n },\n },\n },\n required: ['findings'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst live = findings.filter(Boolean)\nif (!live.length) {\n const output = { ok: true, scope, summary: 'No findings.', byDimension: {}, priorityActions: [] }\n return {\n summary: output.summary,\n sections: [{ kind: 'json', title: 'Audit result', value: output }],\n structuredOutput: output,\n }\n}\nconst byDimension = {}\nfor (let i = 0; i < dimensions.length; i++) {\n byDimension[dimensions[i].key] = live[i]?.findings ?? []\n}\n\nconst summary = await agent(\n 'Synthesize a compact report from these per-dimension findings. Deduplicate near-identical items. ' +\n 'Order by severity (high → low). Cap topFindings at 20. ' +\n 'Also return priorityActions: the top 5 fixes ranked by impact, each with effort (S|M|L).\\\\n\\\\n' +\n JSON.stringify(byDimension, null, 2),\n {\n label: 'report synthesis',\n schema: {\n type: 'object',\n properties: {\n topFindings: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n dimension: { type: 'string' },\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n fix: { type: 'string' },\n },\n required: ['dimension', 'file', 'severity', 'title'],\n },\n },\n priorityActions: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file: { type: 'string' },\n severity: { type: 'string' },\n title: { type: 'string' },\n effort: { type: 'string', enum: ['S', 'M', 'L'] },\n },\n required: ['file', 'severity', 'title', 'effort'],\n },\n },\n summary: { type: 'string' },\n },\n required: ['topFindings', 'priorityActions', 'summary'],\n },\n },\n)\n\nconst output = {\n ok: true,\n scope,\n dimensions: dimensions.map((d) => d.key),\n ...(summary ?? { topFindings: [], priorityActions: [], summary: 'synthesis failed' }),\n byDimension,\n}\nreturn {\n summary: output.summary,\n sections: [\n { kind: 'findings', title: 'Top findings', items: output.topFindings.map((item) => ({ title: item.title, severity: item.severity, file: item.file, detail: item.fix })) },\n { kind: 'json', title: 'Priority actions', value: output.priorityActions },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,oBAAoB"}
@@ -9,4 +9,4 @@
9
9
  * - offer: what you provide
10
10
  * - budget_hint: budget range or constraints (optional)
11
11
  */
12
- export declare const CLIENT_PROPOSAL_SCRIPT = "export const meta = {\n name: 'client_proposal',\n description: 'Turn a client brief into a structured proposal with scope, timeline, pricing logic, and risks.',\n whenToUse: 'Freelancer or solo consultant needs a client-ready proposal or SOW draft.',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS startup wants 3-month growth consulting, budget 50\u201380k CNY' },\n { field: 'offer', text: 'Audit funnel, weekly strategy calls, async Slack support' },\n ],\n i18n: {\n zh: {\n description: '\u5C06\u5BA2\u6237\u9700\u6C42\u8F6C\u5316\u4E3A\u542B\u8303\u56F4\u3001\u65F6\u95F4\u7EBF\u3001\u62A5\u4EF7\u903B\u8F91\u4E0E\u98CE\u9669\u8BF4\u660E\u7684\u5BA2\u6237\u65B9\u6848\u3002',\n whenToUse: '\u81EA\u7531\u804C\u4E1A\u8005\u6216\u72EC\u7ACB\u987E\u95EE\u9700\u8981\u8D77\u8349\u5BA2\u6237\u65B9\u6848 / SOW \u65F6\u3002',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS \u521B\u4E1A\u516C\u53F8\u8981 3 \u4E2A\u6708\u589E\u957F\u54A8\u8BE2\uFF0C\u9884\u7B97 5\u20138 \u4E07' },\n { field: 'offer', text: '\u6F0F\u6597\u5BA1\u8BA1\u3001\u6BCF\u5468\u7B56\u7565\u4F1A\u3001Slack \u5F02\u6B65\u652F\u6301' },\n ],\n },\n },\n tags: ['writing', 'content', 'document'],\n estimatedAgents: { min: 4, max: 5 },\n phases: [\n { title: 'Understand' },\n { title: 'Structure' },\n { title: 'Draft' },\n { title: 'Polish' },\n ],\n}\n\nconst clientBrief = args && typeof args === 'object' && args.client_brief\n ? String(args.client_brief)\n : 'Infer the client brief from the most recent user turn.'\n\nconst offer = args && typeof args === 'object' && args.offer\n ? String(args.offer)\n : 'Infer your offer from context.'\n\nconst budgetHint = args && typeof args === 'object' && args.budget_hint\n ? String(args.budget_hint)\n : ''\n\nphase('Understand')\nconst understanding = await agent(\n 'Extract client needs, implicit constraints, success criteria, red flags, and what is out of scope.\\n\\n' +\n 'CLIENT BRIEF:\\n' + clientBrief + '\\nYOUR OFFER:\\n' + offer +\n (budgetHint ? '\\nBUDGET HINT:\\n' + budgetHint : ''),\n {\n label: 'understand',\n schema: {\n type: 'object',\n properties: {\n clientGoals: { type: 'array', items: { type: 'string' } },\n constraints: { type: 'array', items: { type: 'string' } },\n successCriteria: { type: 'array', items: { type: 'string' } },\n redFlags: { type: 'array', items: { type: 'string' } },\n outOfScope: { type: 'array', items: { type: 'string' } },\n },\n required: ['clientGoals', 'successCriteria'],\n },\n },\n)\n\nphase('Structure')\nconst structure = await agent(\n 'Design proposal structure: deliverables, milestones, timeline, pricing tiers or logic, assumptions, and exclusions. Fit a solo operator capacity.\\n\\n' +\n JSON.stringify({ clientBrief, offer, budgetHint, understanding }, null, 2),\n {\n label: 'structure',\n schema: {\n type: 'object',\n properties: {\n deliverables: { type: 'array', items: { type: 'string' } },\n milestones: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n duration: { type: 'string' },\n output: { type: 'string' },\n },\n required: ['name', 'output'],\n },\n },\n pricingApproach: { type: 'string' },\n assumptions: { type: 'array', items: { type: 'string' } },\n },\n required: ['deliverables', 'milestones', 'pricingApproach'],\n },\n },\n)\n\nphase('Draft')\nconst draft = await agent(\n 'Write a client-ready proposal draft in professional but warm tone. Include executive summary, scope, timeline, pricing section (with rationale), risks, and next steps.\\n\\n' +\n JSON.stringify({ understanding, structure }, null, 2),\n {\n label: 'draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n executiveSummary: { type: 'string' },\n scope: { type: 'string' },\n timeline: { type: 'string' },\n pricing: { type: 'string' },\n risks: { type: 'array', items: { type: 'string' } },\n nextSteps: { type: 'array', items: { type: 'string' } },\n },\n required: ['executiveSummary', 'scope', 'pricing', 'nextSteps'],\n },\n },\n)\n\nphase('Polish')\nconst polished = await agent(\n 'Polish the proposal: tighten language, add a one-line value prop, flag anything that could scare the client, and suggest 2 negotiation flex points.\\n\\n' +\n JSON.stringify(draft, null, 2),\n {\n label: 'polish',\n schema: {\n type: 'object',\n properties: {\n valueProp: { type: 'string' },\n fullProposal: { type: 'string' },\n clientConcerns: { type: 'array', items: { type: 'string' } },\n flexPoints: { type: 'array', items: { type: 'string' } },\n },\n required: ['valueProp', 'fullProposal'],\n },\n },\n)\n\nreturn {\n ok: true,\n understanding,\n structure,\n ...(polished ?? { valueProp: '', fullProposal: 'draft failed' }),\n}\n";
12
+ export declare const CLIENT_PROPOSAL_SCRIPT = "export const meta = {\n name: 'client_proposal',\n description: 'Turn a client brief into a structured proposal with scope, timeline, pricing logic, and risks.',\n whenToUse: 'Freelancer or solo consultant needs a client-ready proposal or SOW draft.',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS startup wants 3-month growth consulting, budget 50\u201380k CNY' },\n { field: 'offer', text: 'Audit funnel, weekly strategy calls, async Slack support' },\n ],\n i18n: {\n zh: {\n description: '\u5C06\u5BA2\u6237\u9700\u6C42\u8F6C\u5316\u4E3A\u542B\u8303\u56F4\u3001\u65F6\u95F4\u7EBF\u3001\u62A5\u4EF7\u903B\u8F91\u4E0E\u98CE\u9669\u8BF4\u660E\u7684\u5BA2\u6237\u65B9\u6848\u3002',\n whenToUse: '\u81EA\u7531\u804C\u4E1A\u8005\u6216\u72EC\u7ACB\u987E\u95EE\u9700\u8981\u8D77\u8349\u5BA2\u6237\u65B9\u6848 / SOW \u65F6\u3002',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS \u521B\u4E1A\u516C\u53F8\u8981 3 \u4E2A\u6708\u589E\u957F\u54A8\u8BE2\uFF0C\u9884\u7B97 5\u20138 \u4E07' },\n { field: 'offer', text: '\u6F0F\u6597\u5BA1\u8BA1\u3001\u6BCF\u5468\u7B56\u7565\u4F1A\u3001Slack \u5F02\u6B65\u652F\u6301' },\n ],\n },\n },\n tags: ['writing', 'content', 'document'],\n estimatedAgents: { min: 4, max: 5 },\n phases: [\n { title: 'Understand' },\n { title: 'Structure' },\n { title: 'Draft' },\n { title: 'Polish' },\n ],\n}\n\nconst clientBrief = args && typeof args === 'object' && args.client_brief\n ? String(args.client_brief)\n : 'Infer the client brief from the most recent user turn.'\n\nconst offer = args && typeof args === 'object' && args.offer\n ? String(args.offer)\n : 'Infer your offer from context.'\n\nconst budgetHint = args && typeof args === 'object' && args.budget_hint\n ? String(args.budget_hint)\n : ''\n\nphase('Understand')\nconst understanding = await agent(\n 'Extract client needs, implicit constraints, success criteria, red flags, and what is out of scope.\\n\\n' +\n 'CLIENT BRIEF:\\n' + clientBrief + '\\nYOUR OFFER:\\n' + offer +\n (budgetHint ? '\\nBUDGET HINT:\\n' + budgetHint : ''),\n {\n label: 'understand',\n schema: {\n type: 'object',\n properties: {\n clientGoals: { type: 'array', items: { type: 'string' } },\n constraints: { type: 'array', items: { type: 'string' } },\n successCriteria: { type: 'array', items: { type: 'string' } },\n redFlags: { type: 'array', items: { type: 'string' } },\n outOfScope: { type: 'array', items: { type: 'string' } },\n },\n required: ['clientGoals', 'successCriteria'],\n },\n },\n)\n\nphase('Structure')\nconst structure = await agent(\n 'Design proposal structure: deliverables, milestones, timeline, pricing tiers or logic, assumptions, and exclusions. Fit a solo operator capacity.\\n\\n' +\n JSON.stringify({ clientBrief, offer, budgetHint, understanding }, null, 2),\n {\n label: 'structure',\n schema: {\n type: 'object',\n properties: {\n deliverables: { type: 'array', items: { type: 'string' } },\n milestones: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n duration: { type: 'string' },\n output: { type: 'string' },\n },\n required: ['name', 'output'],\n },\n },\n pricingApproach: { type: 'string' },\n assumptions: { type: 'array', items: { type: 'string' } },\n },\n required: ['deliverables', 'milestones', 'pricingApproach'],\n },\n },\n)\n\nphase('Draft')\nconst draft = await agent(\n 'Write a client-ready proposal draft in professional but warm tone. Include executive summary, scope, timeline, pricing section (with rationale), risks, and next steps.\\n\\n' +\n JSON.stringify({ understanding, structure }, null, 2),\n {\n label: 'draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n executiveSummary: { type: 'string' },\n scope: { type: 'string' },\n timeline: { type: 'string' },\n pricing: { type: 'string' },\n risks: { type: 'array', items: { type: 'string' } },\n nextSteps: { type: 'array', items: { type: 'string' } },\n },\n required: ['executiveSummary', 'scope', 'pricing', 'nextSteps'],\n },\n },\n)\n\nphase('Polish')\nconst polished = await agent(\n 'Polish the proposal: tighten language, add a one-line value prop, flag anything that could scare the client, and suggest 2 negotiation flex points.\\n\\n' +\n JSON.stringify(draft, null, 2),\n {\n label: 'polish',\n schema: {\n type: 'object',\n properties: {\n valueProp: { type: 'string' },\n fullProposal: { type: 'string' },\n clientConcerns: { type: 'array', items: { type: 'string' } },\n flexPoints: { type: 'array', items: { type: 'string' } },\n },\n required: ['valueProp', 'fullProposal'],\n },\n },\n)\n\nconst output = {\n ok: true,\n understanding,\n structure,\n ...(polished ?? { valueProp: '', fullProposal: 'draft failed' }),\n}\nreturn {\n summary: output.valueProp || 'Proposal draft complete.',\n sections: [\n { kind: 'text', title: 'Proposal', content: output.fullProposal },\n { kind: 'questions', title: 'Client concerns', items: output.clientConcerns ?? [] },\n { kind: 'questions', title: 'Flex points', items: output.flexPoints ?? [] },\n ],\n structuredOutput: output,\n}\n";
@@ -142,12 +142,21 @@ const polished = await agent(
142
142
  },
143
143
  )
144
144
 
145
- return {
145
+ const output = {
146
146
  ok: true,
147
147
  understanding,
148
148
  structure,
149
149
  ...(polished ?? { valueProp: '', fullProposal: 'draft failed' }),
150
150
  }
151
+ return {
152
+ summary: output.valueProp || 'Proposal draft complete.',
153
+ sections: [
154
+ { kind: 'text', title: 'Proposal', content: output.fullProposal },
155
+ { kind: 'questions', title: 'Client concerns', items: output.clientConcerns ?? [] },
156
+ { kind: 'questions', title: 'Flex points', items: output.flexPoints ?? [] },
157
+ ],
158
+ structuredOutput: output,
159
+ }
151
160
  `;
152
161
  //#endregion
153
162
  export { CLIENT_PROPOSAL_SCRIPT };
@@ -1 +1 @@
1
- {"version":3,"file":"client-proposal.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/client-proposal.ts"],"sourcesContent":["/**\n * Built-in workflow: `client_proposal`\n *\n * Draft a client-facing proposal from a brief — scope, timeline, pricing logic,\n * risks, and next steps. For freelancers, consultants, and solo service providers.\n *\n * Args:\n * - client_brief: what the client wants\n * - offer: what you provide\n * - budget_hint: budget range or constraints (optional)\n */\n\nexport const CLIENT_PROPOSAL_SCRIPT = `export const meta = {\n name: 'client_proposal',\n description: 'Turn a client brief into a structured proposal with scope, timeline, pricing logic, and risks.',\n whenToUse: 'Freelancer or solo consultant needs a client-ready proposal or SOW draft.',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS startup wants 3-month growth consulting, budget 50–80k CNY' },\n { field: 'offer', text: 'Audit funnel, weekly strategy calls, async Slack support' },\n ],\n i18n: {\n zh: {\n description: '将客户需求转化为含范围、时间线、报价逻辑与风险说明的客户方案。',\n whenToUse: '自由职业者或独立顾问需要起草客户方案 / SOW 时。',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS 创业公司要 3 个月增长咨询,预算 5–8 万' },\n { field: 'offer', text: '漏斗审计、每周策略会、Slack 异步支持' },\n ],\n },\n },\n tags: ['writing', 'content', 'document'],\n estimatedAgents: { min: 4, max: 5 },\n phases: [\n { title: 'Understand' },\n { title: 'Structure' },\n { title: 'Draft' },\n { title: 'Polish' },\n ],\n}\n\nconst clientBrief = args && typeof args === 'object' && args.client_brief\n ? String(args.client_brief)\n : 'Infer the client brief from the most recent user turn.'\n\nconst offer = args && typeof args === 'object' && args.offer\n ? String(args.offer)\n : 'Infer your offer from context.'\n\nconst budgetHint = args && typeof args === 'object' && args.budget_hint\n ? String(args.budget_hint)\n : ''\n\nphase('Understand')\nconst understanding = await agent(\n 'Extract client needs, implicit constraints, success criteria, red flags, and what is out of scope.\\\\n\\\\n' +\n 'CLIENT BRIEF:\\\\n' + clientBrief + '\\\\nYOUR OFFER:\\\\n' + offer +\n (budgetHint ? '\\\\nBUDGET HINT:\\\\n' + budgetHint : ''),\n {\n label: 'understand',\n schema: {\n type: 'object',\n properties: {\n clientGoals: { type: 'array', items: { type: 'string' } },\n constraints: { type: 'array', items: { type: 'string' } },\n successCriteria: { type: 'array', items: { type: 'string' } },\n redFlags: { type: 'array', items: { type: 'string' } },\n outOfScope: { type: 'array', items: { type: 'string' } },\n },\n required: ['clientGoals', 'successCriteria'],\n },\n },\n)\n\nphase('Structure')\nconst structure = await agent(\n 'Design proposal structure: deliverables, milestones, timeline, pricing tiers or logic, assumptions, and exclusions. Fit a solo operator capacity.\\\\n\\\\n' +\n JSON.stringify({ clientBrief, offer, budgetHint, understanding }, null, 2),\n {\n label: 'structure',\n schema: {\n type: 'object',\n properties: {\n deliverables: { type: 'array', items: { type: 'string' } },\n milestones: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n duration: { type: 'string' },\n output: { type: 'string' },\n },\n required: ['name', 'output'],\n },\n },\n pricingApproach: { type: 'string' },\n assumptions: { type: 'array', items: { type: 'string' } },\n },\n required: ['deliverables', 'milestones', 'pricingApproach'],\n },\n },\n)\n\nphase('Draft')\nconst draft = await agent(\n 'Write a client-ready proposal draft in professional but warm tone. Include executive summary, scope, timeline, pricing section (with rationale), risks, and next steps.\\\\n\\\\n' +\n JSON.stringify({ understanding, structure }, null, 2),\n {\n label: 'draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n executiveSummary: { type: 'string' },\n scope: { type: 'string' },\n timeline: { type: 'string' },\n pricing: { type: 'string' },\n risks: { type: 'array', items: { type: 'string' } },\n nextSteps: { type: 'array', items: { type: 'string' } },\n },\n required: ['executiveSummary', 'scope', 'pricing', 'nextSteps'],\n },\n },\n)\n\nphase('Polish')\nconst polished = await agent(\n 'Polish the proposal: tighten language, add a one-line value prop, flag anything that could scare the client, and suggest 2 negotiation flex points.\\\\n\\\\n' +\n JSON.stringify(draft, null, 2),\n {\n label: 'polish',\n schema: {\n type: 'object',\n properties: {\n valueProp: { type: 'string' },\n fullProposal: { type: 'string' },\n clientConcerns: { type: 'array', items: { type: 'string' } },\n flexPoints: { type: 'array', items: { type: 'string' } },\n },\n required: ['valueProp', 'fullProposal'],\n },\n },\n)\n\nreturn {\n ok: true,\n understanding,\n structure,\n ...(polished ?? { valueProp: '', fullProposal: 'draft failed' }),\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,yBAAyB"}
1
+ {"version":3,"file":"client-proposal.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/client-proposal.ts"],"sourcesContent":["/**\n * Built-in workflow: `client_proposal`\n *\n * Draft a client-facing proposal from a brief — scope, timeline, pricing logic,\n * risks, and next steps. For freelancers, consultants, and solo service providers.\n *\n * Args:\n * - client_brief: what the client wants\n * - offer: what you provide\n * - budget_hint: budget range or constraints (optional)\n */\n\nexport const CLIENT_PROPOSAL_SCRIPT = `export const meta = {\n name: 'client_proposal',\n description: 'Turn a client brief into a structured proposal with scope, timeline, pricing logic, and risks.',\n whenToUse: 'Freelancer or solo consultant needs a client-ready proposal or SOW draft.',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS startup wants 3-month growth consulting, budget 50–80k CNY' },\n { field: 'offer', text: 'Audit funnel, weekly strategy calls, async Slack support' },\n ],\n i18n: {\n zh: {\n description: '将客户需求转化为含范围、时间线、报价逻辑与风险说明的客户方案。',\n whenToUse: '自由职业者或独立顾问需要起草客户方案 / SOW 时。',\n examplePrompts: [\n { field: 'client_brief', text: 'SaaS 创业公司要 3 个月增长咨询,预算 5–8 万' },\n { field: 'offer', text: '漏斗审计、每周策略会、Slack 异步支持' },\n ],\n },\n },\n tags: ['writing', 'content', 'document'],\n estimatedAgents: { min: 4, max: 5 },\n phases: [\n { title: 'Understand' },\n { title: 'Structure' },\n { title: 'Draft' },\n { title: 'Polish' },\n ],\n}\n\nconst clientBrief = args && typeof args === 'object' && args.client_brief\n ? String(args.client_brief)\n : 'Infer the client brief from the most recent user turn.'\n\nconst offer = args && typeof args === 'object' && args.offer\n ? String(args.offer)\n : 'Infer your offer from context.'\n\nconst budgetHint = args && typeof args === 'object' && args.budget_hint\n ? String(args.budget_hint)\n : ''\n\nphase('Understand')\nconst understanding = await agent(\n 'Extract client needs, implicit constraints, success criteria, red flags, and what is out of scope.\\\\n\\\\n' +\n 'CLIENT BRIEF:\\\\n' + clientBrief + '\\\\nYOUR OFFER:\\\\n' + offer +\n (budgetHint ? '\\\\nBUDGET HINT:\\\\n' + budgetHint : ''),\n {\n label: 'understand',\n schema: {\n type: 'object',\n properties: {\n clientGoals: { type: 'array', items: { type: 'string' } },\n constraints: { type: 'array', items: { type: 'string' } },\n successCriteria: { type: 'array', items: { type: 'string' } },\n redFlags: { type: 'array', items: { type: 'string' } },\n outOfScope: { type: 'array', items: { type: 'string' } },\n },\n required: ['clientGoals', 'successCriteria'],\n },\n },\n)\n\nphase('Structure')\nconst structure = await agent(\n 'Design proposal structure: deliverables, milestones, timeline, pricing tiers or logic, assumptions, and exclusions. Fit a solo operator capacity.\\\\n\\\\n' +\n JSON.stringify({ clientBrief, offer, budgetHint, understanding }, null, 2),\n {\n label: 'structure',\n schema: {\n type: 'object',\n properties: {\n deliverables: { type: 'array', items: { type: 'string' } },\n milestones: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n duration: { type: 'string' },\n output: { type: 'string' },\n },\n required: ['name', 'output'],\n },\n },\n pricingApproach: { type: 'string' },\n assumptions: { type: 'array', items: { type: 'string' } },\n },\n required: ['deliverables', 'milestones', 'pricingApproach'],\n },\n },\n)\n\nphase('Draft')\nconst draft = await agent(\n 'Write a client-ready proposal draft in professional but warm tone. Include executive summary, scope, timeline, pricing section (with rationale), risks, and next steps.\\\\n\\\\n' +\n JSON.stringify({ understanding, structure }, null, 2),\n {\n label: 'draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n executiveSummary: { type: 'string' },\n scope: { type: 'string' },\n timeline: { type: 'string' },\n pricing: { type: 'string' },\n risks: { type: 'array', items: { type: 'string' } },\n nextSteps: { type: 'array', items: { type: 'string' } },\n },\n required: ['executiveSummary', 'scope', 'pricing', 'nextSteps'],\n },\n },\n)\n\nphase('Polish')\nconst polished = await agent(\n 'Polish the proposal: tighten language, add a one-line value prop, flag anything that could scare the client, and suggest 2 negotiation flex points.\\\\n\\\\n' +\n JSON.stringify(draft, null, 2),\n {\n label: 'polish',\n schema: {\n type: 'object',\n properties: {\n valueProp: { type: 'string' },\n fullProposal: { type: 'string' },\n clientConcerns: { type: 'array', items: { type: 'string' } },\n flexPoints: { type: 'array', items: { type: 'string' } },\n },\n required: ['valueProp', 'fullProposal'],\n },\n },\n)\n\nconst output = {\n ok: true,\n understanding,\n structure,\n ...(polished ?? { valueProp: '', fullProposal: 'draft failed' }),\n}\nreturn {\n summary: output.valueProp || 'Proposal draft complete.',\n sections: [\n { kind: 'text', title: 'Proposal', content: output.fullProposal },\n { kind: 'questions', title: 'Client concerns', items: output.clientConcerns ?? [] },\n { kind: 'questions', title: 'Flex points', items: output.flexPoints ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,yBAAyB"}
@@ -9,4 +9,4 @@
9
9
  * - competitors: competitor names (optional)
10
10
  * - focus: what you care most about (optional)
11
11
  */
12
- export declare const COMPETITOR_SCAN_SCRIPT = "export const meta = {\n name: 'competitor_scan',\n description: 'Scan competitors in parallel and synthesize positioning, pricing, and differentiation opportunities.',\n whenToUse: 'Solo founder comparing alternatives before pricing, positioning, or go-to-market decisions.',\n examplePrompts: [\n { field: 'market', text: 'AI writing assistant for solo creators' },\n { field: 'competitors', text: 'Notion AI, Jasper, Cursor' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u626B\u63CF\u7ADE\u54C1\uFF0C\u7EFC\u5408\u5B9A\u4F4D\u3001\u5B9A\u4EF7\u4E0E\u5DEE\u5F02\u5316\u673A\u4F1A\u3002',\n whenToUse: '\u4E00\u4EBA\u516C\u53F8\u5728\u5B9A\u4EF7\u3001\u5B9A\u4F4D\u6216\u8FDB\u5165\u5E02\u573A\u524D\u9700\u8981\u7ADE\u54C1\u5BF9\u6BD4\u65F6\u3002',\n examplePrompts: [\n { field: 'market', text: '\u9762\u5411\u72EC\u7ACB\u521B\u4F5C\u8005\u7684 AI \u5199\u4F5C\u52A9\u624B' },\n { field: 'competitors', text: 'Notion AI\u3001Jasper\u3001Cursor' },\n ],\n },\n },\n tags: ['research', 'investigation'],\n estimatedAgents: { min: 4, max: 7 },\n phases: [\n { title: 'Frame' },\n { title: 'Scan' },\n { title: 'Synthesize' },\n ],\n}\n\nconst RESEARCH_TOOLS = ['web_search', 'web_fetch']\n\nconst market = args && typeof args === 'object' && args.market\n ? String(args.market)\n : 'Infer the market from the most recent user turn.'\n\nconst competitorsRaw = args && typeof args === 'object' && args.competitors\n ? String(args.competitors)\n : ''\n\nconst focus = args && typeof args === 'object' && args.focus\n ? String(args.focus)\n : 'positioning and pricing'\n\nphase('Frame')\nconst frame = await agent(\n 'Frame this competitor scan. If competitors are not listed, propose 3\u20134 realistic competitors. Return scan criteria and your assumed buyer persona.\\n\\n' +\n 'MARKET:\\n' + market + '\\n' +\n (competitorsRaw ? 'COMPETITORS:\\n' + competitorsRaw + '\\n' : '') +\n 'FOCUS:\\n' + focus,\n {\n label: 'frame',\n toolset: RESEARCH_TOOLS,\n schema: {\n type: 'object',\n properties: {\n competitors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n oneLiner: { type: 'string' },\n },\n required: ['name'],\n },\n },\n criteria: { type: 'array', items: { type: 'string' } },\n buyerPersona: { type: 'string' },\n },\n required: ['competitors', 'criteria'],\n },\n },\n)\n\nif (!frame || !frame.competitors?.length) {\n return { ok: false, reason: 'framing failed', market }\n}\n\nconst competitors = frame.competitors.slice(0, 4)\n\nphase('Scan')\nconst scans = await parallel(\n competitors.map((c) => () =>\n agent(\n 'Research this competitor for a solo founder. Use web search. Return positioning, pricing model, strengths, weaknesses, and target customer \u2014 cite sources where possible.\\n\\n' +\n 'COMPETITOR: ' + c.name + '\\nMARKET: ' + market + '\\nFOCUS: ' + focus,\n {\n label: c.name,\n toolset: RESEARCH_TOOLS,\n maxIterations: 25,\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n positioning: { type: 'string' },\n pricing: { type: 'string' },\n strengths: { type: 'array', items: { type: 'string' } },\n weaknesses: { type: 'array', items: { type: 'string' } },\n targetCustomer: { type: 'string' },\n sources: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'positioning', 'strengths', 'weaknesses'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst synthesis = await agent(\n 'Synthesize a competitor matrix and differentiation playbook for a one-person company. Include whitespace opportunities, pricing band recommendation, and 3 positioning angles to test.\\n\\n' +\n JSON.stringify({ market, focus, frame, scans: scans.filter(Boolean) }, null, 2),\n {\n label: 'synthesis',\n schema: {\n type: 'object',\n properties: {\n matrixSummary: { type: 'string' },\n whitespace: { type: 'array', items: { type: 'string' } },\n pricingBand: { type: 'string' },\n positioningAngles: { type: 'array', items: { type: 'string' } },\n avoidCompetingOn: { type: 'array', items: { type: 'string' } },\n },\n required: ['matrixSummary', 'whitespace', 'positioningAngles'],\n },\n },\n)\n\nreturn {\n ok: true,\n market,\n competitorCount: competitors.length,\n scans: scans.filter(Boolean),\n ...(synthesis ?? { matrixSummary: 'synthesis failed', whitespace: [], positioningAngles: [] }),\n}\n";
12
+ export declare const COMPETITOR_SCAN_SCRIPT = "export const meta = {\n name: 'competitor_scan',\n description: 'Scan competitors in parallel and synthesize positioning, pricing, and differentiation opportunities.',\n whenToUse: 'Solo founder comparing alternatives before pricing, positioning, or go-to-market decisions.',\n examplePrompts: [\n { field: 'market', text: 'AI writing assistant for solo creators' },\n { field: 'competitors', text: 'Notion AI, Jasper, Cursor' },\n ],\n i18n: {\n zh: {\n description: '\u5E76\u884C\u626B\u63CF\u7ADE\u54C1\uFF0C\u7EFC\u5408\u5B9A\u4F4D\u3001\u5B9A\u4EF7\u4E0E\u5DEE\u5F02\u5316\u673A\u4F1A\u3002',\n whenToUse: '\u4E00\u4EBA\u516C\u53F8\u5728\u5B9A\u4EF7\u3001\u5B9A\u4F4D\u6216\u8FDB\u5165\u5E02\u573A\u524D\u9700\u8981\u7ADE\u54C1\u5BF9\u6BD4\u65F6\u3002',\n examplePrompts: [\n { field: 'market', text: '\u9762\u5411\u72EC\u7ACB\u521B\u4F5C\u8005\u7684 AI \u5199\u4F5C\u52A9\u624B' },\n { field: 'competitors', text: 'Notion AI\u3001Jasper\u3001Cursor' },\n ],\n },\n },\n tags: ['research', 'investigation'],\n estimatedAgents: { min: 4, max: 7 },\n phases: [\n { title: 'Frame' },\n { title: 'Scan' },\n { title: 'Synthesize' },\n ],\n}\n\nconst RESEARCH_TOOLS = ['web_search', 'web_fetch']\n\nconst market = args && typeof args === 'object' && args.market\n ? String(args.market)\n : 'Infer the market from the most recent user turn.'\n\nconst competitorsRaw = args && typeof args === 'object' && args.competitors\n ? String(args.competitors)\n : ''\n\nconst focus = args && typeof args === 'object' && args.focus\n ? String(args.focus)\n : 'positioning and pricing'\n\nphase('Frame')\nconst frame = await agent(\n 'Frame this competitor scan. If competitors are not listed, propose 3\u20134 realistic competitors. Return scan criteria and your assumed buyer persona.\\n\\n' +\n 'MARKET:\\n' + market + '\\n' +\n (competitorsRaw ? 'COMPETITORS:\\n' + competitorsRaw + '\\n' : '') +\n 'FOCUS:\\n' + focus,\n {\n label: 'frame',\n toolset: RESEARCH_TOOLS,\n schema: {\n type: 'object',\n properties: {\n competitors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n oneLiner: { type: 'string' },\n },\n required: ['name'],\n },\n },\n criteria: { type: 'array', items: { type: 'string' } },\n buyerPersona: { type: 'string' },\n },\n required: ['competitors', 'criteria'],\n },\n },\n)\n\nif (!frame || !frame.competitors?.length) {\n const output = { ok: false, reason: 'framing failed', market }\n return {\n summary: output.reason,\n sections: [{ kind: 'json', title: 'Scan framing', value: output }],\n structuredOutput: output,\n }\n}\n\nconst competitors = frame.competitors.slice(0, 4)\n\nphase('Scan')\nconst scans = await parallel(\n competitors.map((c) => () =>\n agent(\n 'Research this competitor for a solo founder. Use web search. Return positioning, pricing model, strengths, weaknesses, and target customer \u2014 cite sources where possible.\\n\\n' +\n 'COMPETITOR: ' + c.name + '\\nMARKET: ' + market + '\\nFOCUS: ' + focus,\n {\n label: c.name,\n toolset: RESEARCH_TOOLS,\n maxIterations: 25,\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n positioning: { type: 'string' },\n pricing: { type: 'string' },\n strengths: { type: 'array', items: { type: 'string' } },\n weaknesses: { type: 'array', items: { type: 'string' } },\n targetCustomer: { type: 'string' },\n sources: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'positioning', 'strengths', 'weaknesses'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst synthesis = await agent(\n 'Synthesize a competitor matrix and differentiation playbook for a one-person company. Include whitespace opportunities, pricing band recommendation, and 3 positioning angles to test.\\n\\n' +\n JSON.stringify({ market, focus, frame, scans: scans.filter(Boolean) }, null, 2),\n {\n label: 'synthesis',\n schema: {\n type: 'object',\n properties: {\n matrixSummary: { type: 'string' },\n whitespace: { type: 'array', items: { type: 'string' } },\n pricingBand: { type: 'string' },\n positioningAngles: { type: 'array', items: { type: 'string' } },\n avoidCompetingOn: { type: 'array', items: { type: 'string' } },\n },\n required: ['matrixSummary', 'whitespace', 'positioningAngles'],\n },\n },\n)\n\nconst output = {\n ok: true,\n market,\n competitorCount: competitors.length,\n scans: scans.filter(Boolean),\n ...(synthesis ?? { matrixSummary: 'synthesis failed', whitespace: [], positioningAngles: [] }),\n}\nreturn {\n summary: output.matrixSummary,\n sections: [\n { kind: 'questions', title: 'Whitespace opportunities', items: output.whitespace },\n { kind: 'questions', title: 'Positioning angles', items: output.positioningAngles },\n { kind: 'json', title: 'Competitor scans', value: output.scans },\n ],\n structuredOutput: output,\n}\n";
@@ -83,7 +83,12 @@ const frame = await agent(
83
83
  )
84
84
 
85
85
  if (!frame || !frame.competitors?.length) {
86
- return { ok: false, reason: 'framing failed', market }
86
+ const output = { ok: false, reason: 'framing failed', market }
87
+ return {
88
+ summary: output.reason,
89
+ sections: [{ kind: 'json', title: 'Scan framing', value: output }],
90
+ structuredOutput: output,
91
+ }
87
92
  }
88
93
 
89
94
  const competitors = frame.competitors.slice(0, 4)
@@ -136,13 +141,22 @@ const synthesis = await agent(
136
141
  },
137
142
  )
138
143
 
139
- return {
144
+ const output = {
140
145
  ok: true,
141
146
  market,
142
147
  competitorCount: competitors.length,
143
148
  scans: scans.filter(Boolean),
144
149
  ...(synthesis ?? { matrixSummary: 'synthesis failed', whitespace: [], positioningAngles: [] }),
145
150
  }
151
+ return {
152
+ summary: output.matrixSummary,
153
+ sections: [
154
+ { kind: 'questions', title: 'Whitespace opportunities', items: output.whitespace },
155
+ { kind: 'questions', title: 'Positioning angles', items: output.positioningAngles },
156
+ { kind: 'json', title: 'Competitor scans', value: output.scans },
157
+ ],
158
+ structuredOutput: output,
159
+ }
146
160
  `;
147
161
  //#endregion
148
162
  export { COMPETITOR_SCAN_SCRIPT };
@@ -1 +1 @@
1
- {"version":3,"file":"competitor-scan.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/competitor-scan.ts"],"sourcesContent":["/**\n * Built-in workflow: `competitor_scan`\n *\n * Parallel competitor scan for solopreneurs — positioning, pricing, strengths,\n * weaknesses, and differentiation opportunities.\n *\n * Args:\n * - market: what you are building or selling\n * - competitors: competitor names (optional)\n * - focus: what you care most about (optional)\n */\n\nexport const COMPETITOR_SCAN_SCRIPT = `export const meta = {\n name: 'competitor_scan',\n description: 'Scan competitors in parallel and synthesize positioning, pricing, and differentiation opportunities.',\n whenToUse: 'Solo founder comparing alternatives before pricing, positioning, or go-to-market decisions.',\n examplePrompts: [\n { field: 'market', text: 'AI writing assistant for solo creators' },\n { field: 'competitors', text: 'Notion AI, Jasper, Cursor' },\n ],\n i18n: {\n zh: {\n description: '并行扫描竞品,综合定位、定价与差异化机会。',\n whenToUse: '一人公司在定价、定位或进入市场前需要竞品对比时。',\n examplePrompts: [\n { field: 'market', text: '面向独立创作者的 AI 写作助手' },\n { field: 'competitors', text: 'Notion AI、Jasper、Cursor' },\n ],\n },\n },\n tags: ['research', 'investigation'],\n estimatedAgents: { min: 4, max: 7 },\n phases: [\n { title: 'Frame' },\n { title: 'Scan' },\n { title: 'Synthesize' },\n ],\n}\n\nconst RESEARCH_TOOLS = ['web_search', 'web_fetch']\n\nconst market = args && typeof args === 'object' && args.market\n ? String(args.market)\n : 'Infer the market from the most recent user turn.'\n\nconst competitorsRaw = args && typeof args === 'object' && args.competitors\n ? String(args.competitors)\n : ''\n\nconst focus = args && typeof args === 'object' && args.focus\n ? String(args.focus)\n : 'positioning and pricing'\n\nphase('Frame')\nconst frame = await agent(\n 'Frame this competitor scan. If competitors are not listed, propose 3–4 realistic competitors. Return scan criteria and your assumed buyer persona.\\\\n\\\\n' +\n 'MARKET:\\\\n' + market + '\\\\n' +\n (competitorsRaw ? 'COMPETITORS:\\\\n' + competitorsRaw + '\\\\n' : '') +\n 'FOCUS:\\\\n' + focus,\n {\n label: 'frame',\n toolset: RESEARCH_TOOLS,\n schema: {\n type: 'object',\n properties: {\n competitors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n oneLiner: { type: 'string' },\n },\n required: ['name'],\n },\n },\n criteria: { type: 'array', items: { type: 'string' } },\n buyerPersona: { type: 'string' },\n },\n required: ['competitors', 'criteria'],\n },\n },\n)\n\nif (!frame || !frame.competitors?.length) {\n return { ok: false, reason: 'framing failed', market }\n}\n\nconst competitors = frame.competitors.slice(0, 4)\n\nphase('Scan')\nconst scans = await parallel(\n competitors.map((c) => () =>\n agent(\n 'Research this competitor for a solo founder. Use web search. Return positioning, pricing model, strengths, weaknesses, and target customer — cite sources where possible.\\\\n\\\\n' +\n 'COMPETITOR: ' + c.name + '\\\\nMARKET: ' + market + '\\\\nFOCUS: ' + focus,\n {\n label: c.name,\n toolset: RESEARCH_TOOLS,\n maxIterations: 25,\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n positioning: { type: 'string' },\n pricing: { type: 'string' },\n strengths: { type: 'array', items: { type: 'string' } },\n weaknesses: { type: 'array', items: { type: 'string' } },\n targetCustomer: { type: 'string' },\n sources: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'positioning', 'strengths', 'weaknesses'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst synthesis = await agent(\n 'Synthesize a competitor matrix and differentiation playbook for a one-person company. Include whitespace opportunities, pricing band recommendation, and 3 positioning angles to test.\\\\n\\\\n' +\n JSON.stringify({ market, focus, frame, scans: scans.filter(Boolean) }, null, 2),\n {\n label: 'synthesis',\n schema: {\n type: 'object',\n properties: {\n matrixSummary: { type: 'string' },\n whitespace: { type: 'array', items: { type: 'string' } },\n pricingBand: { type: 'string' },\n positioningAngles: { type: 'array', items: { type: 'string' } },\n avoidCompetingOn: { type: 'array', items: { type: 'string' } },\n },\n required: ['matrixSummary', 'whitespace', 'positioningAngles'],\n },\n },\n)\n\nreturn {\n ok: true,\n market,\n competitorCount: competitors.length,\n scans: scans.filter(Boolean),\n ...(synthesis ?? { matrixSummary: 'synthesis failed', whitespace: [], positioningAngles: [] }),\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,yBAAyB"}
1
+ {"version":3,"file":"competitor-scan.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/competitor-scan.ts"],"sourcesContent":["/**\n * Built-in workflow: `competitor_scan`\n *\n * Parallel competitor scan for solopreneurs — positioning, pricing, strengths,\n * weaknesses, and differentiation opportunities.\n *\n * Args:\n * - market: what you are building or selling\n * - competitors: competitor names (optional)\n * - focus: what you care most about (optional)\n */\n\nexport const COMPETITOR_SCAN_SCRIPT = `export const meta = {\n name: 'competitor_scan',\n description: 'Scan competitors in parallel and synthesize positioning, pricing, and differentiation opportunities.',\n whenToUse: 'Solo founder comparing alternatives before pricing, positioning, or go-to-market decisions.',\n examplePrompts: [\n { field: 'market', text: 'AI writing assistant for solo creators' },\n { field: 'competitors', text: 'Notion AI, Jasper, Cursor' },\n ],\n i18n: {\n zh: {\n description: '并行扫描竞品,综合定位、定价与差异化机会。',\n whenToUse: '一人公司在定价、定位或进入市场前需要竞品对比时。',\n examplePrompts: [\n { field: 'market', text: '面向独立创作者的 AI 写作助手' },\n { field: 'competitors', text: 'Notion AI、Jasper、Cursor' },\n ],\n },\n },\n tags: ['research', 'investigation'],\n estimatedAgents: { min: 4, max: 7 },\n phases: [\n { title: 'Frame' },\n { title: 'Scan' },\n { title: 'Synthesize' },\n ],\n}\n\nconst RESEARCH_TOOLS = ['web_search', 'web_fetch']\n\nconst market = args && typeof args === 'object' && args.market\n ? String(args.market)\n : 'Infer the market from the most recent user turn.'\n\nconst competitorsRaw = args && typeof args === 'object' && args.competitors\n ? String(args.competitors)\n : ''\n\nconst focus = args && typeof args === 'object' && args.focus\n ? String(args.focus)\n : 'positioning and pricing'\n\nphase('Frame')\nconst frame = await agent(\n 'Frame this competitor scan. If competitors are not listed, propose 3–4 realistic competitors. Return scan criteria and your assumed buyer persona.\\\\n\\\\n' +\n 'MARKET:\\\\n' + market + '\\\\n' +\n (competitorsRaw ? 'COMPETITORS:\\\\n' + competitorsRaw + '\\\\n' : '') +\n 'FOCUS:\\\\n' + focus,\n {\n label: 'frame',\n toolset: RESEARCH_TOOLS,\n schema: {\n type: 'object',\n properties: {\n competitors: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n oneLiner: { type: 'string' },\n },\n required: ['name'],\n },\n },\n criteria: { type: 'array', items: { type: 'string' } },\n buyerPersona: { type: 'string' },\n },\n required: ['competitors', 'criteria'],\n },\n },\n)\n\nif (!frame || !frame.competitors?.length) {\n const output = { ok: false, reason: 'framing failed', market }\n return {\n summary: output.reason,\n sections: [{ kind: 'json', title: 'Scan framing', value: output }],\n structuredOutput: output,\n }\n}\n\nconst competitors = frame.competitors.slice(0, 4)\n\nphase('Scan')\nconst scans = await parallel(\n competitors.map((c) => () =>\n agent(\n 'Research this competitor for a solo founder. Use web search. Return positioning, pricing model, strengths, weaknesses, and target customer — cite sources where possible.\\\\n\\\\n' +\n 'COMPETITOR: ' + c.name + '\\\\nMARKET: ' + market + '\\\\nFOCUS: ' + focus,\n {\n label: c.name,\n toolset: RESEARCH_TOOLS,\n maxIterations: 25,\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string' },\n positioning: { type: 'string' },\n pricing: { type: 'string' },\n strengths: { type: 'array', items: { type: 'string' } },\n weaknesses: { type: 'array', items: { type: 'string' } },\n targetCustomer: { type: 'string' },\n sources: { type: 'array', items: { type: 'string' } },\n },\n required: ['name', 'positioning', 'strengths', 'weaknesses'],\n },\n },\n ),\n ),\n)\n\nphase('Synthesize')\nconst synthesis = await agent(\n 'Synthesize a competitor matrix and differentiation playbook for a one-person company. Include whitespace opportunities, pricing band recommendation, and 3 positioning angles to test.\\\\n\\\\n' +\n JSON.stringify({ market, focus, frame, scans: scans.filter(Boolean) }, null, 2),\n {\n label: 'synthesis',\n schema: {\n type: 'object',\n properties: {\n matrixSummary: { type: 'string' },\n whitespace: { type: 'array', items: { type: 'string' } },\n pricingBand: { type: 'string' },\n positioningAngles: { type: 'array', items: { type: 'string' } },\n avoidCompetingOn: { type: 'array', items: { type: 'string' } },\n },\n required: ['matrixSummary', 'whitespace', 'positioningAngles'],\n },\n },\n)\n\nconst output = {\n ok: true,\n market,\n competitorCount: competitors.length,\n scans: scans.filter(Boolean),\n ...(synthesis ?? { matrixSummary: 'synthesis failed', whitespace: [], positioningAngles: [] }),\n}\nreturn {\n summary: output.matrixSummary,\n sections: [\n { kind: 'questions', title: 'Whitespace opportunities', items: output.whitespace },\n { kind: 'questions', title: 'Positioning angles', items: output.positioningAngles },\n { kind: 'json', title: 'Competitor scans', value: output.scans },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;AAYA,MAAa,yBAAyB"}
@@ -10,4 +10,4 @@
10
10
  * - audience: who will read it (optional)
11
11
  * - format: email | post | announcement | document | message (optional)
12
12
  */
13
- export declare const CONTENT_DRAFT_SCRIPT = "export const meta = {\n name: 'content_draft',\n description: 'Draft polished content from multiple tone and audience angles, then synthesize the best version.',\n whenToUse: 'User needs help writing an email, post, announcement, doc section, or message \u2014 not code.',\n examplePrompts: [\n { field: 'topic', text: 'Write a product launch announcement for our mobile app update' },\n { field: 'topic', text: 'Draft a polite follow-up email after a missed meeting' },\n ],\n i18n: {\n zh: {\n description: '\u4ECE\u591A\u4E2A\u8BED\u6C14\u4E0E\u53D7\u4F17\u89D2\u5EA6\u8D77\u8349\u5185\u5BB9\uFF0C\u5E76\u7EFC\u5408\u4EA7\u51FA\u6700\u4F73\u7248\u672C\u3002',\n whenToUse: '\u7528\u6237\u9700\u8981\u5199\u90AE\u4EF6\u3001\u5E16\u5B50\u3001\u516C\u544A\u3001\u6587\u6863\u6BB5\u843D\u6216\u6D88\u606F\u7B49\u975E\u4EE3\u7801\u5185\u5BB9\u65F6\u3002',\n examplePrompts: [\n { field: 'topic', text: '\u5199\u4E00\u4EFD\u79FB\u52A8\u7AEF\u5E94\u7528\u66F4\u65B0\u7684\u4EA7\u54C1\u53D1\u5E03\u516C\u544A' },\n { field: 'topic', text: '\u8D77\u8349\u4E00\u5C01\u9519\u8FC7\u4F1A\u8BAE\u540E\u7684\u793C\u8C8C\u8DDF\u8FDB\u90AE\u4EF6' },\n ],\n },\n },\n tags: ['writing', 'content', 'communication'],\n estimatedAgents: { min: 4, max: 6 },\n phases: [\n { title: 'Brief' },\n { title: 'Angles' },\n { title: 'Draft' },\n ],\n}\n\nconst topic = args && typeof args === 'object' && args.topic\n ? String(args.topic)\n : 'Infer the writing topic from the most recent user turn.'\n\nconst audience = args && typeof args === 'object' && args.audience\n ? String(args.audience)\n : 'general professional audience'\n\nconst format = args && typeof args === 'object' && args.format\n ? String(args.format)\n : 'document'\n\nphase('Brief')\nconst brief = await agent(\n 'Clarify this writing brief. Return the core message, constraints, tone guidance, and 3 distinct angles worth exploring (each with a hook and key point).\\n\\n' +\n 'TOPIC:\\n' + topic + '\\nAUDIENCE:\\n' + audience + '\\nFORMAT:\\n' + format,\n {\n label: 'brief',\n schema: {\n type: 'object',\n properties: {\n coreMessage: { type: 'string' },\n tone: { type: 'string' },\n constraints: { type: 'array', items: { type: 'string' } },\n angles: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n hook: { type: 'string' },\n keyPoint: { type: 'string' },\n },\n required: ['title', 'hook', 'keyPoint'],\n },\n },\n },\n required: ['coreMessage', 'angles'],\n },\n },\n)\n\nif (!brief || !brief.angles?.length) {\n return { ok: false, reason: 'briefing failed', topic, audience, format }\n}\n\nconst angles = brief.angles.slice(0, 3)\n\nphase('Angles')\nconst angleDrafts = await parallel(\n angles.map((a) => () =>\n agent(\n 'Write a complete draft for this angle. Match the requested format and audience. Keep it ready to send or publish with minimal edits.\\n\\n' +\n 'FORMAT: ' + format + '\\nAUDIENCE: ' + audience + '\\nCORE MESSAGE: ' + brief.coreMessage + '\\n' +\n 'ANGLE: ' + a.title + '\\nHOOK: ' + a.hook + '\\nKEY POINT: ' + a.keyPoint,\n {\n label: a.title,\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n body: { type: 'string' },\n subject: { type: 'string' },\n },\n required: ['title', 'body'],\n },\n },\n ),\n ),\n)\n\nphase('Draft')\nconst live = angleDrafts.filter(Boolean)\nconst finalDraft = await agent(\n 'Synthesize the best final draft from these angle-level versions. Pick the strongest hook and structure, merge the best lines, and remove redundancy. ' +\n 'Return the polished draft plus a one-line rationale and two optional shorter variants (e.g. social / SMS length).\\n\\n' +\n JSON.stringify({ brief, drafts: live }, null, 2),\n {\n label: 'final draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n subject: { type: 'string' },\n body: { type: 'string' },\n rationale: { type: 'string' },\n shortVariants: { type: 'array', items: { type: 'string' } },\n },\n required: ['body', 'rationale'],\n },\n },\n)\n\nreturn {\n ok: true,\n topic,\n audience,\n format,\n angleCount: angles.length,\n ...(finalDraft ?? { body: 'draft synthesis failed', rationale: '' }),\n}\n";
13
+ export declare const CONTENT_DRAFT_SCRIPT = "export const meta = {\n name: 'content_draft',\n description: 'Draft polished content from multiple tone and audience angles, then synthesize the best version.',\n whenToUse: 'User needs help writing an email, post, announcement, doc section, or message \u2014 not code.',\n examplePrompts: [\n { field: 'topic', text: 'Write a product launch announcement for our mobile app update' },\n { field: 'topic', text: 'Draft a polite follow-up email after a missed meeting' },\n ],\n i18n: {\n zh: {\n description: '\u4ECE\u591A\u4E2A\u8BED\u6C14\u4E0E\u53D7\u4F17\u89D2\u5EA6\u8D77\u8349\u5185\u5BB9\uFF0C\u5E76\u7EFC\u5408\u4EA7\u51FA\u6700\u4F73\u7248\u672C\u3002',\n whenToUse: '\u7528\u6237\u9700\u8981\u5199\u90AE\u4EF6\u3001\u5E16\u5B50\u3001\u516C\u544A\u3001\u6587\u6863\u6BB5\u843D\u6216\u6D88\u606F\u7B49\u975E\u4EE3\u7801\u5185\u5BB9\u65F6\u3002',\n examplePrompts: [\n { field: 'topic', text: '\u5199\u4E00\u4EFD\u79FB\u52A8\u7AEF\u5E94\u7528\u66F4\u65B0\u7684\u4EA7\u54C1\u53D1\u5E03\u516C\u544A' },\n { field: 'topic', text: '\u8D77\u8349\u4E00\u5C01\u9519\u8FC7\u4F1A\u8BAE\u540E\u7684\u793C\u8C8C\u8DDF\u8FDB\u90AE\u4EF6' },\n ],\n },\n },\n tags: ['writing', 'content', 'communication'],\n estimatedAgents: { min: 4, max: 6 },\n phases: [\n { title: 'Brief' },\n { title: 'Angles' },\n { title: 'Draft' },\n ],\n}\n\nconst topic = args && typeof args === 'object' && args.topic\n ? String(args.topic)\n : 'Infer the writing topic from the most recent user turn.'\n\nconst audience = args && typeof args === 'object' && args.audience\n ? String(args.audience)\n : 'general professional audience'\n\nconst format = args && typeof args === 'object' && args.format\n ? String(args.format)\n : 'document'\n\nphase('Brief')\nconst brief = await agent(\n 'Clarify this writing brief. Return the core message, constraints, tone guidance, and 3 distinct angles worth exploring (each with a hook and key point).\\n\\n' +\n 'TOPIC:\\n' + topic + '\\nAUDIENCE:\\n' + audience + '\\nFORMAT:\\n' + format,\n {\n label: 'brief',\n schema: {\n type: 'object',\n properties: {\n coreMessage: { type: 'string' },\n tone: { type: 'string' },\n constraints: { type: 'array', items: { type: 'string' } },\n angles: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n hook: { type: 'string' },\n keyPoint: { type: 'string' },\n },\n required: ['title', 'hook', 'keyPoint'],\n },\n },\n },\n required: ['coreMessage', 'angles'],\n },\n },\n)\n\nif (!brief || !brief.angles?.length) {\n const output = { ok: false, reason: 'briefing failed', topic, audience, format }\n return {\n summary: output.reason,\n sections: [{ kind: 'json', title: 'Draft briefing', value: output }],\n structuredOutput: output,\n }\n}\n\nconst angles = brief.angles.slice(0, 3)\n\nphase('Angles')\nconst angleDrafts = await parallel(\n angles.map((a) => () =>\n agent(\n 'Write a complete draft for this angle. Match the requested format and audience. Keep it ready to send or publish with minimal edits.\\n\\n' +\n 'FORMAT: ' + format + '\\nAUDIENCE: ' + audience + '\\nCORE MESSAGE: ' + brief.coreMessage + '\\n' +\n 'ANGLE: ' + a.title + '\\nHOOK: ' + a.hook + '\\nKEY POINT: ' + a.keyPoint,\n {\n label: a.title,\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n body: { type: 'string' },\n subject: { type: 'string' },\n },\n required: ['title', 'body'],\n },\n },\n ),\n ),\n)\n\nphase('Draft')\nconst live = angleDrafts.filter(Boolean)\nconst finalDraft = await agent(\n 'Synthesize the best final draft from these angle-level versions. Pick the strongest hook and structure, merge the best lines, and remove redundancy. ' +\n 'Return the polished draft plus a one-line rationale and two optional shorter variants (e.g. social / SMS length).\\n\\n' +\n JSON.stringify({ brief, drafts: live }, null, 2),\n {\n label: 'final draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n subject: { type: 'string' },\n body: { type: 'string' },\n rationale: { type: 'string' },\n shortVariants: { type: 'array', items: { type: 'string' } },\n },\n required: ['body', 'rationale'],\n },\n },\n)\n\nconst output = {\n ok: true,\n topic,\n audience,\n format,\n angleCount: angles.length,\n ...(finalDraft ?? { body: 'draft synthesis failed', rationale: '' }),\n}\nreturn {\n summary: output.rationale || output.title || 'Draft complete.',\n sections: [\n { kind: 'text', title: output.title ?? 'Draft', content: output.body },\n { kind: 'questions', title: 'Short variants', items: output.shortVariants ?? [] },\n ],\n structuredOutput: output,\n}\n";
@@ -81,7 +81,12 @@ const brief = await agent(
81
81
  )
82
82
 
83
83
  if (!brief || !brief.angles?.length) {
84
- return { ok: false, reason: 'briefing failed', topic, audience, format }
84
+ const output = { ok: false, reason: 'briefing failed', topic, audience, format }
85
+ return {
86
+ summary: output.reason,
87
+ sections: [{ kind: 'json', title: 'Draft briefing', value: output }],
88
+ structuredOutput: output,
89
+ }
85
90
  }
86
91
 
87
92
  const angles = brief.angles.slice(0, 3)
@@ -131,7 +136,7 @@ const finalDraft = await agent(
131
136
  },
132
137
  )
133
138
 
134
- return {
139
+ const output = {
135
140
  ok: true,
136
141
  topic,
137
142
  audience,
@@ -139,6 +144,14 @@ return {
139
144
  angleCount: angles.length,
140
145
  ...(finalDraft ?? { body: 'draft synthesis failed', rationale: '' }),
141
146
  }
147
+ return {
148
+ summary: output.rationale || output.title || 'Draft complete.',
149
+ sections: [
150
+ { kind: 'text', title: output.title ?? 'Draft', content: output.body },
151
+ { kind: 'questions', title: 'Short variants', items: output.shortVariants ?? [] },
152
+ ],
153
+ structuredOutput: output,
154
+ }
142
155
  `;
143
156
  //#endregion
144
157
  export { CONTENT_DRAFT_SCRIPT };
@@ -1 +1 @@
1
- {"version":3,"file":"content-draft.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/content-draft.ts"],"sourcesContent":["/**\n * Built-in workflow: `content_draft`\n *\n * Multi-angle content drafting for non-code writing tasks — emails, posts,\n * announcements, docs, or messages. Fans out tone/audience angles in parallel,\n * then synthesizes a polished draft with variants.\n *\n * Args:\n * - topic: what to write about\n * - audience: who will read it (optional)\n * - format: email | post | announcement | document | message (optional)\n */\n\nexport const CONTENT_DRAFT_SCRIPT = `export const meta = {\n name: 'content_draft',\n description: 'Draft polished content from multiple tone and audience angles, then synthesize the best version.',\n whenToUse: 'User needs help writing an email, post, announcement, doc section, or message — not code.',\n examplePrompts: [\n { field: 'topic', text: 'Write a product launch announcement for our mobile app update' },\n { field: 'topic', text: 'Draft a polite follow-up email after a missed meeting' },\n ],\n i18n: {\n zh: {\n description: '从多个语气与受众角度起草内容,并综合产出最佳版本。',\n whenToUse: '用户需要写邮件、帖子、公告、文档段落或消息等非代码内容时。',\n examplePrompts: [\n { field: 'topic', text: '写一份移动端应用更新的产品发布公告' },\n { field: 'topic', text: '起草一封错过会议后的礼貌跟进邮件' },\n ],\n },\n },\n tags: ['writing', 'content', 'communication'],\n estimatedAgents: { min: 4, max: 6 },\n phases: [\n { title: 'Brief' },\n { title: 'Angles' },\n { title: 'Draft' },\n ],\n}\n\nconst topic = args && typeof args === 'object' && args.topic\n ? String(args.topic)\n : 'Infer the writing topic from the most recent user turn.'\n\nconst audience = args && typeof args === 'object' && args.audience\n ? String(args.audience)\n : 'general professional audience'\n\nconst format = args && typeof args === 'object' && args.format\n ? String(args.format)\n : 'document'\n\nphase('Brief')\nconst brief = await agent(\n 'Clarify this writing brief. Return the core message, constraints, tone guidance, and 3 distinct angles worth exploring (each with a hook and key point).\\\\n\\\\n' +\n 'TOPIC:\\\\n' + topic + '\\\\nAUDIENCE:\\\\n' + audience + '\\\\nFORMAT:\\\\n' + format,\n {\n label: 'brief',\n schema: {\n type: 'object',\n properties: {\n coreMessage: { type: 'string' },\n tone: { type: 'string' },\n constraints: { type: 'array', items: { type: 'string' } },\n angles: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n hook: { type: 'string' },\n keyPoint: { type: 'string' },\n },\n required: ['title', 'hook', 'keyPoint'],\n },\n },\n },\n required: ['coreMessage', 'angles'],\n },\n },\n)\n\nif (!brief || !brief.angles?.length) {\n return { ok: false, reason: 'briefing failed', topic, audience, format }\n}\n\nconst angles = brief.angles.slice(0, 3)\n\nphase('Angles')\nconst angleDrafts = await parallel(\n angles.map((a) => () =>\n agent(\n 'Write a complete draft for this angle. Match the requested format and audience. Keep it ready to send or publish with minimal edits.\\\\n\\\\n' +\n 'FORMAT: ' + format + '\\\\nAUDIENCE: ' + audience + '\\\\nCORE MESSAGE: ' + brief.coreMessage + '\\\\n' +\n 'ANGLE: ' + a.title + '\\\\nHOOK: ' + a.hook + '\\\\nKEY POINT: ' + a.keyPoint,\n {\n label: a.title,\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n body: { type: 'string' },\n subject: { type: 'string' },\n },\n required: ['title', 'body'],\n },\n },\n ),\n ),\n)\n\nphase('Draft')\nconst live = angleDrafts.filter(Boolean)\nconst finalDraft = await agent(\n 'Synthesize the best final draft from these angle-level versions. Pick the strongest hook and structure, merge the best lines, and remove redundancy. ' +\n 'Return the polished draft plus a one-line rationale and two optional shorter variants (e.g. social / SMS length).\\\\n\\\\n' +\n JSON.stringify({ brief, drafts: live }, null, 2),\n {\n label: 'final draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n subject: { type: 'string' },\n body: { type: 'string' },\n rationale: { type: 'string' },\n shortVariants: { type: 'array', items: { type: 'string' } },\n },\n required: ['body', 'rationale'],\n },\n },\n)\n\nreturn {\n ok: true,\n topic,\n audience,\n format,\n angleCount: angles.length,\n ...(finalDraft ?? { body: 'draft synthesis failed', rationale: '' }),\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,uBAAuB"}
1
+ {"version":3,"file":"content-draft.js","names":[],"sources":["../../../../../src/agent/workflow/builtins/content-draft.ts"],"sourcesContent":["/**\n * Built-in workflow: `content_draft`\n *\n * Multi-angle content drafting for non-code writing tasks — emails, posts,\n * announcements, docs, or messages. Fans out tone/audience angles in parallel,\n * then synthesizes a polished draft with variants.\n *\n * Args:\n * - topic: what to write about\n * - audience: who will read it (optional)\n * - format: email | post | announcement | document | message (optional)\n */\n\nexport const CONTENT_DRAFT_SCRIPT = `export const meta = {\n name: 'content_draft',\n description: 'Draft polished content from multiple tone and audience angles, then synthesize the best version.',\n whenToUse: 'User needs help writing an email, post, announcement, doc section, or message — not code.',\n examplePrompts: [\n { field: 'topic', text: 'Write a product launch announcement for our mobile app update' },\n { field: 'topic', text: 'Draft a polite follow-up email after a missed meeting' },\n ],\n i18n: {\n zh: {\n description: '从多个语气与受众角度起草内容,并综合产出最佳版本。',\n whenToUse: '用户需要写邮件、帖子、公告、文档段落或消息等非代码内容时。',\n examplePrompts: [\n { field: 'topic', text: '写一份移动端应用更新的产品发布公告' },\n { field: 'topic', text: '起草一封错过会议后的礼貌跟进邮件' },\n ],\n },\n },\n tags: ['writing', 'content', 'communication'],\n estimatedAgents: { min: 4, max: 6 },\n phases: [\n { title: 'Brief' },\n { title: 'Angles' },\n { title: 'Draft' },\n ],\n}\n\nconst topic = args && typeof args === 'object' && args.topic\n ? String(args.topic)\n : 'Infer the writing topic from the most recent user turn.'\n\nconst audience = args && typeof args === 'object' && args.audience\n ? String(args.audience)\n : 'general professional audience'\n\nconst format = args && typeof args === 'object' && args.format\n ? String(args.format)\n : 'document'\n\nphase('Brief')\nconst brief = await agent(\n 'Clarify this writing brief. Return the core message, constraints, tone guidance, and 3 distinct angles worth exploring (each with a hook and key point).\\\\n\\\\n' +\n 'TOPIC:\\\\n' + topic + '\\\\nAUDIENCE:\\\\n' + audience + '\\\\nFORMAT:\\\\n' + format,\n {\n label: 'brief',\n schema: {\n type: 'object',\n properties: {\n coreMessage: { type: 'string' },\n tone: { type: 'string' },\n constraints: { type: 'array', items: { type: 'string' } },\n angles: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n hook: { type: 'string' },\n keyPoint: { type: 'string' },\n },\n required: ['title', 'hook', 'keyPoint'],\n },\n },\n },\n required: ['coreMessage', 'angles'],\n },\n },\n)\n\nif (!brief || !brief.angles?.length) {\n const output = { ok: false, reason: 'briefing failed', topic, audience, format }\n return {\n summary: output.reason,\n sections: [{ kind: 'json', title: 'Draft briefing', value: output }],\n structuredOutput: output,\n }\n}\n\nconst angles = brief.angles.slice(0, 3)\n\nphase('Angles')\nconst angleDrafts = await parallel(\n angles.map((a) => () =>\n agent(\n 'Write a complete draft for this angle. Match the requested format and audience. Keep it ready to send or publish with minimal edits.\\\\n\\\\n' +\n 'FORMAT: ' + format + '\\\\nAUDIENCE: ' + audience + '\\\\nCORE MESSAGE: ' + brief.coreMessage + '\\\\n' +\n 'ANGLE: ' + a.title + '\\\\nHOOK: ' + a.hook + '\\\\nKEY POINT: ' + a.keyPoint,\n {\n label: a.title,\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n body: { type: 'string' },\n subject: { type: 'string' },\n },\n required: ['title', 'body'],\n },\n },\n ),\n ),\n)\n\nphase('Draft')\nconst live = angleDrafts.filter(Boolean)\nconst finalDraft = await agent(\n 'Synthesize the best final draft from these angle-level versions. Pick the strongest hook and structure, merge the best lines, and remove redundancy. ' +\n 'Return the polished draft plus a one-line rationale and two optional shorter variants (e.g. social / SMS length).\\\\n\\\\n' +\n JSON.stringify({ brief, drafts: live }, null, 2),\n {\n label: 'final draft',\n schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n subject: { type: 'string' },\n body: { type: 'string' },\n rationale: { type: 'string' },\n shortVariants: { type: 'array', items: { type: 'string' } },\n },\n required: ['body', 'rationale'],\n },\n },\n)\n\nconst output = {\n ok: true,\n topic,\n audience,\n format,\n angleCount: angles.length,\n ...(finalDraft ?? { body: 'draft synthesis failed', rationale: '' }),\n}\nreturn {\n summary: output.rationale || output.title || 'Draft complete.',\n sections: [\n { kind: 'text', title: output.title ?? 'Draft', content: output.body },\n { kind: 'questions', title: 'Short variants', items: output.shortVariants ?? [] },\n ],\n structuredOutput: output,\n}\n`\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,uBAAuB"}