@open-mercato/ai-assistant 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2

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 (273) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +361 -0
  3. package/README.md +5 -0
  4. package/dist/index.js +154 -0
  5. package/dist/index.js.map +2 -2
  6. package/dist/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.js +73 -0
  7. package/dist/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.js.map +7 -0
  8. package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.js +484 -0
  9. package/dist/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.js.map +7 -0
  10. package/dist/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.js +251 -0
  11. package/dist/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.js.map +7 -0
  12. package/dist/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.js +91 -0
  13. package/dist/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.js.map +7 -0
  14. package/dist/modules/ai_assistant/ai-tools/attachments-pack.js +202 -0
  15. package/dist/modules/ai_assistant/ai-tools/attachments-pack.js.map +7 -0
  16. package/dist/modules/ai_assistant/ai-tools/meta-pack.js +121 -0
  17. package/dist/modules/ai_assistant/ai-tools/meta-pack.js.map +7 -0
  18. package/dist/modules/ai_assistant/ai-tools/search-pack.js +94 -0
  19. package/dist/modules/ai_assistant/ai-tools/search-pack.js.map +7 -0
  20. package/dist/modules/ai_assistant/ai-tools.js +14 -0
  21. package/dist/modules/ai_assistant/ai-tools.js.map +7 -0
  22. package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js +175 -0
  23. package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js.map +7 -0
  24. package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js +174 -0
  25. package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js.map +7 -0
  26. package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js +101 -0
  27. package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js.map +7 -0
  28. package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js +311 -0
  29. package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js.map +7 -0
  30. package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js +246 -0
  31. package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js.map +7 -0
  32. package/dist/modules/ai_assistant/api/ai/agents/route.js +94 -0
  33. package/dist/modules/ai_assistant/api/ai/agents/route.js.map +7 -0
  34. package/dist/modules/ai_assistant/api/ai/chat/route.js +173 -0
  35. package/dist/modules/ai_assistant/api/ai/chat/route.js.map +7 -0
  36. package/dist/modules/ai_assistant/api/ai/run-object/route.js +167 -0
  37. package/dist/modules/ai_assistant/api/ai/run-object/route.js.map +7 -0
  38. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js +1111 -0
  39. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.js.map +7 -0
  40. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.js +10 -0
  41. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.js.map +7 -0
  42. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.js +28 -0
  43. package/dist/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.js.map +7 -0
  44. package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js +10 -0
  45. package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.js.map +7 -0
  46. package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.js +30 -0
  47. package/dist/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.js.map +7 -0
  48. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js +4 -6
  49. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.js.map +2 -2
  50. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js +1 -21
  51. package/dist/modules/ai_assistant/backend/config/ai-assistant/page.meta.js.map +2 -2
  52. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js +462 -0
  53. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.js.map +7 -0
  54. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.js +10 -0
  55. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.js.map +7 -0
  56. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.js +28 -0
  57. package/dist/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.js.map +7 -0
  58. package/dist/modules/ai_assistant/cli.js +78 -12
  59. package/dist/modules/ai_assistant/cli.js.map +2 -2
  60. package/dist/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.js +5 -0
  61. package/dist/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.js.map +7 -0
  62. package/dist/modules/ai_assistant/data/entities/AiAgentPromptOverride.js +5 -0
  63. package/dist/modules/ai_assistant/data/entities/AiAgentPromptOverride.js.map +7 -0
  64. package/dist/modules/ai_assistant/data/entities/AiPendingAction.js +5 -0
  65. package/dist/modules/ai_assistant/data/entities/AiPendingAction.js.map +7 -0
  66. package/dist/modules/ai_assistant/data/entities.js +228 -0
  67. package/dist/modules/ai_assistant/data/entities.js.map +7 -0
  68. package/dist/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.js +95 -0
  69. package/dist/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.js.map +7 -0
  70. package/dist/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.js +95 -0
  71. package/dist/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.js.map +7 -0
  72. package/dist/modules/ai_assistant/data/repositories/AiPendingActionRepository.js +223 -0
  73. package/dist/modules/ai_assistant/data/repositories/AiPendingActionRepository.js.map +7 -0
  74. package/dist/modules/ai_assistant/events.js +33 -0
  75. package/dist/modules/ai_assistant/events.js.map +7 -0
  76. package/dist/modules/ai_assistant/i18n/de.json +252 -0
  77. package/dist/modules/ai_assistant/i18n/en.json +252 -0
  78. package/dist/modules/ai_assistant/i18n/es.json +252 -0
  79. package/dist/modules/ai_assistant/i18n/pl.json +252 -0
  80. package/dist/modules/ai_assistant/lib/agent-policy.js +168 -0
  81. package/dist/modules/ai_assistant/lib/agent-policy.js.map +7 -0
  82. package/dist/modules/ai_assistant/lib/agent-registry.js +195 -0
  83. package/dist/modules/ai_assistant/lib/agent-registry.js.map +7 -0
  84. package/dist/modules/ai_assistant/lib/agent-runtime.js +451 -0
  85. package/dist/modules/ai_assistant/lib/agent-runtime.js.map +7 -0
  86. package/dist/modules/ai_assistant/lib/agent-tools.js +223 -0
  87. package/dist/modules/ai_assistant/lib/agent-tools.js.map +7 -0
  88. package/dist/modules/ai_assistant/lib/agent-transport.js +25 -0
  89. package/dist/modules/ai_assistant/lib/agent-transport.js.map +7 -0
  90. package/dist/modules/ai_assistant/lib/ai-agent-definition.js +11 -0
  91. package/dist/modules/ai_assistant/lib/ai-agent-definition.js.map +7 -0
  92. package/dist/modules/ai_assistant/lib/ai-agents-generated.d.js +1 -0
  93. package/dist/modules/ai_assistant/lib/ai-agents-generated.d.js.map +7 -0
  94. package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js +239 -0
  95. package/dist/modules/ai_assistant/lib/ai-api-operation-runner.js.map +7 -0
  96. package/dist/modules/ai_assistant/lib/ai-overrides.js +189 -0
  97. package/dist/modules/ai_assistant/lib/ai-overrides.js.map +7 -0
  98. package/dist/modules/ai_assistant/lib/ai-tool-definition.js +7 -0
  99. package/dist/modules/ai_assistant/lib/ai-tool-definition.js.map +7 -0
  100. package/dist/modules/ai_assistant/lib/ai-tools-generated.d.js +1 -0
  101. package/dist/modules/ai_assistant/lib/ai-tools-generated.d.js.map +7 -0
  102. package/dist/modules/ai_assistant/lib/api-backed-tool.js +48 -0
  103. package/dist/modules/ai_assistant/lib/api-backed-tool.js.map +7 -0
  104. package/dist/modules/ai_assistant/lib/attachment-bridge-types.js +1 -0
  105. package/dist/modules/ai_assistant/lib/attachment-bridge-types.js.map +7 -0
  106. package/dist/modules/ai_assistant/lib/attachment-parts.js +276 -0
  107. package/dist/modules/ai_assistant/lib/attachment-parts.js.map +7 -0
  108. package/dist/modules/ai_assistant/lib/model-factory.js +68 -0
  109. package/dist/modules/ai_assistant/lib/model-factory.js.map +7 -0
  110. package/dist/modules/ai_assistant/lib/pending-action-cancel.js +86 -0
  111. package/dist/modules/ai_assistant/lib/pending-action-cancel.js.map +7 -0
  112. package/dist/modules/ai_assistant/lib/pending-action-client.js +35 -0
  113. package/dist/modules/ai_assistant/lib/pending-action-client.js.map +7 -0
  114. package/dist/modules/ai_assistant/lib/pending-action-executor.js +243 -0
  115. package/dist/modules/ai_assistant/lib/pending-action-executor.js.map +7 -0
  116. package/dist/modules/ai_assistant/lib/pending-action-recheck.js +246 -0
  117. package/dist/modules/ai_assistant/lib/pending-action-recheck.js.map +7 -0
  118. package/dist/modules/ai_assistant/lib/pending-action-types.js +70 -0
  119. package/dist/modules/ai_assistant/lib/pending-action-types.js.map +7 -0
  120. package/dist/modules/ai_assistant/lib/prepare-mutation.js +315 -0
  121. package/dist/modules/ai_assistant/lib/prepare-mutation.js.map +7 -0
  122. package/dist/modules/ai_assistant/lib/prompt-composition-types.js +7 -0
  123. package/dist/modules/ai_assistant/lib/prompt-composition-types.js.map +7 -0
  124. package/dist/modules/ai_assistant/lib/prompt-override-merge.js +175 -0
  125. package/dist/modules/ai_assistant/lib/prompt-override-merge.js.map +7 -0
  126. package/dist/modules/ai_assistant/lib/schema-utils.js +5 -1
  127. package/dist/modules/ai_assistant/lib/schema-utils.js.map +2 -2
  128. package/dist/modules/ai_assistant/lib/tool-executor.js +13 -2
  129. package/dist/modules/ai_assistant/lib/tool-executor.js.map +2 -2
  130. package/dist/modules/ai_assistant/lib/tool-loader.js +86 -11
  131. package/dist/modules/ai_assistant/lib/tool-loader.js.map +2 -2
  132. package/dist/modules/ai_assistant/lib/tool-test-fixtures.js +120 -0
  133. package/dist/modules/ai_assistant/lib/tool-test-fixtures.js.map +7 -0
  134. package/dist/modules/ai_assistant/lib/tool-test-runner.js +418 -0
  135. package/dist/modules/ai_assistant/lib/tool-test-runner.js.map +7 -0
  136. package/dist/modules/ai_assistant/migrations/Migration20260419100521.js +17 -0
  137. package/dist/modules/ai_assistant/migrations/Migration20260419100521.js.map +7 -0
  138. package/dist/modules/ai_assistant/migrations/Migration20260419132948.js +16 -0
  139. package/dist/modules/ai_assistant/migrations/Migration20260419132948.js.map +7 -0
  140. package/dist/modules/ai_assistant/migrations/Migration20260419134235.js +17 -0
  141. package/dist/modules/ai_assistant/migrations/Migration20260419134235.js.map +7 -0
  142. package/dist/modules/ai_assistant/setup.js +36 -0
  143. package/dist/modules/ai_assistant/setup.js.map +2 -2
  144. package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js +161 -0
  145. package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js.map +7 -0
  146. package/generated/entities/ai_agent_mutation_policy_override/index.ts +9 -0
  147. package/generated/entities/ai_agent_prompt_override/index.ts +10 -0
  148. package/generated/entities/ai_pending_action/index.ts +24 -0
  149. package/generated/entities.ids.generated.ts +13 -0
  150. package/generated/entity-fields-registry.ts +57 -0
  151. package/jest.config.cjs +7 -0
  152. package/package.json +4 -4
  153. package/src/index.ts +215 -0
  154. package/src/modules/ai_assistant/__integration__/README.md +5 -0
  155. package/src/modules/ai_assistant/__integration__/TC-AI-002-agent-policy.spec.ts +115 -0
  156. package/src/modules/ai_assistant/__integration__/TC-AI-AGENT-SETTINGS-005-settings-page.spec.ts +574 -0
  157. package/src/modules/ai_assistant/__integration__/TC-AI-PLAYGROUND-004-playground.spec.ts +333 -0
  158. package/src/modules/ai_assistant/__integration__/TC-INT-AI-TOOLS.spec.ts +135 -0
  159. package/src/modules/ai_assistant/__tests__/events.test.ts +145 -0
  160. package/src/modules/ai_assistant/__tests__/integration/pending-action-contract.test.ts +1015 -0
  161. package/src/modules/ai_assistant/__tests__/integration/ws-c-attachment-bridge.test.ts +235 -0
  162. package/src/modules/ai_assistant/__tests__/integration/ws-c-policy-and-tools.test.ts +330 -0
  163. package/src/modules/ai_assistant/__tests__/integration/ws-c-tool-pack-coverage.test.ts +285 -0
  164. package/src/modules/ai_assistant/ai-tools/__tests__/attachments-pack.test.ts +322 -0
  165. package/src/modules/ai_assistant/ai-tools/__tests__/meta-pack.test.ts +218 -0
  166. package/src/modules/ai_assistant/ai-tools/__tests__/search-pack.test.ts +192 -0
  167. package/src/modules/ai_assistant/ai-tools/attachments-pack.ts +269 -0
  168. package/src/modules/ai_assistant/ai-tools/meta-pack.ts +140 -0
  169. package/src/modules/ai_assistant/ai-tools/search-pack.ts +122 -0
  170. package/src/modules/ai_assistant/ai-tools.ts +21 -0
  171. package/src/modules/ai_assistant/api/ai/actions/[id]/__tests__/route.test.ts +222 -0
  172. package/src/modules/ai_assistant/api/ai/actions/[id]/cancel/__tests__/route.test.ts +286 -0
  173. package/src/modules/ai_assistant/api/ai/actions/[id]/cancel/route.ts +237 -0
  174. package/src/modules/ai_assistant/api/ai/actions/[id]/confirm/__tests__/route.test.ts +339 -0
  175. package/src/modules/ai_assistant/api/ai/actions/[id]/confirm/route.ts +229 -0
  176. package/src/modules/ai_assistant/api/ai/actions/[id]/route.ts +142 -0
  177. package/src/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/__tests__/route.test.ts +367 -0
  178. package/src/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.ts +380 -0
  179. package/src/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/__tests__/route.test.ts +333 -0
  180. package/src/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.ts +307 -0
  181. package/src/modules/ai_assistant/api/ai/agents/route.ts +107 -0
  182. package/src/modules/ai_assistant/api/ai/chat/__tests__/route.test.ts +282 -0
  183. package/src/modules/ai_assistant/api/ai/chat/route.ts +207 -0
  184. package/src/modules/ai_assistant/api/ai/run-object/__tests__/route.test.ts +282 -0
  185. package/src/modules/ai_assistant/api/ai/run-object/route.ts +204 -0
  186. package/src/modules/ai_assistant/backend/config/ai-assistant/agents/AiAgentSettingsPageClient.tsx +1419 -0
  187. package/src/modules/ai_assistant/backend/config/ai-assistant/agents/page.meta.ts +26 -0
  188. package/src/modules/ai_assistant/backend/config/ai-assistant/agents/page.tsx +12 -0
  189. package/src/modules/ai_assistant/backend/config/ai-assistant/legacy/page.meta.ts +28 -0
  190. package/src/modules/ai_assistant/backend/config/ai-assistant/legacy/page.tsx +12 -0
  191. package/src/modules/ai_assistant/backend/config/ai-assistant/page.meta.ts +8 -23
  192. package/src/modules/ai_assistant/backend/config/ai-assistant/page.tsx +15 -10
  193. package/src/modules/ai_assistant/backend/config/ai-assistant/playground/AiPlaygroundPageClient.tsx +604 -0
  194. package/src/modules/ai_assistant/backend/config/ai-assistant/playground/page.meta.ts +26 -0
  195. package/src/modules/ai_assistant/backend/config/ai-assistant/playground/page.tsx +12 -0
  196. package/src/modules/ai_assistant/cli.ts +99 -24
  197. package/src/modules/ai_assistant/data/__tests__/schema-unique-indexes.test.ts +69 -0
  198. package/src/modules/ai_assistant/data/entities/AiAgentMutationPolicyOverride.ts +7 -0
  199. package/src/modules/ai_assistant/data/entities/AiAgentPromptOverride.ts +7 -0
  200. package/src/modules/ai_assistant/data/entities/AiPendingAction.ts +7 -0
  201. package/src/modules/ai_assistant/data/entities.ts +270 -0
  202. package/src/modules/ai_assistant/data/repositories/AiAgentMutationPolicyOverrideRepository.ts +129 -0
  203. package/src/modules/ai_assistant/data/repositories/AiAgentPromptOverrideRepository.ts +132 -0
  204. package/src/modules/ai_assistant/data/repositories/AiPendingActionRepository.ts +334 -0
  205. package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentMutationPolicyOverrideRepository.test.ts +195 -0
  206. package/src/modules/ai_assistant/data/repositories/__tests__/AiAgentPromptOverrideRepository.test.ts +197 -0
  207. package/src/modules/ai_assistant/data/repositories/__tests__/AiPendingActionRepository.test.ts +357 -0
  208. package/src/modules/ai_assistant/events.ts +112 -0
  209. package/src/modules/ai_assistant/i18n/de.json +252 -0
  210. package/src/modules/ai_assistant/i18n/en.json +252 -0
  211. package/src/modules/ai_assistant/i18n/es.json +252 -0
  212. package/src/modules/ai_assistant/i18n/pl.json +252 -0
  213. package/src/modules/ai_assistant/lib/__tests__/agent-policy.mutation-override.test.ts +203 -0
  214. package/src/modules/ai_assistant/lib/__tests__/agent-policy.test.ts +385 -0
  215. package/src/modules/ai_assistant/lib/__tests__/agent-registry.test.ts +217 -0
  216. package/src/modules/ai_assistant/lib/__tests__/agent-runtime-object.test.ts +329 -0
  217. package/src/modules/ai_assistant/lib/__tests__/agent-runtime-parity.test.ts +573 -0
  218. package/src/modules/ai_assistant/lib/__tests__/agent-runtime.test.ts +291 -0
  219. package/src/modules/ai_assistant/lib/__tests__/agent-tools.test.ts +172 -0
  220. package/src/modules/ai_assistant/lib/__tests__/agent-transport.test.ts +41 -0
  221. package/src/modules/ai_assistant/lib/__tests__/ai-agent-definition.test.ts +183 -0
  222. package/src/modules/ai_assistant/lib/__tests__/ai-api-operation-runner.test.ts +432 -0
  223. package/src/modules/ai_assistant/lib/__tests__/ai-overrides.test.ts +308 -0
  224. package/src/modules/ai_assistant/lib/__tests__/api-backed-tool.test.ts +302 -0
  225. package/src/modules/ai_assistant/lib/__tests__/attachment-bridge-and-prompt-types.test.ts +188 -0
  226. package/src/modules/ai_assistant/lib/__tests__/attachment-parts.test.ts +531 -0
  227. package/src/modules/ai_assistant/lib/__tests__/max-steps-budget.integration.test.ts +263 -0
  228. package/src/modules/ai_assistant/lib/__tests__/model-factory.integration.test.ts +183 -0
  229. package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +168 -0
  230. package/src/modules/ai_assistant/lib/__tests__/pending-action-cancel.test.ts +235 -0
  231. package/src/modules/ai_assistant/lib/__tests__/pending-action-client.test.ts +148 -0
  232. package/src/modules/ai_assistant/lib/__tests__/pending-action-executor.test.ts +348 -0
  233. package/src/modules/ai_assistant/lib/__tests__/pending-action-recheck.test.ts +378 -0
  234. package/src/modules/ai_assistant/lib/__tests__/phase-0-additive-contract.test.ts +299 -0
  235. package/src/modules/ai_assistant/lib/__tests__/prepare-mutation.test.ts +610 -0
  236. package/src/modules/ai_assistant/lib/__tests__/prompt-override-merge.test.ts +136 -0
  237. package/src/modules/ai_assistant/lib/__tests__/tool-loader.test.ts +125 -0
  238. package/src/modules/ai_assistant/lib/agent-policy.ts +270 -0
  239. package/src/modules/ai_assistant/lib/agent-registry.ts +277 -0
  240. package/src/modules/ai_assistant/lib/agent-runtime.ts +751 -0
  241. package/src/modules/ai_assistant/lib/agent-tools.ts +396 -0
  242. package/src/modules/ai_assistant/lib/agent-transport.ts +51 -0
  243. package/src/modules/ai_assistant/lib/ai-agent-definition.ts +86 -0
  244. package/src/modules/ai_assistant/lib/ai-agents-generated.d.ts +18 -0
  245. package/src/modules/ai_assistant/lib/ai-api-operation-runner.ts +333 -0
  246. package/src/modules/ai_assistant/lib/ai-overrides.ts +389 -0
  247. package/src/modules/ai_assistant/lib/ai-tool-definition.ts +7 -0
  248. package/src/modules/ai_assistant/lib/ai-tools-generated.d.ts +7 -0
  249. package/src/modules/ai_assistant/lib/api-backed-tool.ts +85 -0
  250. package/src/modules/ai_assistant/lib/attachment-bridge-types.ts +24 -0
  251. package/src/modules/ai_assistant/lib/attachment-parts.ts +433 -0
  252. package/src/modules/ai_assistant/lib/model-factory.ts +212 -0
  253. package/src/modules/ai_assistant/lib/pending-action-cancel.ts +179 -0
  254. package/src/modules/ai_assistant/lib/pending-action-client.ts +126 -0
  255. package/src/modules/ai_assistant/lib/pending-action-executor.ts +424 -0
  256. package/src/modules/ai_assistant/lib/pending-action-recheck.ts +410 -0
  257. package/src/modules/ai_assistant/lib/pending-action-types.ts +194 -0
  258. package/src/modules/ai_assistant/lib/prepare-mutation.ts +448 -0
  259. package/src/modules/ai_assistant/lib/prompt-composition-types.ts +24 -0
  260. package/src/modules/ai_assistant/lib/prompt-override-merge.ts +253 -0
  261. package/src/modules/ai_assistant/lib/schema-utils.ts +14 -2
  262. package/src/modules/ai_assistant/lib/tool-executor.ts +25 -3
  263. package/src/modules/ai_assistant/lib/tool-loader.ts +159 -13
  264. package/src/modules/ai_assistant/lib/tool-test-fixtures.ts +160 -0
  265. package/src/modules/ai_assistant/lib/tool-test-runner.ts +596 -0
  266. package/src/modules/ai_assistant/lib/types.ts +105 -2
  267. package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +871 -0
  268. package/src/modules/ai_assistant/migrations/Migration20260419100521.ts +17 -0
  269. package/src/modules/ai_assistant/migrations/Migration20260419132948.ts +16 -0
  270. package/src/modules/ai_assistant/migrations/Migration20260419134235.ts +17 -0
  271. package/src/modules/ai_assistant/setup.ts +53 -0
  272. package/src/modules/ai_assistant/workers/__tests__/ai-pending-action-cleanup.test.ts +333 -0
  273. package/src/modules/ai_assistant/workers/ai-pending-action-cleanup.ts +269 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+ * General-purpose `meta.*` tool pack (Phase 1 WS-C, Step 3.8).
