@xopcai/xopc 0.0.115 → 0.0.117

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 (578) hide show
  1. package/README.md +26 -10
  2. package/README.zh-CN.md +26 -10
  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/schema/config-schema.d.ts +3 -3
  9. package/dist/extensions/telegram/src/command-handler.js +1 -2
  10. package/dist/extensions/telegram/src/command-handler.js.map +1 -1
  11. package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
  12. package/dist/extensions/telegram/xopc.extension.json +1 -1
  13. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  14. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DVnBfANm.js → agent-avatar-dicebear-BBLhJ2C6.js} +1 -1
  15. package/dist/gateway/static/root/assets/agents-C6xgagZd.js +71 -0
  16. package/dist/gateway/static/root/assets/app-management-settings-panel-CBpLONvG.js +1 -0
  17. package/dist/gateway/static/root/assets/{appearance-settings-BQpPSTHD.js → appearance-settings-CGcc54yj.js} +1 -1
  18. package/dist/gateway/static/root/assets/apps-page-DdDx0V4z.js +1 -0
  19. package/dist/gateway/static/root/assets/{archive-plugin-CXu-Csep.js → archive-plugin-DZsVqMhU.js} +1 -1
  20. package/dist/gateway/static/root/assets/{attachment-load-BAjgOoGY.js → attachment-load-CIol6JWX.js} +1 -1
  21. package/dist/gateway/static/root/assets/{binary-plugins-BSBgB2hO.js → binary-plugins-B3UauMfp.js} +1 -1
  22. package/dist/gateway/static/root/assets/{block-editor-BpXw9TTR.js → block-editor-2HJoFchH.js} +3 -3
  23. package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +8 -0
  24. package/dist/gateway/static/root/assets/capability-presets-api-XQoMTI0A.js +1 -0
  25. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +1 -0
  26. package/dist/gateway/static/root/assets/{channels-settings-BbPUpzWB.js → channels-settings-BYyRzsex.js} +1 -1
  27. package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +2 -0
  28. package/dist/gateway/static/root/assets/cron-api-R41aQCX9.js +1 -0
  29. package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +3 -0
  30. package/dist/gateway/static/root/assets/dreaming-settings-Bceaw1PG.js +1 -0
  31. package/dist/gateway/static/root/assets/{extension-debug-page-D9kgUHCc.js → extension-debug-page-DX5WRE_t.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-CGyhXqzR.js → extension-page-Buah7Bw-.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-DL8Xquqd.js → extension-settings-page-DuroLVnf.js} +1 -1
  34. package/dist/gateway/static/root/assets/{fetch-D0VXA932.js → fetch-B5zdl27C.js} +1 -1
  35. package/dist/gateway/static/root/assets/{format-interval-label-Be8SmgUw.js → format-interval-label-Dn_QKIqb.js} +1 -1
  36. package/dist/gateway/static/root/assets/gateway-config-api-gT4ZhE7h.js +1 -0
  37. package/dist/gateway/static/root/assets/gateway-settings-iISWAZRm.js +1 -0
  38. package/dist/gateway/static/root/assets/{gateway-startup-retry-DERUH61L.js → gateway-startup-retry-B3kL8KGY.js} +1 -1
  39. package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +1 -0
  40. package/dist/gateway/static/root/assets/{goals-config-api-BPmqWk90.js → goals-config-api-AR-fVh0P.js} +1 -1
  41. package/dist/gateway/static/root/assets/goals-page-Cpb21ezg.js +2 -0
  42. package/dist/gateway/static/root/assets/goals-settings-CPAuFwoD.js +1 -0
  43. package/dist/gateway/static/root/assets/{heartbeat-config-api-Bfdzr8oV.js → heartbeat-config-api-D7bKFEeO.js} +1 -1
  44. package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +1 -0
  45. package/dist/gateway/static/root/assets/index-CwhK8qCh.js +122 -0
  46. package/dist/gateway/static/root/assets/index-CyfhARL-.css +1 -0
  47. package/dist/gateway/static/root/assets/{interval-presets-utKbuCRY.js → interval-presets-0DtsnxE0.js} +1 -1
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CjqS6c6V.js → keyboard-shortcuts-settings-BPREtN8B.js} +1 -1
  49. package/dist/gateway/static/root/assets/logs-page-DefCgF4o.js +2 -0
  50. package/dist/gateway/static/root/assets/{markdown-split-DW8C47iB.js → markdown-split-ChbR9LGO.js} +1 -1
  51. package/dist/gateway/static/root/assets/{media-plugins-D6HwDhDT.js → media-plugins-B82oP80n.js} +1 -1
  52. package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +3 -0
  53. package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +2 -0
  54. package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +2 -0
  55. package/dist/gateway/static/root/assets/{note-image-lightbox-pJM35Pz5.js → note-image-lightbox-CDknITM3.js} +1 -1
  56. package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +1 -0
  57. package/dist/gateway/static/root/assets/{preview-open-alternatives-CVwHuyN6.js → preview-open-alternatives-DV3xQsWB.js} +1 -1
  58. package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +1 -0
  59. package/dist/gateway/static/root/assets/{save-bar-controls-Ba-UEk7x.js → save-bar-controls-BODCXnvY.js} +1 -1
  60. package/dist/gateway/static/root/assets/{schedule-field-CNN9595U.js → schedule-field-CgJSCD3B.js} +1 -1
  61. package/dist/gateway/static/root/assets/{schema-form-DnNMmtD5.js → schema-form-qtfEI6QM.js} +1 -1
  62. package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +1 -0
  63. package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +1 -0
  64. package/dist/gateway/static/root/assets/{settings-collapsible-section-CmOz80i5.js → settings-collapsible-section-BHZKjVcS.js} +1 -1
  65. package/dist/gateway/static/root/assets/{settings-form-section-BmK7JJOV.js → settings-form-section-5i35D-J1.js} +1 -1
  66. package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +1 -0
  67. package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +1 -0
  68. package/dist/gateway/static/root/assets/{share-preview-page-Dp2qGrHC.js → share-preview-page-B0H63tDv.js} +1 -1
  69. package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +1 -0
  70. package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +1 -0
  71. package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +2 -0
  72. package/dist/gateway/static/root/assets/system-settings-panel-DXs2VmBt.js +1 -0
  73. package/dist/gateway/static/root/assets/typed-models-lib-4gPuydz_.js +1 -0
  74. package/dist/gateway/static/root/assets/{use-channel-catalog-CHlO8J9G.js → use-channel-catalog-BCjP_VHb.js} +1 -1
  75. package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +1 -0
  76. package/dist/gateway/static/root/assets/{voice-player-store-DDDWYHvg.js → voice-player-store-BlF9V05n.js} +1 -1
  77. package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +18 -0
  78. package/dist/gateway/static/root/index.html +5 -5
  79. package/dist/package.js +1 -1
  80. package/dist/src/agent/agent-manager.d.ts +1 -1
  81. package/dist/src/agent/agent-manager.js +7 -8
  82. package/dist/src/agent/agent-manager.js.map +1 -1
  83. package/dist/src/agent/agent-scope.js +6 -8
  84. package/dist/src/agent/agent-scope.js.map +1 -1
  85. package/dist/src/agent/background-review/coordinator.js +0 -1
  86. package/dist/src/agent/background-review/coordinator.js.map +1 -1
  87. package/dist/src/agent/background-review/run-background-review.d.ts +0 -2
  88. package/dist/src/agent/background-review/run-background-review.js +2 -4
  89. package/dist/src/agent/background-review/run-background-review.js.map +1 -1
  90. package/dist/src/agent/background-review/settings.js +8 -7
  91. package/dist/src/agent/background-review/settings.js.map +1 -1
  92. package/dist/src/agent/bootstrap/bootstrap-context.d.ts +2 -2
  93. package/dist/src/agent/bootstrap/bootstrap-context.js +4 -4
  94. package/dist/src/agent/bootstrap/bootstrap-context.js.map +1 -1
  95. package/dist/src/agent/context/workspace-seed.js +1 -1
  96. package/dist/src/agent/embedded/run-for-session.js +1 -1
  97. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  98. package/dist/src/agent/fallback/candidates.js +6 -3
  99. package/dist/src/agent/fallback/candidates.js.map +1 -1
  100. package/dist/src/agent/goals/checklist-judge.d.ts +1 -0
  101. package/dist/src/agent/goals/checklist-judge.js +1 -1
  102. package/dist/src/agent/goals/checklist-judge.js.map +1 -1
  103. package/dist/src/agent/goals/evaluate-turn.d.ts +1 -0
  104. package/dist/src/agent/goals/evaluate-turn.js +1 -0
  105. package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
  106. package/dist/src/agent/goals/post-turn.js +8 -1
  107. package/dist/src/agent/goals/post-turn.js.map +1 -1
  108. package/dist/src/agent/image/generation/runtime-types.d.ts +2 -0
  109. package/dist/src/agent/image/generation/runtime.js +1 -1
  110. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  111. package/dist/src/agent/image/image-helpers.d.ts +1 -1
  112. package/dist/src/agent/image/image-helpers.js +4 -17
  113. package/dist/src/agent/image/image-helpers.js.map +1 -1
  114. package/dist/src/agent/image/image-model-fallback.js +1 -1
  115. package/dist/src/agent/image/image-model-fallback.js.map +1 -1
  116. package/dist/src/agent/image/inbound-image-handling.js +1 -1
  117. package/dist/src/agent/image/inbound-image-handling.js.map +1 -1
  118. package/dist/src/agent/image/tool-model-config.d.ts +1 -1
  119. package/dist/src/agent/image/tool-model-config.js +2 -2
  120. package/dist/src/agent/image/tool-model-config.js.map +1 -1
  121. package/dist/src/agent/image/understanding/pi-ai-provider.js +5 -2
  122. package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
  123. package/dist/src/agent/image/understanding/provider-registry.d.ts +1 -0
  124. package/dist/src/agent/image/understanding/provider-registry.js +16 -2
  125. package/dist/src/agent/image/understanding/provider-registry.js.map +1 -1
  126. package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js +1 -1
  127. package/dist/src/agent/mcp/resolve-embedded-mcp-tools.js.map +1 -1
  128. package/dist/src/agent/media-generation/runtime-shared.d.ts +5 -2
  129. package/dist/src/agent/media-generation/runtime-shared.js +1 -1
  130. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  131. package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -0
  132. package/dist/src/agent/memory/builtin-memory-store.js +4 -0
  133. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  134. package/dist/src/agent/memory/builtin-provider.d.ts +31 -9
  135. package/dist/src/agent/memory/builtin-provider.js +261 -11
  136. package/dist/src/agent/memory/builtin-provider.js.map +1 -1
  137. package/dist/src/agent/memory/context-assembler.d.ts +10 -0
  138. package/dist/src/agent/memory/context-assembler.js +26 -0
  139. package/dist/src/agent/memory/context-assembler.js.map +1 -0
  140. package/dist/src/agent/memory/create-memory-manager.js +25 -7
  141. package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
  142. package/dist/src/agent/memory/dreaming/config.d.ts +1 -6
  143. package/dist/src/agent/memory/dreaming/config.js +8 -8
  144. package/dist/src/agent/memory/dreaming/config.js.map +1 -1
  145. package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +2 -0
  146. package/dist/src/agent/memory/dreaming/deep-promotion.js +24 -0
  147. package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
  148. package/dist/src/agent/memory/index.d.ts +1 -0
  149. package/dist/src/agent/memory/index.js +4 -3
  150. package/dist/src/agent/memory/inject-prefetch.js +6 -2
  151. package/dist/src/agent/memory/inject-prefetch.js.map +1 -1
  152. package/dist/src/agent/memory/manager.d.ts +37 -1
  153. package/dist/src/agent/memory/manager.js +332 -40
  154. package/dist/src/agent/memory/manager.js.map +1 -1
  155. package/dist/src/agent/memory/memory-config.js +12 -15
  156. package/dist/src/agent/memory/memory-config.js.map +1 -1
  157. package/dist/src/agent/memory/plugin-discovery.d.ts +19 -5
  158. package/dist/src/agent/memory/plugin-discovery.js +97 -31
  159. package/dist/src/agent/memory/plugin-discovery.js.map +1 -1
  160. package/dist/src/agent/memory/provider.d.ts +20 -15
  161. package/dist/src/agent/memory/stub-memory-provider.d.ts +17 -2
  162. package/dist/src/agent/memory/stub-memory-provider.js +20 -3
  163. package/dist/src/agent/memory/stub-memory-provider.js.map +1 -1
  164. package/dist/src/agent/memory/types.d.ts +136 -0
  165. package/dist/src/agent/models/manager.d.ts +1 -1
  166. package/dist/src/agent/models/manager.js +1 -1
  167. package/dist/src/agent/models/manager.js.map +1 -1
  168. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +1 -1
  169. package/dist/src/agent/orchestration/agent-orchestrator.js +2 -1
  170. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  171. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +2 -2
  172. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +1 -1
  173. package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +1 -1
  174. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +2 -6
  175. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +2 -8
  176. package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js.map +1 -1
  177. package/dist/src/agent/reply/post-compaction-context.js +11 -6
  178. package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
  179. package/dist/src/agent/reply/startup-context.js +8 -9
  180. package/dist/src/agent/reply/startup-context.js.map +1 -1
  181. package/dist/src/agent/service/process-direct-streaming.js +1 -4
  182. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  183. package/dist/src/agent/service/session-context-report.js +1 -1
  184. package/dist/src/agent/service/session-context-report.js.map +1 -1
  185. package/dist/src/agent/service.js +21 -25
  186. package/dist/src/agent/service.js.map +1 -1
  187. package/dist/src/agent/service.types.d.ts +1 -2
  188. package/dist/src/agent/session/session-hydrator.js +1 -2
  189. package/dist/src/agent/session/session-hydrator.js.map +1 -1
  190. package/dist/src/agent/session/session-inspector.d.ts +1 -1
  191. package/dist/src/agent/session/session-inspector.js +9 -14
  192. package/dist/src/agent/session/session-inspector.js.map +1 -1
  193. package/dist/src/agent/skills/hub-pull.js +1 -1
  194. package/dist/src/agent/starter-agents.d.ts +1 -3
  195. package/dist/src/agent/starter-agents.js +13 -21
  196. package/dist/src/agent/starter-agents.js.map +1 -1
  197. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -2
  198. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  199. package/dist/src/agent/tools/composio-tool.d.ts +8 -0
  200. package/dist/src/agent/tools/composio-tool.js +46 -0
  201. package/dist/src/agent/tools/composio-tool.js.map +1 -0
  202. package/dist/src/agent/tools/curated-memory-tool.d.ts +2 -5
  203. package/dist/src/agent/tools/curated-memory-tool.js +20 -16
  204. package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
  205. package/dist/src/agent/tools/factory.d.ts +0 -4
  206. package/dist/src/agent/tools/factory.js +32 -66
  207. package/dist/src/agent/tools/factory.js.map +1 -1
  208. package/dist/src/agent/tools/image-generate-tool.d.ts +1 -1
  209. package/dist/src/agent/tools/image-generate-tool.js +19 -14
  210. package/dist/src/agent/tools/image-generate-tool.js.map +1 -1
  211. package/dist/src/agent/tools/image-tool.js +1 -3
  212. package/dist/src/agent/tools/image-tool.js.map +1 -1
  213. package/dist/src/agent/tools/index.d.ts +1 -0
  214. package/dist/src/agent/tools/index.js +2 -1
  215. package/dist/src/agent/tools/memory-tool.d.ts +2 -2
  216. package/dist/src/agent/tools/memory-tool.js +39 -14
  217. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  218. package/dist/src/agent/tools/session-search-tool.js +1 -3
  219. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  220. package/dist/src/agent/tools/web-extract.js +6 -5
  221. package/dist/src/agent/tools/web-extract.js.map +1 -1
  222. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  223. package/dist/src/agent/workflow/builtins/audit-repo.js +15 -2
  224. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  225. package/dist/src/agent/workflow/builtins/client-proposal.d.ts +1 -1
  226. package/dist/src/agent/workflow/builtins/client-proposal.js +10 -1
  227. package/dist/src/agent/workflow/builtins/client-proposal.js.map +1 -1
  228. package/dist/src/agent/workflow/builtins/competitor-scan.d.ts +1 -1
  229. package/dist/src/agent/workflow/builtins/competitor-scan.js +16 -2
  230. package/dist/src/agent/workflow/builtins/competitor-scan.js.map +1 -1
  231. package/dist/src/agent/workflow/builtins/content-draft.d.ts +1 -1
  232. package/dist/src/agent/workflow/builtins/content-draft.js +15 -2
  233. package/dist/src/agent/workflow/builtins/content-draft.js.map +1 -1
  234. package/dist/src/agent/workflow/builtins/content-repurpose.d.ts +1 -1
  235. package/dist/src/agent/workflow/builtins/content-repurpose.js +10 -1
  236. package/dist/src/agent/workflow/builtins/content-repurpose.js.map +1 -1
  237. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  238. package/dist/src/agent/workflow/builtins/debug-incident.js +9 -1
  239. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  240. package/dist/src/agent/workflow/builtins/decision-compare.d.ts +1 -1
  241. package/dist/src/agent/workflow/builtins/decision-compare.js +16 -2
  242. package/dist/src/agent/workflow/builtins/decision-compare.js.map +1 -1
  243. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +1 -1
  244. package/dist/src/agent/workflow/builtins/implementation-plan.js +11 -1
  245. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -1
  246. package/dist/src/agent/workflow/builtins/inbox-triage.d.ts +1 -1
  247. package/dist/src/agent/workflow/builtins/inbox-triage.js +11 -1
  248. package/dist/src/agent/workflow/builtins/inbox-triage.js.map +1 -1
  249. package/dist/src/agent/workflow/builtins/meeting-prep.d.ts +1 -1
  250. package/dist/src/agent/workflow/builtins/meeting-prep.js +9 -1
  251. package/dist/src/agent/workflow/builtins/meeting-prep.js.map +1 -1
  252. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  253. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +9 -1
  254. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  255. package/dist/src/agent/workflow/builtins/offer-design.d.ts +1 -1
  256. package/dist/src/agent/workflow/builtins/offer-design.js +10 -1
  257. package/dist/src/agent/workflow/builtins/offer-design.js.map +1 -1
  258. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  259. package/dist/src/agent/workflow/builtins/pr-review.js +9 -1
  260. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  261. package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
  262. package/dist/src/agent/workflow/builtins/release-check.js +10 -1
  263. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
  264. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  265. package/dist/src/agent/workflow/builtins/research.js +16 -2
  266. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  267. package/dist/src/agent/workflow/builtins/weekly-review.d.ts +1 -1
  268. package/dist/src/agent/workflow/builtins/weekly-review.js +9 -1
  269. package/dist/src/agent/workflow/builtins/weekly-review.js.map +1 -1
  270. package/dist/src/agent/workflow/subagent-runner.js +1 -3
  271. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  272. package/dist/src/agent-manifest/index.d.ts +4 -0
  273. package/dist/src/agent-manifest/index.js +10 -0
  274. package/dist/src/agent-manifest/index.js.map +1 -0
  275. package/dist/src/agent-manifest/prompt.d.ts +2 -0
  276. package/dist/src/agent-manifest/prompt.js +57 -0
  277. package/dist/src/agent-manifest/prompt.js.map +1 -0
  278. package/dist/src/agent-manifest/resolver.d.ts +11 -0
  279. package/dist/src/agent-manifest/resolver.js +93 -0
  280. package/dist/src/agent-manifest/resolver.js.map +1 -0
  281. package/dist/src/agent-manifest/schema.d.ts +778 -0
  282. package/dist/src/agent-manifest/schema.js +267 -0
  283. package/dist/src/agent-manifest/schema.js.map +1 -0
  284. package/dist/src/agent-manifest/validator.d.ts +24 -0
  285. package/dist/src/agent-manifest/validator.js +87 -0
  286. package/dist/src/agent-manifest/validator.js.map +1 -0
  287. package/dist/src/agent-runtime/boundary-guard.d.ts +12 -0
  288. package/dist/src/agent-runtime/boundary-guard.js +23 -0
  289. package/dist/src/agent-runtime/boundary-guard.js.map +1 -0
  290. package/dist/src/agent-runtime/index.d.ts +7 -0
  291. package/dist/src/agent-runtime/index.js +8 -0
  292. package/dist/src/agent-runtime/memory-runtime.d.ts +21 -0
  293. package/dist/src/agent-runtime/memory-runtime.js +50 -0
  294. package/dist/src/agent-runtime/memory-runtime.js.map +1 -0
  295. package/dist/src/agent-runtime/model-router.d.ts +11 -0
  296. package/dist/src/agent-runtime/model-router.js +16 -0
  297. package/dist/src/agent-runtime/model-router.js.map +1 -0
  298. package/dist/src/agent-runtime/run-trace.d.ts +27 -0
  299. package/dist/src/agent-runtime/run-trace.js +53 -0
  300. package/dist/src/agent-runtime/run-trace.js.map +1 -0
  301. package/dist/src/agent-runtime/runtime-profile.d.ts +24 -0
  302. package/dist/src/agent-runtime/runtime-profile.js +44 -0
  303. package/dist/src/agent-runtime/runtime-profile.js.map +1 -0
  304. package/dist/src/agent-runtime/tool-registry.d.ts +28 -0
  305. package/dist/src/agent-runtime/tool-registry.js +52 -0
  306. package/dist/src/agent-runtime/tool-registry.js.map +1 -0
  307. package/dist/src/agent-runtime/workflow-runtime.d.ts +31 -0
  308. package/dist/src/agent-runtime/workflow-runtime.js +34 -0
  309. package/dist/src/agent-runtime/workflow-runtime.js.map +1 -0
  310. package/dist/src/browser/actions/extension-registry-bridge.js +1 -1
  311. package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
  312. package/dist/src/browser/actions/registry.js +5 -8
  313. package/dist/src/browser/actions/registry.js.map +1 -1
  314. package/dist/src/browser/backend-from-config.d.ts +1 -1
  315. package/dist/src/browser/backend-from-config.js +50 -71
  316. package/dist/src/browser/backend-from-config.js.map +1 -1
  317. package/dist/src/browser/browser-command-timeout.d.ts +0 -1
  318. package/dist/src/browser/browser-command-timeout.js +3 -7
  319. package/dist/src/browser/browser-command-timeout.js.map +1 -1
  320. package/dist/src/browser/providers/browser-ext-install.d.ts +2 -12
  321. package/dist/src/browser/providers/browser-ext-install.js +3 -8
  322. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  323. package/dist/src/browser/readiness.js +16 -16
  324. package/dist/src/browser/readiness.js.map +1 -1
  325. package/dist/src/browser/schemas.js +1 -1
  326. package/dist/src/browser/schemas.js.map +1 -1
  327. package/dist/src/chat-commands/builtins/config.js +4 -4
  328. package/dist/src/chat-commands/builtins/config.js.map +1 -1
  329. package/dist/src/chat-commands/builtins/thinking.js +16 -42
  330. package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
  331. package/dist/src/chat-commands/config-paths.js +1 -1
  332. package/dist/src/chat-commands/config-paths.js.map +1 -1
  333. package/dist/src/chat-commands/context.js +3 -4
  334. package/dist/src/chat-commands/context.js.map +1 -1
  335. package/dist/src/cli/command-manifest.js +1 -1
  336. package/dist/src/cli/command-manifest.js.map +1 -1
  337. package/dist/src/cli/commands/agent.js +3 -1
  338. package/dist/src/cli/commands/agent.js.map +1 -1
  339. package/dist/src/cli/commands/agents.js +3 -6
  340. package/dist/src/cli/commands/agents.js.map +1 -1
  341. package/dist/src/cli/commands/browser-cli-helpers.js +9 -11
  342. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  343. package/dist/src/cli/commands/config.js +5 -5
  344. package/dist/src/cli/commands/config.js.map +1 -1
  345. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  346. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -17
  347. package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
  348. package/dist/src/cli/commands/goal.js +1 -1
  349. package/dist/src/cli/commands/image.js +13 -372
  350. package/dist/src/cli/commands/image.js.map +1 -1
  351. package/dist/src/cli/commands/models.js +26 -10
  352. package/dist/src/cli/commands/models.js.map +1 -1
  353. package/dist/src/cli/commands/onboard/channels/registry.js.map +1 -1
  354. package/dist/src/cli/commands/onboard/model.js +20 -22
  355. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  356. package/dist/src/cli/commands/onboard.js +1 -1
  357. package/dist/src/cli/commands/onboard.js.map +1 -1
  358. package/dist/src/cli/utils/init-workspace-core.d.ts +1 -4
  359. package/dist/src/cli/utils/init-workspace-core.js +7 -6
  360. package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
  361. package/dist/src/commands/agents.config.d.ts +0 -1
  362. package/dist/src/commands/agents.config.js +66 -12
  363. package/dist/src/commands/agents.config.js.map +1 -1
  364. package/dist/src/config/agent-profile.d.ts +5 -17
  365. package/dist/src/config/agent-profile.js +31 -64
  366. package/dist/src/config/agent-profile.js.map +1 -1
  367. package/dist/src/config/agent-typed-models.d.ts +1 -1
  368. package/dist/src/config/agent-typed-models.js +0 -1
  369. package/dist/src/config/agent-typed-models.js.map +1 -1
  370. package/dist/src/config/index.js +3 -3
  371. package/dist/src/config/integration.d.ts +1 -1
  372. package/dist/src/config/reload.js +1 -1
  373. package/dist/src/config/reload.js.map +1 -1
  374. package/dist/src/config/rules.js +6 -56
  375. package/dist/src/config/rules.js.map +1 -1
  376. package/dist/src/config/schema.d.ts +925 -781
  377. package/dist/src/config/schema.js +157 -424
  378. package/dist/src/config/schema.js.map +1 -1
  379. package/dist/src/connectors/composio-triggers.d.ts +10 -0
  380. package/dist/src/connectors/composio-triggers.js +32 -0
  381. package/dist/src/connectors/composio-triggers.js.map +1 -0
  382. package/dist/src/connectors/composio.d.ts +54 -0
  383. package/dist/src/connectors/composio.js +334 -0
  384. package/dist/src/connectors/composio.js.map +1 -0
  385. package/dist/src/connectors/health.js +16 -1
  386. package/dist/src/connectors/health.js.map +1 -1
  387. package/dist/src/connectors/install.d.ts +2 -1
  388. package/dist/src/connectors/install.js +50 -13
  389. package/dist/src/connectors/install.js.map +1 -1
  390. package/dist/src/connectors/instances.js +57 -6
  391. package/dist/src/connectors/instances.js.map +1 -1
  392. package/dist/src/connectors/lifecycle.d.ts +3 -0
  393. package/dist/src/connectors/lifecycle.js +23 -0
  394. package/dist/src/connectors/lifecycle.js.map +1 -0
  395. package/dist/src/connectors/materialize.js +2 -1
  396. package/dist/src/connectors/materialize.js.map +1 -1
  397. package/dist/src/connectors/providers.d.ts +1 -0
  398. package/dist/src/connectors/providers.js +10 -2
  399. package/dist/src/connectors/providers.js.map +1 -1
  400. package/dist/src/connectors/registries/modelscope.d.ts +2 -0
  401. package/dist/src/connectors/registries/modelscope.js +205 -0
  402. package/dist/src/connectors/registries/modelscope.js.map +1 -0
  403. package/dist/src/connectors/registries/official-mcp.d.ts +2 -0
  404. package/dist/src/connectors/registries/official-mcp.js +142 -0
  405. package/dist/src/connectors/registries/official-mcp.js.map +1 -0
  406. package/dist/src/connectors/registries/search.d.ts +12 -0
  407. package/dist/src/connectors/registries/search.js +89 -0
  408. package/dist/src/connectors/registries/search.js.map +1 -0
  409. package/dist/src/connectors/registries/smithery.d.ts +2 -0
  410. package/dist/src/connectors/registries/smithery.js +98 -0
  411. package/dist/src/connectors/registries/smithery.js.map +1 -0
  412. package/dist/src/connectors/registries/types.d.ts +20 -0
  413. package/dist/src/connectors/registries/types.js +1 -0
  414. package/dist/src/connectors/secret-store.js +4 -2
  415. package/dist/src/connectors/secret-store.js.map +1 -1
  416. package/dist/src/connectors/setup-secrets.d.ts +15 -0
  417. package/dist/src/connectors/setup-secrets.js +64 -0
  418. package/dist/src/connectors/setup-secrets.js.map +1 -0
  419. package/dist/src/connectors/supervisor.d.ts +15 -0
  420. package/dist/src/connectors/supervisor.js +73 -0
  421. package/dist/src/connectors/supervisor.js.map +1 -0
  422. package/dist/src/connectors/types.d.ts +27 -3
  423. package/dist/src/connectors/usage.js +6 -1
  424. package/dist/src/connectors/usage.js.map +1 -1
  425. package/dist/src/cron/index.js +1 -1
  426. package/dist/src/cron/service.js +1 -1
  427. package/dist/src/cron/validation.d.ts +3 -3
  428. package/dist/src/extensions/activation-context.js +13 -7
  429. package/dist/src/extensions/activation-context.js.map +1 -1
  430. package/dist/src/gateway/agents-admin.d.ts +17 -18
  431. package/dist/src/gateway/agents-admin.js +123 -88
  432. package/dist/src/gateway/agents-admin.js.map +1 -1
  433. package/dist/src/gateway/capability-presets-admin.d.ts +56 -0
  434. package/dist/src/gateway/capability-presets-admin.js +214 -0
  435. package/dist/src/gateway/capability-presets-admin.js.map +1 -0
  436. package/dist/src/gateway/hono/lib/agent-model.d.ts +1 -1
  437. package/dist/src/gateway/hono/lib/agent-model.js +1 -1
  438. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  439. package/dist/src/gateway/hono/lib/config-payload.d.ts +234 -127
  440. package/dist/src/gateway/hono/lib/config-payload.js +13 -37
  441. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  442. package/dist/src/gateway/hono/routes/agents.js +56 -33
  443. package/dist/src/gateway/hono/routes/agents.js.map +1 -1
  444. package/dist/src/gateway/hono/routes/browser.js +8 -15
  445. package/dist/src/gateway/hono/routes/browser.js.map +1 -1
  446. package/dist/src/gateway/hono/routes/capability-presets.d.ts +3 -0
  447. package/dist/src/gateway/hono/routes/capability-presets.js +145 -0
  448. package/dist/src/gateway/hono/routes/capability-presets.js.map +1 -0
  449. package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +1 -17
  450. package/dist/src/gateway/hono/routes/config-patch/agents.js +2 -443
  451. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  452. package/dist/src/gateway/hono/routes/config-patch/misc.js +7 -1
  453. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  454. package/dist/src/gateway/hono/routes/config.js +1 -1
  455. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  456. package/dist/src/gateway/hono/routes/connectors.js +230 -3
  457. package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
  458. package/dist/src/gateway/hono/routes/dreaming.js +7 -0
  459. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  460. package/dist/src/gateway/hono/routes/goals.js +52 -5
  461. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  462. package/dist/src/gateway/hono/routes/index.js +2 -0
  463. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  464. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  465. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  466. package/dist/src/gateway/hono/routes/memory.d.ts +3 -0
  467. package/dist/src/gateway/hono/routes/memory.js +290 -0
  468. package/dist/src/gateway/hono/routes/memory.js.map +1 -0
  469. package/dist/src/gateway/hono/routes/voice.js +14 -1
  470. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  471. package/dist/src/gateway/hono/sse.js.map +1 -1
  472. package/dist/src/gateway/service/agent-runner.d.ts +5 -12
  473. package/dist/src/gateway/service/agent-runner.js +8 -8
  474. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  475. package/dist/src/gateway/service/run-gateway-agent.d.ts +2 -10
  476. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  477. package/dist/src/gateway/service.d.ts +2 -2
  478. package/dist/src/gateway/service.js +20 -16
  479. package/dist/src/gateway/service.js.map +1 -1
  480. package/dist/src/gateway/user-turn-input.d.ts +18 -0
  481. package/dist/src/gateway/user-turn-input.js +16 -0
  482. package/dist/src/gateway/user-turn-input.js.map +1 -0
  483. package/dist/src/goals/goal-queue-store.d.ts +2 -1
  484. package/dist/src/goals/goal-queue-store.js +2 -2
  485. package/dist/src/goals/goal-queue-store.js.map +1 -1
  486. package/dist/src/goals/goal-queue-types.d.ts +4 -3
  487. package/dist/src/goals/goal-runner.js +25 -3
  488. package/dist/src/goals/goal-runner.js.map +1 -1
  489. package/dist/src/goals/goal-service.d.ts +6 -1
  490. package/dist/src/goals/goal-service.js +9 -2
  491. package/dist/src/goals/goal-service.js.map +1 -1
  492. package/dist/src/goals/goal-store.d.ts +7 -1
  493. package/dist/src/goals/goal-store.js +42 -0
  494. package/dist/src/goals/goal-store.js.map +1 -1
  495. package/dist/src/goals/types.d.ts +10 -0
  496. package/dist/src/notes/agent-context.js +2 -2
  497. package/dist/src/providers/index.d.ts +2 -2
  498. package/dist/src/providers/index.js +10 -14
  499. package/dist/src/providers/index.js.map +1 -1
  500. package/dist/src/session/index.js +1 -1
  501. package/dist/src/session/session-workspace.js +7 -2
  502. package/dist/src/session/session-workspace.js.map +1 -1
  503. package/dist/src/session/store.js +5 -0
  504. package/dist/src/session/store.js.map +1 -1
  505. package/dist/src/session/thinking-resolve.d.ts +1 -1
  506. package/dist/src/session/thinking-resolve.js +1 -1
  507. package/dist/src/session/thinking-resolve.js.map +1 -1
  508. package/dist/src/storage/sqlite/connection.js +1 -1
  509. package/dist/src/storage/sqlite/index.d.ts +1 -0
  510. package/dist/src/storage/sqlite/index.js +2 -1
  511. package/dist/src/storage/sqlite/memory-records-repository.d.ts +101 -0
  512. package/dist/src/storage/sqlite/memory-records-repository.js +309 -0
  513. package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -0
  514. package/dist/src/storage/sqlite/migrations/011_goal_context_messages.sql +8 -0
  515. package/dist/src/storage/sqlite/migrations/012_memory_records.sql +63 -0
  516. package/dist/src/storage/sqlite/migrations/013_memory_trace_events.sql +21 -0
  517. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  518. package/dist/src/storage/sqlite/migrations/runner.js +4 -4
  519. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  520. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  521. package/dist/src/storage/sqlite/schema.js +3 -3
  522. package/dist/src/storage/sqlite/schema.sql +95 -0
  523. package/dist/src/tui/backends/embedded-backend.js +6 -4
  524. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  525. package/dist/src/tui/extension-host/load-extensions.js.map +1 -1
  526. package/dist/src/voice/tts/openai-compatible-speech.d.ts +1 -1
  527. package/dist/src/voice/tts/openai-compatible-speech.js.map +1 -1
  528. package/dist/src/voice/tts/providers/edge-speech.js +14 -2
  529. package/dist/src/voice/tts/providers/edge-speech.js.map +1 -1
  530. package/dist/src/voice/tts/speak-core.js +3 -3
  531. package/dist/src/voice/tts/speak-core.js.map +1 -1
  532. package/dist/src/voice/tts/speech-provider-types.d.ts +2 -2
  533. package/dist/src/voice/tts/types.js +1 -1
  534. package/dist/src/voice/tts/types.js.map +1 -1
  535. package/dist/src/workflows/domain/result.d.ts +0 -1
  536. package/dist/src/workflows/engine/workflow-engine.js +7 -23
  537. package/dist/src/workflows/engine/workflow-engine.js.map +1 -1
  538. package/dist/src/workflows/service/workflow-run-service.js +3 -4
  539. package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
  540. package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
  541. package/package.json +4 -3
  542. package/dist/gateway/static/root/assets/agent-browser-settings-page-DPXc4hz8.js +0 -6
  543. package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CTJ0YnRQ.js +0 -1
  544. package/dist/gateway/static/root/assets/agents-zJXQfJ_W.js +0 -71
  545. package/dist/gateway/static/root/assets/app-management-settings-panel-DzGbdr04.js +0 -1
  546. package/dist/gateway/static/root/assets/apps-page-CPjfyzSD.js +0 -1
  547. package/dist/gateway/static/root/assets/config-api-NOoPiIYz.js +0 -3
  548. package/dist/gateway/static/root/assets/connectors-settings-CAXYMOdp.js +0 -2
  549. package/dist/gateway/static/root/assets/cron-api-C9BOqAXd.js +0 -1
  550. package/dist/gateway/static/root/assets/cron-page-DuUbBeKI.js +0 -3
  551. package/dist/gateway/static/root/assets/dreaming-settings-DQ4DtiK1.js +0 -1
  552. package/dist/gateway/static/root/assets/gateway-config-api-C-xjn__h.js +0 -1
  553. package/dist/gateway/static/root/assets/gateway-settings-BMPwIjKI.js +0 -1
  554. package/dist/gateway/static/root/assets/goal-detail-page-BJsyjJnF.js +0 -1
  555. package/dist/gateway/static/root/assets/goals-page-BerDgIhw.js +0 -2
  556. package/dist/gateway/static/root/assets/goals-settings-ByTjeAto.js +0 -1
  557. package/dist/gateway/static/root/assets/heartbeat-settings-TbHgcjTn.js +0 -1
  558. package/dist/gateway/static/root/assets/index-AkTrf6Pb.js +0 -122
  559. package/dist/gateway/static/root/assets/index-fh5sXTj9.css +0 -1
  560. package/dist/gateway/static/root/assets/logs-page-DGXuPf5B.js +0 -2
  561. package/dist/gateway/static/root/assets/messages-upgxw6Ub.js +0 -3
  562. package/dist/gateway/static/root/assets/models-hub-panel-Bot16nn7.js +0 -2
  563. package/dist/gateway/static/root/assets/note-detail-page-Brlyou8M.js +0 -2
  564. package/dist/gateway/static/root/assets/notes-page-DvZ4pwc-.js +0 -1
  565. package/dist/gateway/static/root/assets/remote-access-hub-BZEDmxbZ.js +0 -1
  566. package/dist/gateway/static/root/assets/sessions-page-DdGGlsfn.js +0 -1
  567. package/dist/gateway/static/root/assets/settings-advanced-gate-DlkEkPf9.js +0 -1
  568. package/dist/gateway/static/root/assets/settings-page-DFPTrsPF.js +0 -1
  569. package/dist/gateway/static/root/assets/setup-status-panel-CYCCfgh4.js +0 -1
  570. package/dist/gateway/static/root/assets/shares-settings-Bff1pGd0.js +0 -1
  571. package/dist/gateway/static/root/assets/skill-reload-api-CJGKpBur.js +0 -1
  572. package/dist/gateway/static/root/assets/skills-page-C6ocduTD.js +0 -2
  573. package/dist/gateway/static/root/assets/system-settings-panel-5jrIEr5b.js +0 -1
  574. package/dist/gateway/static/root/assets/use-agent-defaults-form-BuiXLIs5.js +0 -1
  575. package/dist/gateway/static/root/assets/use-settings-tab-guard-CW5JORnl.js +0 -1
  576. package/dist/gateway/static/root/assets/voice-api-key-field-DDoQyghO.js +0 -1
  577. package/dist/gateway/static/root/assets/workflow-page.utils-CKjeEGqx.js +0 -1
  578. package/dist/gateway/static/root/assets/workflows-page-B604ehHG.js +0 -18
