@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,348 @@
1
+ import { z } from 'zod'
2
+ import type { AwilixContainer } from 'awilix'
3
+ import {
4
+ executePendingActionConfirm,
5
+ PENDING_ACTION_CONFIRMED_EVENT_ID,
6
+ } from '../pending-action-executor'
7
+ import type { AiActionConfirmedPayload } from '../../events'
8
+ import type { AiAgentDefinition } from '../ai-agent-definition'
9
+ import type { AiToolDefinition } from '../types'
10
+ import type { AiPendingAction } from '../../data/entities'
11
+
12
+ function makeAction(overrides: Partial<AiPendingAction> = {}): AiPendingAction {
13
+ return {
14
+ id: 'pa_1',
15
+ tenantId: 'tenant-1',
16
+ organizationId: 'org-1',
17
+ agentId: 'catalog.merchandising_assistant',
18
+ toolName: 'catalog.update_product',
19
+ status: 'pending',
20
+ fieldDiff: [],
21
+ records: null,
22
+ failedRecords: null,
23
+ sideEffectsSummary: null,
24
+ recordVersion: 'v-1',
25
+ attachmentIds: [],
26
+ normalizedInput: { productId: 'p-1', patch: { title: 'New' } },
27
+ queueMode: 'inline',
28
+ executionResult: null,
29
+ targetEntityType: 'product',
30
+ targetRecordId: 'p-1',
31
+ conversationId: null,
32
+ idempotencyKey: 'idem_1',
33
+ createdByUserId: 'user-1',
34
+ createdAt: new Date('2026-04-18T10:00:00.000Z'),
35
+ expiresAt: new Date('2026-04-18T11:00:00.000Z'),
36
+ resolvedAt: null,
37
+ resolvedByUserId: null,
38
+ ...overrides,
39
+ } as unknown as AiPendingAction
40
+ }
41
+
42
+ function makeAgent(): AiAgentDefinition {
43
+ return {
44
+ id: 'catalog.merchandising_assistant',
45
+ moduleId: 'catalog',
46
+ label: 'Catalog Agent',
47
+ description: '...',
48
+ systemPrompt: '...',
49
+ allowedTools: ['catalog.update_product'],
50
+ readOnly: false,
51
+ mutationPolicy: 'confirm-required',
52
+ }
53
+ }
54
+
55
+ function makeTool(overrides: Partial<AiToolDefinition> = {}): AiToolDefinition {
56
+ return {
57
+ name: 'catalog.update_product',
58
+ description: 'Update product',
59
+ inputSchema: z.object({ productId: z.string(), patch: z.object({}).passthrough() }),
60
+ handler: async () => ({ recordId: 'p-1', commandName: 'catalog.product.update' }),
61
+ isMutation: true,
62
+ ...overrides,
63
+ } as AiToolDefinition
64
+ }
65
+
66
+ function makeRepoStub(initialRow: AiPendingAction) {
67
+ let row = { ...initialRow } as AiPendingAction & Record<string, unknown>
68
+ const setStatus = jest.fn(
69
+ async (_id: string, nextStatus: string, _scope: unknown, extra?: Record<string, unknown>) => {
70
+ row = {
71
+ ...row,
72
+ status: nextStatus as never,
73
+ }
74
+ if (extra && 'executionResult' in extra) {
75
+ row.executionResult = (extra.executionResult ?? null) as never
76
+ }
77
+ if (extra && 'failedRecords' in extra) {
78
+ row.failedRecords = (extra.failedRecords ?? null) as never
79
+ }
80
+ if (extra && 'resolvedByUserId' in extra) {
81
+ row.resolvedByUserId = extra.resolvedByUserId as never
82
+ }
83
+ if (nextStatus !== 'executing') {
84
+ row.resolvedAt = ((extra?.now as Date | undefined) ?? new Date()) as never
85
+ }
86
+ return row as AiPendingAction
87
+ },
88
+ )
89
+ return {
90
+ setStatus,
91
+ get current() {
92
+ return row
93
+ },
94
+ }
95
+ }
96
+
97
+ function makeCtx() {
98
+ return {
99
+ tenantId: 'tenant-1',
100
+ organizationId: 'org-1',
101
+ userId: 'user-1',
102
+ userFeatures: ['ai_assistant.view'],
103
+ isSuperAdmin: false,
104
+ container: {
105
+ resolve: (name: string) => {
106
+ if (name === 'em') return {}
107
+ if (name === 'eventBus') return { emitEvent: async () => {} }
108
+ throw new Error(`unknown dep ${name}`)
109
+ },
110
+ } as unknown as AwilixContainer,
111
+ }
112
+ }
113
+
114
+ describe('executePendingActionConfirm', () => {
115
+ it('transitions pending → confirmed → executing → confirmed on handler success and emits typed ai.action.confirmed', async () => {
116
+ const repo = makeRepoStub(makeAction())
117
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
118
+ const result = await executePendingActionConfirm({
119
+ action: makeAction(),
120
+ agent: makeAgent(),
121
+ tool: makeTool(),
122
+ ctx: makeCtx(),
123
+ repo: repo as unknown as never,
124
+ emitEvent,
125
+ })
126
+ expect(result.ok).toBe(true)
127
+ expect(repo.setStatus).toHaveBeenCalledTimes(3)
128
+ expect(repo.setStatus.mock.calls.map((call) => call[1])).toEqual([
129
+ 'confirmed',
130
+ 'executing',
131
+ 'confirmed',
132
+ ])
133
+ expect(result.executionResult).toEqual({
134
+ recordId: 'p-1',
135
+ commandName: 'catalog.product.update',
136
+ })
137
+ expect(emitEvent).toHaveBeenCalledTimes(1)
138
+ const [emittedId, emittedPayload] = emitEvent.mock.calls[0] as [
139
+ 'ai.action.confirmed',
140
+ AiActionConfirmedPayload,
141
+ ]
142
+ expect(emittedId).toBe(PENDING_ACTION_CONFIRMED_EVENT_ID)
143
+ expect(emittedPayload).toMatchObject({
144
+ pendingActionId: 'pa_1',
145
+ agentId: 'catalog.merchandising_assistant',
146
+ toolName: 'catalog.update_product',
147
+ status: 'confirmed',
148
+ tenantId: 'tenant-1',
149
+ organizationId: 'org-1',
150
+ userId: 'user-1',
151
+ resolvedByUserId: 'user-1',
152
+ executionResult: {
153
+ recordId: 'p-1',
154
+ commandName: 'catalog.product.update',
155
+ },
156
+ })
157
+ expect(typeof emittedPayload.resolvedAt).toBe('string')
158
+ })
159
+
160
+ it('transitions pending → confirmed → executing → failed on handler throw and emits typed failure payload', async () => {
161
+ const repo = makeRepoStub(makeAction())
162
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
163
+ const throwingTool = makeTool({
164
+ handler: async () => {
165
+ throw new Error('db constraint')
166
+ },
167
+ })
168
+ const result = await executePendingActionConfirm({
169
+ action: makeAction(),
170
+ agent: makeAgent(),
171
+ tool: throwingTool,
172
+ ctx: makeCtx(),
173
+ repo: repo as unknown as never,
174
+ emitEvent,
175
+ })
176
+ expect(result.ok).toBe(false)
177
+ expect(repo.setStatus.mock.calls.map((call) => call[1])).toEqual([
178
+ 'confirmed',
179
+ 'executing',
180
+ 'failed',
181
+ ])
182
+ expect(result.executionResult.error).toMatchObject({ code: 'handler_error', message: 'db constraint' })
183
+ expect(emitEvent).toHaveBeenCalledTimes(1)
184
+ const [emittedId, emittedPayload] = emitEvent.mock.calls[0] as [
185
+ 'ai.action.confirmed',
186
+ AiActionConfirmedPayload,
187
+ ]
188
+ expect(emittedId).toBe(PENDING_ACTION_CONFIRMED_EVENT_ID)
189
+ expect(emittedPayload.status).toBe('failed')
190
+ expect(emittedPayload.executionResult).toMatchObject({
191
+ error: { code: 'handler_error', message: 'db constraint' },
192
+ })
193
+ })
194
+
195
+ it('idempotent: calling twice on already-confirmed row returns prior result without re-executing', async () => {
196
+ const priorResult = { recordId: 'p-1', commandName: 'catalog.product.update' }
197
+ const repo = makeRepoStub(
198
+ makeAction({
199
+ status: 'confirmed' as never,
200
+ executionResult: priorResult as never,
201
+ }),
202
+ )
203
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
204
+ const handlerSpy = jest.fn(async () => ({ recordId: 'p-2' }))
205
+ const result = await executePendingActionConfirm({
206
+ action: makeAction({
207
+ status: 'confirmed' as never,
208
+ executionResult: priorResult as never,
209
+ }),
210
+ agent: makeAgent(),
211
+ tool: makeTool({ handler: handlerSpy }),
212
+ ctx: makeCtx(),
213
+ repo: repo as unknown as never,
214
+ emitEvent,
215
+ })
216
+ expect(result.ok).toBe(true)
217
+ expect(result.executionResult).toEqual(priorResult)
218
+ expect(handlerSpy).not.toHaveBeenCalled()
219
+ expect(repo.setStatus).not.toHaveBeenCalled()
220
+ expect(emitEvent).not.toHaveBeenCalled()
221
+ })
222
+
223
+ it('carries partial-stale failedRecords[] onto the confirmed row', async () => {
224
+ const repo = makeRepoStub(makeAction())
225
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
226
+ const failed = [
227
+ { recordId: 'r-2', error: { code: 'stale_version', message: 'x' } },
228
+ ]
229
+ const result = await executePendingActionConfirm({
230
+ action: makeAction(),
231
+ agent: makeAgent(),
232
+ tool: makeTool(),
233
+ ctx: makeCtx(),
234
+ repo: repo as unknown as never,
235
+ emitEvent,
236
+ failedRecords: failed,
237
+ })
238
+ expect(result.ok).toBe(true)
239
+ const firstCallExtra = repo.setStatus.mock.calls[0][3]
240
+ expect(firstCallExtra).toMatchObject({ failedRecords: failed })
241
+ })
242
+
243
+ it('Step 5.18 — batch handler returns per-record failures: merged into row.failedRecords[]', async () => {
244
+ const repo = makeRepoStub(makeAction({ toolName: 'catalog.bulk_update_products' }))
245
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
246
+ const batchTool = makeTool({
247
+ name: 'catalog.bulk_update_products',
248
+ handler: async () => ({
249
+ commandName: 'catalog.products.update',
250
+ records: [
251
+ { recordId: 'p-1', status: 'updated', before: { title: 'A' }, after: { title: 'A*' } },
252
+ { recordId: 'p-2', status: 'updated', before: { title: 'B' }, after: { title: 'B*' } },
253
+ {
254
+ recordId: 'p-3',
255
+ status: 'failed',
256
+ before: { title: 'C' },
257
+ after: null,
258
+ error: { code: 'command_failed', message: 'db constraint' },
259
+ },
260
+ ],
261
+ failedRecordIds: ['p-3'],
262
+ }),
263
+ })
264
+ const result = await executePendingActionConfirm({
265
+ action: makeAction({ toolName: 'catalog.bulk_update_products' }),
266
+ agent: makeAgent(),
267
+ tool: batchTool,
268
+ ctx: makeCtx(),
269
+ repo: repo as unknown as never,
270
+ emitEvent,
271
+ })
272
+ expect(result.ok).toBe(true)
273
+ expect(repo.setStatus.mock.calls.map((call) => call[1])).toEqual([
274
+ 'confirmed',
275
+ 'executing',
276
+ 'confirmed',
277
+ ])
278
+ const finalExtra = repo.setStatus.mock.calls[2][3] as Record<string, unknown>
279
+ expect(finalExtra.failedRecords).toEqual([
280
+ { recordId: 'p-3', error: { code: 'command_failed', message: 'db constraint' } },
281
+ ])
282
+ expect(repo.current.failedRecords).toEqual([
283
+ { recordId: 'p-3', error: { code: 'command_failed', message: 'db constraint' } },
284
+ ])
285
+ expect(emitEvent).toHaveBeenCalledTimes(1)
286
+ const [, emittedPayload] = emitEvent.mock.calls[0] as [
287
+ 'ai.action.confirmed',
288
+ AiActionConfirmedPayload,
289
+ ]
290
+ expect(emittedPayload.failedRecords).toEqual([
291
+ { recordId: 'p-3', error: { code: 'command_failed', message: 'db constraint' } },
292
+ ])
293
+ })
294
+
295
+ it('Step 5.18 — partial-stale + handler failure merged into one failedRecords[] list', async () => {
296
+ const repo = makeRepoStub(makeAction({ toolName: 'catalog.bulk_update_products' }))
297
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
298
+ const stale = [
299
+ { recordId: 'p-2', error: { code: 'stale_version', message: 'x' } },
300
+ ]
301
+ const batchTool = makeTool({
302
+ name: 'catalog.bulk_update_products',
303
+ handler: async () => ({
304
+ commandName: 'catalog.products.update',
305
+ records: [
306
+ { recordId: 'p-1', status: 'updated', before: { title: 'A' }, after: { title: 'A*' } },
307
+ {
308
+ recordId: 'p-3',
309
+ status: 'failed',
310
+ before: { title: 'C' },
311
+ after: null,
312
+ error: { code: 'command_failed', message: 'db constraint' },
313
+ },
314
+ ],
315
+ failedRecordIds: ['p-3'],
316
+ }),
317
+ })
318
+ const result = await executePendingActionConfirm({
319
+ action: makeAction({ toolName: 'catalog.bulk_update_products' }),
320
+ agent: makeAgent(),
321
+ tool: batchTool,
322
+ ctx: makeCtx(),
323
+ repo: repo as unknown as never,
324
+ emitEvent,
325
+ failedRecords: stale,
326
+ })
327
+ expect(result.ok).toBe(true)
328
+ const finalExtra = repo.setStatus.mock.calls[2][3] as Record<string, unknown>
329
+ const merged = finalExtra.failedRecords as Array<{ recordId: string }>
330
+ expect(merged.map((entry) => entry.recordId).sort()).toEqual(['p-2', 'p-3'])
331
+ })
332
+
333
+ it('Step 5.18 — single-record success: row.failedRecords remains null', async () => {
334
+ const repo = makeRepoStub(makeAction())
335
+ const emitEvent = jest.fn().mockResolvedValue(undefined)
336
+ const result = await executePendingActionConfirm({
337
+ action: makeAction(),
338
+ agent: makeAgent(),
339
+ tool: makeTool(),
340
+ ctx: makeCtx(),
341
+ repo: repo as unknown as never,
342
+ emitEvent,
343
+ })
344
+ expect(result.ok).toBe(true)
345
+ const finalExtra = repo.setStatus.mock.calls[2][3] as Record<string, unknown>
346
+ expect(finalExtra.failedRecords).toBeNull()
347
+ })
348
+ })