@xopcai/xopc 0.0.116 → 0.0.118

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 (677) hide show
  1. package/README.md +44 -28
  2. package/README.zh-CN.md +63 -45
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/demo-memory/src/index.d.ts +6 -0
  5. package/dist/extensions/demo-memory/src/index.js +132 -0
  6. package/dist/extensions/demo-memory/src/index.js.map +1 -0
  7. package/dist/extensions/demo-memory/xopc.extension.json +15 -0
  8. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  9. package/dist/extensions/feishu/src/schema/config-schema.d.ts +3 -3
  10. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  11. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  12. package/dist/extensions/telegram/src/command-handler.js +1 -2
  13. package/dist/extensions/telegram/src/command-handler.js.map +1 -1
  14. package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
  15. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  16. package/dist/extensions/telegram/src/plugin.js +1 -1
  17. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  18. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  19. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  20. package/dist/extensions/telegram/xopc.extension.json +1 -1
  21. package/dist/extensions/weixin/src/api/api.js +2 -2
  22. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  23. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  24. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  25. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  26. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  27. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  28. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  29. package/dist/extensions/weixin/src/plugin.js +1 -1
  30. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  31. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  32. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CWM1UU5P.js → agent-avatar-dicebear-dzUrQoeZ.js} +1 -1
  33. package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +2 -0
  34. package/dist/gateway/static/root/assets/{app-management-settings-panel-yXSXY_bu.js → app-management-settings-panel-bxYJVJpx.js} +1 -1
  35. package/dist/gateway/static/root/assets/{appearance-settings-DjY1P_ug.js → appearance-settings-BCIykXlI.js} +1 -1
  36. package/dist/gateway/static/root/assets/apps-page--wMEL00f.js +1 -0
  37. package/dist/gateway/static/root/assets/{archive-plugin-CytE5j-e.js → archive-plugin-Cki4SfU2.js} +1 -1
  38. package/dist/gateway/static/root/assets/{attachment-load-BvvrN6rF.js → attachment-load-D-KnS2Do.js} +1 -1
  39. package/dist/gateway/static/root/assets/{binary-plugins-IBWSitnj.js → binary-plugins-D2sgvJja.js} +1 -1
  40. package/dist/gateway/static/root/assets/{block-editor-C-wDpsf-.js → block-editor-DIq-4Gvb.js} +27 -27
  41. package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +8 -0
  42. package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +1 -0
  43. package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +1 -0
  44. package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +1 -0
  45. package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +2 -0
  46. package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +1 -0
  47. package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +3 -0
  48. package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +1 -0
  49. package/dist/gateway/static/root/assets/{extension-debug-page-BAIyjDlq.js → extension-debug-page-DYu1KaFQ.js} +1 -1
  50. package/dist/gateway/static/root/assets/{extension-page-DEhv2GpC.js → extension-page-B3W6QwlZ.js} +1 -1
  51. package/dist/gateway/static/root/assets/{extension-settings-page-DOuAxTDW.js → extension-settings-page-D7VQ-cxE.js} +1 -1
  52. package/dist/gateway/static/root/assets/{fetch-CTsREQIe.js → fetch-B7xDPu-R.js} +1 -1
  53. package/dist/gateway/static/root/assets/{format-interval-label-D35Bfhtx.js → format-interval-label-BzxafKxR.js} +1 -1
  54. package/dist/gateway/static/root/assets/gateway-config-api-BTBLSeUu.js +1 -0
  55. package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +1 -0
  56. package/dist/gateway/static/root/assets/{gateway-startup-retry-C1KAHrd2.js → gateway-startup-retry-CYj9FWCp.js} +1 -1
  57. package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +1 -0
  58. package/dist/gateway/static/root/assets/{goals-config-api-KnLGpu6h.js → goals-config-api-CQQgzPr3.js} +1 -1
  59. package/dist/gateway/static/root/assets/goals-page-BHitvJAv.js +2 -0
  60. package/dist/gateway/static/root/assets/{goals-settings-DtPtqZi8.js → goals-settings-CYVY4NGp.js} +1 -1
  61. package/dist/gateway/static/root/assets/{heartbeat-config-api-uKw1f0IG.js → heartbeat-config-api-DriO_CN9.js} +1 -1
  62. package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +1 -0
  63. package/dist/gateway/static/root/assets/index-C17Tsd_b.css +1 -0
  64. package/dist/gateway/static/root/assets/index-Cc41r16l.js +191 -0
  65. package/dist/gateway/static/root/assets/{interval-presets-Dq0FXJ65.js → interval-presets-DFPCKW_W.js} +1 -1
  66. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-C9_t4m7t.js → keyboard-shortcuts-settings-CcVcqstx.js} +1 -1
  67. package/dist/gateway/static/root/assets/{logs-page-SNkWzidV.js → logs-page-C2Uqvae9.js} +2 -2
  68. package/dist/gateway/static/root/assets/{markdown-split-Ca87W8-h.js → markdown-split-BwOFrJ2E.js} +1 -1
  69. package/dist/gateway/static/root/assets/{media-plugins-BAcUjPRJ.js → media-plugins-Cnz6Q5G6.js} +1 -1
  70. package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +3 -0
  71. package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +2 -0
  72. package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +2 -0
  73. package/dist/gateway/static/root/assets/{note-image-lightbox-hnSX5SSn.js → note-image-lightbox-B-Svpmza.js} +1 -1
  74. package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +1 -0
  75. package/dist/gateway/static/root/assets/{preview-open-alternatives-CNgM20H5.js → preview-open-alternatives-Bss4TiwP.js} +1 -1
  76. package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +1 -0
  77. package/dist/gateway/static/root/assets/{save-bar-controls-CcdjGcfT.js → save-bar-controls-BRNjdgKq.js} +1 -1
  78. package/dist/gateway/static/root/assets/{schedule-field-CYr39z76.js → schedule-field-CUCKODde.js} +1 -1
  79. package/dist/gateway/static/root/assets/{schema-form-BRAJgZQ2.js → schema-form-Dub9sy8r.js} +1 -1
  80. package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +1 -0
  81. package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +1 -0
  82. package/dist/gateway/static/root/assets/{settings-collapsible-section-BhzjeGWi.js → settings-collapsible-section-BeFLavGi.js} +1 -1
  83. package/dist/gateway/static/root/assets/{settings-form-section-Cz3Pcr9b.js → settings-form-section-dmyaPOTG.js} +1 -1
  84. package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +1 -0
  85. package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +1 -0
  86. package/dist/gateway/static/root/assets/{share-preview-page-DL4y9K5e.js → share-preview-page-C8glrdqe.js} +1 -1
  87. package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +1 -0
  88. package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +1 -0
  89. package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +2 -0
  90. package/dist/gateway/static/root/assets/{system-settings-panel-FD2jxRZ3.js → system-settings-panel-DI-LN_8G.js} +1 -1
  91. package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +1 -0
  92. package/dist/gateway/static/root/assets/{use-channel-catalog-BInPrfR5.js → use-channel-catalog-DqlWTsDb.js} +1 -1
  93. package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +1 -0
  94. package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +1 -0
  95. package/dist/gateway/static/root/assets/voice-api-key-field-C73IVZeC.js +1 -0
  96. package/dist/gateway/static/root/assets/{voice-player-store-1U3vFppm.js → voice-player-store-C_ArLJPM.js} +1 -1
  97. package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +18 -0
  98. package/dist/gateway/static/root/index.html +5 -5
  99. package/dist/package.js +1 -1
  100. package/dist/src/agent/agent-manager.d.ts +1 -1
  101. package/dist/src/agent/agent-manager.js +14 -14
  102. package/dist/src/agent/agent-manager.js.map +1 -1
  103. package/dist/src/agent/agent-scope.js +5 -9
  104. package/dist/src/agent/agent-scope.js.map +1 -1
  105. package/dist/src/agent/background-review/coordinator.js +0 -1
  106. package/dist/src/agent/background-review/coordinator.js.map +1 -1
  107. package/dist/src/agent/background-review/prompts.d.ts +2 -2
  108. package/dist/src/agent/background-review/prompts.js +2 -2
  109. package/dist/src/agent/background-review/prompts.js.map +1 -1
  110. package/dist/src/agent/background-review/run-background-review.d.ts +0 -2
  111. package/dist/src/agent/background-review/run-background-review.js +2 -4
  112. package/dist/src/agent/background-review/run-background-review.js.map +1 -1
  113. package/dist/src/agent/background-review/settings.d.ts +1 -1
  114. package/dist/src/agent/background-review/settings.js +8 -8
  115. package/dist/src/agent/background-review/settings.js.map +1 -1
  116. package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
  117. package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
  118. package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
  119. package/dist/src/agent/bootstrap/bootstrap-context.d.ts +2 -2
  120. package/dist/src/agent/bootstrap/bootstrap-context.js +4 -4
  121. package/dist/src/agent/bootstrap/bootstrap-context.js.map +1 -1
  122. package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
  123. package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
  124. package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
  125. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
  126. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  127. package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
  128. package/dist/src/agent/bootstrap/load-bootstrap-files.js +18 -17
  129. package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
  130. package/dist/src/agent/bootstrap/project-agents-context.js +1 -1
  131. package/dist/src/agent/bootstrap/types.d.ts +1 -1
  132. package/dist/src/agent/context/workspace-seed.js +3 -3
  133. package/dist/src/agent/context/workspace-state.js +1 -1
  134. package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
  135. package/dist/src/agent/context/workspace.d.ts +4 -2
  136. package/dist/src/agent/context/workspace.js +6 -5
  137. package/dist/src/agent/context/workspace.js.map +1 -1
  138. package/dist/src/agent/embedded/run-for-session.js +4 -1
  139. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  140. package/dist/src/agent/fallback/candidates.js +11 -9
  141. package/dist/src/agent/fallback/candidates.js.map +1 -1
  142. package/dist/src/agent/goals/goal-locale.js +2 -2
  143. package/dist/src/agent/goals/post-turn.js +3 -3
  144. package/dist/src/agent/image/generation/runtime-types.d.ts +2 -0
  145. package/dist/src/agent/image/generation/runtime.js +1 -1
  146. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  147. package/dist/src/agent/image/image-helpers.d.ts +1 -1
  148. package/dist/src/agent/image/image-helpers.js +4 -17
  149. package/dist/src/agent/image/image-helpers.js.map +1 -1
  150. package/dist/src/agent/image/image-model-fallback.js +1 -1
  151. package/dist/src/agent/image/image-model-fallback.js.map +1 -1
  152. package/dist/src/agent/image/inbound-image-handling.js +1 -1
  153. package/dist/src/agent/image/inbound-image-handling.js.map +1 -1
  154. package/dist/src/agent/image/load-image-media.js +2 -2
  155. package/dist/src/agent/image/tool-model-config.d.ts +1 -1
  156. package/dist/src/agent/image/tool-model-config.js +2 -2
  157. package/dist/src/agent/image/tool-model-config.js.map +1 -1
  158. package/dist/src/agent/ipc/inbox.js +3 -3
  159. package/dist/src/agent/ipc/socket.js +1 -1
  160. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  161. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  162. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  163. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  164. package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js +1 -1
  165. package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js.map +1 -1
  166. package/dist/src/agent/media-generation/runtime-shared.d.ts +5 -2
  167. package/dist/src/agent/media-generation/runtime-shared.js +1 -1
  168. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  169. package/dist/src/agent/memory/builtin-memory-store.d.ts +6 -2
  170. package/dist/src/agent/memory/builtin-memory-store.js +15 -6
  171. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  172. package/dist/src/agent/memory/builtin-provider.d.ts +31 -9
  173. package/dist/src/agent/memory/builtin-provider.js +290 -11
  174. package/dist/src/agent/memory/builtin-provider.js.map +1 -1
  175. package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
  176. package/dist/src/agent/memory/candidate-extractor.js +60 -0
  177. package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
  178. package/dist/src/agent/memory/context-assembler.d.ts +10 -0
  179. package/dist/src/agent/memory/context-assembler.js +26 -0
  180. package/dist/src/agent/memory/context-assembler.js.map +1 -0
  181. package/dist/src/agent/memory/create-memory-manager.js +25 -7
  182. package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
  183. package/dist/src/agent/memory/dreaming/config.d.ts +1 -6
  184. package/dist/src/agent/memory/dreaming/config.js +8 -8
  185. package/dist/src/agent/memory/dreaming/config.js.map +1 -1
  186. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +2 -0
  187. package/dist/src/agent/memory/dreaming/deep-promotion.js +25 -1
  188. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
  189. package/dist/src/agent/memory/dreaming/events.js +1 -1
  190. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  191. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  192. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  193. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  194. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  195. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  196. package/dist/src/agent/memory/index.d.ts +1 -0
  197. package/dist/src/agent/memory/index.js +4 -3
  198. package/dist/src/agent/memory/inject-prefetch.js +6 -2
  199. package/dist/src/agent/memory/inject-prefetch.js.map +1 -1
  200. package/dist/src/agent/memory/manager.d.ts +39 -2
  201. package/dist/src/agent/memory/manager.js +355 -39
  202. package/dist/src/agent/memory/manager.js.map +1 -1
  203. package/dist/src/agent/memory/memory-config.js +15 -15
  204. package/dist/src/agent/memory/memory-config.js.map +1 -1
  205. package/dist/src/agent/memory/memory-flush.js +1 -1
  206. package/dist/src/agent/memory/plugin-discovery.d.ts +19 -5
  207. package/dist/src/agent/memory/plugin-discovery.js +97 -31
  208. package/dist/src/agent/memory/plugin-discovery.js.map +1 -1
  209. package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
  210. package/dist/src/agent/memory/provider.d.ts +20 -15
  211. package/dist/src/agent/memory/stub-memory-provider.d.ts +17 -2
  212. package/dist/src/agent/memory/stub-memory-provider.js +20 -3
  213. package/dist/src/agent/memory/stub-memory-provider.js.map +1 -1
  214. package/dist/src/agent/memory/types.d.ts +162 -3
  215. package/dist/src/agent/models/manager.d.ts +1 -1
  216. package/dist/src/agent/models/manager.js +2 -2
  217. package/dist/src/agent/models/manager.js.map +1 -1
  218. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +1 -1
  219. package/dist/src/agent/orchestration/agent-orchestrator.js +2 -1
  220. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  221. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +2 -2
  222. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +1 -1
  223. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +1 -1
  224. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -6
  225. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +2 -8
  226. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js.map +1 -1
  227. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  228. package/dist/src/agent/prompt/memory/index.js +19 -13
  229. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  230. package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
  231. package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
  232. package/dist/src/agent/prompt/service-prompt-builder.js +5 -20
  233. package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
  234. package/dist/src/agent/reply/post-compaction-context.js +10 -7
  235. package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
  236. package/dist/src/agent/reply/startup-context.js +7 -12
  237. package/dist/src/agent/reply/startup-context.js.map +1 -1
  238. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  239. package/dist/src/agent/sandbox/path-policy.js +2 -2
  240. package/dist/src/agent/service/process-direct-streaming.js +1 -4
  241. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  242. package/dist/src/agent/service/session-context-report.js +1 -1
  243. package/dist/src/agent/service/session-context-report.js.map +1 -1
  244. package/dist/src/agent/service.d.ts +3 -3
  245. package/dist/src/agent/service.js +30 -35
  246. package/dist/src/agent/service.js.map +1 -1
  247. package/dist/src/agent/service.types.d.ts +1 -2
  248. package/dist/src/agent/session/session-hydrator.js +1 -2
  249. package/dist/src/agent/session/session-hydrator.js.map +1 -1
  250. package/dist/src/agent/session/session-inspector.d.ts +1 -1
  251. package/dist/src/agent/session/session-inspector.js +10 -15
  252. package/dist/src/agent/session/session-inspector.js.map +1 -1
  253. package/dist/src/agent/skills/config.js +2 -2
  254. package/dist/src/agent/skills/filesystem-watcher.js +1 -1
  255. package/dist/src/agent/skills/hub-hash.js +2 -2
  256. package/dist/src/agent/skills/hub-lock.js +1 -1
  257. package/dist/src/agent/skills/hub-pull.js +3 -3
  258. package/dist/src/agent/skills/index.js +2 -2
  259. package/dist/src/agent/skills/installer.js +2 -2
  260. package/dist/src/agent/skills/managed-store.js +1 -1
  261. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  262. package/dist/src/agent/skills/skill-manager.js +1 -1
  263. package/dist/src/agent/skills/skill-view-path.js +1 -1
  264. package/dist/src/agent/skills/test-framework.js +1 -1
  265. package/dist/src/agent/starter-agents.d.ts +1 -3
  266. package/dist/src/agent/starter-agents.js +14 -22
  267. package/dist/src/agent/starter-agents.js.map +1 -1
  268. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -2
  269. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  270. package/dist/src/agent/tools/curated-memory-tool.d.ts +2 -5
  271. package/dist/src/agent/tools/curated-memory-tool.js +77 -18
  272. package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
  273. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  274. package/dist/src/agent/tools/factory.d.ts +0 -4
  275. package/dist/src/agent/tools/factory.js +19 -58
  276. package/dist/src/agent/tools/factory.js.map +1 -1
  277. package/dist/src/agent/tools/find.js +1 -1
  278. package/dist/src/agent/tools/grep.js +1 -1
  279. package/dist/src/agent/tools/image-generate-tool.d.ts +1 -1
  280. package/dist/src/agent/tools/image-generate-tool.js +20 -15
  281. package/dist/src/agent/tools/image-generate-tool.js.map +1 -1
  282. package/dist/src/agent/tools/image-tool.js +1 -3
  283. package/dist/src/agent/tools/image-tool.js.map +1 -1
  284. package/dist/src/agent/tools/memory-tool.d.ts +2 -2
  285. package/dist/src/agent/tools/memory-tool.js +39 -14
  286. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  287. package/dist/src/agent/tools/session-search-tool.js +1 -3
  288. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  289. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  290. package/dist/src/agent/tools/web-extract.js +8 -9
  291. package/dist/src/agent/tools/web-extract.js.map +1 -1
  292. package/dist/src/agent/tools/workflow-tool.js +1 -1
  293. package/dist/src/agent/workflow/catalog.js +1 -1
  294. package/dist/src/agent/workflow/subagent-runner.js +1 -3
  295. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  296. package/dist/src/agent-manifest/index.d.ts +4 -0
  297. package/dist/src/agent-manifest/index.js +10 -0
  298. package/dist/src/agent-manifest/index.js.map +1 -0
  299. package/dist/src/agent-manifest/prompt.d.ts +2 -0
  300. package/dist/src/agent-manifest/prompt.js +57 -0
  301. package/dist/src/agent-manifest/prompt.js.map +1 -0
  302. package/dist/src/agent-manifest/resolver.d.ts +12 -0
  303. package/dist/src/agent-manifest/resolver.js +95 -0
  304. package/dist/src/agent-manifest/resolver.js.map +1 -0
  305. package/dist/src/agent-manifest/schema.d.ts +1010 -0
  306. package/dist/src/agent-manifest/schema.js +269 -0
  307. package/dist/src/agent-manifest/schema.js.map +1 -0
  308. package/dist/src/agent-manifest/validator.d.ts +25 -0
  309. package/dist/src/agent-manifest/validator.js +88 -0
  310. package/dist/src/agent-manifest/validator.js.map +1 -0
  311. package/dist/src/agent-runtime/boundary-guard.d.ts +12 -0
  312. package/dist/src/agent-runtime/boundary-guard.js +23 -0
  313. package/dist/src/agent-runtime/boundary-guard.js.map +1 -0
  314. package/dist/src/agent-runtime/index.d.ts +7 -0
  315. package/dist/src/agent-runtime/index.js +8 -0
  316. package/dist/src/agent-runtime/memory-runtime.d.ts +21 -0
  317. package/dist/src/agent-runtime/memory-runtime.js +50 -0
  318. package/dist/src/agent-runtime/memory-runtime.js.map +1 -0
  319. package/dist/src/agent-runtime/model-router.d.ts +11 -0
  320. package/dist/src/agent-runtime/model-router.js +16 -0
  321. package/dist/src/agent-runtime/model-router.js.map +1 -0
  322. package/dist/src/agent-runtime/run-trace.d.ts +27 -0
  323. package/dist/src/agent-runtime/run-trace.js +53 -0
  324. package/dist/src/agent-runtime/run-trace.js.map +1 -0
  325. package/dist/src/agent-runtime/runtime-profile.d.ts +24 -0
  326. package/dist/src/agent-runtime/runtime-profile.js +44 -0
  327. package/dist/src/agent-runtime/runtime-profile.js.map +1 -0
  328. package/dist/src/agent-runtime/tool-registry.d.ts +28 -0
  329. package/dist/src/agent-runtime/tool-registry.js +52 -0
  330. package/dist/src/agent-runtime/tool-registry.js.map +1 -0
  331. package/dist/src/agent-runtime/workflow-runtime.d.ts +31 -0
  332. package/dist/src/agent-runtime/workflow-runtime.js +34 -0
  333. package/dist/src/agent-runtime/workflow-runtime.js.map +1 -0
  334. package/dist/src/ai-assist/text-assist.js +1 -1
  335. package/dist/src/auth/credentials.js +2 -2
  336. package/dist/src/auth/profiles/store.js +2 -2
  337. package/dist/src/auth/sync-provider-auth.js +1 -1
  338. package/dist/src/browser/actions/extension-registry-bridge.js +1 -1
  339. package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
  340. package/dist/src/browser/actions/registry.js +5 -8
  341. package/dist/src/browser/actions/registry.js.map +1 -1
  342. package/dist/src/browser/backend-from-config.d.ts +1 -1
  343. package/dist/src/browser/backend-from-config.js +50 -71
  344. package/dist/src/browser/backend-from-config.js.map +1 -1
  345. package/dist/src/browser/browser-command-timeout.d.ts +0 -1
  346. package/dist/src/browser/browser-command-timeout.js +3 -7
  347. package/dist/src/browser/browser-command-timeout.js.map +1 -1
  348. package/dist/src/browser/cache-dir-policy.js +1 -1
  349. package/dist/src/browser/cdp-local-launcher.js +2 -2
  350. package/dist/src/browser/pipeline/source.js +1 -1
  351. package/dist/src/browser/providers/browser-ext-install.d.ts +2 -12
  352. package/dist/src/browser/providers/browser-ext-install.js +7 -12
  353. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  354. package/dist/src/browser/providers/cloakbrowser.js +5 -5
  355. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  356. package/dist/src/browser/readiness.js +16 -16
  357. package/dist/src/browser/readiness.js.map +1 -1
  358. package/dist/src/browser/schemas.js +1 -1
  359. package/dist/src/browser/schemas.js.map +1 -1
  360. package/dist/src/browser/stealth.js +1 -1
  361. package/dist/src/channels/catalog/channel-catalog-service.js +1 -1
  362. package/dist/src/channels/outbound/persist-store.js +1 -1
  363. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  364. package/dist/src/channels/pairing/pairing-store.js +2 -2
  365. package/dist/src/channels/pipeline.d.ts +1 -1
  366. package/dist/src/channels/pipeline.js.map +1 -1
  367. package/dist/src/chat-commands/agent-edit.js +2 -3
  368. package/dist/src/chat-commands/agent-edit.js.map +1 -1
  369. package/dist/src/chat-commands/builtins/config.js +6 -6
  370. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  371. package/dist/src/chat-commands/builtins/model.js +2 -2
  372. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  373. package/dist/src/chat-commands/builtins/thinking.js +16 -42
  374. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  375. package/dist/src/chat-commands/config-paths.js +1 -1
  376. package/dist/src/chat-commands/config-paths.js.map +1 -1
  377. package/dist/src/chat-commands/context.js +3 -4
  378. package/dist/src/chat-commands/context.js.map +1 -1
  379. package/dist/src/cli/command-manifest.d.ts +1 -1
  380. package/dist/src/cli/command-manifest.js +2 -2
  381. package/dist/src/cli/command-manifest.js.map +1 -1
  382. package/dist/src/cli/commands/agent.js +3 -1
  383. package/dist/src/cli/commands/agent.js.map +1 -1
  384. package/dist/src/cli/commands/agents.js +3 -6
  385. package/dist/src/cli/commands/agents.js.map +1 -1
  386. package/dist/src/cli/commands/browser-cli-helpers.js +9 -11
  387. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  388. package/dist/src/cli/commands/config.js +6 -6
  389. package/dist/src/cli/commands/config.js.map +1 -1
  390. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  391. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  392. package/dist/src/cli/commands/doctor/checks/provider-auth.js +3 -18
  393. package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
  394. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  395. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -2
  396. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
  397. package/dist/src/cli/commands/extension-create.js +1 -1
  398. package/dist/src/cli/commands/extension-dev.js +2 -2
  399. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  400. package/dist/src/cli/commands/extension-pack.js +2 -2
  401. package/dist/src/cli/commands/extension.js +3 -3
  402. package/dist/src/cli/commands/gateway/logs.js +1 -1
  403. package/dist/src/cli/commands/goal.js +1 -1
  404. package/dist/src/cli/commands/image.js +13 -372
  405. package/dist/src/cli/commands/image.js.map +1 -1
  406. package/dist/src/cli/commands/init.js +7 -6
  407. package/dist/src/cli/commands/init.js.map +1 -1
  408. package/dist/src/cli/commands/models.js +14 -16
  409. package/dist/src/cli/commands/models.js.map +1 -1
  410. package/dist/src/cli/commands/onboard/channels/registry.js.map +1 -1
  411. package/dist/src/cli/commands/onboard/model.js +28 -23
  412. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  413. package/dist/src/cli/commands/onboard.js +3 -3
  414. package/dist/src/cli/commands/onboard.js.map +1 -1
  415. package/dist/src/cli/commands/skills-test.js +1 -1
  416. package/dist/src/cli/commands/tui.js +2 -2
  417. package/dist/src/cli/commands/tui.js.map +1 -1
  418. package/dist/src/cli/index.d.ts +1 -0
  419. package/dist/src/cli/index.js +10 -5
  420. package/dist/src/cli/index.js.map +1 -1
  421. package/dist/src/cli/registry.js +1 -1
  422. package/dist/src/cli/registry.js.map +1 -1
  423. package/dist/src/cli/templates.d.ts +1 -1
  424. package/dist/src/cli/templates.js +2 -12
  425. package/dist/src/cli/templates.js.map +1 -1
  426. package/dist/src/cli/utils/gateway-client.js +1 -1
  427. package/dist/src/cli/utils/init-workspace-core.d.ts +1 -4
  428. package/dist/src/cli/utils/init-workspace-core.js +9 -8
  429. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  430. package/dist/src/commands/agents.config.d.ts +0 -1
  431. package/dist/src/commands/agents.config.js +59 -13
  432. package/dist/src/commands/agents.config.js.map +1 -1
  433. package/dist/src/config/agent-profile.d.ts +5 -17
  434. package/dist/src/config/agent-profile.js +32 -64
  435. package/dist/src/config/agent-profile.js.map +1 -1
  436. package/dist/src/config/agent-typed-models.d.ts +1 -1
  437. package/dist/src/config/agent-typed-models.js +3 -6
  438. package/dist/src/config/agent-typed-models.js.map +1 -1
  439. package/dist/src/config/gateway-bind.js +1 -1
  440. package/dist/src/config/index.js +9 -9
  441. package/dist/src/config/integration.d.ts +1 -1
  442. package/dist/src/config/loader.js +4 -4
  443. package/dist/src/config/models-json.js +2 -2
  444. package/dist/src/config/paths-state.js +1 -1
  445. package/dist/src/config/paths.d.ts +8 -1
  446. package/dist/src/config/paths.js +17 -4
  447. package/dist/src/config/paths.js.map +1 -1
  448. package/dist/src/config/profile.js +1 -1
  449. package/dist/src/config/reload.js +2 -2
  450. package/dist/src/config/reload.js.map +1 -1
  451. package/dist/src/config/rules.js +6 -56
  452. package/dist/src/config/rules.js.map +1 -1
  453. package/dist/src/config/schema.d.ts +916 -779
  454. package/dist/src/config/schema.js +174 -423
  455. package/dist/src/config/schema.js.map +1 -1
  456. package/dist/src/config/workspace-path.js +1 -1
  457. package/dist/src/connectors/composio-triggers.js +1 -1
  458. package/dist/src/cron/executor.js +1 -1
  459. package/dist/src/cron/index.js +1 -1
  460. package/dist/src/cron/service.js +2 -2
  461. package/dist/src/cron/validation.d.ts +3 -3
  462. package/dist/src/daemon/constants.js +1 -1
  463. package/dist/src/daemon/install-plan.js +2 -2
  464. package/dist/src/daemon/launchd.js +2 -2
  465. package/dist/src/daemon/schtasks.js +2 -2
  466. package/dist/src/daemon/systemd.js +2 -2
  467. package/dist/src/extensions/activation-context.js +13 -7
  468. package/dist/src/extensions/activation-context.js.map +1 -1
  469. package/dist/src/extensions/bundle-mcp.js +1 -1
  470. package/dist/src/extensions/discover-extensions.js +2 -2
  471. package/dist/src/extensions/health.js +1 -1
  472. package/dist/src/extensions/install.js +2 -2
  473. package/dist/src/extensions/loader.js +2 -2
  474. package/dist/src/extensions/lockfile.js +3 -3
  475. package/dist/src/extensions/security.js +1 -1
  476. package/dist/src/extensions/update.js +2 -2
  477. package/dist/src/gateway/agents-admin.d.ts +24 -18
  478. package/dist/src/gateway/agents-admin.js +158 -92
  479. package/dist/src/gateway/agents-admin.js.map +1 -1
  480. package/dist/src/gateway/capability-presets-admin.d.ts +56 -0
  481. package/dist/src/gateway/capability-presets-admin.js +214 -0
  482. package/dist/src/gateway/capability-presets-admin.js.map +1 -0
  483. package/dist/src/gateway/chat-stream/mapper.js +9 -2
  484. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  485. package/dist/src/gateway/file-path-classifier.js +2 -2
  486. package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
  487. package/dist/src/gateway/global-defaults-admin.js +146 -0
  488. package/dist/src/gateway/global-defaults-admin.js.map +1 -0
  489. package/dist/src/gateway/hono/lib/agent-model.d.ts +1 -1
  490. package/dist/src/gateway/hono/lib/agent-model.js +1 -1
  491. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  492. package/dist/src/gateway/hono/lib/config-payload.d.ts +234 -127
  493. package/dist/src/gateway/hono/lib/config-payload.js +14 -38
  494. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  495. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  496. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  497. package/dist/src/gateway/hono/routes/agents.js +88 -33
  498. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  499. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  500. package/dist/src/gateway/hono/routes/browser.js +8 -15
  501. package/dist/src/gateway/hono/routes/browser.js.map +1 -1
  502. package/dist/src/gateway/hono/routes/capability-presets.d.ts +3 -0
  503. package/dist/src/gateway/hono/routes/capability-presets.js +145 -0
  504. package/dist/src/gateway/hono/routes/capability-presets.js.map +1 -0
  505. package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
  506. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  507. package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +1 -17
  508. package/dist/src/gateway/hono/routes/config-patch/agents.js +2 -443
  509. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  510. package/dist/src/gateway/hono/routes/config-patch/misc.js +7 -1
  511. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  512. package/dist/src/gateway/hono/routes/config.js +1 -1
  513. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  514. package/dist/src/gateway/hono/routes/dreaming.js +8 -1
  515. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  516. package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
  517. package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
  518. package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
  519. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  520. package/dist/src/gateway/hono/routes/index.js +2 -0
  521. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  522. package/dist/src/gateway/hono/routes/lazy-bundles.js +17 -1
  523. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  524. package/dist/src/gateway/hono/routes/memory.d.ts +3 -0
  525. package/dist/src/gateway/hono/routes/memory.js +361 -0
  526. package/dist/src/gateway/hono/routes/memory.js.map +1 -0
  527. package/dist/src/gateway/hono/routes/models.js +2 -2
  528. package/dist/src/gateway/hono/routes/shares.js +1 -1
  529. package/dist/src/gateway/hono/routes/workflows.js +1 -1
  530. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  531. package/dist/src/gateway/lock.js +3 -3
  532. package/dist/src/gateway/ports.js +1 -1
  533. package/dist/src/gateway/service/config-coordinator.js +1 -1
  534. package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
  535. package/dist/src/gateway/service/marketplace-service.js +13 -9
  536. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  537. package/dist/src/gateway/service.d.ts +1 -1
  538. package/dist/src/gateway/service.js +15 -16
  539. package/dist/src/gateway/service.js.map +1 -1
  540. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  541. package/dist/src/goals/goal-workflow-judge.js +2 -2
  542. package/dist/src/i18n/goals-bundle.js +1 -1
  543. package/dist/src/i18n/index.js +1 -1
  544. package/dist/src/i18n/share-tool-bundle.js +2 -2
  545. package/dist/src/infra/brew.js +1 -1
  546. package/dist/src/infra/package-json.js +1 -1
  547. package/dist/src/infra/package-update-steps.js +1 -1
  548. package/dist/src/infra/path-env.js +2 -2
  549. package/dist/src/infra/restart.js +1 -1
  550. package/dist/src/infra/stable-node-path.js +1 -1
  551. package/dist/src/infra/update-check.js +1 -1
  552. package/dist/src/infra/update-global.js +1 -1
  553. package/dist/src/infra/update-lock.js +2 -2
  554. package/dist/src/infra/update-restart.js +1 -1
  555. package/dist/src/infra/update-runner.js +1 -1
  556. package/dist/src/infra/update-startup.js +1 -1
  557. package/dist/src/infra/write-file-atomic.js +2 -2
  558. package/dist/src/media/store.js +1 -1
  559. package/dist/src/notes/agent-context.js +3 -3
  560. package/dist/src/notes/service.js +4 -2
  561. package/dist/src/notes/service.js.map +1 -1
  562. package/dist/src/notes/store.js +2 -2
  563. package/dist/src/project-trust/trust-store.js +2 -2
  564. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  565. package/dist/src/providers/index.d.ts +5 -6
  566. package/dist/src/providers/index.js +26 -30
  567. package/dist/src/providers/index.js.map +1 -1
  568. package/dist/src/providers/model-registry.js +4 -4
  569. package/dist/src/session/index.js +1 -1
  570. package/dist/src/session/init-session-turn.js +1 -1
  571. package/dist/src/session/resolve-session.js +1 -1
  572. package/dist/src/session/session-title.js +2 -2
  573. package/dist/src/session/store.js +1 -1
  574. package/dist/src/session/thinking-resolve.d.ts +1 -1
  575. package/dist/src/session/thinking-resolve.js +1 -1
  576. package/dist/src/session/thinking-resolve.js.map +1 -1
  577. package/dist/src/share/share-auto.js +2 -2
  578. package/dist/src/share/share-store.js +3 -3
  579. package/dist/src/share/share-thumbnail.js +2 -2
  580. package/dist/src/share/share-zip.js +1 -1
  581. package/dist/src/share/site-share-store.js +3 -3
  582. package/dist/src/share/site-static-serve.js +1 -1
  583. package/dist/src/storage/sqlite/connection.js +2 -2
  584. package/dist/src/storage/sqlite/index.d.ts +1 -0
  585. package/dist/src/storage/sqlite/index.js +2 -1
  586. package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
  587. package/dist/src/storage/sqlite/memory-index-repository.js +17 -16
  588. package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
  589. package/dist/src/storage/sqlite/memory-records-repository.d.ts +144 -0
  590. package/dist/src/storage/sqlite/memory-records-repository.js +453 -0
  591. package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -0
  592. package/dist/src/storage/sqlite/migrations/012_memory_records.sql +63 -0
  593. package/dist/src/storage/sqlite/migrations/013_memory_trace_events.sql +21 -0
  594. package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
  595. package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
  596. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  597. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  598. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  599. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  600. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  601. package/dist/src/storage/sqlite/schema.js +2 -2
  602. package/dist/src/storage/sqlite/schema.sql +86 -0
  603. package/dist/src/tui/backends/embedded-backend.d.ts +3 -0
  604. package/dist/src/tui/backends/embedded-backend.js +43 -24
  605. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  606. package/dist/src/tui/backends/gateway-sse-backend.d.ts +1 -0
  607. package/dist/src/tui/backends/gateway-sse-backend.js +16 -3
  608. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  609. package/dist/src/tui/clipboard-image.js +3 -3
  610. package/dist/src/tui/components/tui-header.d.ts +0 -1
  611. package/dist/src/tui/components/tui-header.js +3 -8
  612. package/dist/src/tui/components/tui-header.js.map +1 -1
  613. package/dist/src/tui/extension-host/load-extensions.js +1 -1
  614. package/dist/src/tui/extension-host/load-extensions.js.map +1 -1
  615. package/dist/src/tui/theme-manager.js +1 -1
  616. package/dist/src/tui/tui-command-formatters.js +4 -4
  617. package/dist/src/tui/tui-commands.js +2 -2
  618. package/dist/src/tui/tui-keybindings-file.js +1 -1
  619. package/dist/src/tui/tui-scoped-models.js +2 -2
  620. package/dist/src/tui/tui-settings.js +1 -1
  621. package/dist/src/tui/tui-startup-resources.js +2 -1
  622. package/dist/src/tui/tui-startup-resources.js.map +1 -1
  623. package/dist/src/tui/tui-startup-text.js +12 -12
  624. package/dist/src/tui/tui-startup-text.js.map +1 -1
  625. package/dist/src/tui/tui.js +10 -7
  626. package/dist/src/tui/tui.js.map +1 -1
  627. package/dist/src/tunnel/frpc-binary.js +4 -4
  628. package/dist/src/tunnel/frpc-config.js +1 -1
  629. package/dist/src/tunnel/frpc-extract.js +1 -1
  630. package/dist/src/tunnel/tunnel-state.js +1 -1
  631. package/dist/src/utils/logger/audit.js +1 -1
  632. package/dist/src/utils/logger/log-store.js +1 -1
  633. package/dist/src/utils/logger/rotation.js +1 -1
  634. package/dist/src/utils/logger/streams.js +1 -1
  635. package/dist/src/voice/tts/audio.js +1 -1
  636. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  637. package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
  638. package/dist/src/workflows/service/workflow-run-service.js +4 -5
  639. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  640. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  641. package/dist/src/workflows/store/event-store.js +1 -1
  642. package/dist/src/workflows/store/run-store.js +1 -1
  643. package/package.json +3 -2
  644. package/dist/gateway/static/root/assets/agent-browser-settings-page-D1SyFYeh.js +0 -6
  645. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-C9YxgvuI.js +0 -1
  646. package/dist/gateway/static/root/assets/agents-CteVs3UO.js +0 -71
  647. package/dist/gateway/static/root/assets/apps-page-CVQ1M8Ax.js +0 -1
  648. package/dist/gateway/static/root/assets/channels-settings-Cd3JbeQ1.js +0 -1
  649. package/dist/gateway/static/root/assets/config-api-C4RAtTKW.js +0 -3
  650. package/dist/gateway/static/root/assets/connectors-page-MsMa5qBr.js +0 -2
  651. package/dist/gateway/static/root/assets/cron-api-sJNMqB6P.js +0 -1
  652. package/dist/gateway/static/root/assets/cron-page-D30CSwkn.js +0 -3
  653. package/dist/gateway/static/root/assets/dreaming-settings-6fCUWRQf.js +0 -1
  654. package/dist/gateway/static/root/assets/gateway-config-api-C6989a-W.js +0 -1
  655. package/dist/gateway/static/root/assets/gateway-settings-BpF26t91.js +0 -1
  656. package/dist/gateway/static/root/assets/goal-detail-page-DOjhmRyf.js +0 -1
  657. package/dist/gateway/static/root/assets/goals-page-Xl9_wrFc.js +0 -2
  658. package/dist/gateway/static/root/assets/heartbeat-settings-DN9vEj9P.js +0 -1
  659. package/dist/gateway/static/root/assets/index-C8ytlAF2.js +0 -122
  660. package/dist/gateway/static/root/assets/index-CVpJW2NS.css +0 -1
  661. package/dist/gateway/static/root/assets/messages-BqzIDrlr.js +0 -3
  662. package/dist/gateway/static/root/assets/models-hub-panel-BO4o-GmO.js +0 -2
  663. package/dist/gateway/static/root/assets/note-detail-page-DLV_XDmT.js +0 -2
  664. package/dist/gateway/static/root/assets/notes-page-ycsDlkFA.js +0 -1
  665. package/dist/gateway/static/root/assets/remote-access-hub-DQpnE8K9.js +0 -1
  666. package/dist/gateway/static/root/assets/sessions-page-BZui7iAY.js +0 -1
  667. package/dist/gateway/static/root/assets/settings-advanced-gate-DEfzZ1ax.js +0 -1
  668. package/dist/gateway/static/root/assets/settings-page-CLuSsu1-.js +0 -1
  669. package/dist/gateway/static/root/assets/setup-status-panel-Cq4qpXLi.js +0 -1
  670. package/dist/gateway/static/root/assets/shares-settings-B9F3HyYQ.js +0 -1
  671. package/dist/gateway/static/root/assets/skill-reload-api-Bp9UPPwm.js +0 -1
  672. package/dist/gateway/static/root/assets/skills-page-BIoBsfSV.js +0 -2
  673. package/dist/gateway/static/root/assets/use-agent-defaults-form-Cz2_pPzu.js +0 -1
  674. package/dist/gateway/static/root/assets/use-settings-tab-guard-nuHMmZQv.js +0 -1
  675. package/dist/gateway/static/root/assets/voice-api-key-field-BUIrKb8s.js +0 -1
  676. package/dist/gateway/static/root/assets/workflows-page-qE3SexnO.js +0 -18
  677. package/dist/src/agent/context/workspace-templates/USER.md +0 -24