@@ -25,26 +25,13 @@ function coerceImageAssistantText(params) {
25
25
  if (text.trim()) return text.trim();
26
26
  throw new Error(`Image model returned no text (${params.provider}/${params.model}).`);
27
27
  }
28
- function coerceImageModelConfig(cfg) {
29
- return coerceToolModelConfig(cfg?.agents?.defaults?.imageModel);
28
+ function coerceImageModelConfig(_cfg) {
29
+ return coerceToolModelConfig(void 0);
30
30
  }
31
31
  function applyImageGenerationModelConfigDefaults(cfg, imageGenerationModelConfig) {
32
32
  if (!cfg) return;
33
- const primary = imageGenerationModelConfig.primary?.trim();
34
- if (!primary) return cfg;
35
- return {
36
- ...cfg,
37
- agents: {
38
- ...cfg.agents,
39
- defaults: {
40
- ...cfg.agents?.defaults,
41
- imageGenerationModel: {
42
- primary,
43
- ...imageGenerationModelConfig.fallbacks?.length ? { fallbacks: imageGenerationModelConfig.fallbacks } : {}
44
- }
45
- }
46
- }
47
- };
33
+ if (!imageGenerationModelConfig.primary?.trim()) return cfg;
34
+ return cfg;
48
35
  }
49
36
  function resolvePromptAndModelOverride(args, defaultPrompt) {
50
37
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"image-helpers.js","names":[],"sources":["../../../../src/agent/image/image-helpers.ts"],"sourcesContent":["import type { AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { AssistantMessage } from '@earendil-works/pi-ai';\nimport type { Config } from '../../config/schema.js';\nimport { extractTextContent } from '../context/workspace.js';\nimport type { ImageAttempt } from './image-model-fallback.js';\nimport { coerceToolModelConfig, type ToolModelConfig } from './tool-model-config.js';\n\nexport type ImageModelConfig = ToolModelConfig;\n\nexport function decodeDataUrl(dataUrl: string): {\n buffer: Buffer;\n mimeType: string;\n kind: 'image';\n} {\n const trimmed = dataUrl.trim();\n const match = /^data:([^;,]+);base64,([a-z0-9+/=\\r\\n]+)$/i.exec(trimmed);\n if (!match) {\n throw new Error('Invalid data URL (expected base64 data: URL).');\n }\n const mimeType = (match[1] ?? '').trim().toLowerCase();\n if (!mimeType.startsWith('image/')) {\n throw new Error(`Unsupported data URL type: ${mimeType || 'unknown'}`);\n }\n const b64 = (match[2] ?? '').trim();\n const buffer = Buffer.from(b64, 'base64');\n if (buffer.length === 0) {\n throw new Error('Invalid data URL: empty payload.');\n }\n return { buffer, mimeType, kind: 'image' };\n}\n\nexport function coerceImageAssistantText(params: {\n message: AssistantMessage;\n provider: string;\n model: string;\n}): string {\n const stop = params.message.stopReason;\n const errorMessage = params.message.errorMessage?.trim();\n if (stop === 'error' || stop === 'aborted') {\n throw new Error(\n errorMessage\n ? `Image model failed (${params.provider}/${params.model}): ${errorMessage}`\n : `Image model failed (${params.provider}/${params.model})`,\n );\n }\n if (errorMessage) {\n throw new Error(`Image model failed (${params.provider}/${params.model}): ${errorMessage}`);\n }\n const text = extractTextContent(\n params.message.content as Array<{ type: string; text?: string }>,\n );\n if (text.trim()) {\n return text.trim();\n }\n throw new Error(`Image model returned no text (${params.provider}/${params.model}).`);\n}\n\nexport function coerceImageModelConfig(cfg?: Config): ImageModelConfig {\n return coerceToolModelConfig(cfg?.agents?.defaults?.imageModel);\n}\n\nexport function applyImageGenerationModelConfigDefaults(\n cfg: Config | undefined,\n imageGenerationModelConfig: ToolModelConfig,\n): Config | undefined {\n if (!cfg) {\n return undefined;\n }\n const primary = imageGenerationModelConfig.primary?.trim();\n if (!primary) {\n return cfg;\n }\n return {\n ...cfg,\n agents: {\n ...cfg.agents,\n defaults: {\n ...cfg.agents?.defaults,\n imageGenerationModel: {\n primary,\n ...(imageGenerationModelConfig.fallbacks?.length ? { fallbacks: imageGenerationModelConfig.fallbacks } : {}),\n },\n },\n },\n };\n}\n\nexport function resolvePromptAndModelOverride(\n args: Record<string, unknown>,\n defaultPrompt: string,\n): {\n prompt: string;\n modelOverride?: string;\n} {\n const prompt =\n typeof args.prompt === 'string' && args.prompt.trim() ? args.prompt.trim() : defaultPrompt;\n const modelOverride =\n typeof args.model === 'string' && args.model.trim() ? args.model.trim() : undefined;\n return { prompt, modelOverride };\n}\n\nexport function buildImageToolTextResult(\n result: { text: string; provider: string; model: string; attempts: ImageAttempt[] },\n extraDetails: Record<string, unknown>,\n): AgentToolResult<Record<string, unknown>> {\n return {\n content: [{ type: 'text', text: result.text }],\n details: {\n model: `${result.provider}/${result.model}`,\n ...extraDetails,\n attempts: result.attempts,\n },\n };\n}\n"],"mappings":";;;AASA,SAAgB,cAAc,SAI5B;CACA,MAAM,UAAU,QAAQ,MAAM;CAC9B,MAAM,QAAQ,6CAA6C,KAAK,QAAQ;AACxE,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,gDAAgD;CAElE,MAAM,YAAY,MAAM,MAAM,IAAI,MAAM,CAAC,aAAa;AACtD,KAAI,CAAC,SAAS,WAAW,SAAS,CAChC,OAAM,IAAI,MAAM,8BAA8B,YAAY,YAAY;CAExE,MAAM,OAAO,MAAM,MAAM,IAAI,MAAM;CACnC,MAAM,SAAS,OAAO,KAAK,KAAK,SAAS;AACzC,KAAI,OAAO,WAAW,EACpB,OAAM,IAAI,MAAM,mCAAmC;AAErD,QAAO;EAAE;EAAQ;EAAU,MAAM;EAAS;;AAG5C,SAAgB,yBAAyB,QAI9B;CACT,MAAM,OAAO,OAAO,QAAQ;CAC5B,MAAM,eAAe,OAAO,QAAQ,cAAc,MAAM;AACxD,KAAI,SAAS,WAAW,SAAS,UAC/B,OAAM,IAAI,MACR,eACI,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,KAAK,iBAC5D,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,GAC5D;AAEH,KAAI,aACF,OAAM,IAAI,MAAM,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,KAAK,eAAe;CAE7F,MAAM,OAAO,mBACX,OAAO,QAAQ,QAChB;AACD,KAAI,KAAK,MAAM,CACb,QAAO,KAAK,MAAM;AAEpB,OAAM,IAAI,MAAM,iCAAiC,OAAO,SAAS,GAAG,OAAO,MAAM,IAAI;;AAGvF,SAAgB,uBAAuB,KAAgC;AACrE,QAAO,sBAAsB,KAAK,QAAQ,UAAU,WAAW;;AAGjE,SAAgB,wCACd,KACA,4BACoB;AACpB,KAAI,CAAC,IACH;CAEF,MAAM,UAAU,2BAA2B,SAAS,MAAM;AAC1D,KAAI,CAAC,QACH,QAAO;AAET,QAAO;EACL,GAAG;EACH,QAAQ;GACN,GAAG,IAAI;GACP,UAAU;IACR,GAAG,IAAI,QAAQ;IACf,sBAAsB;KACpB;KACA,GAAI,2BAA2B,WAAW,SAAS,EAAE,WAAW,2BAA2B,WAAW,GAAG,EAAE;KAC5G;IACF;GACF;EACF;;AAGH,SAAgB,8BACd,MACA,eAIA;AAKA,QAAO;EAAE,QAHP,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,MAAM,GAAG,KAAK,OAAO,MAAM,GAAG;EAG9D,eADf,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,MAAM,GAAG,KAAK,MAAM,MAAM,GAAG,KAAA;EAC5C;;AAGlC,SAAgB,yBACd,QACA,cAC0C;AAC1C,QAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,OAAO;GAAM,CAAC;EAC9C,SAAS;GACP,OAAO,GAAG,OAAO,SAAS,GAAG,OAAO;GACpC,GAAG;GACH,UAAU,OAAO;GAClB;EACF"}
1
+ {"version":3,"file":"image-helpers.js","names":[],"sources":["../../../../src/agent/image/image-helpers.ts"],"sourcesContent":["import type { AgentToolResult } from '@earendil-works/pi-agent-core';\nimport type { AssistantMessage } from '@earendil-works/pi-ai';\nimport type { Config } from '../../config/schema.js';\nimport { extractTextContent } from '../context/workspace.js';\nimport type { ImageAttempt } from './image-model-fallback.js';\nimport { coerceToolModelConfig, type ToolModelConfig } from './tool-model-config.js';\n\nexport type ImageModelConfig = ToolModelConfig;\n\nexport function decodeDataUrl(dataUrl: string): {\n buffer: Buffer;\n mimeType: string;\n kind: 'image';\n} {\n const trimmed = dataUrl.trim();\n const match = /^data:([^;,]+);base64,([a-z0-9+/=\\r\\n]+)$/i.exec(trimmed);\n if (!match) {\n throw new Error('Invalid data URL (expected base64 data: URL).');\n }\n const mimeType = (match[1] ?? '').trim().toLowerCase();\n if (!mimeType.startsWith('image/')) {\n throw new Error(`Unsupported data URL type: ${mimeType || 'unknown'}`);\n }\n const b64 = (match[2] ?? '').trim();\n const buffer = Buffer.from(b64, 'base64');\n if (buffer.length === 0) {\n throw new Error('Invalid data URL: empty payload.');\n }\n return { buffer, mimeType, kind: 'image' };\n}\n\nexport function coerceImageAssistantText(params: {\n message: AssistantMessage;\n provider: string;\n model: string;\n}): string {\n const stop = params.message.stopReason;\n const errorMessage = params.message.errorMessage?.trim();\n if (stop === 'error' || stop === 'aborted') {\n throw new Error(\n errorMessage\n ? `Image model failed (${params.provider}/${params.model}): ${errorMessage}`\n : `Image model failed (${params.provider}/${params.model})`,\n );\n }\n if (errorMessage) {\n throw new Error(`Image model failed (${params.provider}/${params.model}): ${errorMessage}`);\n }\n const text = extractTextContent(\n params.message.content as Array<{ type: string; text?: string }>,\n );\n if (text.trim()) {\n return text.trim();\n }\n throw new Error(`Image model returned no text (${params.provider}/${params.model}).`);\n}\n\nexport function coerceImageModelConfig(_cfg?: Config): ImageModelConfig {\n return coerceToolModelConfig(undefined);\n}\n\nexport function applyImageGenerationModelConfigDefaults(\n cfg: Config | undefined,\n imageGenerationModelConfig: ToolModelConfig,\n): Config | undefined {\n if (!cfg) {\n return undefined;\n }\n const primary = imageGenerationModelConfig.primary?.trim();\n if (!primary) {\n return cfg;\n }\n return cfg;\n}\n\nexport function resolvePromptAndModelOverride(\n args: Record<string, unknown>,\n defaultPrompt: string,\n): {\n prompt: string;\n modelOverride?: string;\n} {\n const prompt =\n typeof args.prompt === 'string' && args.prompt.trim() ? args.prompt.trim() : defaultPrompt;\n const modelOverride =\n typeof args.model === 'string' && args.model.trim() ? args.model.trim() : undefined;\n return { prompt, modelOverride };\n}\n\nexport function buildImageToolTextResult(\n result: { text: string; provider: string; model: string; attempts: ImageAttempt[] },\n extraDetails: Record<string, unknown>,\n): AgentToolResult<Record<string, unknown>> {\n return {\n content: [{ type: 'text', text: result.text }],\n details: {\n model: `${result.provider}/${result.model}`,\n ...extraDetails,\n attempts: result.attempts,\n },\n };\n}\n"],"mappings":";;;AASA,SAAgB,cAAc,SAI5B;CACA,MAAM,UAAU,QAAQ,MAAM;CAC9B,MAAM,QAAQ,6CAA6C,KAAK,QAAQ;AACxE,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,gDAAgD;CAElE,MAAM,YAAY,MAAM,MAAM,IAAI,MAAM,CAAC,aAAa;AACtD,KAAI,CAAC,SAAS,WAAW,SAAS,CAChC,OAAM,IAAI,MAAM,8BAA8B,YAAY,YAAY;CAExE,MAAM,OAAO,MAAM,MAAM,IAAI,MAAM;CACnC,MAAM,SAAS,OAAO,KAAK,KAAK,SAAS;AACzC,KAAI,OAAO,WAAW,EACpB,OAAM,IAAI,MAAM,mCAAmC;AAErD,QAAO;EAAE;EAAQ;EAAU,MAAM;EAAS;;AAG5C,SAAgB,yBAAyB,QAI9B;CACT,MAAM,OAAO,OAAO,QAAQ;CAC5B,MAAM,eAAe,OAAO,QAAQ,cAAc,MAAM;AACxD,KAAI,SAAS,WAAW,SAAS,UAC/B,OAAM,IAAI,MACR,eACI,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,KAAK,iBAC5D,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,GAC5D;AAEH,KAAI,aACF,OAAM,IAAI,MAAM,uBAAuB,OAAO,SAAS,GAAG,OAAO,MAAM,KAAK,eAAe;CAE7F,MAAM,OAAO,mBACX,OAAO,QAAQ,QAChB;AACD,KAAI,KAAK,MAAM,CACb,QAAO,KAAK,MAAM;AAEpB,OAAM,IAAI,MAAM,iCAAiC,OAAO,SAAS,GAAG,OAAO,MAAM,IAAI;;AAGvF,SAAgB,uBAAuB,MAAiC;AACtE,QAAO,sBAAsB,KAAA,EAAU;;AAGzC,SAAgB,wCACd,KACA,4BACoB;AACpB,KAAI,CAAC,IACH;AAGF,KAAI,CADY,2BAA2B,SAAS,MAAM,CAExD,QAAO;AAET,QAAO;;AAGT,SAAgB,8BACd,MACA,eAIA;AAKA,QAAO;EAAE,QAHP,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,MAAM,GAAG,KAAK,OAAO,MAAM,GAAG;EAG9D,eADf,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,MAAM,GAAG,KAAK,MAAM,MAAM,GAAG,KAAA;EAC5C;;AAGlC,SAAgB,yBACd,QACA,cAC0C;AAC1C,QAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM,OAAO;GAAM,CAAC;EAC9C,SAAS;GACP,OAAO,GAAG,OAAO,SAAS,GAAG,OAAO;GACpC,GAAG;GACH,UAAU,OAAO;GAClB;EACF"}
@@ -21,7 +21,7 @@ async function runWithImageModelFallback(params) {
21
21
  toolConfig: params.toolConfig,
22
22
  modelOverride: params.modelOverride
23
23
  });