3
+ *
4
+ * `list_agents` enumerates agents the caller can invoke; `describe_agent`
5
+ * returns a serializable description (Zod output schema → JSON-Schema when
6
+ * possible, otherwise a `non-serializable` marker). Both tools treat a
7
+ * missing agent registry as an empty list — the chat runtime must not
8
+ * crash if `ai-agents.generated.ts` has not been emitted yet.
9
+ */
10
+ import { z } from 'zod'
11
+ import type { AiAgentDefinition } from '../lib/ai-agent-definition'
12
+ import { listAgents, getAgent } from '../lib/agent-registry'
13
+ import { hasRequiredFeatures } from '../lib/auth'
14
+ import { defineAiTool } from '../lib/ai-tool-definition'
15
+ import type { AiToolDefinition } from '../lib/types'
16
+
17
+ function summarizeAgent(agent: AiAgentDefinition): Record<string, unknown> {
18
+ return {
19
+ id: agent.id,
20
+ moduleId: agent.moduleId,
21
+ label: agent.label,
22
+ description: agent.description,
23
+ requiredFeatures: agent.requiredFeatures ?? [],
24
+ allowedTools: agent.allowedTools,
25
+ executionMode: agent.executionMode ?? 'chat',
26
+ mutationPolicy: agent.mutationPolicy ?? 'read-only',
27
+ readOnly: typeof agent.readOnly === 'boolean' ? agent.readOnly : true,
28
+ maxSteps: agent.maxSteps ?? null,
29
+ acceptedMediaTypes: agent.acceptedMediaTypes ?? [],
30
+ domain: agent.domain ?? null,
31
+ keywords: agent.keywords ?? [],
32
+ suggestions: agent.suggestions ?? [],
33
+ dataCapabilities: agent.dataCapabilities ?? null,
34
+ hasOutputSchema: Boolean(agent.output),
35
+ hasPageContextResolver: typeof agent.resolvePageContext === 'function',
36
+ }
37
+ }
38
+
39
+ function serializeStructuredOutput(
40
+ output: AiAgentDefinition['output'],
41
+ ): Record<string, unknown> | null {
42
+ if (!output) return null
43
+ try {
44
+ const jsonSchema = z.toJSONSchema(output.schema as unknown as z.ZodType, {
45
+ unrepresentable: 'any',
46
+ })
47
+ return {
48
+ schemaName: output.schemaName,
49
+ mode: output.mode ?? 'generate',
50
+ jsonSchema,
51
+ }
52
+ } catch (error) {
53
+ return {
54
+ schemaName: output.schemaName,
55
+ mode: output.mode ?? 'generate',
56
+ note: 'non-serializable',
57
+ error: error instanceof Error ? error.message : String(error),
58
+ }
59
+ }
60
+ }
61
+
62
+ function serializePrompt(agent: AiAgentDefinition): Record<string, unknown> {
63
+ return {
64
+ systemPrompt: agent.systemPrompt,
65
+ hasDynamicPageContext: typeof agent.resolvePageContext === 'function',
66
+ }
67
+ }
68
+
69
+ const listAgentsInput = z.object({
70
+ moduleId: z.string().optional().describe('Restrict results to one module id.'),
71
+ })
72
+
73
+ const listAgentsTool = defineAiTool({
74
+ name: 'meta.list_agents',
75
+ displayName: 'List agents',
76
+ description:
77
+ 'List registered AI agents the caller can invoke. Filters by requiredFeatures RBAC; returns { agents: [] } if the registry is empty.',
78
+ inputSchema: listAgentsInput,
79
+ requiredFeatures: ['ai_assistant.view'],
80
+ tags: ['read', 'meta'],
81
+ handler: async (rawInput, ctx) => {
82
+ const input = listAgentsInput.parse(rawInput)
83
+ let all: AiAgentDefinition[] = []
84
+ try {
85
+ all = listAgents()
86
+ } catch {
87
+ all = []
88
+ }
89
+ const filtered = all.filter((agent) => {
90
+ if (input.moduleId && agent.moduleId !== input.moduleId) return false
91
+ const features = agent.requiredFeatures ?? []
92
+ return hasRequiredFeatures(features, ctx.userFeatures, ctx.isSuperAdmin)
93
+ })
94
+ return {
95
+ agents: filtered.map(summarizeAgent),
96
+ total: filtered.length,
97
+ }
98
+ },
99
+ })
100
+
101
+ const describeAgentInput = z.object({
102
+ agentId: z.string().min(1).describe('Agent id (e.g. "catalog.merchandising_assistant").'),
103
+ })
104
+
105
+ const describeAgentTool = defineAiTool({
106
+ name: 'meta.describe_agent',
107
+ displayName: 'Describe agent',
108
+ description:
109
+ 'Return metadata, RBAC, allowed tools, execution mode, output schema (JSON-Schema when representable), and prompt shape for a single agent. Never throws — returns { agent: null, reason } if missing or forbidden.',
110
+ inputSchema: describeAgentInput,
111
+ requiredFeatures: ['ai_assistant.view'],
112
+ tags: ['read', 'meta'],
113
+ handler: async (rawInput, ctx) => {
114
+ const input = describeAgentInput.parse(rawInput)
115
+ let agent: AiAgentDefinition | undefined
116
+ try {
117
+ agent = getAgent(input.agentId)
118
+ } catch {
119
+ agent = undefined
120
+ }
121
+ if (!agent) {
122
+ return { agent: null, reason: 'not_found' as const }
123
+ }
124
+ const features = agent.requiredFeatures ?? []
125
+ if (!hasRequiredFeatures(features, ctx.userFeatures, ctx.isSuperAdmin)) {
126
+ return { agent: null, reason: 'forbidden' as const }
127
+ }
128
+ return {
129
+ agent: {
130
+ ...summarizeAgent(agent),
131
+ output: serializeStructuredOutput(agent.output),
132
+ prompt: serializePrompt(agent),
133
+ },
134
+ }
135
+ },
136
+ })
137
+
138
+ export const metaAiTools: AiToolDefinition<any, any>[] = [listAgentsTool, describeAgentTool]
139
+
140
+ export default metaAiTools
@@ -0,0 +1,122 @@
1
+ /**
2
+ * General-purpose `search.*` tool pack (Phase 1 WS-C, Step 3.8).
3
+ *
4
+ * These tools are discovered by the generator alongside any other module
5
+ * `ai-tools.ts`; they expose the existing `@open-mercato/search` runtime to
6
+ * agents that whitelist them via `allowedTools`.
7
+ */
8
+ import { z } from 'zod'
9
+ import type { SearchOptions, SearchResult, SearchStrategyId } from '@open-mercato/shared/modules/search'
10
+ import { defineAiTool } from '../lib/ai-tool-definition'
11
+ import type { AiToolDefinition } from '../lib/types'
12
+
13
+ type SearchServiceLike = {
14
+ search: (query: string, options: SearchOptions) => Promise<SearchResult[]>
15
+ }
16
+
17
+ const hybridSearchInput = z.object({
18
+ q: z.string().min(1).describe('Search query text.'),
19
+ limit: z
20
+ .number()
21
+ .int()
22
+ .min(1)
23
+ .max(100)
24
+ .optional()
25
+ .describe('Maximum results (default 20, max 100).'),
26
+ strategies: z
27
+ .array(z.enum(['fulltext', 'vector', 'tokens']))
28
+ .optional()
29
+ .describe('Subset of strategies to run; defaults to the module defaults.'),
30
+ entityTypes: z
31
+ .array(z.string())
32
+ .optional()
33
+ .describe('Filter to specific entity ids (e.g. "catalog:product").'),
34
+ })
35
+
36
+ const hybridSearchTool = defineAiTool({
37
+ name: 'search.hybrid_search',
38
+ displayName: 'Hybrid search',
39
+ description:
40
+ 'Run a global fulltext + vector + token search across enabled entities for the current tenant/organization.',
41
+ inputSchema: hybridSearchInput,
42
+ requiredFeatures: ['search.view'],
43
+ tags: ['read', 'search'],
44
+ handler: async (rawInput, ctx) => {
45
+ if (!ctx.tenantId) {
46
+ throw new Error('Tenant context is required for search.hybrid_search')
47
+ }
48
+ const input = hybridSearchInput.parse(rawInput)
49
+ const service = ctx.container.resolve<SearchServiceLike>('searchService')
50
+ const limit = input.limit ?? 20
51
+ const started = Date.now()
52
+ const results = await service.search(input.q, {
53
+ tenantId: ctx.tenantId,
54
+ organizationId: ctx.organizationId,
55
+ limit,
56
+ strategies: input.strategies as SearchStrategyId[] | undefined,
57
+ entityTypes: input.entityTypes,
58
+ })
59
+ const timingMs = Date.now() - started
60
+ const strategiesUsed = Array.from(
61
+ new Set(results.map((result) => result.source).filter((id): id is SearchStrategyId => typeof id === 'string')),
62
+ )
63
+ return {
64
+ query: input.q,
65
+ totalResults: results.length,
66
+ results,
67
+ strategiesUsed,
68
+ timing: { ms: timingMs },
69
+ }
70
+ },
71
+ })
72
+
73
+ const getRecordContextInput = z.object({
74
+ entityId: z.string().min(1).describe('Entity identifier (e.g. "customers:customer_person_profile").'),
75
+ recordId: z.string().min(1).describe('Record primary key (UUID).'),
76
+ })
77
+
78
+ const getRecordContextTool = defineAiTool({
79
+ name: 'search.get_record_context',
80
+ displayName: 'Get record context',
81
+ description:
82
+ 'Resolve presenter, links, and URL for a specific record by re-querying the search index. Returns { found: false } when no hit matches the recordId.',
83
+ inputSchema: getRecordContextInput,
84
+ requiredFeatures: ['search.view'],
85
+ tags: ['read', 'search'],
86
+ handler: async (rawInput, ctx) => {
87
+ if (!ctx.tenantId) {
88
+ throw new Error('Tenant context is required for search.get_record_context')
89
+ }
90
+ const input = getRecordContextInput.parse(rawInput)
91
+ const service = ctx.container.resolve<SearchServiceLike>('searchService')
92
+ const results = await service.search(input.recordId, {
93
+ tenantId: ctx.tenantId,
94
+ organizationId: ctx.organizationId,
95
+ limit: 5,
96
+ entityTypes: [input.entityId],
97
+ })
98
+ const match = results.find((result) => result.recordId === input.recordId)
99
+ if (!match) {
100
+ return {
101
+ found: false as const,
102
+ entityId: input.entityId,
103
+ recordId: input.recordId,
104
+ }
105
+ }
106
+ return {
107
+ found: true as const,
108
+ entityId: match.entityId,
109
+ recordId: match.recordId,
110
+ presenter: match.presenter,
111
+ url: match.url,
112
+ links: match.links,
113
+ metadata: match.metadata,
114
+ source: match.source,
115
+ score: match.score,
116
+ }
117
+ },
118
+ })
119
+
120
+ export const searchAiTools: AiToolDefinition<any, any>[] = [hybridSearchTool, getRecordContextTool]
121
+
122
+ export default searchAiTools
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Module-root AI tools contribution for `ai_assistant` (Phase 1 WS-C, Step 3.8).
3
+ *
4
+ * The generator scans every module for a top-level `ai-tools.ts` and takes
5
+ * the `aiTools` (or `default`) export as the module contribution. This file
6
+ * aggregates the three general-purpose tool packs (`search.*`,
7
+ * `attachments.*`, `meta.*`) so they flow through the existing
8
+ * `ai-tools.generated.ts` pipeline without any new generator plumbing.
9
+ */
10
+ import type { AiToolDefinition } from './lib/types'
11
+ import searchAiTools from './ai-tools/search-pack'
12
+ import attachmentsAiTools from './ai-tools/attachments-pack'
13
+ import metaAiTools from './ai-tools/meta-pack'
14
+
15
+ export const aiTools: AiToolDefinition<any, any>[] = [
16
+ ...searchAiTools,
17
+ ...attachmentsAiTools,
18
+ ...metaAiTools,
19
+ ]
20
+
21
+ export default aiTools
@@ -0,0 +1,222 @@
1
+ const authMock = jest.fn()
2
+ const loadAclMock = jest.fn()
3
+ const createRequestContainerMock = jest.fn()
4
+ const repoGetByIdMock = jest.fn()
5
+
6
+ jest.mock('@open-mercato/shared/lib/auth/server', () => ({
7
+ getAuthFromRequest: (...args: unknown[]) => authMock(...args),
8
+ }))
9
+
10
+ jest.mock('@open-mercato/shared/lib/di/container', () => ({
11
+ createRequestContainer: (...args: unknown[]) => createRequestContainerMock(...args),
12
+ }))
13
+
14
+ jest.mock('../../../../../data/repositories/AiPendingActionRepository', () => ({
15
+ AiPendingActionRepository: jest.fn().mockImplementation(() => ({
16
+ getById: repoGetByIdMock,
17
+ })),
18
+ }))
19
+
20
+ import { GET } from '../route'
21
+
22
+ function buildRequest(): Request {
23
+ return new Request('http://localhost/api/ai_assistant/ai/actions/pa_123', {
24
+ method: 'GET',
25
+ headers: { 'content-type': 'application/json' },
26
+ })
27
+ }
28
+
29
+ function buildContext(id: string) {
30
+ return { params: Promise.resolve({ id }) }
31
+ }
32
+
33
+ function makeRow(overrides: Record<string, unknown> = {}) {
34
+ return {
35
+ id: 'pa_123',
36
+ agentId: 'catalog.merchandising_assistant',
37
+ toolName: 'catalog.update_product',
38
+ status: 'pending',
39
+ fieldDiff: [{ field: 'title', before: 'Old', after: 'New' }],
40
+ records: null,
41
+ failedRecords: null,
42
+ sideEffectsSummary: null,
43
+ attachmentIds: [],
44
+ targetEntityType: 'product',
45
+ targetRecordId: 'prod_1',
46
+ recordVersion: 'v1',
47
+ queueMode: 'inline',
48
+ executionResult: null,
49
+ createdAt: new Date('2026-04-18T10:00:00.000Z'),
50
+ expiresAt: new Date('2026-04-18T10:15:00.000Z'),
51
+ resolvedAt: null,
52
+ resolvedByUserId: null,
53
+ // server-internal fields — MUST NOT leak through the serializer
54
+ normalizedInput: { secret: 'do-not-leak' },
55
+ createdByUserId: 'user-1',
56
+ idempotencyKey: 'idem_abc',
57
+ tenantId: 'tenant-1',
58
+ organizationId: 'org-1',
59
+ ...overrides,
60
+ }
61
+ }
62
+
63
+ describe('GET /api/ai/actions/:id route (Step 5.7)', () => {
64
+ let consoleErrorSpy: jest.SpyInstance
65
+
66
+ beforeEach(() => {
67
+ jest.clearAllMocks()
68
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
69
+ authMock.mockResolvedValue({
70
+ sub: 'user-1',
71
+ tenantId: 'tenant-1',
72
+ orgId: 'org-1',
73
+ })
74
+ loadAclMock.mockResolvedValue({
75
+ features: ['ai_assistant.view'],
76
+ isSuperAdmin: false,
77
+ })
78
+ createRequestContainerMock.mockResolvedValue({
79
+ resolve: (name: string) => {
80
+ if (name === 'rbacService') {
81
+ return {
82
+ loadAcl: loadAclMock,
83
+ hasAllFeatures: (required: string[], granted: string[]) =>
84
+ required.every((feature) => granted.includes(feature)),
85
+ }
86
+ }
87
+ if (name === 'em') {
88
+ return {}
89
+ }
90
+ return null
91
+ },
92
+ })
93
+ })
94
+
95
+ afterEach(() => {
96
+ consoleErrorSpy.mockRestore()
97
+ })
98
+
99
+ it('returns 401 when unauthenticated', async () => {
100
+ authMock.mockResolvedValueOnce(null)
101
+
102
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
103
+
104
+ expect(response.status).toBe(401)
105
+ // 401 envelope does include `code: 'unauthenticated'` in this module's
106
+ // routes (see chat/route.ts + prompt-override/route.ts). TC-AI-002
107
+ // only requires "status 401 — body shape not asserted", and this route
108
+ // follows the same shape. We still assert status only here to keep
109
+ // contract parity with TC-AI-002 and avoid pinning downstream envelope
110
+ // changes into this test.
111
+ })
112
+
113
+ it('happy path: tenant-matching id returns 200 + serialized row', async () => {
114
+ repoGetByIdMock.mockResolvedValueOnce(makeRow())
115
+
116
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
117
+
118
+ expect(response.status).toBe(200)
119
+ const body = await response.json()
120
+ expect(body.id).toBe('pa_123')
121
+ expect(body.agentId).toBe('catalog.merchandising_assistant')
122
+ expect(body.status).toBe('pending')
123
+ expect(body.toolName).toBe('catalog.update_product')
124
+ expect(body.fieldDiff).toEqual([{ field: 'title', before: 'Old', after: 'New' }])
125
+ expect(body.createdAt).toBe('2026-04-18T10:00:00.000Z')
126
+ expect(body.expiresAt).toBe('2026-04-18T10:15:00.000Z')
127
+ expect(body.resolvedAt).toBeNull()
128
+ expect(body.resolvedByUserId).toBeNull()
129
+ expect(body.queueMode).toBe('inline')
130
+
131
+ // Repository was called with the tenant/org scope from the auth context.
132
+ expect(repoGetByIdMock).toHaveBeenCalledTimes(1)
133
+ expect(repoGetByIdMock).toHaveBeenCalledWith('pa_123', {
134
+ tenantId: 'tenant-1',
135
+ organizationId: 'org-1',
136
+ userId: 'user-1',
137
+ })
138
+ })
139
+
140
+ it('cross-tenant id returns 404 pending_action_not_found', async () => {
141
+ // Repository is tenant-scoped: getById returns null when the row belongs
142
+ // to a different tenant/org.
143
+ repoGetByIdMock.mockResolvedValueOnce(null)
144
+
145
+ const response = await GET(buildRequest() as any, buildContext('pa_from_other_tenant'))
146
+
147
+ expect(response.status).toBe(404)
148
+ const body = await response.json()
149
+ expect(body.code).toBe('pending_action_not_found')
150
+ })
151
+
152
+ it('returns 404 when the id is unknown (no row)', async () => {
153
+ repoGetByIdMock.mockResolvedValueOnce(null)
154
+
155
+ const response = await GET(buildRequest() as any, buildContext('pa_missing'))
156
+
157
+ expect(response.status).toBe(404)
158
+ const body = await response.json()
159
+ expect(body.code).toBe('pending_action_not_found')
160
+ })
161
+
162
+ it('returns 403 when the caller lacks ai_assistant.view', async () => {
163
+ loadAclMock.mockResolvedValueOnce({
164
+ features: ['catalog.view'],
165
+ isSuperAdmin: false,
166
+ })
167
+
168
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
169
+
170
+ expect(response.status).toBe(403)
171
+ const body = await response.json()
172
+ expect(body.code).toBe('forbidden')
173
+ expect(repoGetByIdMock).not.toHaveBeenCalled()
174
+ })
175
+
176
+ it('internal fields are never present in the response body', async () => {
177
+ repoGetByIdMock.mockResolvedValueOnce(makeRow())
178
+
179
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
180
+
181
+ expect(response.status).toBe(200)
182
+ const body = await response.json()
183
+ expect(body).not.toHaveProperty('normalizedInput')
184
+ expect(body).not.toHaveProperty('createdByUserId')
185
+ expect(body).not.toHaveProperty('idempotencyKey')
186
+ expect(body).not.toHaveProperty('tenantId')
187
+ expect(body).not.toHaveProperty('organizationId')
188
+ })
189
+
190
+ it('returns 400 when the id param is empty', async () => {
191
+ const response = await GET(buildRequest() as any, buildContext(''))
192
+
193
+ expect(response.status).toBe(400)
194
+ const body = await response.json()
195
+ expect(body.code).toBe('validation_error')
196
+ })
197
+
198
+ it('returns 404 when the caller has no tenant scope', async () => {
199
+ authMock.mockResolvedValueOnce({
200
+ sub: 'user-1',
201
+ tenantId: null,
202
+ orgId: null,
203
+ })
204
+
205
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
206
+
207
+ expect(response.status).toBe(404)
208
+ const body = await response.json()
209
+ expect(body.code).toBe('pending_action_not_found')
210
+ expect(repoGetByIdMock).not.toHaveBeenCalled()
211
+ })
212
+
213
+ it('returns 500 when the repository throws', async () => {
214
+ repoGetByIdMock.mockRejectedValueOnce(new Error('db down'))
215
+
216
+ const response = await GET(buildRequest() as any, buildContext('pa_123'))
217
+
218
+ expect(response.status).toBe(500)
219
+ const body = await response.json()
220
+ expect(body.code).toBe('internal_error')
221
+ })
222
+ })