@@ -1,4 +1,3 @@
1
- import { memoryGet, memorySearch } from "../prompt/memory/index.js";
2
1
  import { recordDreamingRecalls } from "../memory/dreaming/short-term-store.js";
3
2
  import { Type } from "@sinclair/typebox";
4
3
  //#region src/agent/tools/memory-tool.ts
@@ -8,7 +7,7 @@ const MemorySearchSchema = Type.Object({
8
7
  minScore: Type.Optional(Type.Number())
9
8
  });
10
9
  function createMemorySearchTool(options) {
11
- const { workspaceDir, memoriesDir } = options;
10
+ const { workspaceDir, getMemoryManager } = options;
12
11
  return {
13
12
  name: "memory_search",
14
13
  label: "🔍 Memory Search",
@@ -17,27 +16,49 @@ function createMemorySearchTool(options) {
17
16
  async execute(_toolCallId, params, _signal) {
18
17
  const { query, maxResults, minScore } = params;
19
18
  try {
20
- const results = await memorySearch(workspaceDir, query, {
19
+ const results = await getMemoryManager().search({
20
+ query,
21
21
  maxResults,
22
- minScore,
23
- memoriesDir
22
+ minScore
23
+ });
24
+ for (const result of results) getMemoryManager().recordSignal({
25
+ source: "search_recall",
26
+ recordId: result.record.id,
27
+ score: result.score,
28
+ content: result.snippet,
29
+ metadata: {
30
+ providerId: result.citation.providerId,
31
+ path: result.citation.path,
32
+ lineStart: result.citation.lineStart,
33
+ lineEnd: result.citation.lineEnd
34
+ }
24
35
  });
25
36
  recordDreamingRecalls({
26
37
  workspaceDir,
27
38
  query,
28
- matches: results
39
+ matches: results.map((entry) => ({
40
+ file: entry.citation.path ?? entry.record.source.path ?? entry.record.id,
41
+ lines: entry.snippet,
42
+ score: entry.score,
43
+ lineNumbers: entry.citation.lineStart != null ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart] : []
44
+ }))
29
45
  }).catch(() => {});
30
46
  const withCitations = results.map((entry) => ({
31
- ...entry,
32
- citation: `${entry.file}#L${entry.lineNumbers[0]}${entry.lineNumbers.length > 1 ? `-L${entry.lineNumbers[entry.lineNumbers.length - 1]}` : ""}`,
33
- snippet: `${entry.lines.trim()}\n\nSource: ${entry.file}#L${entry.lineNumbers[0]}${entry.lineNumbers.length > 1 ? `-L${entry.lineNumbers[entry.lineNumbers.length - 1]}` : ""}`
47
+ id: entry.record.id,
48
+ kind: entry.record.kind,
49
+ file: entry.citation.path ?? entry.record.source.path,
50
+ lines: entry.snippet,
51
+ score: entry.score,
52
+ lineNumbers: entry.citation.lineStart != null ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart] : [],
53
+ citation: `${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ""}` : ""}`,
54
+ snippet: `${entry.snippet.trim()}\n\nSource: ${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ""}` : ""}`
34
55
  }));
35
56
  return {
36
57
  content: [{
37
58
  type: "text",
38
59
  text: JSON.stringify({
39
60
  results: withCitations,
40
- provider: "simple"
61
+ provider: "memory-manager"
41
62
  }, null, 2)
42
63
  }],
43
64
  details: { results: withCitations }
@@ -61,7 +82,7 @@ const MemoryGetSchema = Type.Object({
61
82
  lines: Type.Optional(Type.Number())
62
83
  });
63
84
  function createMemoryGetTool(options) {
64
- const { workspaceDir, memoriesDir } = options;
85
+ const { getMemoryManager } = options;
65
86
  return {
66
87
  name: "memory_get",
67
88
  label: "📄 Memory Get",
@@ -70,7 +91,11 @@ function createMemoryGetTool(options) {
70
91
  async execute(_toolCallId, params, _signal) {
71
92
  const { path, from, lines } = params;
72
93
  try {
73
- const result = memoryGet(workspaceDir, path, from, lines, memoriesDir);
94
+ const result = await getMemoryManager().read({
95
+ path,
96
+ from,
97
+ lines
98
+ });
74
99
  if (!result) return {
75
100
  content: [{
76
101
  type: "text",
@@ -84,11 +109,11 @@ function createMemoryGetTool(options) {
84
109
  return {
85
110
  content: [{
86
111
  type: "text",
87
- text: result.content
112
+ text: result.record.content
88
113
  }],
89
114
  details: {
90
115
  path,
91
- text: result.content,
116
+ text: result.record.content,
92
117
  lineNumbers: result.lineNumbers
93
118
  }
94
119
  };
@@ -1 +1 @@
1
- {"version":3,"file":"memory-tool.js","names":[],"sources":["../../../../src/agent/tools/memory-tool.ts"],"sourcesContent":["// Memory search tools for xopc agent\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { memorySearch, memoryGet } from '../prompt/memory/index.js';\nimport { recordDreamingRecalls } from '../memory/dreaming/short-term-store.js';\n\n// =============================================================================\n// Memory Search Tool\n// =============================================================================\nconst MemorySearchSchema = Type.Object({\n query: Type.String(),\n maxResults: Type.Optional(Type.Number()),\n minScore: Type.Optional(Type.Number()),\n});\n\ntype MemorySearchParams = { query: string; maxResults?: number; minScore?: number };\n\nexport interface MemoryToolOptions {\n workspaceDir: string;\n /** Agent home curated memories dir, e.g. ~/.xopc/agents/<id>/memories/ */\n memoriesDir?: string;\n}\n\nexport function createMemorySearchTool(options: MemoryToolOptions): AgentTool {\n const { workspaceDir, memoriesDir } = options;\n return {\n name: 'memory_search',\n label: '🔍 Memory Search',\n description:\n 'Mandatory recall step: semantically search profile MEMORY.md, agent-home `memories/*.md`, and workspace `memory/*.md` before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with path + lines.',\n parameters: MemorySearchSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { query, maxResults, minScore } = params as MemorySearchParams;\n\n try {\n const results = await memorySearch(workspaceDir, query, { maxResults, minScore, memoriesDir });\n // Dreaming: record short-term recall evidence from memory_search.\n // Only records workspace daily notes (`memory/YYYY-MM-DD.md`) and ignores curated/long-term files.\n void recordDreamingRecalls({ workspaceDir, query, matches: results }).catch(() => {});\n const withCitations = results.map((entry) => ({\n ...entry,\n citation: `${entry.file}#L${entry.lineNumbers[0]}${entry.lineNumbers.length > 1 ? `-L${entry.lineNumbers[entry.lineNumbers.length - 1]}` : ''}`,\n snippet: `${entry.lines.trim()}\\n\\nSource: ${entry.file}#L${entry.lineNumbers[0]}${entry.lineNumbers.length > 1 ? `-L${entry.lineNumbers[entry.lineNumbers.length - 1]}` : ''}`,\n }));\n\n return {\n content: [{ type: 'text', text: JSON.stringify({ results: withCitations, provider: 'simple' }, null, 2) }],\n details: { results: withCitations },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Search error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n\n// =============================================================================\n// Memory Get Tool\n// =============================================================================\nconst MemoryGetSchema = Type.Object({\n path: Type.String(),\n from: Type.Optional(Type.Number()),\n lines: Type.Optional(Type.Number()),\n});\n\ntype MemoryGetParams = { path: string; from?: number; lines?: number };\n\nexport function createMemoryGetTool(options: MemoryToolOptions): AgentTool {\n const { workspaceDir, memoriesDir } = options;\n return {\n name: 'memory_get',\n label: '📄 Memory Get',\n description: 'Safe snippet read from MEMORY.md or memory/*.md with optional from/lines; use after memory_search to pull only the needed lines and keep context small.',\n parameters: MemoryGetSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { path, from, lines } = params as MemoryGetParams;\n\n try {\n const result = memoryGet(workspaceDir, path, from, lines, memoriesDir);\n if (!result) {\n return {\n content: [{ type: 'text', text: `File not found: ${path}` }],\n details: { path, text: '' },\n };\n }\n return {\n content: [{ type: 'text', text: result.content }],\n details: { path, text: result.content, lineNumbers: result.lineNumbers },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Read error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n"],"mappings":";;;;AASA,MAAM,qBAAqB,KAAK,OAAO;CACrC,OAAO,KAAK,QAAQ;CACpB,YAAY,KAAK,SAAS,KAAK,QAAQ,CAAC;CACxC,UAAU,KAAK,SAAS,KAAK,QAAQ,CAAC;CACvC,CAAC;AAUF,SAAgB,uBAAuB,SAAuC;CAC5E,MAAM,EAAE,cAAc,gBAAgB;AACtC,QAAO;EACL,MAAM;EACN,OAAO;EACP,aACE;EACF,YAAY;EAEZ,MAAM,QACJ,aACA,QACA,SAC8B;GAC9B,MAAM,EAAE,OAAO,YAAY,aAAa;AAExC,OAAI;IACF,MAAM,UAAU,MAAM,aAAa,cAAc,OAAO;KAAE;KAAY;KAAU;KAAa,CAAC;AAGzF,0BAAsB;KAAE;KAAc;KAAO,SAAS;KAAS,CAAC,CAAC,YAAY,GAAG;IACrF,MAAM,gBAAgB,QAAQ,KAAK,WAAW;KAC5C,GAAG;KACH,UAAU,GAAG,MAAM,KAAK,IAAI,MAAM,YAAY,KAAK,MAAM,YAAY,SAAS,IAAI,KAAK,MAAM,YAAY,MAAM,YAAY,SAAS,OAAO;KAC3I,SAAS,GAAG,MAAM,MAAM,MAAM,CAAC,cAAc,MAAM,KAAK,IAAI,MAAM,YAAY,KAAK,MAAM,YAAY,SAAS,IAAI,KAAK,MAAM,YAAY,MAAM,YAAY,SAAS,OAAO;KAC5K,EAAE;AAEH,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,KAAK,UAAU;OAAE,SAAS;OAAe,UAAU;OAAU,EAAE,MAAM,EAAE;MAAE,CAAC;KAC1G,SAAS,EAAE,SAAS,eAAe;KACpC;YACM,KAAK;IACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,iBAAiB;MAAW,CAAC;KAC7D,SAAS,EAAE,OAAO,SAAS;KAC5B;;;EAGN;;AAMH,MAAM,kBAAkB,KAAK,OAAO;CAClC,MAAM,KAAK,QAAQ;CACnB,MAAM,KAAK,SAAS,KAAK,QAAQ,CAAC;CAClC,OAAO,KAAK,SAAS,KAAK,QAAQ,CAAC;CACpC,CAAC;AAIF,SAAgB,oBAAoB,SAAuC;CACzE,MAAM,EAAE,cAAc,gBAAgB;AACtC,QAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,YAAY;EAEZ,MAAM,QACJ,aACA,QACA,SAC8B;GAC9B,MAAM,EAAE,MAAM,MAAM,UAAU;AAE9B,OAAI;IACF,MAAM,SAAS,UAAU,cAAc,MAAM,MAAM,OAAO,YAAY;AACtE,QAAI,CAAC,OACH,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,mBAAmB;MAAQ,CAAC;KAC5D,SAAS;MAAE;MAAM,MAAM;MAAI;KAC5B;AAEH,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,OAAO;MAAS,CAAC;KACjD,SAAS;MAAE;MAAM,MAAM,OAAO;MAAS,aAAa,OAAO;MAAa;KACzE;YACM,KAAK;IACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,eAAe;MAAW,CAAC;KAC3D,SAAS,EAAE,OAAO,SAAS;KAC5B;;;EAGN"}
1
+ {"version":3,"file":"memory-tool.js","names":[],"sources":["../../../../src/agent/tools/memory-tool.ts"],"sourcesContent":["// Memory search tools for xopc agent\nimport { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { recordDreamingRecalls } from '../memory/dreaming/short-term-store.js';\nimport type { MemoryManager } from '../memory/manager.js';\n\n// =============================================================================\n// Memory Search Tool\n// =============================================================================\nconst MemorySearchSchema = Type.Object({\n query: Type.String(),\n maxResults: Type.Optional(Type.Number()),\n minScore: Type.Optional(Type.Number()),\n});\n\ntype MemorySearchParams = { query: string; maxResults?: number; minScore?: number };\n\nexport interface MemoryToolOptions {\n workspaceDir: string;\n getMemoryManager: () => MemoryManager;\n}\n\nexport function createMemorySearchTool(options: MemoryToolOptions): AgentTool {\n const { workspaceDir, getMemoryManager } = options;\n return {\n name: 'memory_search',\n label: '🔍 Memory Search',\n description:\n 'Mandatory recall step: semantically search profile MEMORY.md, agent-home `memories/*.md`, and workspace `memory/*.md` before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with path + lines.',\n parameters: MemorySearchSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { query, maxResults, minScore } = params as MemorySearchParams;\n\n try {\n const results = await getMemoryManager().search({ query, maxResults, minScore });\n for (const result of results) {\n getMemoryManager().recordSignal({\n source: 'search_recall',\n recordId: result.record.id,\n score: result.score,\n content: result.snippet,\n metadata: {\n providerId: result.citation.providerId,\n path: result.citation.path,\n lineStart: result.citation.lineStart,\n lineEnd: result.citation.lineEnd,\n },\n });\n }\n // Dreaming: record short-term recall evidence from memory_search.\n // Only records workspace daily notes (`memory/YYYY-MM-DD.md`) and ignores curated/long-term files.\n void recordDreamingRecalls({\n workspaceDir,\n query,\n matches: results.map((entry) => ({\n file: entry.citation.path ?? entry.record.source.path ?? entry.record.id,\n lines: entry.snippet,\n score: entry.score,\n lineNumbers:\n entry.citation.lineStart != null\n ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart]\n : [],\n })),\n }).catch(() => {});\n const withCitations = results.map((entry) => ({\n id: entry.record.id,\n kind: entry.record.kind,\n file: entry.citation.path ?? entry.record.source.path,\n lines: entry.snippet,\n score: entry.score,\n lineNumbers:\n entry.citation.lineStart != null\n ? [entry.citation.lineStart, entry.citation.lineEnd ?? entry.citation.lineStart]\n : [],\n citation: `${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ''}` : ''}`,\n snippet: `${entry.snippet.trim()}\\n\\nSource: ${entry.citation.path ?? entry.record.id}${entry.citation.lineStart != null ? `#L${entry.citation.lineStart}${entry.citation.lineEnd && entry.citation.lineEnd !== entry.citation.lineStart ? `-L${entry.citation.lineEnd}` : ''}` : ''}`,\n }));\n\n return {\n content: [{ type: 'text', text: JSON.stringify({ results: withCitations, provider: 'memory-manager' }, null, 2) }],\n details: { results: withCitations },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Search error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n\n// =============================================================================\n// Memory Get Tool\n// =============================================================================\nconst MemoryGetSchema = Type.Object({\n path: Type.String(),\n from: Type.Optional(Type.Number()),\n lines: Type.Optional(Type.Number()),\n});\n\ntype MemoryGetParams = { path: string; from?: number; lines?: number };\n\nexport function createMemoryGetTool(options: MemoryToolOptions): AgentTool {\n const { getMemoryManager } = options;\n return {\n name: 'memory_get',\n label: '📄 Memory Get',\n description: 'Safe snippet read from MEMORY.md or memory/*.md with optional from/lines; use after memory_search to pull only the needed lines and keep context small.',\n parameters: MemoryGetSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n _signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const { path, from, lines } = params as MemoryGetParams;\n\n try {\n const result = await getMemoryManager().read({ path, from, lines });\n if (!result) {\n return {\n content: [{ type: 'text', text: `File not found: ${path}` }],\n details: { path, text: '' },\n };\n }\n return {\n content: [{ type: 'text', text: result.record.content }],\n details: { path, text: result.record.content, lineNumbers: result.lineNumbers },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Read error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -10,9 +10,7 @@ init_logger();
10
10
  const log = createLogger("Agent:SessionSearch");
11
11
  const MAX_SUMMARY_CHARS = 2e4;
12
12
  function resolveSummaryModel(getConfig) {
13
- const envRef = process.env.XOPC_SESSION_SEARCH_MODEL?.trim();
14
- const configRef = getConfig?.()?.agents?.defaults?.sessionSearch?.summaryModel?.trim();
15
- const ref = envRef || configRef;
13
+ const ref = process.env.XOPC_SESSION_SEARCH_MODEL?.trim();
16
14
  if (ref) try {
17
15
  return resolveModel(ref);
18
16
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"session-search-tool.js","names":[],"sources":["../../../../src/agent/tools/session-search-tool.ts"],"sourcesContent":["// Cross-session transcript search + optional LLM summaries\nimport { Type } from '@sinclair/typebox';\nimport type { AgentMessage, AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { readAgentMessageContent } from '../memory/agent-message-access.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('Agent:SessionSearch');\n\nconst MAX_SUMMARY_CHARS = 20_000;\n\nfunction resolveSummaryModel(getConfig?: () => Config | undefined) {\n const envRef = process.env.XOPC_SESSION_SEARCH_MODEL?.trim();\n const configRef = getConfig?.()?.agents?.defaults?.sessionSearch?.summaryModel?.trim();\n const ref = envRef || configRef;\n if (ref) {\n try {\n return resolveModel(ref);\n } catch (err) {\n log.warn({ err, ref }, 'session_search: summary model resolve failed, using fallback');\n }\n }\n try {\n return resolveModel('openai/gpt-4o-mini');\n } catch {\n const d = getDefaultModelSync(getConfig?.());\n return resolveModel(d);\n }\n}\n\nfunction extractTextFromContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return '';\n }\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) {\n continue;\n }\n const c = item as { type?: string; text?: string };\n if (c.type === 'text' && typeof c.text === 'string') {\n parts.push(c.text);\n }\n }\n return parts.join(' ');\n}\n\nfunction formatMessagesForSummary(messages: AgentMessage[]): string {\n const lines: string[] = [];\n let total = 0;\n for (const msg of messages) {\n const role = String(msg.role || 'unknown').toUpperCase();\n const text = extractTextFromContent(readAgentMessageContent(msg));\n const line = `${role}: ${text}`;\n if (total + line.length > MAX_SUMMARY_CHARS) {\n lines.push('… [truncated]');\n break;\n }\n lines.push(line);\n total += line.length + 1;\n }\n return lines.join('\\n\\n');\n}\n\nasync function summarizeSession(\n messages: AgentMessage[],\n query: string,\n getConfig: (() => Config | undefined) | undefined,\n signal: AbortSignal | undefined,\n logMeta?: { summarizingSessionKey: string },\n): Promise<string> {\n if (messages.length === 0) {\n return 'No messages in session.';\n }\n\n const formatted = formatMessagesForSummary(messages);\n const prompt = `Summarize this conversation for someone searching with: \"${query}\". Focus on facts, decisions, and names. Max 200 words. Use the same language as the conversation when possible.\n\nConversation:\n${formatted}`;\n\n const userMsg: UserMessage = { role: 'user', content: prompt, timestamp: Date.now() };\n const model = resolveSummaryModel(getConfig);\n\n try {\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens: 400,\n temperature: 0.15,\n signal: signal as AbortSignal,\n },\n );\n\n let text = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n text += String((c as { text?: string }).text || '');\n }\n }\n }\n return text.trim() || '[Empty summary]';\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n {\n err,\n summarizingSessionKey: logMeta?.summarizingSessionKey,\n queryLength: query.length,\n messageCount: messages.length,\n },\n `session_search LLM summarization failed${logMeta?.summarizingSessionKey ? ` (session ${logMeta.summarizingSessionKey})` : ''}: ${msg}`,\n );\n return `[Summarization failed: ${msg}]`;\n }\n}\n\nconst SessionSearchSchema = Type.Object({\n query: Type.Optional(\n Type.String({ description: 'Keyword search over past sessions. Omit to list recent sessions.' }),\n ),\n roleFilter: Type.Optional(\n Type.Union([\n Type.Literal('user'),\n Type.Literal('assistant'),\n Type.Literal('system'),\n Type.Literal('tool'),\n Type.Literal('toolResult'),\n ]),\n ),\n limit: Type.Optional(Type.Number({ minimum: 1, maximum: 15 })),\n excludeSessionKey: Type.Optional(\n Type.String({ description: 'Exclude this session key from keyword results (default: current chat).' }),\n ),\n});\n\nexport interface SessionSearchToolDeps {\n getSessionStore: () => SessionStore;\n getConfig?: () => Config | undefined;\n getCurrentSessionKey?: () => string | undefined;\n}\n\ntype SessionSearchParams = {\n query?: string;\n roleFilter?: 'user' | 'assistant' | 'system' | 'tool' | 'toolResult';\n limit?: number;\n excludeSessionKey?: string;\n};\n\nexport function createSessionSearchTool(deps: SessionSearchToolDeps): AgentTool {\n return {\n name: 'session_search',\n label: 'Session search',\n description:\n 'Search other chat sessions by keywords and get short summaries, or omit `query` to list recent sessions (no LLM cost). Uses the same session store as the gateway. Narrow with roleFilter if needed.',\n parameters: SessionSearchSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const p = params as SessionSearchParams;\n const store = deps.getSessionStore();\n const limit = Math.min(15, Math.max(1, p.limit ?? 5));\n const query = p.query?.trim() ?? '';\n\n try {\n if (!query) {\n const listed = await store.list({\n limit: limit + 5,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n const items = listed.items.slice(0, limit).map((s) => ({\n key: s.key,\n name: s.name,\n updatedAt: s.updatedAt,\n messageCount: s.messageCount,\n sourceChannel: s.sourceChannel,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n { success: true, mode: 'recent', results: items, total: listed.total },\n null,\n 2,\n ),\n },\n ],\n details: { mode: 'recent', items },\n };\n }\n\n const listed = await store.list({\n search: query,\n limit: limit + 10,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n let matches = listed.items.map((item) => ({ key: item.key, score: 1 }));\n\n const exclude = p.excludeSessionKey?.trim() || deps.getCurrentSessionKey?.() || '';\n if (exclude) {\n matches = matches.filter((m) => m.key !== exclude);\n }\n\n const top = matches.slice(0, limit);\n\n const summaries = await Promise.all(\n top.map(async ({ key, score }) => {\n let messages = await store.load(key);\n\n if (p.roleFilter) {\n messages = messages.filter((m) => m.role === p.roleFilter);\n }\n\n const summary = await summarizeSession(messages, query, deps.getConfig, signal, {\n summarizingSessionKey: key,\n });\n return { sessionKey: key, score, summary };\n }),\n );\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n mode: 'keyword',\n query,\n results: summaries,\n count: summaries.length,\n },\n null,\n 2,\n ),\n },\n ],\n details: { query, summaries },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `session_search error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session-search-tool.js","names":[],"sources":["../../../../src/agent/tools/session-search-tool.ts"],"sourcesContent":["// Cross-session transcript search + optional LLM summaries\nimport { Type } from '@sinclair/typebox';\nimport type { AgentMessage, AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { readAgentMessageContent } from '../memory/agent-message-access.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('Agent:SessionSearch');\n\nconst MAX_SUMMARY_CHARS = 20_000;\n\nfunction resolveSummaryModel(getConfig?: () => Config | undefined) {\n const envRef = process.env.XOPC_SESSION_SEARCH_MODEL?.trim();\n const ref = envRef;\n if (ref) {\n try {\n return resolveModel(ref);\n } catch (err) {\n log.warn({ err, ref }, 'session_search: summary model resolve failed, using fallback');\n }\n }\n try {\n return resolveModel('openai/gpt-4o-mini');\n } catch {\n const d = getDefaultModelSync(getConfig?.());\n return resolveModel(d);\n }\n}\n\nfunction extractTextFromContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return '';\n }\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) {\n continue;\n }\n const c = item as { type?: string; text?: string };\n if (c.type === 'text' && typeof c.text === 'string') {\n parts.push(c.text);\n }\n }\n return parts.join(' ');\n}\n\nfunction formatMessagesForSummary(messages: AgentMessage[]): string {\n const lines: string[] = [];\n let total = 0;\n for (const msg of messages) {\n const role = String(msg.role || 'unknown').toUpperCase();\n const text = extractTextFromContent(readAgentMessageContent(msg));\n const line = `${role}: ${text}`;\n if (total + line.length > MAX_SUMMARY_CHARS) {\n lines.push('… [truncated]');\n break;\n }\n lines.push(line);\n total += line.length + 1;\n }\n return lines.join('\\n\\n');\n}\n\nasync function summarizeSession(\n messages: AgentMessage[],\n query: string,\n getConfig: (() => Config | undefined) | undefined,\n signal: AbortSignal | undefined,\n logMeta?: { summarizingSessionKey: string },\n): Promise<string> {\n if (messages.length === 0) {\n return 'No messages in session.';\n }\n\n const formatted = formatMessagesForSummary(messages);\n const prompt = `Summarize this conversation for someone searching with: \"${query}\". Focus on facts, decisions, and names. Max 200 words. Use the same language as the conversation when possible.\n\nConversation:\n${formatted}`;\n\n const userMsg: UserMessage = { role: 'user', content: prompt, timestamp: Date.now() };\n const model = resolveSummaryModel(getConfig);\n\n try {\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens: 400,\n temperature: 0.15,\n signal: signal as AbortSignal,\n },\n );\n\n let text = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n text += String((c as { text?: string }).text || '');\n }\n }\n }\n return text.trim() || '[Empty summary]';\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n {\n err,\n summarizingSessionKey: logMeta?.summarizingSessionKey,\n queryLength: query.length,\n messageCount: messages.length,\n },\n `session_search LLM summarization failed${logMeta?.summarizingSessionKey ? ` (session ${logMeta.summarizingSessionKey})` : ''}: ${msg}`,\n );\n return `[Summarization failed: ${msg}]`;\n }\n}\n\nconst SessionSearchSchema = Type.Object({\n query: Type.Optional(\n Type.String({ description: 'Keyword search over past sessions. Omit to list recent sessions.' }),\n ),\n roleFilter: Type.Optional(\n Type.Union([\n Type.Literal('user'),\n Type.Literal('assistant'),\n Type.Literal('system'),\n Type.Literal('tool'),\n Type.Literal('toolResult'),\n ]),\n ),\n limit: Type.Optional(Type.Number({ minimum: 1, maximum: 15 })),\n excludeSessionKey: Type.Optional(\n Type.String({ description: 'Exclude this session key from keyword results (default: current chat).' }),\n ),\n});\n\nexport interface SessionSearchToolDeps {\n getSessionStore: () => SessionStore;\n getConfig?: () => Config | undefined;\n getCurrentSessionKey?: () => string | undefined;\n}\n\ntype SessionSearchParams = {\n query?: string;\n roleFilter?: 'user' | 'assistant' | 'system' | 'tool' | 'toolResult';\n limit?: number;\n excludeSessionKey?: string;\n};\n\nexport function createSessionSearchTool(deps: SessionSearchToolDeps): AgentTool {\n return {\n name: 'session_search',\n label: 'Session search',\n description:\n 'Search other chat sessions by keywords and get short summaries, or omit `query` to list recent sessions (no LLM cost). Uses the same session store as the gateway. Narrow with roleFilter if needed.',\n parameters: SessionSearchSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{}>> {\n const p = params as SessionSearchParams;\n const store = deps.getSessionStore();\n const limit = Math.min(15, Math.max(1, p.limit ?? 5));\n const query = p.query?.trim() ?? '';\n\n try {\n if (!query) {\n const listed = await store.list({\n limit: limit + 5,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n const items = listed.items.slice(0, limit).map((s) => ({\n key: s.key,\n name: s.name,\n updatedAt: s.updatedAt,\n messageCount: s.messageCount,\n sourceChannel: s.sourceChannel,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n { success: true, mode: 'recent', results: items, total: listed.total },\n null,\n 2,\n ),\n },\n ],\n details: { mode: 'recent', items },\n };\n }\n\n const listed = await store.list({\n search: query,\n limit: limit + 10,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n let matches = listed.items.map((item) => ({ key: item.key, score: 1 }));\n\n const exclude = p.excludeSessionKey?.trim() || deps.getCurrentSessionKey?.() || '';\n if (exclude) {\n matches = matches.filter((m) => m.key !== exclude);\n }\n\n const top = matches.slice(0, limit);\n\n const summaries = await Promise.all(\n top.map(async ({ key, score }) => {\n let messages = await store.load(key);\n\n if (p.roleFilter) {\n messages = messages.filter((m) => m.role === p.roleFilter);\n }\n\n const summary = await summarizeSession(messages, query, deps.getConfig, signal, {\n summarizingSessionKey: key,\n });\n return { sessionKey: key, score, summary };\n }),\n );\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n mode: 'keyword',\n query,\n results: summaries,\n count: summaries.length,\n },\n null,\n 2,\n ),\n },\n ],\n details: { query, summaries },\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `session_search error: ${message}` }],\n details: { error: message },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { resolveStateDir } from "../../config/paths-state.js";
2
2
  import { init_paths } from "../../config/paths.js";
3
3
  import { createSkillConfigManager } from "../skills/config.js";
4
4
  import { applyPatchToContent, atomicWriteUtf8, effectiveAgentWritePolicy, ensureCategorySegment, isPathInsideDir, maxSkillMdChars, maxSupportFileBytes, mutatableSkillOrNull, resolveCreateSkillDir, scanSkillDirOrError, validateSkillMdContent, validateSkillNameSegment, validateSupportingRelativePath } from "../skills/skill-manage-ops.js";
5
- import { existsSync, rmSync } from "fs";
6
5
  import { join } from "path";
6
+ import { existsSync, rmSync } from "fs";
7
7
  import { readFile, rm } from "fs/promises";
8
8
  import { Type } from "@sinclair/typebox";
9
9
  //#region src/agent/tools/skill-manage-tool.ts
@@ -44,16 +44,13 @@ function stripHtmlBoilerplate(html, maxRaw = MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT)
44
44
  return cleaned;
45
45
  }
46
46
  function resolveExtractionModel(config) {
47
- const envRef = process.env.XOPC_WEB_EXTRACT_MODEL?.trim();
48
- const configRef = typeof config?.agents?.defaults?.webExtract?.model === "string" ? config.agents.defaults.webExtract.model.trim() : "";
49
- const ref = envRef || configRef;
47
+ const ref = process.env.XOPC_WEB_EXTRACT_MODEL?.trim();
50
48
  if (ref) try {
51
49
  return resolveModel(ref);
52
50
  } catch {}
53
- for (const candidate of ["openai/gpt-4o-mini", "google/gemini-2.0-flash"]) try {
54
- return resolveModel(candidate);
55
- } catch {}
56
- return resolveModel(getDefaultModelSync(config));
51
+ const defaultRef = getDefaultModelSync(config);
52
+ if (!defaultRef) throw new Error("No global default model configured for web extraction");
53
+ return resolveModel(defaultRef);
57
54
  }
58
55
  function buildExtractionSystemPrompt(maxLength) {
59
56
  return `You are a web content extractor. Given raw HTML/text from a web page, extract the relevant content as clean, well-structured markdown.
@@ -195,6 +192,9 @@ async function synthesizeChunkSummaries(summaries, url, instruction, maxLength,
195
192
  return fallback.length > outputCap ? fallback.slice(0, outputCap) + "\n\n[...truncated due to synthesis failure]" : fallback;
196
193
  }
197
194
  }
195
+ function resolveConfiguredMaxLength() {
196
+ return DEFAULT_WEB_EXTRACT_MAX_LENGTH;
197
+ }
198
198
  function createWebExtractTool(deps) {
199
199
  return {
200
200
  name: "web_extract",
@@ -204,8 +204,7 @@ function createWebExtractTool(deps) {
204
204
  async execute(_toolCallId, params, signal) {
205
205
  const { url, instruction } = params;
206
206
  const cfg = deps.getConfig();
207
- const configuredDefault = cfg?.agents?.defaults?.webExtract?.maxLength ?? 15e3;
208
- const maxLength = params.maxLength ?? configuredDefault;
207
+ const maxLength = params.maxLength ?? resolveConfiguredMaxLength();
209
208
  try {
210
209
  const safety = checkUrlSafety(url);
211
210
  if (!safety.safe) return {
@@ -1 +1 @@
1
- {"version":3,"file":"web-extract.js","names":[],"sources":["../../../../src/agent/tools/web-extract.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { checkUrlSafety, checkWebsiteBlocklist, cleanBase64Images } from './url-safety.js';\n\nconst log = createLogger('web-extract');\n\nexport const DEFAULT_WEB_EXTRACT_MAX_LENGTH = 15_000;\nexport const MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT = 200_000;\nconst EXTRACTION_TIMEOUT_MS = 30_000;\n\n// Large-document chunked processing thresholds (inspired by hermes-agent)\nconst MAX_CONTENT_SIZE = 2_000_000; // 2M chars — refuse entirely above this\nconst CHUNK_THRESHOLD = 500_000; // 500k chars — use chunked processing above this\nconst CHUNK_SIZE = 100_000; // 100k chars per chunk\nconst MAX_OUTPUT_SIZE = 15_000; // Hard cap on final output size\n\nconst WebExtractSchema = Type.Object({\n url: Type.String({ description: 'URL to extract content from' }),\n instruction: Type.Optional(\n Type.String({\n description:\n 'What to extract or focus on. Examples: \"main article text\", ' +\n '\"pricing table\", \"API documentation for the auth endpoint\". ' +\n 'If omitted, extracts the main content.',\n }),\n ),\n maxLength: Type.Optional(\n Type.Number({\n description: 'Maximum characters in the extracted content (default: from config or 15000)',\n }),\n ),\n});\n\nexport interface WebExtractDeps {\n getConfig: () => Config | undefined;\n}\n\nasync function fetchPageContent(url: string, signal?: AbortSignal): Promise<string> {\n const response = await fetch(url, {\n signal,\n headers: {\n 'User-Agent': 'Mozilla/5.0 (compatible; xopc/1.0)',\n Accept: 'text/html,application/xhtml+xml,text/plain,application/json',\n },\n redirect: 'follow',\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n const json: unknown = await response.json();\n return JSON.stringify(json, null, 2);\n }\n\n return await response.text();\n}\n\nexport function stripHtmlBoilerplate(\n html: string,\n maxRaw = MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT,\n): string {\n let cleaned = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<svg[\\s\\S]*?<\\/svg>/gi, '')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '')\n .replace(/<!--[\\s\\S]*?-->/g, '');\n\n // Remove base64 images early to avoid wasting characters on them\n cleaned = cleanBase64Images(cleaned);\n cleaned = cleaned.replace(/\\s+/g, ' ').trim();\n\n if (cleaned.length > maxRaw) {\n cleaned = cleaned.slice(0, maxRaw) + '\\n\\n[...truncated]';\n }\n\n return cleaned;\n}\n\nfunction resolveExtractionModel(config?: Config) {\n const envRef = process.env.XOPC_WEB_EXTRACT_MODEL?.trim();\n const configRef =\n typeof config?.agents?.defaults?.webExtract?.model === 'string'\n ? config.agents.defaults.webExtract.model.trim()\n : '';\n const ref = envRef || configRef;\n\n if (ref) {\n try {\n return resolveModel(ref);\n } catch {\n /* fall through */\n }\n }\n\n for (const candidate of ['openai/gpt-4o-mini', 'google/gemini-2.0-flash']) {\n try {\n return resolveModel(candidate);\n } catch {\n /* next */\n }\n }\n\n return resolveModel(getDefaultModelSync(config));\n}\n\nfunction buildExtractionSystemPrompt(maxLength: number): string {\n return (\n 'You are a web content extractor. Given raw HTML/text from a web page, ' +\n 'extract the relevant content as clean, well-structured markdown.\\n\\n' +\n 'Rules:\\n' +\n '- Remove navigation, headers, footers, ads, cookie banners, sidebars\\n' +\n '- Preserve the main content structure (headings, lists, tables, code blocks)\\n' +\n '- Keep URLs for important links\\n' +\n '- If the page has structured data (tables, specs), preserve the structure\\n' +\n `- Keep output under ${maxLength} characters\\n` +\n '- If content is truncated, note what was cut\\n' +\n '- Output ONLY the extracted content, no meta-commentary'\n );\n}\n\n// ---------------------------------------------------------------------------\n// LLM call helper — shared by single-pass and chunked extraction\n// ---------------------------------------------------------------------------\n\nfunction buildTimeoutSignal(signal: AbortSignal | undefined): AbortSignal | undefined {\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(EXTRACTION_TIMEOUT_MS)\n : undefined;\n if (signal && timeoutSignal && typeof AbortSignal.any === 'function') {\n return AbortSignal.any([signal, timeoutSignal]);\n }\n return signal ?? timeoutSignal;\n}\n\nfunction extractTextFromCompletion(result: { content?: unknown }): string {\n let text = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n text += String((c as { text?: string }).text || '');\n }\n }\n }\n return text.trim();\n}\n\nasync function callExtractionLlm(\n systemPrompt: string,\n userPrompt: string,\n maxTokens: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n const model = resolveExtractionModel(config);\n const userMsg: UserMessage = {\n role: 'user',\n content: `${systemPrompt}\\n\\n---\\n\\n${userPrompt}`,\n timestamp: Date.now(),\n };\n\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens,\n temperature: 0.2,\n signal: buildTimeoutSignal(signal) as AbortSignal,\n },\n );\n\n return extractTextFromCompletion(result);\n}\n\n// ---------------------------------------------------------------------------\n// Single-pass extraction (content < CHUNK_THRESHOLD)\n// ---------------------------------------------------------------------------\n\nasync function extractWithLlm(\n rawContent: string,\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n const contentLength = rawContent.length;\n\n // Refuse absurdly large content\n if (contentLength > MAX_CONTENT_SIZE) {\n const sizeMb = (contentLength / 1_000_000).toFixed(1);\n return (\n `[Content too large to process: ${sizeMb}MB. ` +\n 'Try using web_fetch for raw text, or search for a more focused source.]'\n );\n }\n\n // Route to chunked processing for large documents\n if (contentLength > CHUNK_THRESHOLD) {\n log.info(\n { url, contentLength, chunkSize: CHUNK_SIZE },\n 'Large document detected, using chunked extraction',\n );\n return extractLargeDocumentChunked(rawContent, url, instruction, maxLength, config, signal);\n }\n\n // Standard single-pass extraction\n const systemPrompt = buildExtractionSystemPrompt(maxLength);\n const body = instruction\n ? `Extract from this page (${url}):\\n\\nFOCUS: ${instruction}\\n\\n---\\n\\n${rawContent}`\n : `Extract the main content from this page (${url}):\\n\\n---\\n\\n${rawContent}`;\n\n const text = await callExtractionLlm(\n systemPrompt,\n body,\n Math.min(Math.ceil(maxLength / 3), 8000),\n config,\n signal,\n );\n\n if (!text) return 'No content could be extracted.';\n\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n if (text.length > outputCap) {\n return text.slice(0, outputCap) + '\\n\\n[...output truncated to maxLength]';\n }\n\n log.debug(\n { url, originalChars: contentLength, extractedChars: text.length },\n 'Single-pass extraction complete',\n );\n return text;\n}\n\n// ---------------------------------------------------------------------------\n// Chunked extraction for large documents (inspired by hermes-agent)\n//\n// Flow: split → parallel chunk summaries → synthesis pass\n// ---------------------------------------------------------------------------\n\nasync function extractLargeDocumentChunked(\n content: string,\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n // Split content into chunks\n const chunks: string[] = [];\n for (let offset = 0; offset < content.length; offset += CHUNK_SIZE) {\n chunks.push(content.slice(offset, offset + CHUNK_SIZE));\n }\n log.info({ url, chunkCount: chunks.length, chunkSize: CHUNK_SIZE }, 'Split into chunks');\n\n // Summarize each chunk in parallel\n const chunkPromises = chunks.map(async (chunk, index) => {\n const chunkLabel = `[Chunk ${index + 1}/${chunks.length}]`;\n try {\n const systemPrompt =\n 'You are an expert content analyst processing a SECTION of a larger document. ' +\n 'Extract and summarize the key information from THIS SECTION ONLY.\\n\\n' +\n 'Guidelines:\\n' +\n '- Do NOT write introductions or conclusions — this is a partial document\\n' +\n '- Extract ALL key facts, figures, data points, and insights\\n' +\n '- Preserve important quotes, code snippets, and specific details verbatim\\n' +\n '- Use bullet points and structured formatting\\n' +\n '- Note references to other sections without trying to resolve them';\n\n const focusLine = instruction ? `\\nFOCUS: ${instruction}\\n` : '';\n const userPrompt =\n `${chunkLabel} Extract key information from this section of ${url}:` +\n `${focusLine}\\n\\n${chunk}`;\n\n const summary = await callExtractionLlm(systemPrompt, userPrompt, 6000, config, signal);\n if (summary) {\n log.debug(\n { url, chunk: index + 1, originalChars: chunk.length, summaryChars: summary.length },\n 'Chunk summarized',\n );\n }\n return { index, summary: summary || null };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, chunk: index + 1, error: message }, 'Chunk summarization failed');\n return { index, summary: null };\n }\n });\n\n const chunkResults = await Promise.all(chunkPromises);\n\n // Collect successful summaries in order\n const summaries: string[] = [];\n for (const { index, summary } of chunkResults.sort((a, b) => a.index - b.index)) {\n if (summary) {\n summaries.push(`## Section ${index + 1}\\n${summary}`);\n }\n }\n\n if (summaries.length === 0) {\n // All chunks failed — fall back to truncated raw content\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n const truncated = content.slice(0, outputCap);\n return truncated + '\\n\\n[...all chunk summaries failed; showing truncated raw content]';\n }\n\n log.info(\n { url, successfulChunks: summaries.length, totalChunks: chunks.length },\n 'Chunk summaries collected, synthesizing',\n );\n\n // Single chunk — return directly\n if (summaries.length === 1) {\n const result = summaries[0];\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n return result.length > outputCap\n ? result.slice(0, outputCap) + '\\n\\n[...truncated]'\n : result;\n }\n\n // Synthesize multiple chunk summaries into one cohesive summary\n return synthesizeChunkSummaries(summaries, url, instruction, maxLength, config, signal, content.length);\n}\n\nasync function synthesizeChunkSummaries(\n summaries: string[],\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n originalContentLength: number,\n): Promise<string> {\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n\n const systemPrompt =\n 'You synthesize multiple section summaries into one cohesive, comprehensive summary. ' +\n 'Remove redundancy, preserve all key facts and actionable information, ' +\n 'and organize with clear markdown structure.';\n\n const focusLine = instruction ? `\\nFOCUS: ${instruction}\\n` : '';\n const combined = summaries.join('\\n\\n---\\n\\n');\n const userPrompt =\n `Synthesize these section summaries from ${url} into ONE unified markdown summary ` +\n `(under ${outputCap} characters):${focusLine}\\n\\n${combined}`;\n\n try {\n const synthesized = await callExtractionLlm(systemPrompt, userPrompt, 8000, config, signal);\n\n if (!synthesized) {\n // Synthesis LLM returned empty — fall back to concatenation\n log.warn({ url }, 'Synthesis returned empty, concatenating chunk summaries');\n const fallback = summaries.join('\\n\\n');\n return fallback.length > outputCap\n ? fallback.slice(0, outputCap) + '\\n\\n[...truncated]'\n : fallback;\n }\n\n const finalOutput = synthesized.length > outputCap\n ? synthesized.slice(0, outputCap) + '\\n\\n[...summary truncated for context management]'\n : synthesized;\n\n const compressionRatio = finalOutput.length / originalContentLength;\n log.info(\n {\n url,\n originalChars: originalContentLength,\n extractedChars: finalOutput.length,\n compressionPercent: `${(compressionRatio * 100).toFixed(1)}%`,\n },\n 'Chunked extraction complete',\n );\n\n return finalOutput;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, error: message }, 'Synthesis failed, concatenating chunk summaries');\n const fallback = summaries.join('\\n\\n');\n return fallback.length > outputCap\n ? fallback.slice(0, outputCap) + '\\n\\n[...truncated due to synthesis failure]'\n : fallback;\n }\n}\n\ntype WebExtractParams = { url: string; instruction?: string; maxLength?: number };\n\nexport function createWebExtractTool(deps: WebExtractDeps): AgentTool {\n return {\n name: 'web_extract',\n label: '📄 Web Extract',\n description:\n 'Extract and summarize content from a web page using LLM-powered extraction.\\n\\n' +\n 'Unlike web_fetch (which returns cleaned plain text from HTML), this tool uses a ' +\n 'dedicated model pass to produce focused markdown. Use when you need semantic extraction ' +\n 'or a specific focus (instruction), not just a single readability pass.\\n\\n' +\n 'WHEN TO USE:\\n' +\n '- Reading articles, blog posts, documentation\\n' +\n '- Extracting specific data (pricing, specs, API docs)\\n' +\n '- Summarizing long pages to save context\\n\\n' +\n 'WHEN TO USE web_fetch INSTEAD:\\n' +\n '- Inspecting raw-ish page text quickly without an extra LLM call\\n' +\n '- Downloading JSON/API responses\\n' +\n '- Debugging page rendering issues',\n parameters: WebExtractSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{ url: string; extractedLength: number }>> {\n const { url, instruction } = params as WebExtractParams;\n const cfg = deps.getConfig();\n const configuredDefault =\n cfg?.agents?.defaults?.webExtract?.maxLength ?? DEFAULT_WEB_EXTRACT_MAX_LENGTH;\n const maxLength = (params as WebExtractParams).maxLength ?? configuredDefault;\n\n try {\n // SSRF protection\n const safety = checkUrlSafety(url);\n if (!safety.safe) {\n return {\n content: [{ type: 'text', text: `Blocked: ${safety.reason}` }],\n details: { url, extractedLength: 0 },\n };\n }\n\n // Website blocklist check\n const blocked = checkWebsiteBlocklist(url, cfg?.tools?.web?.blocklist);\n if (blocked) {\n return {\n content: [{ type: 'text', text: `Blocked: ${blocked.message}` }],\n details: { url, extractedLength: 0 },\n };\n }\n\n const rawContent = await fetchPageContent(url, signal);\n const cleaned = stripHtmlBoilerplate(rawContent);\n const trimmed = cleaned.trim();\n const looksStructured = trimmed.startsWith('{') || trimmed.startsWith('[');\n if (trimmed.length < 100 && !looksStructured) {\n return {\n content: [\n { type: 'text', text: `Page at ${url} appears to have no extractable content.` },\n ],\n details: { url, extractedLength: 0 },\n };\n }\n\n const extracted = await extractWithLlm(\n cleaned,\n url,\n instruction,\n maxLength,\n cfg,\n signal,\n );\n\n return {\n content: [{ type: 'text', text: extracted }],\n details: { url, extractedLength: extracted.length },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, error: message }, 'web_extract failed');\n return {\n content: [{ type: 'text', text: `Failed to extract content from ${url}: ${message}` }],\n details: { url, extractedLength: 0 },\n };\n }\n },\n } as any;\n}\n"],"mappings":";;;;;;;gBAK6E;aACxB;AAGrD,MAAM,MAAM,aAAa,cAAc;AAEvC,MAAa,iCAAiC;AAC9C,MAAa,qCAAqC;AAClD,MAAM,wBAAwB;AAG9B,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AACxB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AAExB,MAAM,mBAAmB,KAAK,OAAO;CACnC,KAAK,KAAK,OAAO,EAAE,aAAa,+BAA+B,CAAC;CAChE,aAAa,KAAK,SAChB,KAAK,OAAO,EACV,aACE,wKAGH,CAAC,CACH;CACD,WAAW,KAAK,SACd,KAAK,OAAO,EACV,aAAa,+EACd,CAAC,CACH;CACF,CAAC;AAMF,eAAe,iBAAiB,KAAa,QAAuC;CAClF,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC;EACA,SAAS;GACP,cAAc;GACd,QAAQ;GACT;EACD,UAAU;EACX,CAAC;AAEF,KAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,aAAa;AAIpE,MADoB,SAAS,QAAQ,IAAI,eAAe,IAAI,IAC5C,SAAS,mBAAmB,EAAE;EAC5C,MAAM,OAAgB,MAAM,SAAS,MAAM;AAC3C,SAAO,KAAK,UAAU,MAAM,MAAM,EAAE;;AAGtC,QAAO,MAAM,SAAS,MAAM;;AAG9B,SAAgB,qBACd,MACA,SAAS,oCACD;CACR,IAAI,UAAU,KACX,QAAQ,+BAA+B,GAAG,CAC1C,QAAQ,6BAA6B,GAAG,CACxC,QAAQ,yBAAyB,GAAG,CACpC,QAAQ,mCAAmC,GAAG,CAC9C,QAAQ,oBAAoB,GAAG;AAGlC,WAAU,kBAAkB,QAAQ;AACpC,WAAU,QAAQ,QAAQ,QAAQ,IAAI,CAAC,MAAM;AAE7C,KAAI,QAAQ,SAAS,OACnB,WAAU,QAAQ,MAAM,GAAG,OAAO,GAAG;AAGvC,QAAO;;AAGT,SAAS,uBAAuB,QAAiB;CAC/C,MAAM,SAAS,QAAQ,IAAI,wBAAwB,MAAM;CACzD,MAAM,YACJ,OAAO,QAAQ,QAAQ,UAAU,YAAY,UAAU,WACnD,OAAO,OAAO,SAAS,WAAW,MAAM,MAAM,GAC9C;CACN,MAAM,MAAM,UAAU;AAEtB,KAAI,IACF,KAAI;AACF,SAAO,aAAa,IAAI;SAClB;AAKV,MAAK,MAAM,aAAa,CAAC,sBAAsB,0BAA0B,CACvE,KAAI;AACF,SAAO,aAAa,UAAU;SACxB;AAKV,QAAO,aAAa,oBAAoB,OAAO,CAAC;;AAGlD,SAAS,4BAA4B,WAA2B;AAC9D,QACE;;;;;;;sBAOuB,UAAU;;;AAUrC,SAAS,mBAAmB,QAA0D;CACpF,MAAM,gBACJ,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY,aACjE,YAAY,QAAQ,sBAAsB,GAC1C,KAAA;AACN,KAAI,UAAU,iBAAiB,OAAO,YAAY,QAAQ,WACxD,QAAO,YAAY,IAAI,CAAC,QAAQ,cAAc,CAAC;AAEjD,QAAO,UAAU;;AAGnB,SAAS,0BAA0B,QAAuC;CACxE,IAAI,OAAO;AACX,KAAI,MAAM,QAAQ,OAAO,QAAQ;OAC1B,MAAM,KAAK,OAAO,QACrB,KAAI,KAAK,OAAO,MAAM,YAAa,EAAwB,SAAS,OAClE,SAAQ,OAAQ,EAAwB,QAAQ,GAAG;;AAIzD,QAAO,KAAK,MAAM;;AAGpB,eAAe,kBACb,cACA,YACA,WACA,QACA,QACiB;AAkBjB,QAAO,0BAA0B,MAVZ,SAPP,uBAAuB,OAQ9B,EACL,EAAE,UAAU,CAAC;EAPb,MAAM;EACN,SAAS,GAAG,aAAa,aAAa;EACtC,WAAW,KAAK,KAAK;EAKD,CAAC,EAAE,EACvB;EACE;EACA,aAAa;EACb,QAAQ,mBAAmB,OAAO;EACnC,CACF,CAEuC;;AAO1C,eAAe,eACb,YACA,KACA,aACA,WACA,QACA,QACiB;CACjB,MAAM,gBAAgB,WAAW;AAGjC,KAAI,gBAAgB,iBAElB,QACE,mCAFc,gBAAgB,KAAW,QAAQ,EAET,CAAC;AAM7C,KAAI,gBAAgB,iBAAiB;AACnC,MAAI,KACF;GAAE;GAAK;GAAe,WAAW;GAAY,EAC7C,oDACD;AACD,SAAO,4BAA4B,YAAY,KAAK,aAAa,WAAW,QAAQ,OAAO;;CAS7F,MAAM,OAAO,MAAM,kBALE,4BAA4B,UAMnC,EALD,cACT,2BAA2B,IAAI,eAAe,YAAY,aAAa,eACvE,4CAA4C,IAAI,eAAe,cAKjE,KAAK,IAAI,KAAK,KAAK,YAAY,EAAE,EAAE,IAAK,EACxC,QACA,OACD;AAED,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,YAAY,KAAK,IAAI,WAAW,gBAAgB;AACtD,KAAI,KAAK,SAAS,UAChB,QAAO,KAAK,MAAM,GAAG,UAAU,GAAG;AAGpC,KAAI,MACF;EAAE;EAAK,eAAe;EAAe,gBAAgB,KAAK;EAAQ,EAClE,kCACD;AACD,QAAO;;AAST,eAAe,4BACb,SACA,KACA,aACA,WACA,QACA,QACiB;CAEjB,MAAM,SAAmB,EAAE;AAC3B,MAAK,IAAI,SAAS,GAAG,SAAS,QAAQ,QAAQ,UAAU,WACtD,QAAO,KAAK,QAAQ,MAAM,QAAQ,SAAS,WAAW,CAAC;AAEzD,KAAI,KAAK;EAAE;EAAK,YAAY,OAAO;EAAQ,WAAW;EAAY,EAAE,oBAAoB;CAGxF,MAAM,gBAAgB,OAAO,IAAI,OAAO,OAAO,UAAU;EACvD,MAAM,aAAa,UAAU,QAAQ,EAAE,GAAG,OAAO,OAAO;AACxD,MAAI;GAgBF,MAAM,UAAU,MAAM,kBAAkB,seAAc,GAHjD,WAAW,gDAAgD,IAAI,GAFlD,cAAc,YAAY,YAAY,MAAM,GAG/C,MAAM,SAE6C,KAAM,QAAQ,OAAO;AACvF,OAAI,QACF,KAAI,MACF;IAAE;IAAK,OAAO,QAAQ;IAAG,eAAe,MAAM;IAAQ,cAAc,QAAQ;IAAQ,EACpF,mBACD;AAEH,UAAO;IAAE;IAAO,SAAS,WAAW;IAAM;WACnC,OAAO;GACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,OAAI,KAAK;IAAE;IAAK,OAAO,QAAQ;IAAG,OAAO;IAAS,EAAE,6BAA6B;AACjF,UAAO;IAAE;IAAO,SAAS;IAAM;;GAEjC;CAEF,MAAM,eAAe,MAAM,QAAQ,IAAI,cAAc;CAGrD,MAAM,YAAsB,EAAE;AAC9B,MAAK,MAAM,EAAE,OAAO,aAAa,aAAa,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,CAC7E,KAAI,QACF,WAAU,KAAK,cAAc,QAAQ,EAAE,IAAI,UAAU;AAIzD,KAAI,UAAU,WAAW,GAAG;EAE1B,MAAM,YAAY,KAAK,IAAI,WAAW,gBAAgB;AAEtD,SADkB,QAAQ,MAAM,GAAG,UACnB,GAAG;;AAGrB,KAAI,KACF;EAAE;EAAK,kBAAkB,UAAU;EAAQ,aAAa,OAAO;EAAQ,EACvE,0CACD;AAGD,KAAI,UAAU,WAAW,GAAG;EAC1B,MAAM,SAAS,UAAU;EACzB,MAAM,YAAY,KAAK,IAAI,WAAW,gBAAgB;AACtD,SAAO,OAAO,SAAS,YACnB,OAAO,MAAM,GAAG,UAAU,GAAG,uBAC7B;;AAIN,QAAO,yBAAyB,WAAW,KAAK,aAAa,WAAW,QAAQ,QAAQ,QAAQ,OAAO;;AAGzG,eAAe,yBACb,WACA,KACA,aACA,WACA,QACA,QACA,uBACiB;CACjB,MAAM,YAAY,KAAK,IAAI,WAAW,gBAAgB;CAEtD,MAAM,eACJ;CAMF,MAAM,aACJ,2CAA2C,IAAI,4CACrC,UAAU,eAJJ,cAAc,YAAY,YAAY,MAAM,GAIf,MAH9B,UAAU,KAAK,cAG6B;AAE7D,KAAI;EACF,MAAM,cAAc,MAAM,kBAAkB,cAAc,YAAY,KAAM,QAAQ,OAAO;AAE3F,MAAI,CAAC,aAAa;AAEhB,OAAI,KAAK,EAAE,KAAK,EAAE,0DAA0D;GAC5E,MAAM,WAAW,UAAU,KAAK,OAAO;AACvC,UAAO,SAAS,SAAS,YACrB,SAAS,MAAM,GAAG,UAAU,GAAG,uBAC/B;;EAGN,MAAM,cAAc,YAAY,SAAS,YACrC,YAAY,MAAM,GAAG,UAAU,GAAG,sDAClC;EAEJ,MAAM,mBAAmB,YAAY,SAAS;AAC9C,MAAI,KACF;GACE;GACA,eAAe;GACf,gBAAgB,YAAY;GAC5B,oBAAoB,IAAI,mBAAmB,KAAK,QAAQ,EAAE,CAAC;GAC5D,EACD,8BACD;AAED,SAAO;UACA,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,MAAI,KAAK;GAAE;GAAK,OAAO;GAAS,EAAE,kDAAkD;EACpF,MAAM,WAAW,UAAU,KAAK,OAAO;AACvC,SAAO,SAAS,SAAS,YACrB,SAAS,MAAM,GAAG,UAAU,GAAG,gDAC/B;;;AAMR,SAAgB,qBAAqB,MAAiC;AACpE,QAAO;EACL,MAAM;EACN,OAAO;EACP,aACE;EAYF,YAAY;EAEZ,MAAM,QACJ,aACA,QACA,QACoE;GACpE,MAAM,EAAE,KAAK,gBAAgB;GAC7B,MAAM,MAAM,KAAK,WAAW;GAC5B,MAAM,oBACJ,KAAK,QAAQ,UAAU,YAAY,aAAA;GACrC,MAAM,YAAa,OAA4B,aAAa;AAE5D,OAAI;IAEF,MAAM,SAAS,eAAe,IAAI;AAClC,QAAI,CAAC,OAAO,KACV,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,YAAY,OAAO;MAAU,CAAC;KAC9D,SAAS;MAAE;MAAK,iBAAiB;MAAG;KACrC;IAIH,MAAM,UAAU,sBAAsB,KAAK,KAAK,OAAO,KAAK,UAAU;AACtE,QAAI,QACF,QAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,YAAY,QAAQ;MAAW,CAAC;KAChE,SAAS;MAAE;MAAK,iBAAiB;MAAG;KACrC;IAIH,MAAM,UAAU,qBAAqB,MADZ,iBAAiB,KAAK,OAAO,CACN;IAChD,MAAM,UAAU,QAAQ,MAAM;IAC9B,MAAM,kBAAkB,QAAQ,WAAW,IAAI,IAAI,QAAQ,WAAW,IAAI;AAC1E,QAAI,QAAQ,SAAS,OAAO,CAAC,gBAC3B,QAAO;KACL,SAAS,CACP;MAAE,MAAM;MAAQ,MAAM,WAAW,IAAI;MAA2C,CACjF;KACD,SAAS;MAAE;MAAK,iBAAiB;MAAG;KACrC;IAGH,MAAM,YAAY,MAAM,eACtB,SACA,KACA,aACA,WACA,KACA,OACD;AAED,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;MAAW,CAAC;KAC5C,SAAS;MAAE;MAAK,iBAAiB,UAAU;MAAQ;KACpD;YACM,OAAO;IACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAI,KAAK;KAAE;KAAK,OAAO;KAAS,EAAE,qBAAqB;AACvD,WAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,kCAAkC,IAAI,IAAI;MAAW,CAAC;KACtF,SAAS;MAAE;MAAK,iBAAiB;MAAG;KACrC;;;EAGN"}
1
+ {"version":3,"file":"web-extract.js","names":[],"sources":["../../../../src/agent/tools/web-extract.ts"],"sourcesContent":["import { Type } from '@sinclair/typebox';\nimport type { AgentTool, AgentToolResult } from '@earendil-works/pi-agent-core';\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { checkUrlSafety, checkWebsiteBlocklist, cleanBase64Images } from './url-safety.js';\n\nconst log = createLogger('web-extract');\n\nexport const DEFAULT_WEB_EXTRACT_MAX_LENGTH = 15_000;\nexport const MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT = 200_000;\nconst EXTRACTION_TIMEOUT_MS = 30_000;\n\n// Large-document chunked processing thresholds (inspired by hermes-agent)\nconst MAX_CONTENT_SIZE = 2_000_000; // 2M chars — refuse entirely above this\nconst CHUNK_THRESHOLD = 500_000; // 500k chars — use chunked processing above this\nconst CHUNK_SIZE = 100_000; // 100k chars per chunk\nconst MAX_OUTPUT_SIZE = 15_000; // Hard cap on final output size\n\nconst WebExtractSchema = Type.Object({\n url: Type.String({ description: 'URL to extract content from' }),\n instruction: Type.Optional(\n Type.String({\n description:\n 'What to extract or focus on. Examples: \"main article text\", ' +\n '\"pricing table\", \"API documentation for the auth endpoint\". ' +\n 'If omitted, extracts the main content.',\n }),\n ),\n maxLength: Type.Optional(\n Type.Number({\n description: 'Maximum characters in the extracted content (default: from config or 15000)',\n }),\n ),\n});\n\nexport interface WebExtractDeps {\n getConfig: () => Config | undefined;\n}\n\nasync function fetchPageContent(url: string, signal?: AbortSignal): Promise<string> {\n const response = await fetch(url, {\n signal,\n headers: {\n 'User-Agent': 'Mozilla/5.0 (compatible; xopc/1.0)',\n Accept: 'text/html,application/xhtml+xml,text/plain,application/json',\n },\n redirect: 'follow',\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = response.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n const json: unknown = await response.json();\n return JSON.stringify(json, null, 2);\n }\n\n return await response.text();\n}\n\nexport function stripHtmlBoilerplate(\n html: string,\n maxRaw = MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT,\n): string {\n let cleaned = html\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<svg[\\s\\S]*?<\\/svg>/gi, '')\n .replace(/<noscript[\\s\\S]*?<\\/noscript>/gi, '')\n .replace(/<!--[\\s\\S]*?-->/g, '');\n\n // Remove base64 images early to avoid wasting characters on them\n cleaned = cleanBase64Images(cleaned);\n cleaned = cleaned.replace(/\\s+/g, ' ').trim();\n\n if (cleaned.length > maxRaw) {\n cleaned = cleaned.slice(0, maxRaw) + '\\n\\n[...truncated]';\n }\n\n return cleaned;\n}\n\nfunction resolveExtractionModel(config?: Config) {\n const envRef = process.env.XOPC_WEB_EXTRACT_MODEL?.trim();\n const ref = envRef;\n\n if (ref) {\n try {\n return resolveModel(ref);\n } catch {\n /* fall through */\n }\n }\n\n const defaultRef = getDefaultModelSync(config);\n if (!defaultRef) {\n throw new Error('No global default model configured for web extraction');\n }\n\n return resolveModel(defaultRef);\n}\n\nfunction buildExtractionSystemPrompt(maxLength: number): string {\n return (\n 'You are a web content extractor. Given raw HTML/text from a web page, ' +\n 'extract the relevant content as clean, well-structured markdown.\\n\\n' +\n 'Rules:\\n' +\n '- Remove navigation, headers, footers, ads, cookie banners, sidebars\\n' +\n '- Preserve the main content structure (headings, lists, tables, code blocks)\\n' +\n '- Keep URLs for important links\\n' +\n '- If the page has structured data (tables, specs), preserve the structure\\n' +\n `- Keep output under ${maxLength} characters\\n` +\n '- If content is truncated, note what was cut\\n' +\n '- Output ONLY the extracted content, no meta-commentary'\n );\n}\n\n// ---------------------------------------------------------------------------\n// LLM call helper — shared by single-pass and chunked extraction\n// ---------------------------------------------------------------------------\n\nfunction buildTimeoutSignal(signal: AbortSignal | undefined): AbortSignal | undefined {\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(EXTRACTION_TIMEOUT_MS)\n : undefined;\n if (signal && timeoutSignal && typeof AbortSignal.any === 'function') {\n return AbortSignal.any([signal, timeoutSignal]);\n }\n return signal ?? timeoutSignal;\n}\n\nfunction extractTextFromCompletion(result: { content?: unknown }): string {\n let text = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n text += String((c as { text?: string }).text || '');\n }\n }\n }\n return text.trim();\n}\n\nasync function callExtractionLlm(\n systemPrompt: string,\n userPrompt: string,\n maxTokens: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n const model = resolveExtractionModel(config);\n const userMsg: UserMessage = {\n role: 'user',\n content: `${systemPrompt}\\n\\n---\\n\\n${userPrompt}`,\n timestamp: Date.now(),\n };\n\n const result = await complete(\n model,\n { messages: [userMsg] },\n {\n maxTokens,\n temperature: 0.2,\n signal: buildTimeoutSignal(signal) as AbortSignal,\n },\n );\n\n return extractTextFromCompletion(result);\n}\n\n// ---------------------------------------------------------------------------\n// Single-pass extraction (content < CHUNK_THRESHOLD)\n// ---------------------------------------------------------------------------\n\nasync function extractWithLlm(\n rawContent: string,\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n const contentLength = rawContent.length;\n\n // Refuse absurdly large content\n if (contentLength > MAX_CONTENT_SIZE) {\n const sizeMb = (contentLength / 1_000_000).toFixed(1);\n return (\n `[Content too large to process: ${sizeMb}MB. ` +\n 'Try using web_fetch for raw text, or search for a more focused source.]'\n );\n }\n\n // Route to chunked processing for large documents\n if (contentLength > CHUNK_THRESHOLD) {\n log.info(\n { url, contentLength, chunkSize: CHUNK_SIZE },\n 'Large document detected, using chunked extraction',\n );\n return extractLargeDocumentChunked(rawContent, url, instruction, maxLength, config, signal);\n }\n\n // Standard single-pass extraction\n const systemPrompt = buildExtractionSystemPrompt(maxLength);\n const body = instruction\n ? `Extract from this page (${url}):\\n\\nFOCUS: ${instruction}\\n\\n---\\n\\n${rawContent}`\n : `Extract the main content from this page (${url}):\\n\\n---\\n\\n${rawContent}`;\n\n const text = await callExtractionLlm(\n systemPrompt,\n body,\n Math.min(Math.ceil(maxLength / 3), 8000),\n config,\n signal,\n );\n\n if (!text) return 'No content could be extracted.';\n\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n if (text.length > outputCap) {\n return text.slice(0, outputCap) + '\\n\\n[...output truncated to maxLength]';\n }\n\n log.debug(\n { url, originalChars: contentLength, extractedChars: text.length },\n 'Single-pass extraction complete',\n );\n return text;\n}\n\n// ---------------------------------------------------------------------------\n// Chunked extraction for large documents (inspired by hermes-agent)\n//\n// Flow: split → parallel chunk summaries → synthesis pass\n// ---------------------------------------------------------------------------\n\nasync function extractLargeDocumentChunked(\n content: string,\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n): Promise<string> {\n // Split content into chunks\n const chunks: string[] = [];\n for (let offset = 0; offset < content.length; offset += CHUNK_SIZE) {\n chunks.push(content.slice(offset, offset + CHUNK_SIZE));\n }\n log.info({ url, chunkCount: chunks.length, chunkSize: CHUNK_SIZE }, 'Split into chunks');\n\n // Summarize each chunk in parallel\n const chunkPromises = chunks.map(async (chunk, index) => {\n const chunkLabel = `[Chunk ${index + 1}/${chunks.length}]`;\n try {\n const systemPrompt =\n 'You are an expert content analyst processing a SECTION of a larger document. ' +\n 'Extract and summarize the key information from THIS SECTION ONLY.\\n\\n' +\n 'Guidelines:\\n' +\n '- Do NOT write introductions or conclusions — this is a partial document\\n' +\n '- Extract ALL key facts, figures, data points, and insights\\n' +\n '- Preserve important quotes, code snippets, and specific details verbatim\\n' +\n '- Use bullet points and structured formatting\\n' +\n '- Note references to other sections without trying to resolve them';\n\n const focusLine = instruction ? `\\nFOCUS: ${instruction}\\n` : '';\n const userPrompt =\n `${chunkLabel} Extract key information from this section of ${url}:` +\n `${focusLine}\\n\\n${chunk}`;\n\n const summary = await callExtractionLlm(systemPrompt, userPrompt, 6000, config, signal);\n if (summary) {\n log.debug(\n { url, chunk: index + 1, originalChars: chunk.length, summaryChars: summary.length },\n 'Chunk summarized',\n );\n }\n return { index, summary: summary || null };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, chunk: index + 1, error: message }, 'Chunk summarization failed');\n return { index, summary: null };\n }\n });\n\n const chunkResults = await Promise.all(chunkPromises);\n\n // Collect successful summaries in order\n const summaries: string[] = [];\n for (const { index, summary } of chunkResults.sort((a, b) => a.index - b.index)) {\n if (summary) {\n summaries.push(`## Section ${index + 1}\\n${summary}`);\n }\n }\n\n if (summaries.length === 0) {\n // All chunks failed — fall back to truncated raw content\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n const truncated = content.slice(0, outputCap);\n return truncated + '\\n\\n[...all chunk summaries failed; showing truncated raw content]';\n }\n\n log.info(\n { url, successfulChunks: summaries.length, totalChunks: chunks.length },\n 'Chunk summaries collected, synthesizing',\n );\n\n // Single chunk — return directly\n if (summaries.length === 1) {\n const result = summaries[0];\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n return result.length > outputCap\n ? result.slice(0, outputCap) + '\\n\\n[...truncated]'\n : result;\n }\n\n // Synthesize multiple chunk summaries into one cohesive summary\n return synthesizeChunkSummaries(summaries, url, instruction, maxLength, config, signal, content.length);\n}\n\nasync function synthesizeChunkSummaries(\n summaries: string[],\n url: string,\n instruction: string | undefined,\n maxLength: number,\n config: Config | undefined,\n signal: AbortSignal | undefined,\n originalContentLength: number,\n): Promise<string> {\n const outputCap = Math.min(maxLength, MAX_OUTPUT_SIZE);\n\n const systemPrompt =\n 'You synthesize multiple section summaries into one cohesive, comprehensive summary. ' +\n 'Remove redundancy, preserve all key facts and actionable information, ' +\n 'and organize with clear markdown structure.';\n\n const focusLine = instruction ? `\\nFOCUS: ${instruction}\\n` : '';\n const combined = summaries.join('\\n\\n---\\n\\n');\n const userPrompt =\n `Synthesize these section summaries from ${url} into ONE unified markdown summary ` +\n `(under ${outputCap} characters):${focusLine}\\n\\n${combined}`;\n\n try {\n const synthesized = await callExtractionLlm(systemPrompt, userPrompt, 8000, config, signal);\n\n if (!synthesized) {\n // Synthesis LLM returned empty — fall back to concatenation\n log.warn({ url }, 'Synthesis returned empty, concatenating chunk summaries');\n const fallback = summaries.join('\\n\\n');\n return fallback.length > outputCap\n ? fallback.slice(0, outputCap) + '\\n\\n[...truncated]'\n : fallback;\n }\n\n const finalOutput = synthesized.length > outputCap\n ? synthesized.slice(0, outputCap) + '\\n\\n[...summary truncated for context management]'\n : synthesized;\n\n const compressionRatio = finalOutput.length / originalContentLength;\n log.info(\n {\n url,\n originalChars: originalContentLength,\n extractedChars: finalOutput.length,\n compressionPercent: `${(compressionRatio * 100).toFixed(1)}%`,\n },\n 'Chunked extraction complete',\n );\n\n return finalOutput;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, error: message }, 'Synthesis failed, concatenating chunk summaries');\n const fallback = summaries.join('\\n\\n');\n return fallback.length > outputCap\n ? fallback.slice(0, outputCap) + '\\n\\n[...truncated due to synthesis failure]'\n : fallback;\n }\n}\n\ntype WebExtractParams = { url: string; instruction?: string; maxLength?: number };\n\nfunction resolveConfiguredMaxLength(): number {\n return DEFAULT_WEB_EXTRACT_MAX_LENGTH;\n}\n\nexport function createWebExtractTool(deps: WebExtractDeps): AgentTool {\n return {\n name: 'web_extract',\n label: '📄 Web Extract',\n description:\n 'Extract and summarize content from a web page using LLM-powered extraction.\\n\\n' +\n 'Unlike web_fetch (which returns cleaned plain text from HTML), this tool uses a ' +\n 'dedicated model pass to produce focused markdown. Use when you need semantic extraction ' +\n 'or a specific focus (instruction), not just a single readability pass.\\n\\n' +\n 'WHEN TO USE:\\n' +\n '- Reading articles, blog posts, documentation\\n' +\n '- Extracting specific data (pricing, specs, API docs)\\n' +\n '- Summarizing long pages to save context\\n\\n' +\n 'WHEN TO USE web_fetch INSTEAD:\\n' +\n '- Inspecting raw-ish page text quickly without an extra LLM call\\n' +\n '- Downloading JSON/API responses\\n' +\n '- Debugging page rendering issues',\n parameters: WebExtractSchema,\n\n async execute(\n _toolCallId: string,\n params: any,\n signal?: AbortSignal,\n ): Promise<AgentToolResult<{ url: string; extractedLength: number }>> {\n const { url, instruction } = params as WebExtractParams;\n const cfg = deps.getConfig();\n const maxLength = (params as WebExtractParams).maxLength ?? resolveConfiguredMaxLength();\n\n try {\n // SSRF protection\n const safety = checkUrlSafety(url);\n if (!safety.safe) {\n return {\n content: [{ type: 'text', text: `Blocked: ${safety.reason}` }],\n details: { url, extractedLength: 0 },\n };\n }\n\n // Website blocklist check\n const blocked = checkWebsiteBlocklist(url, cfg?.tools?.web?.blocklist);\n if (blocked) {\n return {\n content: [{ type: 'text', text: `Blocked: ${blocked.message}` }],\n details: { url, extractedLength: 0 },\n };\n }\n\n const rawContent = await fetchPageContent(url, signal);\n const cleaned = stripHtmlBoilerplate(rawContent);\n const trimmed = cleaned.trim();\n const looksStructured = trimmed.startsWith('{') || trimmed.startsWith('[');\n if (trimmed.length < 100 && !looksStructured) {\n return {\n content: [\n { type: 'text', text: `Page at ${url} appears to have no extractable content.` },\n ],\n details: { url, extractedLength: 0 },\n };\n }\n\n const extracted = await extractWithLlm(\n cleaned,\n url,\n instruction,\n maxLength,\n cfg,\n signal,\n );\n\n return {\n content: [{ type: 'text', text: extracted }],\n details: { url, extractedLength: extracted.length },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.warn({ url, error: message }, 'web_extract failed');\n return {\n content: [{ type: 'text', text: `Failed to extract content from ${url}: ${message}` }],\n details: { url, extractedLength: 0 },\n };\n }\n },\n } as any;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
+ import { extractProfileAgentId } from "../../config/agent-profile.js";
1
2
  import { createLogger } from "../../utils/logger/index.js";
2
3
  import { init_logger } from "../../utils/logger.js";
3
- import { extractProfileAgentId } from "../../config/agent-profile.js";
4
4
  import { parseWorkflowScript } from "../workflow/parser.js";
5
5
  import "../workflow/index.js";
6
6
  import { Type } from "@sinclair/typebox";
@@ -1,8 +1,8 @@
1
1
  import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
2
  import { BUILTIN_WORKFLOWS } from "./builtins/index.js";
3
3
  import { parseWorkflowScript } from "./parser.js";
4
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
5
4
  import { join } from "node:path";
5
+ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
6
6
  //#region src/agent/workflow/catalog.ts
7
7
  /**
8
8
  * Catalog for named workflows.
@@ -168,9 +168,7 @@ function safeResolveDefaultModel(get) {
168
168
  return null;
169
169
  }
170
170
  }
171
- function resolveSubagentStreamMode(getConfig) {
172
- const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;
173
- if (mode === "off" || mode === "steps" || mode === "full") return mode;
171
+ function resolveSubagentStreamMode(_getConfig) {
174
172
  return "steps";
175
173
  }
176
174
  function mapChildProgressEvent(event) {
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner, SubagentProgressEvent } from './types.js';\n\nconst log = createLogger('Agent:WorkflowSubagent');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n sessionStore?: SessionStore;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n const streamMode = resolveSubagentStreamMode(this.deps.getConfig);\n\n let transcriptPersistQueue: Promise<void> = Promise.resolve();\n const persistTranscriptSnapshot = opts.sessionKey && this.deps.sessionStore\n ? (messages: Parameters<SessionStore['saveMessages']>[1]) => {\n const store = this.deps.sessionStore;\n const key = opts.sessionKey;\n if (!store || !key) return;\n const snapshot = cloneAgentMessages(messages);\n transcriptPersistQueue = transcriptPersistQueue\n .then(async () => {\n await store.saveMessages(key, snapshot);\n emitSessionTranscriptUpdate({ sessionKey: key });\n })\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, sessionKey: key, errorMessage: msg },\n `Failed to persist workflow subagent transcript snapshot: ${msg}`,\n );\n });\n }\n : undefined;\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n progressHooks:\n opts.onProgress && streamMode !== 'off'\n ? {\n mode: streamMode === 'full' ? 'full' : 'steps',\n onProgress: (event) => {\n opts.onProgress?.(mapChildProgressEvent(event));\n },\n }\n : undefined,\n onTranscriptSnapshot: persistTranscriptSnapshot,\n };\n\n if (opts.sessionKey && opts.sessionMetadata && this.deps.sessionStore) {\n await this.preparePersistentSubagentSession(opts.sessionKey, opts.sessionMetadata);\n }\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary, messages } = await handle.run();\n await transcriptPersistQueue;\n if (opts.sessionKey && this.deps.sessionStore) {\n await this.deps.sessionStore.saveMessages(opts.sessionKey, messages);\n emitSessionTranscriptUpdate({ sessionKey: opts.sessionKey });\n }\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n private async preparePersistentSubagentSession(\n sessionKey: string,\n metadata: NonNullable<SubagentRunOptions['sessionMetadata']>,\n ): Promise<void> {\n const store = this.deps.sessionStore;\n if (!store) return;\n await store.resolveTranscriptPath(sessionKey, {\n metadata: {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n sourceChannel: 'workflow',\n sourceChatId: metadata.workflowRunId,\n routing: {\n agentId: metadata.workflowAgentId || 'main',\n source: 'workflow',\n accountId: 'default',\n peerKind: 'subagent',\n peerId: metadata.workflowRunId,\n },\n },\n });\n await store.updateMetadata(sessionKey, {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n name: metadata.workflowAgentLabel,\n tags: ['workflow-subagent', metadata.workflowDefinitionId],\n });\n }\n}\n\nfunction cloneAgentMessages(messages: Parameters<SessionStore['saveMessages']>[1]): Parameters<SessionStore['saveMessages']>[1] {\n return messages.map((message) => structuredClone(message));\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n\nfunction resolveSubagentStreamMode(\n getConfig: () => Config | undefined,\n): 'off' | 'steps' | 'full' {\n const mode = getConfig()?.agents?.defaults?.workflow?.subagentStream;\n if (mode === 'off' || mode === 'steps' || mode === 'full') return mode;\n return 'steps';\n}\n\nfunction mapChildProgressEvent(event: {\n type: 'tool_start' | 'tool_end' | 'iteration' | 'text_delta' | 'thinking_delta';\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n isError?: boolean;\n resultPreview?: string;\n error?: string;\n count?: number;\n max?: number;\n delta?: string;\n}): SubagentProgressEvent {\n switch (event.type) {\n case 'tool_start':\n return {\n type: 'tool_start',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n args: event.args ?? {},\n };\n case 'tool_end':\n return {\n type: 'tool_end',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n isError: Boolean(event.isError),\n resultPreview: event.resultPreview,\n error: event.error,\n };\n case 'iteration':\n return {\n type: 'iteration',\n count: event.count ?? 0,\n max: event.max ?? 0,\n };\n case 'text_delta':\n return { type: 'text_delta', delta: event.delta ?? '' };\n case 'thinking_delta':\n return { type: 'thinking_delta', delta: event.delta ?? '' };\n default:\n return { type: 'text_delta', delta: '' };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"subagent-runner.js","names":[],"sources":["../../../../src/agent/workflow/subagent-runner.ts"],"sourcesContent":["/**\n * Adapter: spawns one isolated child agent per `agent()` call from a workflow.\n *\n * Wraps the existing `createDelegateChildHandle` so the workflow runtime stays\n * decoupled from the LLM stack (it sees only the `SubagentRunner` interface).\n *\n * Key behaviour:\n * - When `opts.schema` is provided, we inject `structured_output` into the child\n * tool set and unwrap the captured value on success. If the subagent finishes\n * without ever calling `structured_output`, we treat it as failure (`null`).\n * - Failures and aborts resolve to `null`. The workflow runtime continues — this\n * matches the pi-dynamic-workflows contract and keeps fan-out pipelines robust.\n * - We do NOT mutate `createDelegateChildHandle` — we just leverage its\n * `buildChildTools` injection point.\n */\n\nimport type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n type BuildChildToolsOptions,\n createDelegateChildHandle,\n type DelegateChildHandleOptions,\n} from '../child-agent-factory.js';\nimport {\n DEFAULT_DELEGATE_TOOLS,\n DELEGATE_BLOCKED_TOOLS,\n} from '../tools/delegate-tool.js';\nimport type { ToolExecutorConfig } from '../tools/executor.js';\n\nimport {\n createStructuredOutputTool,\n STRUCTURED_OUTPUT_TOOL_NAME,\n type StructuredOutputCapture,\n} from './structured-output-tool.js';\nimport type { SubagentRunOptions, SubagentRunner, SubagentProgressEvent } from './types.js';\n\nconst log = createLogger('Agent:WorkflowSubagent');\n\nconst DEFAULT_MAX_ITERATIONS = 30;\n\nexport interface DelegateSubagentRunnerDeps {\n workspace: string;\n bus: MessageBus;\n /** Resolves the default subagent model (typically the parent agent's primary model). */\n getDefaultModel: () => Model<Api>;\n getConfig: () => Config | undefined;\n toolExecutorConfig?: Partial<ToolExecutorConfig>;\n sessionStore?: SessionStore;\n /**\n * Provided by the workflow tool from `AgentToolsFactory` — mirrors how\n * `delegate-tool` is wired (avoids importing `tools/factory.ts` here and\n * breaking the existing factory ↔ delegate-tool ↔ child-agent-factory\n * dependency contract).\n */\n buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];\n}\n\nexport class DelegateSubagentRunner implements SubagentRunner {\n constructor(private readonly deps: DelegateSubagentRunnerDeps) {}\n\n async run<T = string>(prompt: string, opts: SubagentRunOptions<T>): Promise<T | null> {\n if (opts.signal?.aborted) return null;\n\n const capture: StructuredOutputCapture<T> = { called: false, value: undefined };\n const wantStructured = Boolean(opts.schema);\n\n const allowed = resolveAllowedToolNames(opts.allowedToolNames, wantStructured);\n const model = opts.model ?? safeResolveDefaultModel(this.deps.getDefaultModel);\n if (!model) {\n log.warn({ label: opts.label }, 'subagent run skipped: no primary model resolved');\n return null;\n }\n\n const fullPrompt = buildPrompt(prompt, opts, wantStructured);\n const streamMode = resolveSubagentStreamMode(this.deps.getConfig);\n\n let transcriptPersistQueue: Promise<void> = Promise.resolve();\n const persistTranscriptSnapshot = opts.sessionKey && this.deps.sessionStore\n ? (messages: Parameters<SessionStore['saveMessages']>[1]) => {\n const store = this.deps.sessionStore;\n const key = opts.sessionKey;\n if (!store || !key) return;\n const snapshot = cloneAgentMessages(messages);\n transcriptPersistQueue = transcriptPersistQueue\n .then(async () => {\n await store.saveMessages(key, snapshot);\n emitSessionTranscriptUpdate({ sessionKey: key });\n })\n .catch((err) => {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(\n { err, sessionKey: key, errorMessage: msg },\n `Failed to persist workflow subagent transcript snapshot: ${msg}`,\n );\n });\n }\n : undefined;\n\n const childOptions: DelegateChildHandleOptions = {\n workspace: this.deps.workspace,\n goal: fullPrompt,\n allowedToolNames: allowed,\n maxIterations: opts.maxIterations ?? DEFAULT_MAX_ITERATIONS,\n model,\n bus: this.deps.bus,\n getConfig: this.deps.getConfig,\n toolExecutorConfig: this.deps.toolExecutorConfig,\n buildChildTools: (childOpts) => {\n const base = this.deps.buildChildTools(childOpts);\n if (!wantStructured || !opts.schema) return base;\n // Replace any existing tool with the same name so the per-run capture wins.\n const filtered = base.filter((t) => t.name !== STRUCTURED_OUTPUT_TOOL_NAME);\n return [\n ...filtered,\n createStructuredOutputTool({ schema: opts.schema, capture }) as unknown as AgentTool<any, any>,\n ];\n },\n progressHooks:\n opts.onProgress && streamMode !== 'off'\n ? {\n mode: streamMode === 'full' ? 'full' : 'steps',\n onProgress: (event) => {\n opts.onProgress?.(mapChildProgressEvent(event));\n },\n }\n : undefined,\n onTranscriptSnapshot: persistTranscriptSnapshot,\n };\n\n if (opts.sessionKey && opts.sessionMetadata && this.deps.sessionStore) {\n await this.preparePersistentSubagentSession(opts.sessionKey, opts.sessionMetadata);\n }\n\n const handle = createDelegateChildHandle(childOptions);\n const onAbort = () => handle.abort();\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n const { summary, messages } = await handle.run();\n await transcriptPersistQueue;\n if (opts.sessionKey && this.deps.sessionStore) {\n await this.deps.sessionStore.saveMessages(opts.sessionKey, messages);\n emitSessionTranscriptUpdate({ sessionKey: opts.sessionKey });\n }\n if (opts.signal?.aborted) return null;\n\n if (wantStructured) {\n if (!capture.called) {\n log.warn({ label: opts.label }, 'subagent finished without calling structured_output');\n return null;\n }\n return capture.value as T;\n }\n return summary as unknown as T;\n } catch (e) {\n if (opts.rethrow) throw e;\n const msg = e instanceof Error ? e.message : String(e);\n log.warn({ err: e, label: opts.label, errorMessage: msg }, `subagent run failed: ${msg}`);\n return null;\n } finally {\n opts.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n private async preparePersistentSubagentSession(\n sessionKey: string,\n metadata: NonNullable<SubagentRunOptions['sessionMetadata']>,\n ): Promise<void> {\n const store = this.deps.sessionStore;\n if (!store) return;\n await store.resolveTranscriptPath(sessionKey, {\n metadata: {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n sourceChannel: 'workflow',\n sourceChatId: metadata.workflowRunId,\n routing: {\n agentId: metadata.workflowAgentId || 'main',\n source: 'workflow',\n accountId: 'default',\n peerKind: 'subagent',\n peerId: metadata.workflowRunId,\n },\n },\n });\n await store.updateMetadata(sessionKey, {\n sessionType: 'workflow-subagent',\n hiddenFromSessionList: true,\n parentSessionKey: metadata.parentSessionKey,\n workflowRunId: metadata.workflowRunId,\n workflowDefinitionId: metadata.workflowDefinitionId,\n workflowAgentId: metadata.workflowAgentId,\n workflowAgentLabel: metadata.workflowAgentLabel,\n name: metadata.workflowAgentLabel,\n tags: ['workflow-subagent', metadata.workflowDefinitionId],\n });\n }\n}\n\nfunction cloneAgentMessages(messages: Parameters<SessionStore['saveMessages']>[1]): Parameters<SessionStore['saveMessages']>[1] {\n return messages.map((message) => structuredClone(message));\n}\n\nfunction resolveAllowedToolNames(\n requested: string[] | undefined,\n wantStructured: boolean,\n): string[] {\n const base = requested && requested.length > 0 ? requested : [...DEFAULT_DELEGATE_TOOLS];\n const filtered = base\n .map((s) => String(s).trim())\n .filter((s) => s.length > 0)\n .filter((s) => !DELEGATE_BLOCKED_TOOLS.has(s));\n if (wantStructured && !filtered.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {\n filtered.push(STRUCTURED_OUTPUT_TOOL_NAME);\n }\n return [...new Set(filtered)];\n}\n\nfunction buildPrompt(prompt: string, opts: SubagentRunOptions<unknown>, structured: boolean): string {\n const parts: string[] = [];\n if (opts.instructions?.trim()) parts.push(opts.instructions.trim());\n if (opts.label) parts.push(`Task label: ${opts.label}`);\n if (opts.phase) parts.push(`Workflow phase: ${opts.phase}`);\n parts.push(prompt);\n if (structured) {\n parts.push(\n [\n 'Final output contract:',\n '- Your final action MUST be a structured_output tool call.',\n '- The structured_output arguments are the return value of this subagent.',\n '- Do not emit a prose final answer instead of structured_output.',\n '- If you need to inspect files or run commands first, do so, then call structured_output exactly once.',\n ].join('\\n'),\n );\n }\n return parts.join('\\n\\n');\n}\n\nfunction safeResolveDefaultModel(get: () => Model<Api>): Model<Api> | null {\n try {\n return get();\n } catch (e) {\n log.warn({ err: e }, 'failed to resolve default subagent model');\n return null;\n }\n}\n\nfunction resolveSubagentStreamMode(\n _getConfig: () => Config | undefined,\n): 'off' | 'steps' | 'full' {\n return 'steps';\n}\n\nfunction mapChildProgressEvent(event: {\n type: 'tool_start' | 'tool_end' | 'iteration' | 'text_delta' | 'thinking_delta';\n toolCallId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n isError?: boolean;\n resultPreview?: string;\n error?: string;\n count?: number;\n max?: number;\n delta?: string;\n}): SubagentProgressEvent {\n switch (event.type) {\n case 'tool_start':\n return {\n type: 'tool_start',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n args: event.args ?? {},\n };\n case 'tool_end':\n return {\n type: 'tool_end',\n toolCallId: event.toolCallId ?? '',\n toolName: event.toolName ?? 'tool',\n isError: Boolean(event.isError),\n resultPreview: event.resultPreview,\n error: event.error,\n };\n case 'iteration':\n return {\n type: 'iteration',\n count: event.count ?? 0,\n max: event.max ?? 0,\n };\n case 'text_delta':\n return { type: 'text_delta', delta: event.delta ?? '' };\n case 'thinking_delta':\n return { type: 'thinking_delta', delta: event.delta ?? '' };\n default:\n return { type: 'text_delta', delta: '' };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './schema.js';
2
+ export * from './resolver.js';
3
+ export * from './validator.js';
4
+ export * from './prompt.js';
@@ -0,0 +1,10 @@
1
+ import { AgentConfigEntrySchema, AgentIdentitySchema, AgentManifestSchema, AgentResponsibilitiesSchema, BoundaryPolicySchema, CapabilityPresetSchema, DEFAULT_CAPABILITY_PRESET_ID, DreamingDeepPolicySchema, DreamingLightPolicySchema, DreamingPhasePolicySchema, DreamingPolicySchema, DreamingRemPolicySchema, ManifestModelRoleSchema, MemoryPolicySchema, ModelPolicyPatchSchema, ModelPolicySchema, PromptPolicySchema, RuntimePolicySchema, SkillPolicySchema, ToolModeSchema, ToolPolicySchema, ToolPolicySetSchema, ToolScopeSchema, WorkflowPolicySchema, WorkspacePolicySchema, init_schema } from "./schema.js";
2
+ import { getManifestSource, resolveEffectiveAgentManifest } from "./resolver.js";
3
+ import { validateAgentManifest } from "./validator.js";
4
+ import { buildAgentManifestPromptSection } from "./prompt.js";
5
+ //#region src/agent-manifest/index.ts
6
+ init_schema();
7
+ //#endregion
8
+ export { AgentConfigEntrySchema, AgentIdentitySchema, AgentManifestSchema, AgentResponsibilitiesSchema, BoundaryPolicySchema, CapabilityPresetSchema, DEFAULT_CAPABILITY_PRESET_ID, DreamingDeepPolicySchema, DreamingLightPolicySchema, DreamingPhasePolicySchema, DreamingPolicySchema, DreamingRemPolicySchema, ManifestModelRoleSchema, MemoryPolicySchema, ModelPolicyPatchSchema, ModelPolicySchema, PromptPolicySchema, RuntimePolicySchema, SkillPolicySchema, ToolModeSchema, ToolPolicySchema, ToolPolicySetSchema, ToolScopeSchema, WorkflowPolicySchema, WorkspacePolicySchema, buildAgentManifestPromptSection, getManifestSource, resolveEffectiveAgentManifest, validateAgentManifest };
9
+
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/agent-manifest/index.ts"],"sourcesContent":["export * from './schema.js';\nexport * from './resolver.js';\nexport * from './validator.js';\nexport * from './prompt.js';\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import type { EffectiveAgentManifest } from './schema.js';
2
+ export declare function buildAgentManifestPromptSection(manifest: EffectiveAgentManifest): string;
@@ -0,0 +1,57 @@
1
+ //#region src/agent-manifest/prompt.ts
2
+ function listBlock(items) {
3
+ return (items ?? []).map((item) => `- ${item}`).join("\n");
4
+ }
5
+ function toolPolicySummary(manifest) {
6
+ const rows = Object.entries(manifest.tools.builtin).toSorted(([a], [b]) => a.localeCompare(b)).map(([name, policy]) => {
7
+ const scope = policy.scope ? `, scope=${policy.scope}` : "";
8
+ return `- ${name}: ${policy.mode}${scope}`;
9
+ });
10
+ return rows.length > 0 ? rows.join("\n") : "- No built-in tools declared";
11
+ }
12
+ function memorySummary(manifest) {
13
+ return [`Mode: ${manifest.memory.mode}`, `Sources: ${manifest.memory.sources.join(", ") || "none"}`].join("\n");
14
+ }
15
+ function buildAgentManifestPromptSection(manifest) {
16
+ const sections = [
17
+ `<agent_identity>
18
+ Name: ${manifest.identity.name}
19
+ Role: ${manifest.identity.role}
20
+ Language: ${manifest.identity.language}
21
+ Tone: ${manifest.identity.tone}
22
+ </agent_identity>`,
23
+ `<responsibilities>
24
+ Primary:
25
+ ${listBlock(manifest.responsibilities.primary)}
26
+ ${manifest.responsibilities.secondary?.length ? `Secondary:\n${listBlock(manifest.responsibilities.secondary)}` : ""}
27
+ ${manifest.responsibilities.outOfScope?.length ? `Out of scope:\n${listBlock(manifest.responsibilities.outOfScope)}` : ""}
28
+ </responsibilities>`,
29
+ `<boundaries>
30
+ Requires confirmation:
31
+ ${listBlock(manifest.boundaries.requiresConfirmation)}
32
+ Forbidden:
33
+ ${listBlock(manifest.boundaries.forbidden)}
34
+ Escalation:
35
+ ${listBlock(manifest.boundaries.escalation)}
36
+ </boundaries>`,
37
+ `<tool_policy>
38
+ ${toolPolicySummary(manifest)}
39
+ </tool_policy>`,
40
+ `<memory_policy>
41
+ ${memorySummary(manifest)}
42
+ </memory_policy>`
43
+ ];
44
+ if (manifest.workflows.default || manifest.workflows.allowed?.length) sections.push(`<workflow_policy>
45
+ Default: ${manifest.workflows.default ?? "none"}
46
+ Allowed:
47
+ ${listBlock(manifest.workflows.allowed)}
48
+ </workflow_policy>`);
49
+ if (manifest.prompt?.customInstructions?.trim()) sections.push(`<custom_instructions>
50
+ ${manifest.prompt.customInstructions.trim()}
51
+ </custom_instructions>`);
52
+ return sections.join("\n\n");
53
+ }
54
+ //#endregion
55
+ export { buildAgentManifestPromptSection };
56
+
57
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","names":[],"sources":["../../../src/agent-manifest/prompt.ts"],"sourcesContent":["import type { EffectiveAgentManifest } from './schema.js';\n\nfunction listBlock(items: readonly string[] | undefined): string {\n return (items ?? []).map((item) => `- ${item}`).join('\\n');\n}\n\nfunction toolPolicySummary(manifest: EffectiveAgentManifest): string {\n const rows = Object.entries(manifest.tools.builtin)\n .toSorted(([a], [b]) => a.localeCompare(b))\n .map(([name, policy]) => {\n const scope = policy.scope ? `, scope=${policy.scope}` : '';\n return `- ${name}: ${policy.mode}${scope}`;\n });\n return rows.length > 0 ? rows.join('\\n') : '- No built-in tools declared';\n}\n\nfunction memorySummary(manifest: EffectiveAgentManifest): string {\n return [\n `Mode: ${manifest.memory.mode}`,\n `Sources: ${manifest.memory.sources.join(', ') || 'none'}`,\n ].join('\\n');\n}\n\nexport function buildAgentManifestPromptSection(manifest: EffectiveAgentManifest): string {\n const sections = [\n `<agent_identity>\nName: ${manifest.identity.name}\nRole: ${manifest.identity.role}\nLanguage: ${manifest.identity.language}\nTone: ${manifest.identity.tone}\n</agent_identity>`,\n `<responsibilities>\nPrimary:\n${listBlock(manifest.responsibilities.primary)}\n${manifest.responsibilities.secondary?.length ? `Secondary:\\n${listBlock(manifest.responsibilities.secondary)}` : ''}\n${manifest.responsibilities.outOfScope?.length ? `Out of scope:\\n${listBlock(manifest.responsibilities.outOfScope)}` : ''}\n</responsibilities>`,\n `<boundaries>\nRequires confirmation:\n${listBlock(manifest.boundaries.requiresConfirmation)}\nForbidden:\n${listBlock(manifest.boundaries.forbidden)}\nEscalation:\n${listBlock(manifest.boundaries.escalation)}\n</boundaries>`,\n `<tool_policy>\n${toolPolicySummary(manifest)}\n</tool_policy>`,\n `<memory_policy>\n${memorySummary(manifest)}\n</memory_policy>`,\n ];\n\n if (manifest.workflows.default || manifest.workflows.allowed?.length) {\n sections.push(`<workflow_policy>\nDefault: ${manifest.workflows.default ?? 'none'}\nAllowed:\n${listBlock(manifest.workflows.allowed)}\n</workflow_policy>`);\n }\n\n if (manifest.prompt?.customInstructions?.trim()) {\n sections.push(`<custom_instructions>\n${manifest.prompt.customInstructions.trim()}\n</custom_instructions>`);\n }\n\n return sections.join('\\n\\n');\n}\n"],"mappings":";AAEA,SAAS,UAAU,OAA8C;AAC/D,SAAQ,SAAS,EAAE,EAAE,KAAK,SAAS,KAAK,OAAO,CAAC,KAAK,KAAK;;AAG5D,SAAS,kBAAkB,UAA0C;CACnE,MAAM,OAAO,OAAO,QAAQ,SAAS,MAAM,QAAQ,CAChD,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAC1C,KAAK,CAAC,MAAM,YAAY;EACvB,MAAM,QAAQ,OAAO,QAAQ,WAAW,OAAO,UAAU;AACzD,SAAO,KAAK,KAAK,IAAI,OAAO,OAAO;GACnC;AACJ,QAAO,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK,GAAG;;AAG7C,SAAS,cAAc,UAA0C;AAC/D,QAAO,CACL,SAAS,SAAS,OAAO,QACzB,YAAY,SAAS,OAAO,QAAQ,KAAK,KAAK,IAAI,SACnD,CAAC,KAAK,KAAK;;AAGd,SAAgB,gCAAgC,UAA0C;CACxF,MAAM,WAAW;EACf;QACI,SAAS,SAAS,KAAK;QACvB,SAAS,SAAS,KAAK;YACnB,SAAS,SAAS,SAAS;QAC/B,SAAS,SAAS,KAAK;;EAE3B;;EAEF,UAAU,SAAS,iBAAiB,QAAQ,CAAC;EAC7C,SAAS,iBAAiB,WAAW,SAAS,eAAe,UAAU,SAAS,iBAAiB,UAAU,KAAK,GAAG;EACnH,SAAS,iBAAiB,YAAY,SAAS,kBAAkB,UAAU,SAAS,iBAAiB,WAAW,KAAK,GAAG;;EAEtH;;EAEF,UAAU,SAAS,WAAW,qBAAqB,CAAC;;EAEpD,UAAU,SAAS,WAAW,UAAU,CAAC;;EAEzC,UAAU,SAAS,WAAW,WAAW,CAAC;;EAExC;EACF,kBAAkB,SAAS,CAAC;;EAE1B;EACF,cAAc,SAAS,CAAC;;EAEvB;AAED,KAAI,SAAS,UAAU,WAAW,SAAS,UAAU,SAAS,OAC5D,UAAS,KAAK;WACP,SAAS,UAAU,WAAW,OAAO;;EAE9C,UAAU,SAAS,UAAU,QAAQ,CAAC;oBACpB;AAGlB,KAAI,SAAS,QAAQ,oBAAoB,MAAM,CAC7C,UAAS,KAAK;EAChB,SAAS,OAAO,mBAAmB,MAAM,CAAC;wBACpB;AAGtB,QAAO,SAAS,KAAK,OAAO"}