24
- if (refs.length === 0) throw new Error("No image model configured. Set agents.defaults.imageModel.primary or add fallbacks.");
24
+ if (refs.length === 0) throw new Error("No image-capable model is available.");
25
25
  const attempts = [];
26
26
  let lastErr;
27
27
  for (const modelRef of refs) try {
@@ -1 +1 @@
1
- {"version":3,"file":"image-model-fallback.js","names":[],"sources":["../../../../src/agent/image/image-model-fallback.ts"],"sourcesContent":["import type { ToolModelConfig } from './tool-model-config.js';\n\nexport type ImageAttempt = { provider: string; model: string; error: string };\n\nfunction collectModelRefs(params: {\n toolConfig: ToolModelConfig;\n modelOverride?: string;\n}): string[] {\n const refs: string[] = [];\n const add = (raw: string | undefined) => {\n const t = raw?.trim();\n if (t?.includes('/')) {\n refs.push(t);\n }\n };\n add(params.modelOverride);\n add(params.toolConfig.primary);\n for (const f of params.toolConfig.fallbacks ?? []) {\n add(f);\n }\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of refs) {\n if (!seen.has(r)) {\n seen.add(r);\n out.push(r);\n }\n }\n return out;\n}\n\nexport async function runWithImageModelFallback<T>(params: {\n toolConfig: ToolModelConfig;\n modelOverride?: string;\n run: (modelRef: string) => Promise<T>;\n}): Promise<{ result: T; attempts: ImageAttempt[] }> {\n const refs = collectModelRefs({\n toolConfig: params.toolConfig,\n modelOverride: params.modelOverride,\n });\n if (refs.length === 0) {\n throw new Error(\n 'No image model configured. Set agents.defaults.imageModel.primary or add fallbacks.',\n );\n }\n\n const attempts: ImageAttempt[] = [];\n let lastErr: unknown;\n\n for (const modelRef of refs) {\n try {\n const result = await params.run(modelRef);\n return { result, attempts };\n } catch (err) {\n lastErr = err;\n const msg = err instanceof Error ? err.message : String(err);\n const slash = modelRef.indexOf('/');\n attempts.push({\n provider: slash > 0 ? modelRef.slice(0, slash) : modelRef,\n model: slash > 0 ? modelRef.slice(slash + 1) : '',\n error: msg,\n });\n }\n }\n\n const summary = attempts.map((a) => `${a.provider}/${a.model}: ${a.error}`).join(' | ');\n throw new Error(\n `All image models failed (${attempts.length}): ${summary || (lastErr instanceof Error ? lastErr.message : String(lastErr))}`,\n );\n}\n"],"mappings":";AAIA,SAAS,iBAAiB,QAGb;CACX,MAAM,OAAiB,EAAE;CACzB,MAAM,OAAO,QAA4B;EACvC,MAAM,IAAI,KAAK,MAAM;AACrB,MAAI,GAAG,SAAS,IAAI,CAClB,MAAK,KAAK,EAAE;;AAGhB,KAAI,OAAO,cAAc;AACzB,KAAI,OAAO,WAAW,QAAQ;AAC9B,MAAK,MAAM,KAAK,OAAO,WAAW,aAAa,EAAE,CAC/C,KAAI,EAAE;CAER,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,MAAgB,EAAE;AACxB,MAAK,MAAM,KAAK,KACd,KAAI,CAAC,KAAK,IAAI,EAAE,EAAE;AAChB,OAAK,IAAI,EAAE;AACX,MAAI,KAAK,EAAE;;AAGf,QAAO;;AAGT,eAAsB,0BAA6B,QAIE;CACnD,MAAM,OAAO,iBAAiB;EAC5B,YAAY,OAAO;EACnB,eAAe,OAAO;EACvB,CAAC;AACF,KAAI,KAAK,WAAW,EAClB,OAAM,IAAI,MACR,sFACD;CAGH,MAAM,WAA2B,EAAE;CACnC,IAAI;AAEJ,MAAK,MAAM,YAAY,KACrB,KAAI;AAEF,SAAO;GAAE,QAAA,MADY,OAAO,IAAI,SAAS;GACxB;GAAU;UACpB,KAAK;AACZ,YAAU;EACV,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;EAC5D,MAAM,QAAQ,SAAS,QAAQ,IAAI;AACnC,WAAS,KAAK;GACZ,UAAU,QAAQ,IAAI,SAAS,MAAM,GAAG,MAAM,GAAG;GACjD,OAAO,QAAQ,IAAI,SAAS,MAAM,QAAQ,EAAE,GAAG;GAC/C,OAAO;GACR,CAAC;;CAIN,MAAM,UAAU,SAAS,KAAK,MAAM,GAAG,EAAE,SAAS,GAAG,EAAE,MAAM,IAAI,EAAE,QAAQ,CAAC,KAAK,MAAM;AACvF,OAAM,IAAI,MACR,4BAA4B,SAAS,OAAO,KAAK,YAAY,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,QAAQ,IAC1H"}
1
+ {"version":3,"file":"image-model-fallback.js","names":[],"sources":["../../../../src/agent/image/image-model-fallback.ts"],"sourcesContent":["import type { ToolModelConfig } from './tool-model-config.js';\n\nexport type ImageAttempt = { provider: string; model: string; error: string };\n\nfunction collectModelRefs(params: {\n toolConfig: ToolModelConfig;\n modelOverride?: string;\n}): string[] {\n const refs: string[] = [];\n const add = (raw: string | undefined) => {\n const t = raw?.trim();\n if (t?.includes('/')) {\n refs.push(t);\n }\n };\n add(params.modelOverride);\n add(params.toolConfig.primary);\n for (const f of params.toolConfig.fallbacks ?? []) {\n add(f);\n }\n const seen = new Set<string>();\n const out: string[] = [];\n for (const r of refs) {\n if (!seen.has(r)) {\n seen.add(r);\n out.push(r);\n }\n }\n return out;\n}\n\nexport async function runWithImageModelFallback<T>(params: {\n toolConfig: ToolModelConfig;\n modelOverride?: string;\n run: (modelRef: string) => Promise<T>;\n}): Promise<{ result: T; attempts: ImageAttempt[] }> {\n const refs = collectModelRefs({\n toolConfig: params.toolConfig,\n modelOverride: params.modelOverride,\n });\n if (refs.length === 0) {\n throw new Error(\n 'No image-capable model is available.',\n );\n }\n\n const attempts: ImageAttempt[] = [];\n let lastErr: unknown;\n\n for (const modelRef of refs) {\n try {\n const result = await params.run(modelRef);\n return { result, attempts };\n } catch (err) {\n lastErr = err;\n const msg = err instanceof Error ? err.message : String(err);\n const slash = modelRef.indexOf('/');\n attempts.push({\n provider: slash > 0 ? modelRef.slice(0, slash) : modelRef,\n model: slash > 0 ? modelRef.slice(slash + 1) : '',\n error: msg,\n });\n }\n }\n\n const summary = attempts.map((a) => `${a.provider}/${a.model}: ${a.error}`).join(' | ');\n throw new Error(\n `All image models failed (${attempts.length}): ${summary || (lastErr instanceof Error ? lastErr.message : String(lastErr))}`,\n );\n}\n"],"mappings":";AAIA,SAAS,iBAAiB,QAGb;CACX,MAAM,OAAiB,EAAE;CACzB,MAAM,OAAO,QAA4B;EACvC,MAAM,IAAI,KAAK,MAAM;AACrB,MAAI,GAAG,SAAS,IAAI,CAClB,MAAK,KAAK,EAAE;;AAGhB,KAAI,OAAO,cAAc;AACzB,KAAI,OAAO,WAAW,QAAQ;AAC9B,MAAK,MAAM,KAAK,OAAO,WAAW,aAAa,EAAE,CAC/C,KAAI,EAAE;CAER,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,MAAgB,EAAE;AACxB,MAAK,MAAM,KAAK,KACd,KAAI,CAAC,KAAK,IAAI,EAAE,EAAE;AAChB,OAAK,IAAI,EAAE;AACX,MAAI,KAAK,EAAE;;AAGf,QAAO;;AAGT,eAAsB,0BAA6B,QAIE;CACnD,MAAM,OAAO,iBAAiB;EAC5B,YAAY,OAAO;EACnB,eAAe,OAAO;EACvB,CAAC;AACF,KAAI,KAAK,WAAW,EAClB,OAAM,IAAI,MACR,uCACD;CAGH,MAAM,WAA2B,EAAE;CACnC,IAAI;AAEJ,MAAK,MAAM,YAAY,KACrB,KAAI;AAEF,SAAO;GAAE,QAAA,MADY,OAAO,IAAI,SAAS;GACxB;GAAU;UACpB,KAAK;AACZ,YAAU;EACV,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;EAC5D,MAAM,QAAQ,SAAS,QAAQ,IAAI;AACnC,WAAS,KAAK;GACZ,UAAU,QAAQ,IAAI,SAAS,MAAM,GAAG,MAAM,GAAG;GACjD,OAAO,QAAQ,IAAI,SAAS,MAAM,QAAQ,EAAE,GAAG;GAC/C,OAAO;GACR,CAAC;;CAIN,MAAM,UAAU,SAAS,KAAK,MAAM,GAAG,EAAE,SAAS,GAAG,EAAE,MAAM,IAAI,EAAE,QAAQ,CAAC,KAAK,MAAM;AACvF,OAAM,IAAI,MACR,4BAA4B,SAAS,OAAO,KAAK,YAAY,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,QAAQ,IAC1H"}
@@ -13,7 +13,7 @@ async function resolveInboundImageContentParts(params) {
13
13
  const fallbacks = toolCfg?.fallbacks ?? [];
14
14
  if (!primary) return [{
15
15
  type: "text",
16
- text: `[${params.images.length} image(s) attached; configure agents.defaults.imageModel to describe them.]`
16
+ text: `[${params.images.length} image(s) attached; no image-capable model is available to describe them.]`
17
17
  }];
18
18
  try {
19
19
  return [{
@@ -1 +1 @@
1
- {"version":3,"file":"inbound-image-handling.js","names":[],"sources":["../../../../src/agent/image/inbound-image-handling.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { describeImagesWithFallback } from './understanding/runtime.js';\nimport { resolveImageModelConfigForTool } from './tool-model-config.js';\nimport { resolveImageHandlingStrategy } from './vision-detection.js';\n\nexport async function resolveInboundImageContentParts(params: {\n modelRef: string;\n cfg?: Config;\n userTextForContext: string;\n images: Array<{ data: string; mimeType: string }>;\n}): Promise<Array<{ type: 'image'; data: string; mimeType: string } | { type: 'text'; text: string }>> {\n const strategy = resolveImageHandlingStrategy(params.modelRef);\n if (strategy === 'native') {\n return params.images.map((att) => ({\n type: 'image' as const,\n data: att.data,\n mimeType: att.mimeType,\n }));\n }\n\n const toolCfg = resolveImageModelConfigForTool({ cfg: params.cfg });\n const primary = toolCfg?.primary;\n const fallbacks = toolCfg?.fallbacks ?? [];\n\n if (!primary) {\n return [\n {\n type: 'text' as const,\n text: `[${params.images.length} image(s) attached; configure agents.defaults.imageModel to describe them.]`,\n },\n ];\n }\n\n try {\n const buffers = params.images.map((att) => ({\n buffer: Buffer.from(att.data, 'base64'),\n mimeType: att.mimeType,\n }));\n const prompt = params.userTextForContext.trim()\n ? `Describe these images in the context of the user's message: \"${params.userTextForContext}\"`\n : 'Describe these images in detail.';\n const result = await describeImagesWithFallback({\n modelRef: primary,\n fallbacks,\n images: buffers,\n prompt,\n maxTokens: 1024,\n timeoutMs: 30_000,\n });\n return [{ type: 'text' as const, text: `[Image description: ${result.text}]` }];\n } catch (err) {\n return [\n {\n type: 'text' as const,\n text: `[${params.images.length} image(s) attached but could not be described: ${err instanceof Error ? err.message : String(err)}]`,\n },\n ];\n }\n}\n"],"mappings":";;;;AAKA,eAAsB,gCAAgC,QAKiD;AAErG,KADiB,6BAA6B,OAAO,SACzC,KAAK,SACf,QAAO,OAAO,OAAO,KAAK,SAAS;EACjC,MAAM;EACN,MAAM,IAAI;EACV,UAAU,IAAI;EACf,EAAE;CAGL,MAAM,UAAU,+BAA+B,EAAE,KAAK,OAAO,KAAK,CAAC;CACnE,MAAM,UAAU,SAAS;CACzB,MAAM,YAAY,SAAS,aAAa,EAAE;AAE1C,KAAI,CAAC,QACH,QAAO,CACL;EACE,MAAM;EACN,MAAM,IAAI,OAAO,OAAO,OAAO;EAChC,CACF;AAGH,KAAI;AAgBF,SAAO,CAAC;GAAE,MAAM;GAAiB,MAAM,wBAAuB,MARzC,2BAA2B;IAC9C,UAAU;IACV;IACA,QAVc,OAAO,OAAO,KAAK,SAAS;KAC1C,QAAQ,OAAO,KAAK,IAAI,MAAM,SAAS;KACvC,UAAU,IAAI;KACf,EAOgB;IACf,QAPa,OAAO,mBAAmB,MAAM,GAC3C,gEAAgE,OAAO,mBAAmB,KAC1F;IAMF,WAAW;IACX,WAAW;IACZ,CAAC,EACmE,KAAK;GAAI,CAAC;UACxE,KAAK;AACZ,SAAO,CACL;GACE,MAAM;GACN,MAAM,IAAI,OAAO,OAAO,OAAO,iDAAiD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;GAClI,CACF"}
1
+ {"version":3,"file":"inbound-image-handling.js","names":[],"sources":["../../../../src/agent/image/inbound-image-handling.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { describeImagesWithFallback } from './understanding/runtime.js';\nimport { resolveImageModelConfigForTool } from './tool-model-config.js';\nimport { resolveImageHandlingStrategy } from './vision-detection.js';\n\nexport async function resolveInboundImageContentParts(params: {\n modelRef: string;\n cfg?: Config;\n userTextForContext: string;\n images: Array<{ data: string; mimeType: string }>;\n}): Promise<Array<{ type: 'image'; data: string; mimeType: string } | { type: 'text'; text: string }>> {\n const strategy = resolveImageHandlingStrategy(params.modelRef);\n if (strategy === 'native') {\n return params.images.map((att) => ({\n type: 'image' as const,\n data: att.data,\n mimeType: att.mimeType,\n }));\n }\n\n const toolCfg = resolveImageModelConfigForTool({ cfg: params.cfg });\n const primary = toolCfg?.primary;\n const fallbacks = toolCfg?.fallbacks ?? [];\n\n if (!primary) {\n return [\n {\n type: 'text' as const,\n text: `[${params.images.length} image(s) attached; no image-capable model is available to describe them.]`,\n },\n ];\n }\n\n try {\n const buffers = params.images.map((att) => ({\n buffer: Buffer.from(att.data, 'base64'),\n mimeType: att.mimeType,\n }));\n const prompt = params.userTextForContext.trim()\n ? `Describe these images in the context of the user's message: \"${params.userTextForContext}\"`\n : 'Describe these images in detail.';\n const result = await describeImagesWithFallback({\n modelRef: primary,\n fallbacks,\n images: buffers,\n prompt,\n maxTokens: 1024,\n timeoutMs: 30_000,\n });\n return [{ type: 'text' as const, text: `[Image description: ${result.text}]` }];\n } catch (err) {\n return [\n {\n type: 'text' as const,\n text: `[${params.images.length} image(s) attached but could not be described: ${err instanceof Error ? err.message : String(err)}]`,\n },\n ];\n }\n}\n"],"mappings":";;;;AAKA,eAAsB,gCAAgC,QAKiD;AAErG,KADiB,6BAA6B,OAAO,SACzC,KAAK,SACf,QAAO,OAAO,OAAO,KAAK,SAAS;EACjC,MAAM;EACN,MAAM,IAAI;EACV,UAAU,IAAI;EACf,EAAE;CAGL,MAAM,UAAU,+BAA+B,EAAE,KAAK,OAAO,KAAK,CAAC;CACnE,MAAM,UAAU,SAAS;CACzB,MAAM,YAAY,SAAS,aAAa,EAAE;AAE1C,KAAI,CAAC,QACH,QAAO,CACL;EACE,MAAM;EACN,MAAM,IAAI,OAAO,OAAO,OAAO;EAChC,CACF;AAGH,KAAI;AAgBF,SAAO,CAAC;GAAE,MAAM;GAAiB,MAAM,wBAAuB,MARzC,2BAA2B;IAC9C,UAAU;IACV;IACA,QAVc,OAAO,OAAO,KAAK,SAAS;KAC1C,QAAQ,OAAO,KAAK,IAAI,MAAM,SAAS;KACvC,UAAU,IAAI;KACf,EAOgB;IACf,QAPa,OAAO,mBAAmB,MAAM,GAC3C,gEAAgE,OAAO,mBAAmB,KAC1F;IAMF,WAAW;IACX,WAAW;IACZ,CAAC,EACmE,KAAK;GAAI,CAAC;UACxE,KAAK;AACZ,SAAO,CACL;GACE,MAAM;GACN,MAAM,IAAI,OAAO,OAAO,OAAO,iDAAiD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAAC;GAClI,CACF"}
@@ -14,7 +14,7 @@ export declare function buildToolModelConfigFromCandidates(params: {
14
14
  candidates: Array<string | null | undefined>;
15
15
  }): ToolModelConfig | null;
16
16
  /**
17
- * Effective image understanding model: explicit `agents.defaults.imageModel`, else inferred from configured providers.
17
+ * Effective image understanding model inferred from configured providers.
18
18
  */
19
19
  export declare function resolveImageModelConfigForTool(params: {
20
20
  cfg?: Config;
@@ -49,10 +49,10 @@ function firstVisionModelRef(provider) {
49
49
  return m ? `${provider}/${m.id}` : void 0;
50
50
  }
51
51
  /**
52
- * Effective image understanding model: explicit `agents.defaults.imageModel`, else inferred from configured providers.
52
+ * Effective image understanding model inferred from configured providers.
53
53
  */
54
54
  function resolveImageModelConfigForTool(params) {
55
- const explicit = coerceToolModelConfig(params.cfg?.agents?.defaults?.imageModel);
55
+ const explicit = coerceToolModelConfig(void 0);
56
56
  if (hasToolModelConfig(explicit)) return explicit;
57
57
  const primary = resolveDefaultModelRef(params.cfg);
58
58
  const primaryCandidates = [];
@@ -1 +1 @@
1
- {"version":3,"file":"tool-model-config.js","names":[],"sources":["../../../../src/agent/image/tool-model-config.ts"],"sourcesContent":["import type { AgentModelConfig, Config } from '../../config/schema.js';\nimport { getAgentDefaultModelRef, parseModelRef } from '../../config/schema.js';\nimport {\n resolveAgentModelFallbackValues,\n resolveAgentModelPrimaryValue,\n} from '../../config/model-input.js';\nimport { getDefaultModelSync, getModelsByProvider, isProviderConfiguredSync } from '../../providers/index.js';\n\nexport type ToolModelConfig = { primary?: string; fallbacks?: string[] };\n\nexport function hasToolModelConfig(model: ToolModelConfig | undefined): boolean {\n return Boolean(\n model?.primary?.trim() || (model?.fallbacks ?? []).some((entry) => entry.trim().length > 0),\n );\n}\n\nexport function resolveDefaultModelRef(cfg?: Config): { provider: string; model: string } {\n const ref = cfg ? getAgentDefaultModelRef(cfg) : undefined;\n if (ref) {\n const p = parseModelRef(ref);\n if (p) {\n return p;\n }\n }\n const fallback = getDefaultModelSync(cfg);\n const p2 = parseModelRef(fallback);\n if (p2) {\n return p2;\n }\n return { provider: 'deepseek', model: 'deepseek-v4-flash' };\n}\n\nexport function coerceToolModelConfig(model?: AgentModelConfig): ToolModelConfig {\n const primary = resolveAgentModelPrimaryValue(model);\n const fallbacks = resolveAgentModelFallbackValues(model);\n return {\n ...(primary?.trim() ? { primary: primary.trim() } : {}),\n ...(fallbacks.length > 0 ? { fallbacks } : {}),\n };\n}\n\nexport function buildToolModelConfigFromCandidates(params: {\n explicit: ToolModelConfig;\n candidates: Array<string | null | undefined>;\n}): ToolModelConfig | null {\n if (hasToolModelConfig(params.explicit)) {\n return params.explicit;\n }\n\n const deduped: string[] = [];\n for (const candidate of params.candidates) {\n const trimmed = candidate?.trim();\n if (!trimmed || !trimmed.includes('/')) {\n continue;\n }\n const provider = trimmed.slice(0, trimmed.indexOf('/')).trim();\n if (!provider || !isProviderConfiguredSync(provider)) {\n continue;\n }\n if (!deduped.includes(trimmed)) {\n deduped.push(trimmed);\n }\n }\n\n if (deduped.length === 0) {\n return null;\n }\n\n return {\n primary: deduped[0],\n ...(deduped.length > 1 ? { fallbacks: deduped.slice(1) } : {}),\n };\n}\n\nfunction firstVisionModelRef(provider: string): string | undefined {\n const m = getModelsByProvider(provider).find((x) => x.input?.includes('image'));\n return m ? `${provider}/${m.id}` : undefined;\n}\n\n/**\n * Effective image understanding model: explicit `agents.defaults.imageModel`, else inferred from configured providers.\n */\nexport function resolveImageModelConfigForTool(params: { cfg?: Config }): ToolModelConfig | null {\n const explicit = coerceToolModelConfig(params.cfg?.agents?.defaults?.imageModel);\n if (hasToolModelConfig(explicit)) {\n return explicit;\n }\n\n const primary = resolveDefaultModelRef(params.cfg);\n const primaryCandidates: string[] = [];\n const vision = firstVisionModelRef(primary.provider);\n if (vision) {\n primaryCandidates.push(vision);\n }\n if (primary.provider === 'openai') {\n primaryCandidates.push('openai/gpt-4o-mini');\n }\n if (primary.provider === 'anthropic') {\n primaryCandidates.push('anthropic/claude-sonnet-4-5');\n }\n if (primary.provider === 'google') {\n primaryCandidates.push('google/gemini-2.0-flash');\n }\n\n return buildToolModelConfigFromCandidates({\n explicit,\n candidates: [\n ...primaryCandidates,\n firstVisionModelRef('openai') ?? 'openai/gpt-4o-mini',\n firstVisionModelRef('anthropic') ?? 'anthropic/claude-sonnet-4-5',\n ],\n });\n}\n"],"mappings":";;;;aACgF;gBAK8B;AAI9G,SAAgB,mBAAmB,OAA6C;AAC9E,QAAO,QACL,OAAO,SAAS,MAAM,KAAK,OAAO,aAAa,EAAE,EAAE,MAAM,UAAU,MAAM,MAAM,CAAC,SAAS,EAAE,CAC5F;;AAGH,SAAgB,uBAAuB,KAAmD;CACxF,MAAM,MAAM,MAAM,wBAAwB,IAAI,GAAG,KAAA;AACjD,KAAI,KAAK;EACP,MAAM,IAAI,cAAc,IAAI;AAC5B,MAAI,EACF,QAAO;;CAIX,MAAM,KAAK,cADM,oBAAoB,IACJ,CAAC;AAClC,KAAI,GACF,QAAO;AAET,QAAO;EAAE,UAAU;EAAY,OAAO;EAAqB;;AAG7D,SAAgB,sBAAsB,OAA2C;CAC/E,MAAM,UAAU,8BAA8B,MAAM;CACpD,MAAM,YAAY,gCAAgC,MAAM;AACxD,QAAO;EACL,GAAI,SAAS,MAAM,GAAG,EAAE,SAAS,QAAQ,MAAM,EAAE,GAAG,EAAE;EACtD,GAAI,UAAU,SAAS,IAAI,EAAE,WAAW,GAAG,EAAE;EAC9C;;AAGH,SAAgB,mCAAmC,QAGxB;AACzB,KAAI,mBAAmB,OAAO,SAAS,CACrC,QAAO,OAAO;CAGhB,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,aAAa,OAAO,YAAY;EACzC,MAAM,UAAU,WAAW,MAAM;AACjC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,IAAI,CACpC;EAEF,MAAM,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,IAAI,CAAC,CAAC,MAAM;AAC9D,MAAI,CAAC,YAAY,CAAC,yBAAyB,SAAS,CAClD;AAEF,MAAI,CAAC,QAAQ,SAAS,QAAQ,CAC5B,SAAQ,KAAK,QAAQ;;AAIzB,KAAI,QAAQ,WAAW,EACrB,QAAO;AAGT,QAAO;EACL,SAAS,QAAQ;EACjB,GAAI,QAAQ,SAAS,IAAI,EAAE,WAAW,QAAQ,MAAM,EAAE,EAAE,GAAG,EAAE;EAC9D;;AAGH,SAAS,oBAAoB,UAAsC;CACjE,MAAM,IAAI,oBAAoB,SAAS,CAAC,MAAM,MAAM,EAAE,OAAO,SAAS,QAAQ,CAAC;AAC/E,QAAO,IAAI,GAAG,SAAS,GAAG,EAAE,OAAO,KAAA;;;;;AAMrC,SAAgB,+BAA+B,QAAkD;CAC/F,MAAM,WAAW,sBAAsB,OAAO,KAAK,QAAQ,UAAU,WAAW;AAChF,KAAI,mBAAmB,SAAS,CAC9B,QAAO;CAGT,MAAM,UAAU,uBAAuB,OAAO,IAAI;CAClD,MAAM,oBAA8B,EAAE;CACtC,MAAM,SAAS,oBAAoB,QAAQ,SAAS;AACpD,KAAI,OACF,mBAAkB,KAAK,OAAO;AAEhC,KAAI,QAAQ,aAAa,SACvB,mBAAkB,KAAK,qBAAqB;AAE9C,KAAI,QAAQ,aAAa,YACvB,mBAAkB,KAAK,8BAA8B;AAEvD,KAAI,QAAQ,aAAa,SACvB,mBAAkB,KAAK,0BAA0B;AAGnD,QAAO,mCAAmC;EACxC;EACA,YAAY;GACV,GAAG;GACH,oBAAoB,SAAS,IAAI;GACjC,oBAAoB,YAAY,IAAI;GACrC;EACF,CAAC"}
1
+ {"version":3,"file":"tool-model-config.js","names":[],"sources":["../../../../src/agent/image/tool-model-config.ts"],"sourcesContent":["import type { AgentModelConfig, Config } from '../../config/schema.js';\nimport { getAgentDefaultModelRef, parseModelRef } from '../../config/schema.js';\nimport {\n resolveAgentModelFallbackValues,\n resolveAgentModelPrimaryValue,\n} from '../../config/model-input.js';\nimport { getDefaultModelSync, getModelsByProvider, isProviderConfiguredSync } from '../../providers/index.js';\n\nexport type ToolModelConfig = { primary?: string; fallbacks?: string[] };\n\nexport function hasToolModelConfig(model: ToolModelConfig | undefined): boolean {\n return Boolean(\n model?.primary?.trim() || (model?.fallbacks ?? []).some((entry) => entry.trim().length > 0),\n );\n}\n\nexport function resolveDefaultModelRef(cfg?: Config): { provider: string; model: string } {\n const ref = cfg ? getAgentDefaultModelRef(cfg) : undefined;\n if (ref) {\n const p = parseModelRef(ref);\n if (p) {\n return p;\n }\n }\n const fallback = getDefaultModelSync(cfg);\n const p2 = parseModelRef(fallback);\n if (p2) {\n return p2;\n }\n return { provider: 'deepseek', model: 'deepseek-v4-flash' };\n}\n\nexport function coerceToolModelConfig(model?: AgentModelConfig): ToolModelConfig {\n const primary = resolveAgentModelPrimaryValue(model);\n const fallbacks = resolveAgentModelFallbackValues(model);\n return {\n ...(primary?.trim() ? { primary: primary.trim() } : {}),\n ...(fallbacks.length > 0 ? { fallbacks } : {}),\n };\n}\n\nexport function buildToolModelConfigFromCandidates(params: {\n explicit: ToolModelConfig;\n candidates: Array<string | null | undefined>;\n}): ToolModelConfig | null {\n if (hasToolModelConfig(params.explicit)) {\n return params.explicit;\n }\n\n const deduped: string[] = [];\n for (const candidate of params.candidates) {\n const trimmed = candidate?.trim();\n if (!trimmed || !trimmed.includes('/')) {\n continue;\n }\n const provider = trimmed.slice(0, trimmed.indexOf('/')).trim();\n if (!provider || !isProviderConfiguredSync(provider)) {\n continue;\n }\n if (!deduped.includes(trimmed)) {\n deduped.push(trimmed);\n }\n }\n\n if (deduped.length === 0) {\n return null;\n }\n\n return {\n primary: deduped[0],\n ...(deduped.length > 1 ? { fallbacks: deduped.slice(1) } : {}),\n };\n}\n\nfunction firstVisionModelRef(provider: string): string | undefined {\n const m = getModelsByProvider(provider).find((x) => x.input?.includes('image'));\n return m ? `${provider}/${m.id}` : undefined;\n}\n\n/**\n * Effective image understanding model inferred from configured providers.\n */\nexport function resolveImageModelConfigForTool(params: { cfg?: Config }): ToolModelConfig | null {\n const explicit = coerceToolModelConfig(undefined);\n if (hasToolModelConfig(explicit)) {\n return explicit;\n }\n\n const primary = resolveDefaultModelRef(params.cfg);\n const primaryCandidates: string[] = [];\n const vision = firstVisionModelRef(primary.provider);\n if (vision) {\n primaryCandidates.push(vision);\n }\n if (primary.provider === 'openai') {\n primaryCandidates.push('openai/gpt-4o-mini');\n }\n if (primary.provider === 'anthropic') {\n primaryCandidates.push('anthropic/claude-sonnet-4-5');\n }\n if (primary.provider === 'google') {\n primaryCandidates.push('google/gemini-2.0-flash');\n }\n\n return buildToolModelConfigFromCandidates({\n explicit,\n candidates: [\n ...primaryCandidates,\n firstVisionModelRef('openai') ?? 'openai/gpt-4o-mini',\n firstVisionModelRef('anthropic') ?? 'anthropic/claude-sonnet-4-5',\n ],\n });\n}\n"],"mappings":";;;;aACgF;gBAK8B;AAI9G,SAAgB,mBAAmB,OAA6C;AAC9E,QAAO,QACL,OAAO,SAAS,MAAM,KAAK,OAAO,aAAa,EAAE,EAAE,MAAM,UAAU,MAAM,MAAM,CAAC,SAAS,EAAE,CAC5F;;AAGH,SAAgB,uBAAuB,KAAmD;CACxF,MAAM,MAAM,MAAM,wBAAwB,IAAI,GAAG,KAAA;AACjD,KAAI,KAAK;EACP,MAAM,IAAI,cAAc,IAAI;AAC5B,MAAI,EACF,QAAO;;CAIX,MAAM,KAAK,cADM,oBAAoB,IACJ,CAAC;AAClC,KAAI,GACF,QAAO;AAET,QAAO;EAAE,UAAU;EAAY,OAAO;EAAqB;;AAG7D,SAAgB,sBAAsB,OAA2C;CAC/E,MAAM,UAAU,8BAA8B,MAAM;CACpD,MAAM,YAAY,gCAAgC,MAAM;AACxD,QAAO;EACL,GAAI,SAAS,MAAM,GAAG,EAAE,SAAS,QAAQ,MAAM,EAAE,GAAG,EAAE;EACtD,GAAI,UAAU,SAAS,IAAI,EAAE,WAAW,GAAG,EAAE;EAC9C;;AAGH,SAAgB,mCAAmC,QAGxB;AACzB,KAAI,mBAAmB,OAAO,SAAS,CACrC,QAAO,OAAO;CAGhB,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,aAAa,OAAO,YAAY;EACzC,MAAM,UAAU,WAAW,MAAM;AACjC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,IAAI,CACpC;EAEF,MAAM,WAAW,QAAQ,MAAM,GAAG,QAAQ,QAAQ,IAAI,CAAC,CAAC,MAAM;AAC9D,MAAI,CAAC,YAAY,CAAC,yBAAyB,SAAS,CAClD;AAEF,MAAI,CAAC,QAAQ,SAAS,QAAQ,CAC5B,SAAQ,KAAK,QAAQ;;AAIzB,KAAI,QAAQ,WAAW,EACrB,QAAO;AAGT,QAAO;EACL,SAAS,QAAQ;EACjB,GAAI,QAAQ,SAAS,IAAI,EAAE,WAAW,QAAQ,MAAM,EAAE,EAAE,GAAG,EAAE;EAC9D;;AAGH,SAAS,oBAAoB,UAAsC;CACjE,MAAM,IAAI,oBAAoB,SAAS,CAAC,MAAM,MAAM,EAAE,OAAO,SAAS,QAAQ,CAAC;AAC/E,QAAO,IAAI,GAAG,SAAS,GAAG,EAAE,OAAO,KAAA;;;;;AAMrC,SAAgB,+BAA+B,QAAkD;CAC/F,MAAM,WAAW,sBAAsB,KAAA,EAAU;AACjD,KAAI,mBAAmB,SAAS,CAC9B,QAAO;CAGT,MAAM,UAAU,uBAAuB,OAAO,IAAI;CAClD,MAAM,oBAA8B,EAAE;CACtC,MAAM,SAAS,oBAAoB,QAAQ,SAAS;AACpD,KAAI,OACF,mBAAkB,KAAK,OAAO;AAEhC,KAAI,QAAQ,aAAa,SACvB,mBAAkB,KAAK,qBAAqB;AAE9C,KAAI,QAAQ,aAAa,YACvB,mBAAkB,KAAK,8BAA8B;AAEvD,KAAI,QAAQ,aAAa,SACvB,mBAAkB,KAAK,0BAA0B;AAGnD,QAAO,mCAAmC;EACxC;EACA,YAAY;GACV,GAAG;GACH,oBAAoB,SAAS,IAAI;GACjC,oBAAoB,YAAY,IAAI;GACrC;EACF,CAAC"}
@@ -1,5 +1,5 @@
1
- import { getApiKey, init_providers, resolveModel } from "../../../providers/index.js";
2
- import { registerImageUnderstandingProvider } from "./provider-registry.js";
1
+ import { getApiKey, getModelsByProvider, init_providers, resolveModel } from "../../../providers/index.js";
2
+ import { registerImageUnderstandingProvider, registerImageUnderstandingProviderFactory } from "./provider-registry.js";
3
3
  import { coerceImageAssistantText } from "../image-helpers.js";
4
4
  import { complete } from "@earendil-works/pi-ai";
5
5
  //#region src/agent/image/understanding/pi-ai-provider.ts
@@ -65,6 +65,9 @@ for (const providerId of [
65
65
  "anthropic",
66
66
  "google"
67
67
  ]) registerImageUnderstandingProvider(buildPiAiImageUnderstandingProvider(providerId));
68
+ registerImageUnderstandingProviderFactory((providerId) => {
69
+ return getModelsByProvider(providerId).some((model) => model.input?.includes("image")) ? buildPiAiImageUnderstandingProvider(providerId) : void 0;
70
+ });
68
71
  //#endregion
69
72
  export { buildPiAiImageUnderstandingProvider };
70
73
 
@@ -1 +1 @@
1
- {"version":3,"file":"pi-ai-provider.js","names":[],"sources":["../../../../../src/agent/image/understanding/pi-ai-provider.ts"],"sourcesContent":["import { complete, type Api, type Context, type Model } from '@earendil-works/pi-ai';\nimport { resolveModel, getApiKey } from '../../../providers/index.js';\nimport { coerceImageAssistantText } from '../image-helpers.js';\nimport { registerImageUnderstandingProvider } from './provider-registry.js';\nimport type { ImageUnderstandingProvider } from './types.js';\n\nfunction resolveMaxTokens(modelMaxTokens: number | undefined, requestedMaxTokens = 4096): number {\n if (\n typeof modelMaxTokens !== 'number' ||\n !Number.isFinite(modelMaxTokens) ||\n modelMaxTokens <= 0\n ) {\n return requestedMaxTokens;\n }\n return Math.min(requestedMaxTokens, modelMaxTokens);\n}\n\nexport function buildPiAiImageUnderstandingProvider(providerId: string): ImageUnderstandingProvider {\n return {\n id: providerId,\n label: `pi-ai (${providerId})`,\n async isConfigured() {\n const apiKey = await getApiKey(providerId);\n return Boolean(apiKey);\n },\n async describeImages(modelId, request) {\n const modelRef = `${providerId}/${modelId}`;\n const model = resolveModel(modelRef) as Model<Api>;\n if (!model.input?.includes('image')) {\n throw new Error(`Model does not support images: ${modelRef}`);\n }\n const apiKey = await getApiKey(providerId);\n if (!apiKey) {\n throw new Error(`No API key configured for provider: ${providerId}`);\n }\n\n const context: Context = {\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: request.prompt },\n ...request.images.map((img) => ({\n type: 'image' as const,\n data: img.buffer.toString('base64'),\n mimeType: img.mimeType || 'image/jpeg',\n })),\n ],\n timestamp: Date.now(),\n },\n ],\n };\n\n const maxTokens = resolveMaxTokens(model.maxTokens, request.maxTokens ?? 512);\n const timeoutMs = request.timeoutMs ?? 60_000;\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(timeoutMs)\n : undefined;\n const signal = (() => {\n if (timeoutSignal && request.signal && typeof AbortSignal.any === 'function') {\n return AbortSignal.any([request.signal, timeoutSignal]);\n }\n if (request.signal) {\n return request.signal;\n }\n if (timeoutSignal) {\n return timeoutSignal;\n }\n const controller = new AbortController();\n setTimeout(() => controller.abort(), timeoutMs);\n return controller.signal;\n })();\n\n const message = await complete(model, context, {\n apiKey,\n maxTokens,\n signal,\n });\n\n const text = coerceImageAssistantText({\n message,\n provider: providerId,\n model: modelId,\n });\n return { text, provider: providerId, model: modelId };\n },\n };\n}\n\nfor (const providerId of ['openai', 'anthropic', 'google']) {\n registerImageUnderstandingProvider(buildPiAiImageUnderstandingProvider(providerId));\n}\n"],"mappings":";;;;;gBACsE;AAKtE,SAAS,iBAAiB,gBAAoC,qBAAqB,MAAc;AAC/F,KACE,OAAO,mBAAmB,YAC1B,CAAC,OAAO,SAAS,eAAe,IAChC,kBAAkB,EAElB,QAAO;AAET,QAAO,KAAK,IAAI,oBAAoB,eAAe;;AAGrD,SAAgB,oCAAoC,YAAgD;AAClG,QAAO;EACL,IAAI;EACJ,OAAO,UAAU,WAAW;EAC5B,MAAM,eAAe;GACnB,MAAM,SAAS,MAAM,UAAU,WAAW;AAC1C,UAAO,QAAQ,OAAO;;EAExB,MAAM,eAAe,SAAS,SAAS;GACrC,MAAM,WAAW,GAAG,WAAW,GAAG;GAClC,MAAM,QAAQ,aAAa,SAAS;AACpC,OAAI,CAAC,MAAM,OAAO,SAAS,QAAQ,CACjC,OAAM,IAAI,MAAM,kCAAkC,WAAW;GAE/D,MAAM,SAAS,MAAM,UAAU,WAAW;AAC1C,OAAI,CAAC,OACH,OAAM,IAAI,MAAM,uCAAuC,aAAa;GAGtE,MAAM,UAAmB,EACvB,UAAU,CACR;IACE,MAAM;IACN,SAAS,CACP;KAAE,MAAM;KAAQ,MAAM,QAAQ;KAAQ,EACtC,GAAG,QAAQ,OAAO,KAAK,SAAS;KAC9B,MAAM;KACN,MAAM,IAAI,OAAO,SAAS,SAAS;KACnC,UAAU,IAAI,YAAY;KAC3B,EAAE,CACJ;IACD,WAAW,KAAK,KAAK;IACtB,CACF,EACF;GAED,MAAM,YAAY,iBAAiB,MAAM,WAAW,QAAQ,aAAa,IAAI;GAC7E,MAAM,YAAY,QAAQ,aAAa;GACvC,MAAM,gBACJ,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY,aACjE,YAAY,QAAQ,UAAU,GAC9B,KAAA;AA2BN,UAAO;IAAE,MALI,yBAAyB;KACpC,SAAA,MAPoB,SAAS,OAAO,SAAS;MAC7C;MACA;MACA,eAlBoB;AACpB,WAAI,iBAAiB,QAAQ,UAAU,OAAO,YAAY,QAAQ,WAChE,QAAO,YAAY,IAAI,CAAC,QAAQ,QAAQ,cAAc,CAAC;AAEzD,WAAI,QAAQ,OACV,QAAO,QAAQ;AAEjB,WAAI,cACF,QAAO;OAET,MAAM,aAAa,IAAI,iBAAiB;AACxC,wBAAiB,WAAW,OAAO,EAAE,UAAU;AAC/C,cAAO,WAAW;UAMZ;MACP,CAAC;KAIA,UAAU;KACV,OAAO;KACR,CACY;IAAE,UAAU;IAAY,OAAO;IAAS;;EAExD;;AAGH,KAAK,MAAM,cAAc;CAAC;CAAU;CAAa;CAAS,CACxD,oCAAmC,oCAAoC,WAAW,CAAC"}
1
+ {"version":3,"file":"pi-ai-provider.js","names":[],"sources":["../../../../../src/agent/image/understanding/pi-ai-provider.ts"],"sourcesContent":["import { complete, type Api, type Context, type Model } from '@earendil-works/pi-ai';\nimport { resolveModel, getApiKey, getModelsByProvider } from '../../../providers/index.js';\nimport { coerceImageAssistantText } from '../image-helpers.js';\nimport {\n registerImageUnderstandingProvider,\n registerImageUnderstandingProviderFactory,\n} from './provider-registry.js';\nimport type { ImageUnderstandingProvider } from './types.js';\n\nfunction resolveMaxTokens(modelMaxTokens: number | undefined, requestedMaxTokens = 4096): number {\n if (\n typeof modelMaxTokens !== 'number' ||\n !Number.isFinite(modelMaxTokens) ||\n modelMaxTokens <= 0\n ) {\n return requestedMaxTokens;\n }\n return Math.min(requestedMaxTokens, modelMaxTokens);\n}\n\nexport function buildPiAiImageUnderstandingProvider(providerId: string): ImageUnderstandingProvider {\n return {\n id: providerId,\n label: `pi-ai (${providerId})`,\n async isConfigured() {\n const apiKey = await getApiKey(providerId);\n return Boolean(apiKey);\n },\n async describeImages(modelId, request) {\n const modelRef = `${providerId}/${modelId}`;\n const model = resolveModel(modelRef) as Model<Api>;\n if (!model.input?.includes('image')) {\n throw new Error(`Model does not support images: ${modelRef}`);\n }\n const apiKey = await getApiKey(providerId);\n if (!apiKey) {\n throw new Error(`No API key configured for provider: ${providerId}`);\n }\n\n const context: Context = {\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: request.prompt },\n ...request.images.map((img) => ({\n type: 'image' as const,\n data: img.buffer.toString('base64'),\n mimeType: img.mimeType || 'image/jpeg',\n })),\n ],\n timestamp: Date.now(),\n },\n ],\n };\n\n const maxTokens = resolveMaxTokens(model.maxTokens, request.maxTokens ?? 512);\n const timeoutMs = request.timeoutMs ?? 60_000;\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(timeoutMs)\n : undefined;\n const signal = (() => {\n if (timeoutSignal && request.signal && typeof AbortSignal.any === 'function') {\n return AbortSignal.any([request.signal, timeoutSignal]);\n }\n if (request.signal) {\n return request.signal;\n }\n if (timeoutSignal) {\n return timeoutSignal;\n }\n const controller = new AbortController();\n setTimeout(() => controller.abort(), timeoutMs);\n return controller.signal;\n })();\n\n const message = await complete(model, context, {\n apiKey,\n maxTokens,\n signal,\n });\n\n const text = coerceImageAssistantText({\n message,\n provider: providerId,\n model: modelId,\n });\n return { text, provider: providerId, model: modelId };\n },\n };\n}\n\nfor (const providerId of ['openai', 'anthropic', 'google']) {\n registerImageUnderstandingProvider(buildPiAiImageUnderstandingProvider(providerId));\n}\n\nregisterImageUnderstandingProviderFactory((providerId) => {\n const hasVisionModel = getModelsByProvider(providerId).some((model) =>\n model.input?.includes('image'),\n );\n return hasVisionModel ? buildPiAiImageUnderstandingProvider(providerId) : undefined;\n});\n"],"mappings":";;;;;gBAC2F;AAQ3F,SAAS,iBAAiB,gBAAoC,qBAAqB,MAAc;AAC/F,KACE,OAAO,mBAAmB,YAC1B,CAAC,OAAO,SAAS,eAAe,IAChC,kBAAkB,EAElB,QAAO;AAET,QAAO,KAAK,IAAI,oBAAoB,eAAe;;AAGrD,SAAgB,oCAAoC,YAAgD;AAClG,QAAO;EACL,IAAI;EACJ,OAAO,UAAU,WAAW;EAC5B,MAAM,eAAe;GACnB,MAAM,SAAS,MAAM,UAAU,WAAW;AAC1C,UAAO,QAAQ,OAAO;;EAExB,MAAM,eAAe,SAAS,SAAS;GACrC,MAAM,WAAW,GAAG,WAAW,GAAG;GAClC,MAAM,QAAQ,aAAa,SAAS;AACpC,OAAI,CAAC,MAAM,OAAO,SAAS,QAAQ,CACjC,OAAM,IAAI,MAAM,kCAAkC,WAAW;GAE/D,MAAM,SAAS,MAAM,UAAU,WAAW;AAC1C,OAAI,CAAC,OACH,OAAM,IAAI,MAAM,uCAAuC,aAAa;GAGtE,MAAM,UAAmB,EACvB,UAAU,CACR;IACE,MAAM;IACN,SAAS,CACP;KAAE,MAAM;KAAQ,MAAM,QAAQ;KAAQ,EACtC,GAAG,QAAQ,OAAO,KAAK,SAAS;KAC9B,MAAM;KACN,MAAM,IAAI,OAAO,SAAS,SAAS;KACnC,UAAU,IAAI,YAAY;KAC3B,EAAE,CACJ;IACD,WAAW,KAAK,KAAK;IACtB,CACF,EACF;GAED,MAAM,YAAY,iBAAiB,MAAM,WAAW,QAAQ,aAAa,IAAI;GAC7E,MAAM,YAAY,QAAQ,aAAa;GACvC,MAAM,gBACJ,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY,aACjE,YAAY,QAAQ,UAAU,GAC9B,KAAA;AA2BN,UAAO;IAAE,MALI,yBAAyB;KACpC,SAAA,MAPoB,SAAS,OAAO,SAAS;MAC7C;MACA;MACA,eAlBoB;AACpB,WAAI,iBAAiB,QAAQ,UAAU,OAAO,YAAY,QAAQ,WAChE,QAAO,YAAY,IAAI,CAAC,QAAQ,QAAQ,cAAc,CAAC;AAEzD,WAAI,QAAQ,OACV,QAAO,QAAQ;AAEjB,WAAI,cACF,QAAO;OAET,MAAM,aAAa,IAAI,iBAAiB;AACxC,wBAAiB,WAAW,OAAO,EAAE,UAAU;AAC/C,cAAO,WAAW;UAMZ;MACP,CAAC;KAIA,UAAU;KACV,OAAO;KACR,CACY;IAAE,UAAU;IAAY,OAAO;IAAS;;EAExD;;AAGH,KAAK,MAAM,cAAc;CAAC;CAAU;CAAa;CAAS,CACxD,oCAAmC,oCAAoC,WAAW,CAAC;AAGrF,2CAA2C,eAAe;AAIxD,QAHuB,oBAAoB,WAAW,CAAC,MAAM,UAC3D,MAAM,OAAO,SAAS,QAAQ,CAEX,GAAG,oCAAoC,WAAW,GAAG,KAAA;EAC1E"}
@@ -1,5 +1,6 @@
1
1
  import type { ImageUnderstandingProvider } from './types.js';
2
2
  export declare function registerImageUnderstandingProvider(provider: ImageUnderstandingProvider): void;
3
+ export declare function registerImageUnderstandingProviderFactory(factory: (providerId: string) => ImageUnderstandingProvider | undefined): void;
3
4
  export declare function getImageUnderstandingProvider(providerId: string): ImageUnderstandingProvider | undefined;
4
5
  export declare function listImageUnderstandingProviders(): ImageUnderstandingProvider[];
5
6
  export declare function clearImageUnderstandingRegistryForTests(): void;
@@ -1,19 +1,33 @@
1
1
  //#region src/agent/image/understanding/provider-registry.ts
2
2
  const registry = /* @__PURE__ */ new Map();
3
+ const providerFactories = /* @__PURE__ */ new Set();
3
4
  function registerImageUnderstandingProvider(provider) {
4
5
  if (!provider.id?.trim()) throw new Error("Image understanding provider id is required");
5
6
  registry.set(provider.id.toLowerCase(), provider);
6
7
  }
8
+ function registerImageUnderstandingProviderFactory(factory) {
9
+ providerFactories.add(factory);
10
+ }
7
11
  function getImageUnderstandingProvider(providerId) {
8
- return registry.get(providerId.toLowerCase());
12
+ const normalized = providerId.trim().toLowerCase();
13
+ if (!normalized) return void 0;
14
+ const registered = registry.get(normalized);
15
+ if (registered) return registered;
16
+ for (const factory of providerFactories) {
17
+ const provider = factory(normalized);
18
+ if (!provider) continue;
19
+ registerImageUnderstandingProvider(provider);
20
+ return registry.get(normalized);
21
+ }
9
22
  }
10
23
  function listImageUnderstandingProviders() {
11
24
  return [...registry.values()];
12
25
  }
13
26
  function clearImageUnderstandingRegistryForTests() {
14
27
  registry.clear();
28
+ providerFactories.clear();
15
29
  }
16
30
  //#endregion
17
- export { clearImageUnderstandingRegistryForTests, getImageUnderstandingProvider, listImageUnderstandingProviders, registerImageUnderstandingProvider };
31
+ export { clearImageUnderstandingRegistryForTests, getImageUnderstandingProvider, listImageUnderstandingProviders, registerImageUnderstandingProvider, registerImageUnderstandingProviderFactory };
18
32
 
19
33
  //# sourceMappingURL=provider-registry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-registry.js","names":[],"sources":["../../../../../src/agent/image/understanding/provider-registry.ts"],"sourcesContent":["import type { ImageUnderstandingProvider } from './types.js';\n\nconst registry = new Map<string, ImageUnderstandingProvider>();\n\nexport function registerImageUnderstandingProvider(provider: ImageUnderstandingProvider): void {\n if (!provider.id?.trim()) {\n throw new Error('Image understanding provider id is required');\n }\n registry.set(provider.id.toLowerCase(), provider);\n}\n\nexport function getImageUnderstandingProvider(\n providerId: string,\n): ImageUnderstandingProvider | undefined {\n return registry.get(providerId.toLowerCase());\n}\n\nexport function listImageUnderstandingProviders(): ImageUnderstandingProvider[] {\n return [...registry.values()];\n}\n\nexport function clearImageUnderstandingRegistryForTests(): void {\n registry.clear();\n}\n"],"mappings":";AAEA,MAAM,2BAAW,IAAI,KAAyC;AAE9D,SAAgB,mCAAmC,UAA4C;AAC7F,KAAI,CAAC,SAAS,IAAI,MAAM,CACtB,OAAM,IAAI,MAAM,8CAA8C;AAEhE,UAAS,IAAI,SAAS,GAAG,aAAa,EAAE,SAAS;;AAGnD,SAAgB,8BACd,YACwC;AACxC,QAAO,SAAS,IAAI,WAAW,aAAa,CAAC;;AAG/C,SAAgB,kCAAgE;AAC9E,QAAO,CAAC,GAAG,SAAS,QAAQ,CAAC;;AAG/B,SAAgB,0CAAgD;AAC9D,UAAS,OAAO"}
1
+ {"version":3,"file":"provider-registry.js","names":[],"sources":["../../../../../src/agent/image/understanding/provider-registry.ts"],"sourcesContent":["import type { ImageUnderstandingProvider } from './types.js';\n\nconst registry = new Map<string, ImageUnderstandingProvider>();\nconst providerFactories = new Set<\n (providerId: string) => ImageUnderstandingProvider | undefined\n>();\n\nexport function registerImageUnderstandingProvider(provider: ImageUnderstandingProvider): void {\n if (!provider.id?.trim()) {\n throw new Error('Image understanding provider id is required');\n }\n registry.set(provider.id.toLowerCase(), provider);\n}\n\nexport function registerImageUnderstandingProviderFactory(\n factory: (providerId: string) => ImageUnderstandingProvider | undefined,\n): void {\n providerFactories.add(factory);\n}\n\nexport function getImageUnderstandingProvider(\n providerId: string,\n): ImageUnderstandingProvider | undefined {\n const normalized = providerId.trim().toLowerCase();\n if (!normalized) return undefined;\n\n const registered = registry.get(normalized);\n if (registered) return registered;\n\n for (const factory of providerFactories) {\n const provider = factory(normalized);\n if (!provider) continue;\n registerImageUnderstandingProvider(provider);\n return registry.get(normalized);\n }\n\n return undefined;\n}\n\nexport function listImageUnderstandingProviders(): ImageUnderstandingProvider[] {\n return [...registry.values()];\n}\n\nexport function clearImageUnderstandingRegistryForTests(): void {\n registry.clear();\n providerFactories.clear();\n}\n"],"mappings":";AAEA,MAAM,2BAAW,IAAI,KAAyC;AAC9D,MAAM,oCAAoB,IAAI,KAE3B;AAEH,SAAgB,mCAAmC,UAA4C;AAC7F,KAAI,CAAC,SAAS,IAAI,MAAM,CACtB,OAAM,IAAI,MAAM,8CAA8C;AAEhE,UAAS,IAAI,SAAS,GAAG,aAAa,EAAE,SAAS;;AAGnD,SAAgB,0CACd,SACM;AACN,mBAAkB,IAAI,QAAQ;;AAGhC,SAAgB,8BACd,YACwC;CACxC,MAAM,aAAa,WAAW,MAAM,CAAC,aAAa;AAClD,KAAI,CAAC,WAAY,QAAO,KAAA;CAExB,MAAM,aAAa,SAAS,IAAI,WAAW;AAC3C,KAAI,WAAY,QAAO;AAEvB,MAAK,MAAM,WAAW,mBAAmB;EACvC,MAAM,WAAW,QAAQ,WAAW;AACpC,MAAI,CAAC,SAAU;AACf,qCAAmC,SAAS;AAC5C,SAAO,SAAS,IAAI,WAAW;;;AAMnC,SAAgB,kCAAgE;AAC9E,QAAO,CAAC,GAAG,SAAS,QAAQ,CAAC;;AAG/B,SAAgB,0CAAgD;AAC9D,UAAS,OAAO;AAChB,mBAAkB,OAAO"}
@@ -5,7 +5,7 @@ import { materializeBundleMcpToolsForRun } from "./bundle-mcp-materialize.js";
5
5
  import "./bundle-mcp-tools.js";
6
6
  //#region src/agent/mcp/resolve-embedded-mcp-tools.ts
7
7
  async function resolveEmbeddedMcpToolsForTurn(params) {
8
- const disabledTools = (params.cfg ? resolveEffectiveAgentProfileForSession(params.cfg, params.sessionKey) : void 0)?.tools.disable;
8
+ const disabledTools = (params.cfg ? resolveEffectiveAgentProfileForSession(params.cfg, params.sessionKey) : void 0)?.tools.denied;
9
9
  if (!shouldCreateBundleMcpRuntimeForAttempt({
10
10
  cfg: params.cfg,
11
11
  disabledTools
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-embedded-mcp-tools.js","names":[],"sources":["../../../../src/agent/mcp/resolve-embedded-mcp-tools.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Config } from '../../config/schema.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport {\n getOrCreateSessionMcpRuntime,\n materializeBundleMcpToolsForRun,\n} from './bundle-mcp-tools.js';\nimport { shouldCreateBundleMcpRuntimeForAttempt } from './bundle-mcp-policy.js';\nimport type { BundleMcpToolRuntime } from './bundle-mcp-types.js';\n\nexport type ResolvedEmbeddedMcpTools = {\n tools: AgentTool[];\n dispose: () => Promise<void>;\n};\n\nexport async function resolveEmbeddedMcpToolsForTurn(params: {\n sessionKey: string;\n workspaceDir: string;\n cfg?: Config;\n baseTools: AgentTool[];\n cleanupOnTurnEnd?: boolean;\n}): Promise<ResolvedEmbeddedMcpTools> {\n const profile = params.cfg\n ? resolveEffectiveAgentProfileForSession(params.cfg, params.sessionKey)\n : undefined;\n const disabledTools = profile?.tools.disable;\n\n if (\n !shouldCreateBundleMcpRuntimeForAttempt({\n cfg: params.cfg,\n disabledTools,\n })\n ) {\n return { tools: [], dispose: async () => {} };\n }\n\n const reserved = new Set(params.baseTools.map((t) => t.name));\n const runtime = await getOrCreateSessionMcpRuntime({\n sessionId: params.sessionKey,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n\n let materialized: BundleMcpToolRuntime;\n try {\n materialized = await materializeBundleMcpToolsForRun({\n runtime,\n reservedToolNames: reserved,\n disposeRuntime: params.cleanupOnTurnEnd\n ? async () => {\n await runtime.dispose();\n }\n : undefined,\n });\n } catch (error) {\n await runtime.dispose().catch(() => {});\n throw error;\n }\n\n const filtered = materialized.tools.filter((tool) => {\n if (disabledTools?.has(tool.name)) {\n return false;\n }\n return true;\n });\n\n return {\n tools: filtered,\n dispose: materialized.dispose,\n };\n}\n\nexport function mergeTurnTools(baseTools: AgentTool[], mcpTools: AgentTool[]): AgentTool[] {\n if (mcpTools.length === 0) {\n return baseTools;\n }\n return [...baseTools, ...mcpTools];\n}\n"],"mappings":";;;;;;AAeA,eAAsB,+BAA+B,QAMf;CAIpC,MAAM,iBAHU,OAAO,MACnB,uCAAuC,OAAO,KAAK,OAAO,WAAW,GACrE,KAAA,IAC2B,MAAM;AAErC,KACE,CAAC,uCAAuC;EACtC,KAAK,OAAO;EACZ;EACD,CAAC,CAEF,QAAO;EAAE,OAAO,EAAE;EAAE,SAAS,YAAY;EAAI;CAG/C,MAAM,WAAW,IAAI,IAAI,OAAO,UAAU,KAAK,MAAM,EAAE,KAAK,CAAC;CAC7D,MAAM,UAAU,MAAM,6BAA6B;EACjD,WAAW,OAAO;EAClB,YAAY,OAAO;EACnB,cAAc,OAAO;EACrB,KAAK,OAAO;EACb,CAAC;CAEF,IAAI;AACJ,KAAI;AACF,iBAAe,MAAM,gCAAgC;GACnD;GACA,mBAAmB;GACnB,gBAAgB,OAAO,mBACnB,YAAY;AACV,UAAM,QAAQ,SAAS;OAEzB,KAAA;GACL,CAAC;UACK,OAAO;AACd,QAAM,QAAQ,SAAS,CAAC,YAAY,GAAG;AACvC,QAAM;;AAUR,QAAO;EACL,OARe,aAAa,MAAM,QAAQ,SAAS;AACnD,OAAI,eAAe,IAAI,KAAK,KAAK,CAC/B,QAAO;AAET,UAAO;IAIQ;EACf,SAAS,aAAa;EACvB;;AAGH,SAAgB,eAAe,WAAwB,UAAoC;AACzF,KAAI,SAAS,WAAW,EACtB,QAAO;AAET,QAAO,CAAC,GAAG,WAAW,GAAG,SAAS"}
1
+ {"version":3,"file":"resolve-embedded-mcp-tools.js","names":[],"sources":["../../../../src/agent/mcp/resolve-embedded-mcp-tools.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { Config } from '../../config/schema.js';\nimport { resolveEffectiveAgentProfileForSession } from '../../config/agent-profile.js';\nimport {\n getOrCreateSessionMcpRuntime,\n materializeBundleMcpToolsForRun,\n} from './bundle-mcp-tools.js';\nimport { shouldCreateBundleMcpRuntimeForAttempt } from './bundle-mcp-policy.js';\nimport type { BundleMcpToolRuntime } from './bundle-mcp-types.js';\n\nexport type ResolvedEmbeddedMcpTools = {\n tools: AgentTool[];\n dispose: () => Promise<void>;\n};\n\nexport async function resolveEmbeddedMcpToolsForTurn(params: {\n sessionKey: string;\n workspaceDir: string;\n cfg?: Config;\n baseTools: AgentTool[];\n cleanupOnTurnEnd?: boolean;\n}): Promise<ResolvedEmbeddedMcpTools> {\n const profile = params.cfg\n ? resolveEffectiveAgentProfileForSession(params.cfg, params.sessionKey)\n : undefined;\n const disabledTools = profile?.tools.denied;\n\n if (\n !shouldCreateBundleMcpRuntimeForAttempt({\n cfg: params.cfg,\n disabledTools,\n })\n ) {\n return { tools: [], dispose: async () => {} };\n }\n\n const reserved = new Set(params.baseTools.map((t) => t.name));\n const runtime = await getOrCreateSessionMcpRuntime({\n sessionId: params.sessionKey,\n sessionKey: params.sessionKey,\n workspaceDir: params.workspaceDir,\n cfg: params.cfg,\n });\n\n let materialized: BundleMcpToolRuntime;\n try {\n materialized = await materializeBundleMcpToolsForRun({\n runtime,\n reservedToolNames: reserved,\n disposeRuntime: params.cleanupOnTurnEnd\n ? async () => {\n await runtime.dispose();\n }\n : undefined,\n });\n } catch (error) {\n await runtime.dispose().catch(() => {});\n throw error;\n }\n\n const filtered = materialized.tools.filter((tool) => {\n if (disabledTools?.has(tool.name)) {\n return false;\n }\n return true;\n });\n\n return {\n tools: filtered,\n dispose: materialized.dispose,\n };\n}\n\nexport function mergeTurnTools(baseTools: AgentTool[], mcpTools: AgentTool[]): AgentTool[] {\n if (mcpTools.length === 0) {\n return baseTools;\n }\n return [...baseTools, ...mcpTools];\n}\n"],"mappings":";;;;;;AAeA,eAAsB,+BAA+B,QAMf;CAIpC,MAAM,iBAHU,OAAO,MACnB,uCAAuC,OAAO,KAAK,OAAO,WAAW,GACrE,KAAA,IAC2B,MAAM;AAErC,KACE,CAAC,uCAAuC;EACtC,KAAK,OAAO;EACZ;EACD,CAAC,CAEF,QAAO;EAAE,OAAO,EAAE;EAAE,SAAS,YAAY;EAAI;CAG/C,MAAM,WAAW,IAAI,IAAI,OAAO,UAAU,KAAK,MAAM,EAAE,KAAK,CAAC;CAC7D,MAAM,UAAU,MAAM,6BAA6B;EACjD,WAAW,OAAO;EAClB,YAAY,OAAO;EACnB,cAAc,OAAO;EACrB,KAAK,OAAO;EACb,CAAC;CAEF,IAAI;AACJ,KAAI;AACF,iBAAe,MAAM,gCAAgC;GACnD;GACA,mBAAmB;GACnB,gBAAgB,OAAO,mBACnB,YAAY;AACV,UAAM,QAAQ,SAAS;OAEzB,KAAA;GACL,CAAC;UACK,OAAO;AACd,QAAM,QAAQ,SAAS,CAAC,YAAY,GAAG;AACvC,QAAM;;AAUR,QAAO;EACL,OARe,aAAa,MAAM,QAAQ,SAAS;AACnD,OAAI,eAAe,IAAI,KAAK,KAAK,CAC/B,QAAO;AAET,UAAO;IAIQ;EACf,SAAS,aAAa;EACvB;;AAGH,SAAgB,eAAe,WAAwB,UAAoC;AACzF,KAAI,SAAS,WAAW,EACtB,QAAO;AAET,QAAO,CAAC,GAAG,WAAW,GAAG,SAAS"}
@@ -23,8 +23,11 @@ export interface CapabilityProviderCandidate {
23
23
  }
24
24
  export interface ResolveCapabilityModelCandidatesParams {
25
25
  cfg?: Config;
26
- /** Active capability model config, e.g. cfg.agents.defaults.imageGenerationModel. */
27
- modelConfig: AgentModelConfig | undefined;
26
+ /** Active capability model config from a manifest/runtime policy. */
27
+ modelConfig: {
28
+ primary?: string;
29
+ fallbacks?: string[];
30
+ } | AgentModelConfig | undefined;
28
31
  /** Caller-supplied per-call override (highest priority). */
29
32
  modelOverride?: string;
30
33
  /** Optional ref parser; defaults to {@link parseCapabilityModelRef}. */
@@ -189,7 +189,7 @@ function throwCapabilityGenerationFailure(params) {
189
189
  });
190
190
  }
191
191
  function buildNoCapabilityModelConfiguredMessage(params) {
192
- const lines = [`No ${params.capabilityLabel} model configured. Set agents.defaults.${params.modelConfigKey} to a "<provider>/<model>" value (or pass modelOverride at call site).`];
192
+ const lines = [`No ${params.capabilityLabel} model configured. Add a manifest/runtime model policy for ${params.modelConfigKey} or pass modelOverride at call site.`];
193
193
  if (params.providers.length > 0) {
194
194
  lines.push("Registered providers:");
195
195
  for (const p of params.providers) {
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-shared.js","names":[],"sources":["../../../../src/agent/media-generation/runtime-shared.ts"],"sourcesContent":["/**\n * Cross-capability runtime helpers shared by image / audio / video\n * generation. Pure functions (no IO) so they can be unit-tested without\n * touching providers.\n *\n * - candidate model resolution\n * - geometry/value nearest-neighbour matching\n * - terminal failure aggregation (FailoverError)\n * - \"no model configured\" message builder\n */\n\nimport type { Config, AgentModelConfig } from '../../config/schema.js';\nimport {\n classifyAttemptError,\n FailoverError,\n type FallbackAttempt,\n type FailoverReason,\n} from '../failover-error.js';\nimport { parseCapabilityModelRef, type ParsedCapabilityModelRef } from './model-ref.js';\n\n// ============================================\n// Candidate resolution\n// ============================================\n\nexport interface CapabilityProviderCandidate {\n id: string;\n aliases?: readonly string[];\n defaultModel?: string | null;\n models?: readonly string[];\n isConfigured?: (ctx: { cfg?: Config; agentDir?: string }) => boolean;\n}\n\nexport interface ResolveCapabilityModelCandidatesParams {\n cfg?: Config;\n /** Active capability model config, e.g. cfg.agents.defaults.imageGenerationModel. */\n modelConfig: AgentModelConfig | undefined;\n /** Caller-supplied per-call override (highest priority). */\n modelOverride?: string;\n /** Optional ref parser; defaults to {@link parseCapabilityModelRef}. */\n parseModelRef?: (raw: string | undefined) => ParsedCapabilityModelRef | null;\n agentDir?: string;\n /** Snapshot of registered providers used to enumerate fallbacks. */\n listProviders: (cfg?: Config) => CapabilityProviderCandidate[];\n /**\n * When true and the explicit candidates fail, append every configured\n * provider's default model.\n */\n autoProviderFallback?: boolean;\n}\n\nexport interface ResolvedCapabilityModelCandidate {\n provider: string;\n model: string;\n}\n\n/**\n * Build the ordered candidate list from:\n * 1. modelOverride\n * 2. modelConfig.primary\n * 3. modelConfig.fallbacks[]\n * 4. (optional) every isConfigured() provider's defaultModel\n *\n * Duplicates are dropped (case-insensitive on provider, exact on model).\n */\nexport function resolveCapabilityModelCandidates(\n params: ResolveCapabilityModelCandidatesParams,\n): ResolvedCapabilityModelCandidate[] {\n const parse = params.parseModelRef ?? parseCapabilityModelRef;\n const out: ResolvedCapabilityModelCandidate[] = [];\n const seen = new Set<string>();\n\n const push = (raw: string | undefined) => {\n const parsed = parse(raw);\n if (!parsed) return;\n const key = `${parsed.provider}::${parsed.model}`;\n if (seen.has(key)) return;\n seen.add(key);\n out.push({ provider: parsed.provider, model: parsed.model });\n };\n\n const normalizedModelConfig = normalizeModelConfig(params.modelConfig);\n push(params.modelOverride);\n push(normalizedModelConfig.primary);\n for (const fb of normalizedModelConfig.fallbacks) push(fb);\n\n if (params.autoProviderFallback) {\n const providers = safeListProviders(params.listProviders, params.cfg);\n for (const provider of providers) {\n if (!provider.defaultModel) continue;\n let configured = true;\n try {\n configured = provider.isConfigured?.({ cfg: params.cfg, agentDir: params.agentDir }) ?? true;\n } catch {\n configured = false;\n }\n if (!configured) continue;\n push(`${provider.id}/${provider.defaultModel}`);\n }\n }\n\n return out;\n}\n\nfunction safeListProviders(\n fn: (cfg?: Config) => CapabilityProviderCandidate[],\n cfg?: Config,\n): CapabilityProviderCandidate[] {\n try {\n return fn(cfg) ?? [];\n } catch {\n return [];\n }\n}\n\n/** Normalize an {@link AgentModelConfig} to `{ primary?, fallbacks }`. */\nfunction normalizeModelConfig(\n cfg: AgentModelConfig | undefined,\n): { primary?: string; fallbacks: string[] } {\n if (!cfg) return { fallbacks: [] };\n return {\n primary: typeof cfg.primary === 'string' ? cfg.primary : undefined,\n fallbacks: Array.isArray(cfg.fallbacks)\n ? cfg.fallbacks.filter((s): s is string => typeof s === 'string')\n : [],\n };\n}\n\n// ============================================\n// Geometry helpers (nearest-neighbour)\n// ============================================\n\nexport function resolveClosestSize(params: {\n requestedSize?: string;\n requestedAspectRatio?: string;\n supportedSizes?: ReadonlyArray<string>;\n}): string | undefined {\n const supported = (params.supportedSizes ?? []).filter((s) => parseSize(s) !== null);\n if (supported.length === 0) return undefined;\n\n const target =\n parseSize(params.requestedSize) ??\n sizeFromAspectRatio(params.requestedAspectRatio, supported.map((s) => parseSize(s)!.totalPixels));\n\n if (!target) return supported[0];\n return supported\n .map((s) => ({ s, parsed: parseSize(s)! }))\n .reduce((best, cur) => {\n const score = sizeDistance(target, cur.parsed);\n return score < best.score ? { s: cur.s, score } : best;\n }, { s: supported[0], score: Number.POSITIVE_INFINITY })\n .s;\n}\n\nexport function resolveClosestAspectRatio(params: {\n requestedAspectRatio?: string;\n requestedSize?: string;\n supportedAspectRatios?: ReadonlyArray<string>;\n}): string | undefined {\n const supported = (params.supportedAspectRatios ?? []).filter((r) => parseAspectRatio(r) !== null);\n if (supported.length === 0) return undefined;\n\n const targetRatio =\n parseAspectRatio(params.requestedAspectRatio)?.value ??\n (() => {\n const sz = parseSize(params.requestedSize);\n return sz ? sz.width / sz.height : undefined;\n })();\n\n if (typeof targetRatio !== 'number' || !Number.isFinite(targetRatio)) {\n return supported[0];\n }\n\n return supported.reduce((best, cur) => {\n const v = parseAspectRatio(cur)!.value;\n const d = Math.abs(Math.log(v) - Math.log(targetRatio));\n return d < best.score ? { s: cur, score: d } : best;\n }, { s: supported[0], score: Number.POSITIVE_INFINITY }).s;\n}\n\nexport function resolveClosestResolution<T extends string>(params: {\n requestedResolution?: T;\n supportedResolutions?: ReadonlyArray<T>;\n}): T | undefined {\n const supported = params.supportedResolutions ?? [];\n if (supported.length === 0) return undefined;\n const requested = params.requestedResolution;\n if (!requested) return undefined;\n if (supported.includes(requested)) return requested;\n\n const order = ['1K', '2K', '4K', '8K'];\n const want = order.indexOf(String(requested));\n if (want < 0) return supported[0];\n\n // Prefer the largest supported value <= requested; otherwise pick the smallest available.\n const ranked = supported\n .map((r) => ({ r, idx: order.indexOf(String(r)) }))\n .filter((x) => x.idx >= 0)\n .sort((a, b) => a.idx - b.idx);\n if (ranked.length === 0) return supported[0];\n\n let chosen = ranked[0].r;\n for (const x of ranked) {\n if (x.idx <= want) chosen = x.r;\n }\n return chosen;\n}\n\nfunction parseSize(raw: string | undefined): { width: number; height: number; totalPixels: number } | null {\n if (typeof raw !== 'string') return null;\n const m = raw.trim().toLowerCase().match(/^(\\d{2,5})\\s*[x×*]\\s*(\\d{2,5})$/);\n if (!m) return null;\n const width = Number(m[1]);\n const height = Number(m[2]);\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;\n return { width, height, totalPixels: width * height };\n}\n\nfunction parseAspectRatio(raw: string | undefined): { value: number } | null {\n if (typeof raw !== 'string') return null;\n const m = raw.trim().match(/^(\\d{1,3})\\s*[:x×/]\\s*(\\d{1,3})$/);\n if (!m) return null;\n const w = Number(m[1]);\n const h = Number(m[2]);\n if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) return null;\n return { value: w / h };\n}\n\nfunction sizeFromAspectRatio(\n ratioStr: string | undefined,\n pixelHints: number[],\n): { width: number; height: number; totalPixels: number } | null {\n const r = parseAspectRatio(ratioStr);\n if (!r) return null;\n const pixels = pixelHints.length > 0 ? Math.round(pixelHints.reduce((a, b) => a + b, 0) / pixelHints.length) : 1024 * 1024;\n const height = Math.round(Math.sqrt(pixels / r.value));\n const width = Math.round(height * r.value);\n return { width, height, totalPixels: width * height };\n}\n\nfunction sizeDistance(\n a: { width: number; height: number; totalPixels: number },\n b: { width: number; height: number; totalPixels: number },\n): number {\n // Combined area + aspect-ratio difference (log-scale on both for stability).\n const areaDelta = Math.abs(Math.log(a.totalPixels) - Math.log(b.totalPixels));\n const ratioA = a.width / a.height;\n const ratioB = b.width / b.height;\n const ratioDelta = Math.abs(Math.log(ratioA) - Math.log(ratioB));\n return areaDelta + ratioDelta * 1.5;\n}\n\n// ============================================\n// Failure aggregation\n// ============================================\n\nexport interface RecordCapabilityCandidateFailureParams {\n attempts: FallbackAttempt[];\n provider: string;\n model: string;\n error: unknown;\n durationMs?: number;\n}\n\n/** Push a structured {@link FallbackAttempt} entry derived from `error`. */\nexport function recordCapabilityCandidateFailure(\n params: RecordCapabilityCandidateFailureParams,\n): FallbackAttempt {\n const cls = classifyAttemptError(params.error);\n const attempt: FallbackAttempt = {\n provider: params.provider,\n model: params.model,\n error: cls.message,\n reason: cls.reason,\n ...(cls.status !== undefined ? { status: cls.status } : {}),\n ...(cls.code !== undefined ? { code: cls.code } : {}),\n ...(params.durationMs !== undefined ? { durationMs: params.durationMs } : {}),\n };\n params.attempts.push(attempt);\n return attempt;\n}\n\nexport interface ThrowCapabilityGenerationFailureParams {\n capabilityLabel: string;\n attempts: FallbackAttempt[];\n lastError: unknown;\n}\n\n/** Throw a unified {@link FailoverError} after all candidates have been exhausted. */\nexport function throwCapabilityGenerationFailure(params: ThrowCapabilityGenerationFailureParams): never {\n // capabilityLabel like \"image generation\" → identifier \"image-generation\"\n const capability = params.capabilityLabel.trim().toLowerCase().replace(/\\s+/g, '-') || 'capability';\n throw new FailoverError({\n capability,\n attempts: params.attempts,\n cause: params.lastError,\n });\n}\n\n// ============================================\n// \"No model configured\" message\n// ============================================\n\nexport interface BuildNoCapabilityModelConfiguredMessageParams {\n /** Display label, e.g. \"image-generation\". */\n capabilityLabel: string;\n /** Config key path, e.g. \"imageGenerationModel\". */\n modelConfigKey: string;\n providers: ReadonlyArray<CapabilityProviderCandidate>;\n /** Optional env-var lookup, e.g. (id) => PROVIDER_ENV_MAP[id]. */\n getProviderEnvVars?: (id: string) => readonly string[] | undefined;\n}\n\nexport function buildNoCapabilityModelConfiguredMessage(\n params: BuildNoCapabilityModelConfiguredMessageParams,\n): string {\n const lines: string[] = [\n `No ${params.capabilityLabel} model configured. Set agents.defaults.${params.modelConfigKey} ` +\n `to a \"<provider>/<model>\" value (or pass modelOverride at call site).`,\n ];\n if (params.providers.length > 0) {\n lines.push('Registered providers:');\n for (const p of params.providers) {\n const envs = params.getProviderEnvVars?.(p.id) ?? [];\n const env = envs.length > 0 ? ` (env: ${envs.join(' | ')})` : '';\n const def = p.defaultModel ? ` default=${p.defaultModel}` : '';\n lines.push(` - ${p.id}${def}${env}`);\n }\n }\n return lines.join('\\n');\n}\n\n/**\n * Build a `metadata.normalization` snapshot from a completed normalization\n * pass. Providers / runtime can spread it into their result metadata.\n */\nexport function buildMediaGenerationNormalizationMetadata(params: {\n normalization?: Record<string, unknown>;\n}): Record<string, unknown> {\n if (!params.normalization || Object.keys(params.normalization).length === 0) return {};\n return { normalization: params.normalization };\n}\n\n// Re-export the union for downstream type narrowing.\nexport type { FailoverReason };\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime-shared.js","names":[],"sources":["../../../../src/agent/media-generation/runtime-shared.ts"],"sourcesContent":["/**\n * Cross-capability runtime helpers shared by image / audio / video\n * generation. Pure functions (no IO) so they can be unit-tested without\n * touching providers.\n *\n * - candidate model resolution\n * - geometry/value nearest-neighbour matching\n * - terminal failure aggregation (FailoverError)\n * - \"no model configured\" message builder\n */\n\nimport type { Config, AgentModelConfig } from '../../config/schema.js';\nimport {\n classifyAttemptError,\n FailoverError,\n type FallbackAttempt,\n type FailoverReason,\n} from '../failover-error.js';\nimport { parseCapabilityModelRef, type ParsedCapabilityModelRef } from './model-ref.js';\n\n// ============================================\n// Candidate resolution\n// ============================================\n\nexport interface CapabilityProviderCandidate {\n id: string;\n aliases?: readonly string[];\n defaultModel?: string | null;\n models?: readonly string[];\n isConfigured?: (ctx: { cfg?: Config; agentDir?: string }) => boolean;\n}\n\nexport interface ResolveCapabilityModelCandidatesParams {\n cfg?: Config;\n /** Active capability model config from a manifest/runtime policy. */\n modelConfig: { primary?: string; fallbacks?: string[] } | AgentModelConfig | undefined;\n /** Caller-supplied per-call override (highest priority). */\n modelOverride?: string;\n /** Optional ref parser; defaults to {@link parseCapabilityModelRef}. */\n parseModelRef?: (raw: string | undefined) => ParsedCapabilityModelRef | null;\n agentDir?: string;\n /** Snapshot of registered providers used to enumerate fallbacks. */\n listProviders: (cfg?: Config) => CapabilityProviderCandidate[];\n /**\n * When true and the explicit candidates fail, append every configured\n * provider's default model.\n */\n autoProviderFallback?: boolean;\n}\n\nexport interface ResolvedCapabilityModelCandidate {\n provider: string;\n model: string;\n}\n\n/**\n * Build the ordered candidate list from:\n * 1. modelOverride\n * 2. modelConfig.primary\n * 3. modelConfig.fallbacks[]\n * 4. (optional) every isConfigured() provider's defaultModel\n *\n * Duplicates are dropped (case-insensitive on provider, exact on model).\n */\nexport function resolveCapabilityModelCandidates(\n params: ResolveCapabilityModelCandidatesParams,\n): ResolvedCapabilityModelCandidate[] {\n const parse = params.parseModelRef ?? parseCapabilityModelRef;\n const out: ResolvedCapabilityModelCandidate[] = [];\n const seen = new Set<string>();\n\n const push = (raw: string | undefined) => {\n const parsed = parse(raw);\n if (!parsed) return;\n const key = `${parsed.provider}::${parsed.model}`;\n if (seen.has(key)) return;\n seen.add(key);\n out.push({ provider: parsed.provider, model: parsed.model });\n };\n\n const normalizedModelConfig = normalizeModelConfig(params.modelConfig);\n push(params.modelOverride);\n push(normalizedModelConfig.primary);\n for (const fb of normalizedModelConfig.fallbacks) push(fb);\n\n if (params.autoProviderFallback) {\n const providers = safeListProviders(params.listProviders, params.cfg);\n for (const provider of providers) {\n if (!provider.defaultModel) continue;\n let configured = true;\n try {\n configured = provider.isConfigured?.({ cfg: params.cfg, agentDir: params.agentDir }) ?? true;\n } catch {\n configured = false;\n }\n if (!configured) continue;\n push(`${provider.id}/${provider.defaultModel}`);\n }\n }\n\n return out;\n}\n\nfunction safeListProviders(\n fn: (cfg?: Config) => CapabilityProviderCandidate[],\n cfg?: Config,\n): CapabilityProviderCandidate[] {\n try {\n return fn(cfg) ?? [];\n } catch {\n return [];\n }\n}\n\n/** Normalize an {@link AgentModelConfig} to `{ primary?, fallbacks }`. */\nfunction normalizeModelConfig(\n cfg: ResolveCapabilityModelCandidatesParams['modelConfig'],\n): { primary?: string; fallbacks: string[] } {\n if (!cfg) return { fallbacks: [] };\n return {\n primary: typeof cfg.primary === 'string' ? cfg.primary : undefined,\n fallbacks: Array.isArray(cfg.fallbacks)\n ? cfg.fallbacks.filter((s): s is string => typeof s === 'string')\n : [],\n };\n}\n\n// ============================================\n// Geometry helpers (nearest-neighbour)\n// ============================================\n\nexport function resolveClosestSize(params: {\n requestedSize?: string;\n requestedAspectRatio?: string;\n supportedSizes?: ReadonlyArray<string>;\n}): string | undefined {\n const supported = (params.supportedSizes ?? []).filter((s) => parseSize(s) !== null);\n if (supported.length === 0) return undefined;\n\n const target =\n parseSize(params.requestedSize) ??\n sizeFromAspectRatio(params.requestedAspectRatio, supported.map((s) => parseSize(s)!.totalPixels));\n\n if (!target) return supported[0];\n return supported\n .map((s) => ({ s, parsed: parseSize(s)! }))\n .reduce((best, cur) => {\n const score = sizeDistance(target, cur.parsed);\n return score < best.score ? { s: cur.s, score } : best;\n }, { s: supported[0], score: Number.POSITIVE_INFINITY })\n .s;\n}\n\nexport function resolveClosestAspectRatio(params: {\n requestedAspectRatio?: string;\n requestedSize?: string;\n supportedAspectRatios?: ReadonlyArray<string>;\n}): string | undefined {\n const supported = (params.supportedAspectRatios ?? []).filter((r) => parseAspectRatio(r) !== null);\n if (supported.length === 0) return undefined;\n\n const targetRatio =\n parseAspectRatio(params.requestedAspectRatio)?.value ??\n (() => {\n const sz = parseSize(params.requestedSize);\n return sz ? sz.width / sz.height : undefined;\n })();\n\n if (typeof targetRatio !== 'number' || !Number.isFinite(targetRatio)) {\n return supported[0];\n }\n\n return supported.reduce((best, cur) => {\n const v = parseAspectRatio(cur)!.value;\n const d = Math.abs(Math.log(v) - Math.log(targetRatio));\n return d < best.score ? { s: cur, score: d } : best;\n }, { s: supported[0], score: Number.POSITIVE_INFINITY }).s;\n}\n\nexport function resolveClosestResolution<T extends string>(params: {\n requestedResolution?: T;\n supportedResolutions?: ReadonlyArray<T>;\n}): T | undefined {\n const supported = params.supportedResolutions ?? [];\n if (supported.length === 0) return undefined;\n const requested = params.requestedResolution;\n if (!requested) return undefined;\n if (supported.includes(requested)) return requested;\n\n const order = ['1K', '2K', '4K', '8K'];\n const want = order.indexOf(String(requested));\n if (want < 0) return supported[0];\n\n // Prefer the largest supported value <= requested; otherwise pick the smallest available.\n const ranked = supported\n .map((r) => ({ r, idx: order.indexOf(String(r)) }))\n .filter((x) => x.idx >= 0)\n .sort((a, b) => a.idx - b.idx);\n if (ranked.length === 0) return supported[0];\n\n let chosen = ranked[0].r;\n for (const x of ranked) {\n if (x.idx <= want) chosen = x.r;\n }\n return chosen;\n}\n\nfunction parseSize(raw: string | undefined): { width: number; height: number; totalPixels: number } | null {\n if (typeof raw !== 'string') return null;\n const m = raw.trim().toLowerCase().match(/^(\\d{2,5})\\s*[x×*]\\s*(\\d{2,5})$/);\n if (!m) return null;\n const width = Number(m[1]);\n const height = Number(m[2]);\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;\n return { width, height, totalPixels: width * height };\n}\n\nfunction parseAspectRatio(raw: string | undefined): { value: number } | null {\n if (typeof raw !== 'string') return null;\n const m = raw.trim().match(/^(\\d{1,3})\\s*[:x×/]\\s*(\\d{1,3})$/);\n if (!m) return null;\n const w = Number(m[1]);\n const h = Number(m[2]);\n if (!Number.isFinite(w) || !Number.isFinite(h) || w <= 0 || h <= 0) return null;\n return { value: w / h };\n}\n\nfunction sizeFromAspectRatio(\n ratioStr: string | undefined,\n pixelHints: number[],\n): { width: number; height: number; totalPixels: number } | null {\n const r = parseAspectRatio(ratioStr);\n if (!r) return null;\n const pixels = pixelHints.length > 0 ? Math.round(pixelHints.reduce((a, b) => a + b, 0) / pixelHints.length) : 1024 * 1024;\n const height = Math.round(Math.sqrt(pixels / r.value));\n const width = Math.round(height * r.value);\n return { width, height, totalPixels: width * height };\n}\n\nfunction sizeDistance(\n a: { width: number; height: number; totalPixels: number },\n b: { width: number; height: number; totalPixels: number },\n): number {\n // Combined area + aspect-ratio difference (log-scale on both for stability).\n const areaDelta = Math.abs(Math.log(a.totalPixels) - Math.log(b.totalPixels));\n const ratioA = a.width / a.height;\n const ratioB = b.width / b.height;\n const ratioDelta = Math.abs(Math.log(ratioA) - Math.log(ratioB));\n return areaDelta + ratioDelta * 1.5;\n}\n\n// ============================================\n// Failure aggregation\n// ============================================\n\nexport interface RecordCapabilityCandidateFailureParams {\n attempts: FallbackAttempt[];\n provider: string;\n model: string;\n error: unknown;\n durationMs?: number;\n}\n\n/** Push a structured {@link FallbackAttempt} entry derived from `error`. */\nexport function recordCapabilityCandidateFailure(\n params: RecordCapabilityCandidateFailureParams,\n): FallbackAttempt {\n const cls = classifyAttemptError(params.error);\n const attempt: FallbackAttempt = {\n provider: params.provider,\n model: params.model,\n error: cls.message,\n reason: cls.reason,\n ...(cls.status !== undefined ? { status: cls.status } : {}),\n ...(cls.code !== undefined ? { code: cls.code } : {}),\n ...(params.durationMs !== undefined ? { durationMs: params.durationMs } : {}),\n };\n params.attempts.push(attempt);\n return attempt;\n}\n\nexport interface ThrowCapabilityGenerationFailureParams {\n capabilityLabel: string;\n attempts: FallbackAttempt[];\n lastError: unknown;\n}\n\n/** Throw a unified {@link FailoverError} after all candidates have been exhausted. */\nexport function throwCapabilityGenerationFailure(params: ThrowCapabilityGenerationFailureParams): never {\n // capabilityLabel like \"image generation\" → identifier \"image-generation\"\n const capability = params.capabilityLabel.trim().toLowerCase().replace(/\\s+/g, '-') || 'capability';\n throw new FailoverError({\n capability,\n attempts: params.attempts,\n cause: params.lastError,\n });\n}\n\n// ============================================\n// \"No model configured\" message\n// ============================================\n\nexport interface BuildNoCapabilityModelConfiguredMessageParams {\n /** Display label, e.g. \"image-generation\". */\n capabilityLabel: string;\n /** Config key path, e.g. \"imageGenerationModel\". */\n modelConfigKey: string;\n providers: ReadonlyArray<CapabilityProviderCandidate>;\n /** Optional env-var lookup, e.g. (id) => PROVIDER_ENV_MAP[id]. */\n getProviderEnvVars?: (id: string) => readonly string[] | undefined;\n}\n\nexport function buildNoCapabilityModelConfiguredMessage(\n params: BuildNoCapabilityModelConfiguredMessageParams,\n): string {\n const lines: string[] = [\n `No ${params.capabilityLabel} model configured. Add a manifest/runtime model policy for ${params.modelConfigKey} ` +\n `or pass modelOverride at call site.`,\n ];\n if (params.providers.length > 0) {\n lines.push('Registered providers:');\n for (const p of params.providers) {\n const envs = params.getProviderEnvVars?.(p.id) ?? [];\n const env = envs.length > 0 ? ` (env: ${envs.join(' | ')})` : '';\n const def = p.defaultModel ? ` default=${p.defaultModel}` : '';\n lines.push(` - ${p.id}${def}${env}`);\n }\n }\n return lines.join('\\n');\n}\n\n/**\n * Build a `metadata.normalization` snapshot from a completed normalization\n * pass. Providers / runtime can spread it into their result metadata.\n */\nexport function buildMediaGenerationNormalizationMetadata(params: {\n normalization?: Record<string, unknown>;\n}): Record<string, unknown> {\n if (!params.normalization || Object.keys(params.normalization).length === 0) return {};\n return { normalization: params.normalization };\n}\n\n// Re-export the union for downstream type narrowing.\nexport type { FailoverReason };\n"],"mappings":"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"}
@@ -14,6 +14,8 @@ export declare class BuiltinMemoryStore {
14
14
  isUserProfileEnabled(): boolean;
15
15
  /** Agent-scoped curated memory directory (`~/.xopc/agents/<id>/memories/`). */
16
16
  get memoriesDir(): string;
17
+ /** Workspace whose MEMORY.md and daily notes participate in local memory search. */
18
+ get workspaceDir(): string;
17
19
  pathFor(target: 'memory' | 'user'): string;
18
20
  /**
19
21
  * Load from disk and freeze {@link getSnapshot}. Sync for agent creation (prefix cache stability).
@@ -28,6 +28,10 @@ var BuiltinMemoryStore = class {
28
28
  get memoriesDir() {
29
29
  return this.config.memoriesDir;
30
30
  }
31
+ /** Workspace whose MEMORY.md and daily notes participate in local memory search. */
32
+ get workspaceDir() {
33
+ return this.config.workspaceDir;
34
+ }
31
35
  pathFor(target) {
32
36
  return join(this.memoriesDir, target === "memory" ? "MEMORY.md" : "USER.md");
33
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"builtin-memory-store.js","names":[],"sources":["../../../../src/agent/memory/builtin-memory-store.ts"],"sourcesContent":["/**\n * Bounded curated memory: agent home `memories/MEMORY.md` + `USER.md`, §-delimited entries.\n * Snapshot for system prompt is captured at load time and not mutated until next load.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport lockfile from 'proper-lockfile';\n\nimport type { MemorySnapshot, MemoryStoreConfig } from './types.js';\n\nexport const MEMORY_ENTRY_DELIMITER = '\\n§\\n';\n\nconst DEFAULT_MEMORY_LIMIT = 2200;\nconst DEFAULT_USER_LIMIT = 1375;\n\nexport class BuiltinMemoryStore {\n private memoryEntries: string[] = [];\n private userEntries: string[] = [];\n private snapshot: MemorySnapshot = { memory: '', user: '' };\n\n constructor(private readonly config: MemoryStoreConfig) {}\n\n /** When false, USER.md is omitted from the snapshot and should not be edited via `curated_memory`. */\n isUserProfileEnabled(): boolean {\n return this.config.userProfileEnabled !== false;\n }\n\n /** Agent-scoped curated memory directory (`~/.xopc/agents/<id>/memories/`). */\n get memoriesDir(): string {\n return this.config.memoriesDir;\n }\n\n pathFor(target: 'memory' | 'user'): string {\n return join(this.memoriesDir, target === 'memory' ? 'MEMORY.md' : 'USER.md');\n }\n\n /**\n * Load from disk and freeze {@link getSnapshot}. Sync for agent creation (prefix cache stability).\n */\n loadFromDiskSync(): void {\n mkdirSync(this.memoriesDir, { recursive: true });\n this.memoryEntries = this.parseFileContent(\n this.readPathSync(join(this.memoriesDir, 'MEMORY.md')),\n );\n this.userEntries =\n this.config.userProfileEnabled === false\n ? []\n : this.parseFileContent(this.readPathSync(join(this.memoriesDir, 'USER.md')));\n this.memoryEntries = dedupePreserveOrder(this.memoryEntries);\n this.userEntries = dedupePreserveOrder(this.userEntries);\n this.snapshot = {\n memory: this.renderBlock('memory', this.memoryEntries),\n user: this.renderBlock('user', this.userEntries),\n };\n }\n\n private readPathSync(path: string): string {\n try {\n if (!existsSync(path)) return '';\n return readFileSync(path, { encoding: 'utf-8' });\n } catch {\n return '';\n }\n }\n\n private parseFileContent(raw: string): string[] {\n if (!raw.trim()) return [];\n return raw\n .split(MEMORY_ENTRY_DELIMITER)\n .map((e) => e.trim())\n .filter(Boolean);\n }\n\n getSnapshot(): MemorySnapshot {\n return this.snapshot;\n }\n\n /**\n * Live entries for read/debug (may differ from snapshot after mutations).\n */\n getLiveEntries(target: 'memory' | 'user'): string[] {\n return target === 'memory' ? [...this.memoryEntries] : [...this.userEntries];\n }\n\n async add(\n target: 'memory' | 'user',\n content: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const trimmed = content.trim();\n if (!trimmed) {\n return { success: false, error: 'Content cannot be empty.' };\n }\n const scanError = scanForThreats(trimmed);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const limit = this.charLimit(target);\n\n if (entries.includes(trimmed)) {\n return { success: false, error: 'Entry already exists' };\n }\n\n const newTotal = calculateTotal([...entries, trimmed]);\n if (newTotal > limit) {\n return {\n success: false,\n error: `Memory at ${calculateTotal(entries)}/${limit} chars. Adding would exceed limit.`,\n };\n }\n\n entries.push(trimmed);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry added.' };\n });\n }\n\n async replace(\n target: 'memory' | 'user',\n oldText: string,\n newContent: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n const nc = newContent.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n if (!nc) {\n return { success: false, error: 'new_content cannot be empty. Use remove to delete entries.' };\n }\n const scanError = scanForThreats(nc);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: Array<{ index: number; entry: string }> = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push({ index: i, entry: entries[i] });\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((m) => m.entry));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((m) =>\n m.entry.length > 80 ? `${m.entry.slice(0, 80)}...` : m.entry,\n );\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n const idx = matches[0].index;\n const limit = this.charLimit(target);\n const testEntries = [...entries];\n testEntries[idx] = nc;\n\n if (calculateTotal(testEntries) > limit) {\n return {\n success: false,\n error: `Replacement would put memory at ${calculateTotal(testEntries)}/${limit} chars.`,\n };\n }\n\n entries[idx] = nc;\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry replaced.' };\n });\n }\n\n async remove(\n target: 'memory' | 'user',\n oldText: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: number[] = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push(i);\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((i) => entries[i]));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((i) => {\n const e = entries[i];\n return e.length > 80 ? `${e.slice(0, 80)}...` : e;\n });\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n entries.splice(matches[0], 1);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry removed.' };\n });\n }\n\n private async withFileLock<T>(\n target: 'memory' | 'user',\n fn: () => Promise<T>,\n ): Promise<T> {\n const filePath = this.pathFor(target);\n await mkdir(this.memoriesDir, { recursive: true });\n if (!existsSync(filePath)) {\n await writeFile(filePath, '', 'utf-8');\n }\n await lockfile.lock(filePath, { retries: 3, stale: 10_000 });\n try {\n return await fn();\n } finally {\n await lockfile.unlock(filePath);\n }\n }\n\n private async reloadTargetFromDisk(target: 'memory' | 'user'): Promise<void> {\n const path = this.pathFor(target);\n let raw = '';\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n raw = '';\n }\n const parsed = dedupePreserveOrder(this.parseFileContent(raw));\n if (target === 'memory') {\n this.memoryEntries = parsed;\n } else {\n this.userEntries = parsed;\n }\n }\n\n private async flushTargetToDisk(target: 'memory' | 'user'): Promise<void> {\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const filePath = this.pathFor(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, filePath);\n }\n\n private charLimit(target: 'memory' | 'user'): number {\n return target === 'memory'\n ? (this.config.memoryCharLimit ?? DEFAULT_MEMORY_LIMIT)\n : (this.config.userCharLimit ?? DEFAULT_USER_LIMIT);\n }\n\n private renderBlock(target: 'memory' | 'user', entries: string[]): string {\n if (entries.length === 0) {\n return '';\n }\n\n const limit = this.charLimit(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const current = content.length;\n const pct = Math.min(100, Math.round((current / limit) * 100));\n\n const header =\n target === 'user'\n ? `USER PROFILE (who the user is) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`\n : `MEMORY (your personal notes) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`;\n\n const separator = '═'.repeat(46);\n return `${separator}\\n${header}\\n${separator}\\n${content}`;\n }\n}\n\nfunction dedupePreserveOrder(entries: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const e of entries) {\n if (seen.has(e)) {\n continue;\n }\n seen.add(e);\n out.push(e);\n }\n return out;\n}\n\nfunction calculateTotal(entries: string[]): number {\n if (entries.length === 0) {\n return 0;\n }\n return entries.join(MEMORY_ENTRY_DELIMITER).length;\n}\n\nexport function scanForThreats(content: string): string | null {\n const patterns: Array<{ regex: RegExp; id: string }> = [\n { regex: /ignore\\s+(previous|all|above|prior)\\s+instructions/i, id: 'prompt_injection' },\n { regex: /you\\s+are\\s+now\\s+/i, id: 'role_hijack' },\n { regex: /do\\s+not\\s+tell\\s+the\\s+user/i, id: 'deception_hide' },\n { regex: /system\\s+prompt\\s+override/i, id: 'sys_prompt_override' },\n {\n regex: /disregard\\s+(your|all|any)\\s+(instructions|rules|guidelines)/i,\n id: 'disregard_rules',\n },\n {\n regex: /act\\s+as\\s+(if|though)\\s+you\\s+(have\\s+no|don't\\s+have)\\s+(restrictions|limits|rules)/i,\n id: 'bypass_restrictions',\n },\n { regex: /curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_curl' },\n { regex: /wget\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_wget' },\n {\n regex: /cat\\s+[^\\n]*(\\.env|credentials|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc)/i,\n id: 'read_secrets',\n },\n { regex: /authorized_keys/i, id: 'ssh_backdoor' },\n { regex: /\\$HOME\\/\\.ssh|\\~\\/\\.ssh/i, id: 'ssh_access' },\n ];\n\n for (const { regex, id } of patterns) {\n if (regex.test(content)) {\n return `Blocked: content matches threat pattern '${id}'. Memory entries are injected into the system prompt and must not contain injection payloads.`;\n }\n }\n\n const invisibleChars = [\n '\\u200b',\n '\\u200c',\n '\\u200d',\n '\\u2060',\n '\\ufeff',\n '\\u202a',\n '\\u202b',\n '\\u202c',\n '\\u202d',\n '\\u202e',\n ];\n for (const char of invisibleChars) {\n if (content.includes(char)) {\n const code = char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');\n return `Blocked: content contains invisible unicode character U+${code} (possible injection).`;\n }\n }\n\n return null;\n}\n"],"mappings":";;;;;;;;;AAYA,MAAa,yBAAyB;AAEtC,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,IAAa,qBAAb,MAAgC;CAC9B,gBAAkC,EAAE;CACpC,cAAgC,EAAE;CAClC,WAAmC;EAAE,QAAQ;EAAI,MAAM;EAAI;CAE3D,YAAY,QAA4C;AAA3B,OAAA,SAAA;;;CAG7B,uBAAgC;AAC9B,SAAO,KAAK,OAAO,uBAAuB;;;CAI5C,IAAI,cAAsB;AACxB,SAAO,KAAK,OAAO;;CAGrB,QAAQ,QAAmC;AACzC,SAAO,KAAK,KAAK,aAAa,WAAW,WAAW,cAAc,UAAU;;;;;CAM9E,mBAAyB;AACvB,YAAU,KAAK,aAAa,EAAE,WAAW,MAAM,CAAC;AAChD,OAAK,gBAAgB,KAAK,iBACxB,KAAK,aAAa,KAAK,KAAK,aAAa,YAAY,CAAC,CACvD;AACD,OAAK,cACH,KAAK,OAAO,uBAAuB,QAC/B,EAAE,GACF,KAAK,iBAAiB,KAAK,aAAa,KAAK,KAAK,aAAa,UAAU,CAAC,CAAC;AACjF,OAAK,gBAAgB,oBAAoB,KAAK,cAAc;AAC5D,OAAK,cAAc,oBAAoB,KAAK,YAAY;AACxD,OAAK,WAAW;GACd,QAAQ,KAAK,YAAY,UAAU,KAAK,cAAc;GACtD,MAAM,KAAK,YAAY,QAAQ,KAAK,YAAY;GACjD;;CAGH,aAAqB,MAAsB;AACzC,MAAI;AACF,OAAI,CAAC,WAAW,KAAK,CAAE,QAAO;AAC9B,UAAO,aAAa,MAAM,EAAE,UAAU,SAAS,CAAC;UAC1C;AACN,UAAO;;;CAIX,iBAAyB,KAAuB;AAC9C,MAAI,CAAC,IAAI,MAAM,CAAE,QAAO,EAAE;AAC1B,SAAO,IACJ,MAAM,uBAAuB,CAC7B,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;;CAGpB,cAA8B;AAC5B,SAAO,KAAK;;;;;CAMd,eAAe,QAAqC;AAClD,SAAO,WAAW,WAAW,CAAC,GAAG,KAAK,cAAc,GAAG,CAAC,GAAG,KAAK,YAAY;;CAG9E,MAAM,IACJ,QACA,SACiE;EACjE,MAAM,UAAU,QAAQ,MAAM;AAC9B,MAAI,CAAC,QACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA4B;EAE9D,MAAM,YAAY,eAAe,QAAQ;AACzC,MAAI,UACF,QAAO;GAAE,SAAS;GAAO,OAAO;GAAW;AAG7C,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,QAAQ,KAAK,UAAU,OAAO;AAEpC,OAAI,QAAQ,SAAS,QAAQ,CAC3B,QAAO;IAAE,SAAS;IAAO,OAAO;IAAwB;AAI1D,OADiB,eAAe,CAAC,GAAG,SAAS,QAAQ,CACzC,GAAG,MACb,QAAO;IACL,SAAS;IACT,OAAO,aAAa,eAAe,QAAQ,CAAC,GAAG,MAAM;IACtD;AAGH,WAAQ,KAAK,QAAQ;AACrB,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAgB;IACjD;;CAGJ,MAAM,QACJ,QACA,SACA,YACiE;EACjE,MAAM,KAAK,QAAQ,MAAM;EACzB,MAAM,KAAK,WAAW,MAAM;AAC5B,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA6B;AAE/D,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA8D;EAEhG,MAAM,YAAY,eAAe,GAAG;AACpC,MAAI,UACF,QAAO;GAAE,SAAS;GAAO,OAAO;GAAW;AAG7C,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,UAAmD,EAAE;AAC3D,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,GAAG,SAAS,GAAG,CACzB,SAAQ,KAAK;IAAE,OAAO;IAAG,OAAO,QAAQ;IAAI,CAAC;AAIjD,OAAI,QAAQ,WAAW,EACrB,QAAO;IAAE,SAAS;IAAO,OAAO,qBAAqB,GAAG;IAAK;AAG/D,OAAI,QAAQ,SAAS;QAEf,IADoB,IAAI,QAAQ,KAAK,MAAM,EAAE,MAAM,CACxC,CAAC,OAAO,EAIrB,QAAO;KACL,SAAS;KACT,OAAO,6BAA6B,GAAG,iCALxB,QAAQ,KAAK,MAC5B,EAAE,MAAM,SAAS,KAAK,GAAG,EAAE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,MAIyB,CAAC,KAAK,MAAM;KAC7F;;GAIL,MAAM,MAAM,QAAQ,GAAG;GACvB,MAAM,QAAQ,KAAK,UAAU,OAAO;GACpC,MAAM,cAAc,CAAC,GAAG,QAAQ;AAChC,eAAY,OAAO;AAEnB,OAAI,eAAe,YAAY,GAAG,MAChC,QAAO;IACL,SAAS;IACT,OAAO,mCAAmC,eAAe,YAAY,CAAC,GAAG,MAAM;IAChF;AAGH,WAAQ,OAAO;AACf,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAmB;IACpD;;CAGJ,MAAM,OACJ,QACA,SACiE;EACjE,MAAM,KAAK,QAAQ,MAAM;AACzB,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA6B;AAG/D,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,UAAoB,EAAE;AAC5B,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,GAAG,SAAS,GAAG,CACzB,SAAQ,KAAK,EAAE;AAInB,OAAI,QAAQ,WAAW,EACrB,QAAO;IAAE,SAAS;IAAO,OAAO,qBAAqB,GAAG;IAAK;AAG/D,OAAI,QAAQ,SAAS;QAEf,IADoB,IAAI,QAAQ,KAAK,MAAM,QAAQ,GAAG,CAC3C,CAAC,OAAO,EAKrB,QAAO;KACL,SAAS;KACT,OAAO,6BAA6B,GAAG,iCANxB,QAAQ,KAAK,MAAM;MAClC,MAAM,IAAI,QAAQ;AAClB,aAAO,EAAE,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,OAAO;OAIgC,CAAC,KAAK,MAAM;KAC7F;;AAIL,WAAQ,OAAO,QAAQ,IAAI,EAAE;AAC7B,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAkB;IACnD;;CAGJ,MAAc,aACZ,QACA,IACY;EACZ,MAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,QAAM,MAAM,KAAK,aAAa,EAAE,WAAW,MAAM,CAAC;AAClD,MAAI,CAAC,WAAW,SAAS,CACvB,OAAM,UAAU,UAAU,IAAI,QAAQ;AAExC,QAAM,SAAS,KAAK,UAAU;GAAE,SAAS;GAAG,OAAO;GAAQ,CAAC;AAC5D,MAAI;AACF,UAAO,MAAM,IAAI;YACT;AACR,SAAM,SAAS,OAAO,SAAS;;;CAInC,MAAc,qBAAqB,QAA0C;EAC3E,MAAM,OAAO,KAAK,QAAQ,OAAO;EACjC,IAAI,MAAM;AACV,MAAI;AACF,SAAM,MAAM,SAAS,MAAM,QAAQ;UAC7B;AACN,SAAM;;EAER,MAAM,SAAS,oBAAoB,KAAK,iBAAiB,IAAI,CAAC;AAC9D,MAAI,WAAW,SACb,MAAK,gBAAgB;MAErB,MAAK,cAAc;;CAIvB,MAAc,kBAAkB,QAA0C;EACxE,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;EAChE,MAAM,WAAW,KAAK,QAAQ,OAAO;EACrC,MAAM,UAAU,QAAQ,KAAK,uBAAuB;EACpD,MAAM,UAAU,GAAG,SAAS,OAAO,KAAK,KAAK;AAC7C,QAAM,UAAU,SAAS,SAAS,QAAQ;AAC1C,QAAM,OAAO,SAAS,SAAS;;CAGjC,UAAkB,QAAmC;AACnD,SAAO,WAAW,WACb,KAAK,OAAO,mBAAmB,uBAC/B,KAAK,OAAO,iBAAiB;;CAGpC,YAAoB,QAA2B,SAA2B;AACxE,MAAI,QAAQ,WAAW,EACrB,QAAO;EAGT,MAAM,QAAQ,KAAK,UAAU,OAAO;EACpC,MAAM,UAAU,QAAQ,KAAK,uBAAuB;EACpD,MAAM,UAAU,QAAQ;EACxB,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,MAAO,UAAU,QAAS,IAAI,CAAC;EAE9D,MAAM,SACJ,WAAW,SACP,mCAAmC,IAAI,MAAM,QAAQ,gBAAgB,CAAC,GAAG,MAAM,gBAAgB,CAAC,WAChG,iCAAiC,IAAI,MAAM,QAAQ,gBAAgB,CAAC,GAAG,MAAM,gBAAgB,CAAC;EAEpG,MAAM,YAAY,IAAI,OAAO,GAAG;AAChC,SAAO,GAAG,UAAU,IAAI,OAAO,IAAI,UAAU,IAAI;;;AAIrD,SAAS,oBAAoB,SAA6B;CACxD,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,MAAgB,EAAE;AACxB,MAAK,MAAM,KAAK,SAAS;AACvB,MAAI,KAAK,IAAI,EAAE,CACb;AAEF,OAAK,IAAI,EAAE;AACX,MAAI,KAAK,EAAE;;AAEb,QAAO;;AAGT,SAAS,eAAe,SAA2B;AACjD,KAAI,QAAQ,WAAW,EACrB,QAAO;AAET,QAAO,QAAQ,KAAK,uBAAuB,CAAC;;AAG9C,SAAgB,eAAe,SAAgC;AAwB7D,MAAK,MAAM,EAAE,OAAO,QAAQ;EAtB1B;GAAE,OAAO;GAAuD,IAAI;GAAoB;EACxF;GAAE,OAAO;GAAuB,IAAI;GAAe;EACnD;GAAE,OAAO;GAAiC,IAAI;GAAkB;EAChE;GAAE,OAAO;GAA+B,IAAI;GAAuB;EACnE;GACE,OAAO;GACP,IAAI;GACL;EACD;GACE,OAAO;GACP,IAAI;GACL;EACD;GAAE,OAAO;GAAoE,IAAI;GAAc;EAC/F;GAAE,OAAO;GAAoE,IAAI;GAAc;EAC/F;GACE,OAAO;GACP,IAAI;GACL;EACD;GAAE,OAAO;GAAoB,IAAI;GAAgB;EACjD;GAAE,OAAO;GAA4B,IAAI;GAAc;EAGrB,CAClC,KAAI,MAAM,KAAK,QAAQ,CACrB,QAAO,4CAA4C,GAAG;AAgB1D,MAAK,MAAM,QAAQ;EAXjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAE+B,CAC/B,KAAI,QAAQ,SAAS,KAAK,CAExB,QAAO,2DADM,KAAK,WAAW,EAAE,CAAC,SAAS,GAAG,CAAC,aAAa,CAAC,SAAS,GAAG,IACD,CAAC;AAI3E,QAAO"}
1
+ {"version":3,"file":"builtin-memory-store.js","names":[],"sources":["../../../../src/agent/memory/builtin-memory-store.ts"],"sourcesContent":["/**\n * Bounded curated memory: agent home `memories/MEMORY.md` + `USER.md`, §-delimited entries.\n * Snapshot for system prompt is captured at load time and not mutated until next load.\n */\n\nimport { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport lockfile from 'proper-lockfile';\n\nimport type { MemorySnapshot, MemoryStoreConfig } from './types.js';\n\nexport const MEMORY_ENTRY_DELIMITER = '\\n§\\n';\n\nconst DEFAULT_MEMORY_LIMIT = 2200;\nconst DEFAULT_USER_LIMIT = 1375;\n\nexport class BuiltinMemoryStore {\n private memoryEntries: string[] = [];\n private userEntries: string[] = [];\n private snapshot: MemorySnapshot = { memory: '', user: '' };\n\n constructor(private readonly config: MemoryStoreConfig) {}\n\n /** When false, USER.md is omitted from the snapshot and should not be edited via `curated_memory`. */\n isUserProfileEnabled(): boolean {\n return this.config.userProfileEnabled !== false;\n }\n\n /** Agent-scoped curated memory directory (`~/.xopc/agents/<id>/memories/`). */\n get memoriesDir(): string {\n return this.config.memoriesDir;\n }\n\n /** Workspace whose MEMORY.md and daily notes participate in local memory search. */\n get workspaceDir(): string {\n return this.config.workspaceDir;\n }\n\n pathFor(target: 'memory' | 'user'): string {\n return join(this.memoriesDir, target === 'memory' ? 'MEMORY.md' : 'USER.md');\n }\n\n /**\n * Load from disk and freeze {@link getSnapshot}. Sync for agent creation (prefix cache stability).\n */\n loadFromDiskSync(): void {\n mkdirSync(this.memoriesDir, { recursive: true });\n this.memoryEntries = this.parseFileContent(\n this.readPathSync(join(this.memoriesDir, 'MEMORY.md')),\n );\n this.userEntries =\n this.config.userProfileEnabled === false\n ? []\n : this.parseFileContent(this.readPathSync(join(this.memoriesDir, 'USER.md')));\n this.memoryEntries = dedupePreserveOrder(this.memoryEntries);\n this.userEntries = dedupePreserveOrder(this.userEntries);\n this.snapshot = {\n memory: this.renderBlock('memory', this.memoryEntries),\n user: this.renderBlock('user', this.userEntries),\n };\n }\n\n private readPathSync(path: string): string {\n try {\n if (!existsSync(path)) return '';\n return readFileSync(path, { encoding: 'utf-8' });\n } catch {\n return '';\n }\n }\n\n private parseFileContent(raw: string): string[] {\n if (!raw.trim()) return [];\n return raw\n .split(MEMORY_ENTRY_DELIMITER)\n .map((e) => e.trim())\n .filter(Boolean);\n }\n\n getSnapshot(): MemorySnapshot {\n return this.snapshot;\n }\n\n /**\n * Live entries for read/debug (may differ from snapshot after mutations).\n */\n getLiveEntries(target: 'memory' | 'user'): string[] {\n return target === 'memory' ? [...this.memoryEntries] : [...this.userEntries];\n }\n\n async add(\n target: 'memory' | 'user',\n content: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const trimmed = content.trim();\n if (!trimmed) {\n return { success: false, error: 'Content cannot be empty.' };\n }\n const scanError = scanForThreats(trimmed);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const limit = this.charLimit(target);\n\n if (entries.includes(trimmed)) {\n return { success: false, error: 'Entry already exists' };\n }\n\n const newTotal = calculateTotal([...entries, trimmed]);\n if (newTotal > limit) {\n return {\n success: false,\n error: `Memory at ${calculateTotal(entries)}/${limit} chars. Adding would exceed limit.`,\n };\n }\n\n entries.push(trimmed);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry added.' };\n });\n }\n\n async replace(\n target: 'memory' | 'user',\n oldText: string,\n newContent: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n const nc = newContent.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n if (!nc) {\n return { success: false, error: 'new_content cannot be empty. Use remove to delete entries.' };\n }\n const scanError = scanForThreats(nc);\n if (scanError) {\n return { success: false, error: scanError };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: Array<{ index: number; entry: string }> = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push({ index: i, entry: entries[i] });\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((m) => m.entry));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((m) =>\n m.entry.length > 80 ? `${m.entry.slice(0, 80)}...` : m.entry,\n );\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n const idx = matches[0].index;\n const limit = this.charLimit(target);\n const testEntries = [...entries];\n testEntries[idx] = nc;\n\n if (calculateTotal(testEntries) > limit) {\n return {\n success: false,\n error: `Replacement would put memory at ${calculateTotal(testEntries)}/${limit} chars.`,\n };\n }\n\n entries[idx] = nc;\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry replaced.' };\n });\n }\n\n async remove(\n target: 'memory' | 'user',\n oldText: string,\n ): Promise<{ success: boolean; error?: string; message?: string }> {\n const ot = oldText.trim();\n if (!ot) {\n return { success: false, error: 'old_text cannot be empty.' };\n }\n\n return this.withFileLock(target, async () => {\n await this.reloadTargetFromDisk(target);\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const matches: number[] = [];\n for (let i = 0; i < entries.length; i++) {\n if (entries[i].includes(ot)) {\n matches.push(i);\n }\n }\n\n if (matches.length === 0) {\n return { success: false, error: `No entry matched '${ot}'.` };\n }\n\n if (matches.length > 1) {\n const uniqueTexts = new Set(matches.map((i) => entries[i]));\n if (uniqueTexts.size > 1) {\n const previews = matches.map((i) => {\n const e = entries[i];\n return e.length > 80 ? `${e.slice(0, 80)}...` : e;\n });\n return {\n success: false,\n error: `Multiple entries matched '${ot}'. Be more specific. Previews: ${previews.join(' | ')}`,\n };\n }\n }\n\n entries.splice(matches[0], 1);\n await this.flushTargetToDisk(target);\n return { success: true, message: 'Entry removed.' };\n });\n }\n\n private async withFileLock<T>(\n target: 'memory' | 'user',\n fn: () => Promise<T>,\n ): Promise<T> {\n const filePath = this.pathFor(target);\n await mkdir(this.memoriesDir, { recursive: true });\n if (!existsSync(filePath)) {\n await writeFile(filePath, '', 'utf-8');\n }\n await lockfile.lock(filePath, { retries: 3, stale: 10_000 });\n try {\n return await fn();\n } finally {\n await lockfile.unlock(filePath);\n }\n }\n\n private async reloadTargetFromDisk(target: 'memory' | 'user'): Promise<void> {\n const path = this.pathFor(target);\n let raw = '';\n try {\n raw = await readFile(path, 'utf-8');\n } catch {\n raw = '';\n }\n const parsed = dedupePreserveOrder(this.parseFileContent(raw));\n if (target === 'memory') {\n this.memoryEntries = parsed;\n } else {\n this.userEntries = parsed;\n }\n }\n\n private async flushTargetToDisk(target: 'memory' | 'user'): Promise<void> {\n const entries = target === 'memory' ? this.memoryEntries : this.userEntries;\n const filePath = this.pathFor(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const tmpPath = `${filePath}.tmp.${Date.now()}`;\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, filePath);\n }\n\n private charLimit(target: 'memory' | 'user'): number {\n return target === 'memory'\n ? (this.config.memoryCharLimit ?? DEFAULT_MEMORY_LIMIT)\n : (this.config.userCharLimit ?? DEFAULT_USER_LIMIT);\n }\n\n private renderBlock(target: 'memory' | 'user', entries: string[]): string {\n if (entries.length === 0) {\n return '';\n }\n\n const limit = this.charLimit(target);\n const content = entries.join(MEMORY_ENTRY_DELIMITER);\n const current = content.length;\n const pct = Math.min(100, Math.round((current / limit) * 100));\n\n const header =\n target === 'user'\n ? `USER PROFILE (who the user is) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`\n : `MEMORY (your personal notes) [${pct}% — ${current.toLocaleString()}/${limit.toLocaleString()} chars]`;\n\n const separator = '═'.repeat(46);\n return `${separator}\\n${header}\\n${separator}\\n${content}`;\n }\n}\n\nfunction dedupePreserveOrder(entries: string[]): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const e of entries) {\n if (seen.has(e)) {\n continue;\n }\n seen.add(e);\n out.push(e);\n }\n return out;\n}\n\nfunction calculateTotal(entries: string[]): number {\n if (entries.length === 0) {\n return 0;\n }\n return entries.join(MEMORY_ENTRY_DELIMITER).length;\n}\n\nexport function scanForThreats(content: string): string | null {\n const patterns: Array<{ regex: RegExp; id: string }> = [\n { regex: /ignore\\s+(previous|all|above|prior)\\s+instructions/i, id: 'prompt_injection' },\n { regex: /you\\s+are\\s+now\\s+/i, id: 'role_hijack' },\n { regex: /do\\s+not\\s+tell\\s+the\\s+user/i, id: 'deception_hide' },\n { regex: /system\\s+prompt\\s+override/i, id: 'sys_prompt_override' },\n {\n regex: /disregard\\s+(your|all|any)\\s+(instructions|rules|guidelines)/i,\n id: 'disregard_rules',\n },\n {\n regex: /act\\s+as\\s+(if|though)\\s+you\\s+(have\\s+no|don't\\s+have)\\s+(restrictions|limits|rules)/i,\n id: 'bypass_restrictions',\n },\n { regex: /curl\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_curl' },\n { regex: /wget\\s+[^\\n]*\\$\\{?\\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)/i, id: 'exfil_wget' },\n {\n regex: /cat\\s+[^\\n]*(\\.env|credentials|\\.netrc|\\.pgpass|\\.npmrc|\\.pypirc)/i,\n id: 'read_secrets',\n },\n { regex: /authorized_keys/i, id: 'ssh_backdoor' },\n { regex: /\\$HOME\\/\\.ssh|\\~\\/\\.ssh/i, id: 'ssh_access' },\n ];\n\n for (const { regex, id } of patterns) {\n if (regex.test(content)) {\n return `Blocked: content matches threat pattern '${id}'. Memory entries are injected into the system prompt and must not contain injection payloads.`;\n }\n }\n\n const invisibleChars = [\n '\\u200b',\n '\\u200c',\n '\\u200d',\n '\\u2060',\n '\\ufeff',\n '\\u202a',\n '\\u202b',\n '\\u202c',\n '\\u202d',\n '\\u202e',\n ];\n for (const char of invisibleChars) {\n if (content.includes(char)) {\n const code = char.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');\n return `Blocked: content contains invisible unicode character U+${code} (possible injection).`;\n }\n }\n\n return null;\n}\n"],"mappings":";;;;;;;;;AAYA,MAAa,yBAAyB;AAEtC,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB;AAE3B,IAAa,qBAAb,MAAgC;CAC9B,gBAAkC,EAAE;CACpC,cAAgC,EAAE;CAClC,WAAmC;EAAE,QAAQ;EAAI,MAAM;EAAI;CAE3D,YAAY,QAA4C;AAA3B,OAAA,SAAA;;;CAG7B,uBAAgC;AAC9B,SAAO,KAAK,OAAO,uBAAuB;;;CAI5C,IAAI,cAAsB;AACxB,SAAO,KAAK,OAAO;;;CAIrB,IAAI,eAAuB;AACzB,SAAO,KAAK,OAAO;;CAGrB,QAAQ,QAAmC;AACzC,SAAO,KAAK,KAAK,aAAa,WAAW,WAAW,cAAc,UAAU;;;;;CAM9E,mBAAyB;AACvB,YAAU,KAAK,aAAa,EAAE,WAAW,MAAM,CAAC;AAChD,OAAK,gBAAgB,KAAK,iBACxB,KAAK,aAAa,KAAK,KAAK,aAAa,YAAY,CAAC,CACvD;AACD,OAAK,cACH,KAAK,OAAO,uBAAuB,QAC/B,EAAE,GACF,KAAK,iBAAiB,KAAK,aAAa,KAAK,KAAK,aAAa,UAAU,CAAC,CAAC;AACjF,OAAK,gBAAgB,oBAAoB,KAAK,cAAc;AAC5D,OAAK,cAAc,oBAAoB,KAAK,YAAY;AACxD,OAAK,WAAW;GACd,QAAQ,KAAK,YAAY,UAAU,KAAK,cAAc;GACtD,MAAM,KAAK,YAAY,QAAQ,KAAK,YAAY;GACjD;;CAGH,aAAqB,MAAsB;AACzC,MAAI;AACF,OAAI,CAAC,WAAW,KAAK,CAAE,QAAO;AAC9B,UAAO,aAAa,MAAM,EAAE,UAAU,SAAS,CAAC;UAC1C;AACN,UAAO;;;CAIX,iBAAyB,KAAuB;AAC9C,MAAI,CAAC,IAAI,MAAM,CAAE,QAAO,EAAE;AAC1B,SAAO,IACJ,MAAM,uBAAuB,CAC7B,KAAK,MAAM,EAAE,MAAM,CAAC,CACpB,OAAO,QAAQ;;CAGpB,cAA8B;AAC5B,SAAO,KAAK;;;;;CAMd,eAAe,QAAqC;AAClD,SAAO,WAAW,WAAW,CAAC,GAAG,KAAK,cAAc,GAAG,CAAC,GAAG,KAAK,YAAY;;CAG9E,MAAM,IACJ,QACA,SACiE;EACjE,MAAM,UAAU,QAAQ,MAAM;AAC9B,MAAI,CAAC,QACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA4B;EAE9D,MAAM,YAAY,eAAe,QAAQ;AACzC,MAAI,UACF,QAAO;GAAE,SAAS;GAAO,OAAO;GAAW;AAG7C,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,QAAQ,KAAK,UAAU,OAAO;AAEpC,OAAI,QAAQ,SAAS,QAAQ,CAC3B,QAAO;IAAE,SAAS;IAAO,OAAO;IAAwB;AAI1D,OADiB,eAAe,CAAC,GAAG,SAAS,QAAQ,CACzC,GAAG,MACb,QAAO;IACL,SAAS;IACT,OAAO,aAAa,eAAe,QAAQ,CAAC,GAAG,MAAM;IACtD;AAGH,WAAQ,KAAK,QAAQ;AACrB,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAgB;IACjD;;CAGJ,MAAM,QACJ,QACA,SACA,YACiE;EACjE,MAAM,KAAK,QAAQ,MAAM;EACzB,MAAM,KAAK,WAAW,MAAM;AAC5B,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA6B;AAE/D,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA8D;EAEhG,MAAM,YAAY,eAAe,GAAG;AACpC,MAAI,UACF,QAAO;GAAE,SAAS;GAAO,OAAO;GAAW;AAG7C,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,UAAmD,EAAE;AAC3D,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,GAAG,SAAS,GAAG,CACzB,SAAQ,KAAK;IAAE,OAAO;IAAG,OAAO,QAAQ;IAAI,CAAC;AAIjD,OAAI,QAAQ,WAAW,EACrB,QAAO;IAAE,SAAS;IAAO,OAAO,qBAAqB,GAAG;IAAK;AAG/D,OAAI,QAAQ,SAAS;QAEf,IADoB,IAAI,QAAQ,KAAK,MAAM,EAAE,MAAM,CACxC,CAAC,OAAO,EAIrB,QAAO;KACL,SAAS;KACT,OAAO,6BAA6B,GAAG,iCALxB,QAAQ,KAAK,MAC5B,EAAE,MAAM,SAAS,KAAK,GAAG,EAAE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,MAIyB,CAAC,KAAK,MAAM;KAC7F;;GAIL,MAAM,MAAM,QAAQ,GAAG;GACvB,MAAM,QAAQ,KAAK,UAAU,OAAO;GACpC,MAAM,cAAc,CAAC,GAAG,QAAQ;AAChC,eAAY,OAAO;AAEnB,OAAI,eAAe,YAAY,GAAG,MAChC,QAAO;IACL,SAAS;IACT,OAAO,mCAAmC,eAAe,YAAY,CAAC,GAAG,MAAM;IAChF;AAGH,WAAQ,OAAO;AACf,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAmB;IACpD;;CAGJ,MAAM,OACJ,QACA,SACiE;EACjE,MAAM,KAAK,QAAQ,MAAM;AACzB,MAAI,CAAC,GACH,QAAO;GAAE,SAAS;GAAO,OAAO;GAA6B;AAG/D,SAAO,KAAK,aAAa,QAAQ,YAAY;AAC3C,SAAM,KAAK,qBAAqB,OAAO;GACvC,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;GAChE,MAAM,UAAoB,EAAE;AAC5B,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,GAAG,SAAS,GAAG,CACzB,SAAQ,KAAK,EAAE;AAInB,OAAI,QAAQ,WAAW,EACrB,QAAO;IAAE,SAAS;IAAO,OAAO,qBAAqB,GAAG;IAAK;AAG/D,OAAI,QAAQ,SAAS;QAEf,IADoB,IAAI,QAAQ,KAAK,MAAM,QAAQ,GAAG,CAC3C,CAAC,OAAO,EAKrB,QAAO;KACL,SAAS;KACT,OAAO,6BAA6B,GAAG,iCANxB,QAAQ,KAAK,MAAM;MAClC,MAAM,IAAI,QAAQ;AAClB,aAAO,EAAE,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,OAAO;OAIgC,CAAC,KAAK,MAAM;KAC7F;;AAIL,WAAQ,OAAO,QAAQ,IAAI,EAAE;AAC7B,SAAM,KAAK,kBAAkB,OAAO;AACpC,UAAO;IAAE,SAAS;IAAM,SAAS;IAAkB;IACnD;;CAGJ,MAAc,aACZ,QACA,IACY;EACZ,MAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,QAAM,MAAM,KAAK,aAAa,EAAE,WAAW,MAAM,CAAC;AAClD,MAAI,CAAC,WAAW,SAAS,CACvB,OAAM,UAAU,UAAU,IAAI,QAAQ;AAExC,QAAM,SAAS,KAAK,UAAU;GAAE,SAAS;GAAG,OAAO;GAAQ,CAAC;AAC5D,MAAI;AACF,UAAO,MAAM,IAAI;YACT;AACR,SAAM,SAAS,OAAO,SAAS;;;CAInC,MAAc,qBAAqB,QAA0C;EAC3E,MAAM,OAAO,KAAK,QAAQ,OAAO;EACjC,IAAI,MAAM;AACV,MAAI;AACF,SAAM,MAAM,SAAS,MAAM,QAAQ;UAC7B;AACN,SAAM;;EAER,MAAM,SAAS,oBAAoB,KAAK,iBAAiB,IAAI,CAAC;AAC9D,MAAI,WAAW,SACb,MAAK,gBAAgB;MAErB,MAAK,cAAc;;CAIvB,MAAc,kBAAkB,QAA0C;EACxE,MAAM,UAAU,WAAW,WAAW,KAAK,gBAAgB,KAAK;EAChE,MAAM,WAAW,KAAK,QAAQ,OAAO;EACrC,MAAM,UAAU,QAAQ,KAAK,uBAAuB;EACpD,MAAM,UAAU,GAAG,SAAS,OAAO,KAAK,KAAK;AAC7C,QAAM,UAAU,SAAS,SAAS,QAAQ;AAC1C,QAAM,OAAO,SAAS,SAAS;;CAGjC,UAAkB,QAAmC;AACnD,SAAO,WAAW,WACb,KAAK,OAAO,mBAAmB,uBAC/B,KAAK,OAAO,iBAAiB;;CAGpC,YAAoB,QAA2B,SAA2B;AACxE,MAAI,QAAQ,WAAW,EACrB,QAAO;EAGT,MAAM,QAAQ,KAAK,UAAU,OAAO;EACpC,MAAM,UAAU,QAAQ,KAAK,uBAAuB;EACpD,MAAM,UAAU,QAAQ;EACxB,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,MAAO,UAAU,QAAS,IAAI,CAAC;EAE9D,MAAM,SACJ,WAAW,SACP,mCAAmC,IAAI,MAAM,QAAQ,gBAAgB,CAAC,GAAG,MAAM,gBAAgB,CAAC,WAChG,iCAAiC,IAAI,MAAM,QAAQ,gBAAgB,CAAC,GAAG,MAAM,gBAAgB,CAAC;EAEpG,MAAM,YAAY,IAAI,OAAO,GAAG;AAChC,SAAO,GAAG,UAAU,IAAI,OAAO,IAAI,UAAU,IAAI;;;AAIrD,SAAS,oBAAoB,SAA6B;CACxD,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,MAAgB,EAAE;AACxB,MAAK,MAAM,KAAK,SAAS;AACvB,MAAI,KAAK,IAAI,EAAE,CACb;AAEF,OAAK,IAAI,EAAE;AACX,MAAI,KAAK,EAAE;;AAEb,QAAO;;AAGT,SAAS,eAAe,SAA2B;AACjD,KAAI,QAAQ,WAAW,EACrB,QAAO;AAET,QAAO,QAAQ,KAAK,uBAAuB,CAAC;;AAG9C,SAAgB,eAAe,SAAgC;AAwB7D,MAAK,MAAM,EAAE,OAAO,QAAQ;EAtB1B;GAAE,OAAO;GAAuD,IAAI;GAAoB;EACxF;GAAE,OAAO;GAAuB,IAAI;GAAe;EACnD;GAAE,OAAO;GAAiC,IAAI;GAAkB;EAChE;GAAE,OAAO;GAA+B,IAAI;GAAuB;EACnE;GACE,OAAO;GACP,IAAI;GACL;EACD;GACE,OAAO;GACP,IAAI;GACL;EACD;GAAE,OAAO;GAAoE,IAAI;GAAc;EAC/F;GAAE,OAAO;GAAoE,IAAI;GAAc;EAC/F;GACE,OAAO;GACP,IAAI;GACL;EACD;GAAE,OAAO;GAAoB,IAAI;GAAgB;EACjD;GAAE,OAAO;GAA4B,IAAI;GAAc;EAGrB,CAClC,KAAI,MAAM,KAAK,QAAQ,CACrB,QAAO,4CAA4C,GAAG;AAgB1D,MAAK,MAAM,QAAQ;EAXjB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAE+B,CAC/B,KAAI,QAAQ,SAAS,KAAK,CAExB,QAAO,2DADM,KAAK,WAAW,EAAE,CAAC,SAAS,GAAG,CAAC,aAAa,CAAC,SAAS,GAAG,IACD,CAAC;AAI3E,QAAO"}
@@ -1,21 +1,43 @@
1
1
  import type { BuiltinMemoryStore } from './builtin-memory-store.js';
2
2
  import type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';
3
+ import type { MemoryDeleteRequest, MemoryListRequest, MemoryReadRequest, MemoryReadResult, MemoryRecord, MemorySearchRequest, MemorySearchResult, MemoryUpdateRequest, MemoryWriteRequest, MemoryWriteResult, MemorySyncEvent } from './types.js';
3
4
  /**
4
- * Builtin curated store: snapshot is injected via {@link MemorySnapshot} in the system prompt builder.
5
- * This provider participates in prefetch/sync orchestration only as a no-op.
5
+ * Builtin local memory provider backed by agent-home curated files, workspace MEMORY.md,
6
+ * daily notes, and the local SQLite FTS index.
6
7
  */
7
8
  export declare class BuiltinMemoryProvider implements MemoryProvider {
8
- private readonly _store;
9
- readonly name = "builtin";
10
- constructor(_store: BuiltinMemoryStore);
9
+ private readonly store;
10
+ readonly id = "local";
11
+ readonly displayName = "Local Markdown Memory";
12
+ readonly capabilities: {
13
+ search: boolean;
14
+ read: boolean;
15
+ write: boolean;
16
+ update: boolean;
17
+ delete: boolean;
18
+ keywordSearch: boolean;
19
+ semanticSearch: boolean;
20
+ hybridSearch: boolean;
21
+ citations: boolean;
22
+ sync: boolean;
23
+ local: boolean;
24
+ };
25
+ private workspaceDir;
26
+ private agentId;
27
+ constructor(store: BuiltinMemoryStore);
11
28
  isAvailable(): boolean;
12
- initialize(_sessionId: string, _options?: MemoryProviderInitOptions): Promise<void>;
13
- /** Curated blocks are injected separately as frozen snapshot; avoid duplicating in provider merge. */
29
+ initialize(_sessionId: string, options?: MemoryProviderInitOptions): Promise<void>;
14
30
  systemPromptBlock(): string;
15
31
  prefetch(): Promise<string>;
16
32
  queuePrefetch(): void;
17
- syncTurn(): void;
18
33
  getToolSchemas(): any[];
19
- handleToolCall(): Promise<string>;
34
+ search(request: MemorySearchRequest): Promise<MemorySearchResult[]>;
35
+ read(request: MemoryReadRequest): Promise<MemoryReadResult | null>;
36
+ get(id: string): Promise<MemoryRecord | null>;
37
+ list(request: MemoryListRequest): Promise<MemoryRecord[]>;
38
+ write(request: MemoryWriteRequest): Promise<MemoryWriteResult>;
39
+ update(request: MemoryUpdateRequest): Promise<MemoryWriteResult>;
40
+ delete(request: MemoryDeleteRequest): Promise<MemoryWriteResult>;
41
+ sync(event: MemorySyncEvent): void;
20
42
  shutdown(): Promise<void>;
21
43
  }