@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,142 @@
1
+ import { NextResponse, type NextRequest } from 'next/server'
2
+ import { z } from 'zod'
3
+ import type { EntityManager } from '@mikro-orm/postgresql'
4
+ import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
5
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
6
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
7
+ import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
8
+ import { AiPendingActionRepository } from '../../../../data/repositories/AiPendingActionRepository'
9
+ import { hasRequiredFeatures } from '../../../../lib/auth'
10
+ import { serializePendingActionForClient } from '../../../../lib/pending-action-client'
11
+
12
+ /**
13
+ * GET `/api/ai/actions/:id` — reconnect/polling endpoint for the Phase 3 WS-C
14
+ * mutation approval gate (spec §9, Step 5.7).
15
+ *
16
+ * When the chat UI bounces (reload, tab switch, SSE reconnect) it carries a
17
+ * `pendingActionId` from an earlier `mutation-preview-card` UI part and needs
18
+ * to re-hydrate the pending row's current state. This route is the authoritative
19
+ * read-side; the confirm/cancel routes (Steps 5.8 / 5.9) use the same
20
+ * whitelist serializer so the UI always sees the same shape.
21
+ */
22
+
23
+ const REQUIRED_FEATURE = 'ai_assistant.view'
24
+
25
+ const idParamSchema = z.object({
26
+ id: z
27
+ .string()
28
+ .trim()
29
+ .min(1, 'id must be a non-empty string')
30
+ .max(128, 'id exceeds the maximum length of 128 characters'),
31
+ })
32
+
33
+ export const openApi: OpenApiRouteDoc = {
34
+ tag: 'AI Assistant',
35
+ summary: 'Pending action (mutation approval gate) read-side',
36
+ methods: {
37
+ GET: {
38
+ operationId: 'aiAssistantGetPendingAction',
39
+ summary: 'Fetch the current state of an AI pending action by id.',
40
+ description:
41
+ 'Returns the tenant-scoped {@link AiPendingAction} addressed by `:id`. Powers the ' +
42
+ 'chat UI reconnect/polling path: after a page reload or SSE reconnect the client ' +
43
+ 'carries the `pendingActionId` from an earlier `mutation-preview-card` UI part and ' +
44
+ 'calls this route to re-hydrate the card. Server-internal fields (`normalizedInput`, ' +
45
+ '`createdByUserId`, `idempotencyKey`) are stripped by a whitelist serializer. ' +
46
+ 'Enforces tenant/org scoping via the repository.',
47
+ responses: [
48
+ {
49
+ status: 200,
50
+ description:
51
+ 'Serialized pending action. Never includes normalizedInput, createdByUserId, or idempotencyKey.',
52
+ mediaType: 'application/json',
53
+ },
54
+ ],
55
+ errors: [
56
+ { status: 401, description: 'Unauthenticated caller.' },
57
+ { status: 403, description: 'Caller lacks the `ai_assistant.view` feature.' },
58
+ { status: 404, description: 'No pending action with the given id is accessible to the caller.' },
59
+ { status: 500, description: 'Internal runtime failure.' },
60
+ ],
61
+ },
62
+ },
63
+ }
64
+
65
+ export const metadata = {
66
+ GET: { requireAuth: true, requireFeatures: [REQUIRED_FEATURE] },
67
+ }
68
+
69
+ interface RouteContext {
70
+ params: Promise<{ id: string }>
71
+ }
72
+
73
+ function jsonError(
74
+ status: number,
75
+ message: string,
76
+ code: string,
77
+ extra?: Record<string, unknown>,
78
+ ): NextResponse {
79
+ return NextResponse.json({ error: message, code, ...(extra ?? {}) }, { status })
80
+ }
81
+
82
+ export async function GET(req: NextRequest, context: RouteContext): Promise<Response> {
83
+ const auth = await getAuthFromRequest(req)
84
+ if (!auth) {
85
+ return jsonError(401, 'Unauthorized', 'unauthenticated')
86
+ }
87
+
88
+ const rawParams = await context.params
89
+ const paramResult = idParamSchema.safeParse(rawParams)
90
+ if (!paramResult.success) {
91
+ return jsonError(400, 'Invalid pending action id.', 'validation_error', {
92
+ issues: paramResult.error.issues,
93
+ })
94
+ }
95
+ const pendingActionId = paramResult.data.id
96
+
97
+ try {
98
+ const container = await createRequestContainer()
99
+ const rbacService = container.resolve<RbacService>('rbacService')
100
+ const acl = await rbacService.loadAcl(auth.sub, {
101
+ tenantId: auth.tenantId,
102
+ organizationId: auth.orgId,
103
+ })
104
+
105
+ if (!hasRequiredFeatures([REQUIRED_FEATURE], acl.features, acl.isSuperAdmin, rbacService)) {
106
+ return jsonError(403, `Caller lacks required feature "${REQUIRED_FEATURE}".`, 'forbidden')
107
+ }
108
+
109
+ if (!auth.tenantId) {
110
+ return jsonError(
111
+ 404,
112
+ `No pending action "${pendingActionId}" accessible to the caller.`,
113
+ 'pending_action_not_found',
114
+ )
115
+ }
116
+
117
+ const em = container.resolve<EntityManager>('em')
118
+ const repo = new AiPendingActionRepository(em)
119
+ const row = await repo.getById(pendingActionId, {
120
+ tenantId: auth.tenantId,
121
+ organizationId: auth.orgId ?? null,
122
+ userId: auth.sub,
123
+ })
124
+
125
+ if (!row) {
126
+ return jsonError(
127
+ 404,
128
+ `No pending action "${pendingActionId}" accessible to the caller.`,
129
+ 'pending_action_not_found',
130
+ )
131
+ }
132
+
133
+ return NextResponse.json(serializePendingActionForClient(row))
134
+ } catch (error) {
135
+ console.error('[AI Pending Action GET] Failure:', error)
136
+ return jsonError(
137
+ 500,
138
+ error instanceof Error ? error.message : 'Failed to load pending action.',
139
+ 'internal_error',
140
+ )
141
+ }
142
+ }
@@ -0,0 +1,367 @@
1
+ import type { AiAgentDefinition } from '../../../../../../lib/ai-agent-definition'
2
+ import {
3
+ resetAgentRegistryForTests,
4
+ seedAgentRegistryForTests,
5
+ } from '../../../../../../lib/agent-registry'
6
+
7
+ const authMock = jest.fn()
8
+ const loadAclMock = jest.fn()
9
+ const createRequestContainerMock = jest.fn()
10
+ const repoGetMock = jest.fn()
11
+ const repoSetMock = jest.fn()
12
+ const repoClearMock = jest.fn()
13
+
14
+ jest.mock('@open-mercato/shared/lib/auth/server', () => ({
15
+ getAuthFromRequest: (...args: unknown[]) => authMock(...args),
16
+ }))
17
+
18
+ jest.mock('@open-mercato/shared/lib/di/container', () => ({
19
+ createRequestContainer: (...args: unknown[]) => createRequestContainerMock(...args),
20
+ }))
21
+
22
+ jest.mock('../../../../../../data/repositories/AiAgentMutationPolicyOverrideRepository', () => ({
23
+ AiAgentMutationPolicyOverrideRepository: jest.fn().mockImplementation(() => ({
24
+ get: repoGetMock,
25
+ set: repoSetMock,
26
+ clear: repoClearMock,
27
+ })),
28
+ }))
29
+
30
+ import { DELETE, GET, POST } from '../route'
31
+
32
+ function makeAgent(
33
+ overrides: Partial<AiAgentDefinition> & Pick<AiAgentDefinition, 'id' | 'moduleId'>,
34
+ ): AiAgentDefinition {
35
+ return {
36
+ label: `${overrides.id} label`,
37
+ description: `${overrides.id} description`,
38
+ systemPrompt: 'You are a test agent.',
39
+ allowedTools: [],
40
+ ...overrides,
41
+ }
42
+ }
43
+
44
+ function buildRequest(body: unknown, method: 'GET' | 'POST' | 'DELETE' = 'POST'): Request {
45
+ return new Request(
46
+ 'http://localhost/api/ai_assistant/ai/agents/catalog.assistant/mutation-policy',
47
+ {
48
+ method,
49
+ headers: { 'content-type': 'application/json' },
50
+ body: method === 'POST' ? JSON.stringify(body) : undefined,
51
+ },
52
+ )
53
+ }
54
+
55
+ function buildParams(agentId: string) {
56
+ return { params: Promise.resolve({ agentId }) }
57
+ }
58
+
59
+ describe('mutation-policy route (Step 5.4)', () => {
60
+ let consoleErrorSpy: jest.SpyInstance
61
+
62
+ beforeEach(() => {
63
+ jest.clearAllMocks()
64
+ resetAgentRegistryForTests()
65
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
66
+ authMock.mockResolvedValue({
67
+ sub: 'user-1',
68
+ tenantId: 'tenant-1',
69
+ orgId: 'org-1',
70
+ })
71
+ loadAclMock.mockResolvedValue({
72
+ features: ['ai_assistant.view', 'ai_assistant.settings.manage'],
73
+ isSuperAdmin: false,
74
+ })
75
+ createRequestContainerMock.mockResolvedValue({
76
+ resolve: (name: string) => {
77
+ if (name === 'rbacService') {
78
+ return {
79
+ loadAcl: loadAclMock,
80
+ hasAllFeatures: (required: string[], granted: string[]) =>
81
+ required.every((feature) => granted.includes(feature)),
82
+ }
83
+ }
84
+ if (name === 'em') {
85
+ return {}
86
+ }
87
+ return null
88
+ },
89
+ })
90
+ repoGetMock.mockResolvedValue(null)
91
+ repoSetMock.mockImplementation(async (input: any) => ({
92
+ id: 'row-1',
93
+ agentId: input.agentId,
94
+ mutationPolicy: input.mutationPolicy,
95
+ notes: input.notes ?? null,
96
+ createdByUserId: null,
97
+ createdAt: new Date('2026-04-18T00:00:00Z'),
98
+ updatedAt: new Date('2026-04-18T00:00:01Z'),
99
+ }))
100
+ repoClearMock.mockResolvedValue(true)
101
+ })
102
+
103
+ afterEach(() => {
104
+ consoleErrorSpy.mockRestore()
105
+ })
106
+
107
+ afterAll(() => {
108
+ resetAgentRegistryForTests()
109
+ })
110
+
111
+ describe('GET', () => {
112
+ it('returns 401 when unauthenticated', async () => {
113
+ authMock.mockResolvedValueOnce(null)
114
+ const response = await GET(
115
+ buildRequest(null, 'GET') as any,
116
+ buildParams('catalog.assistant'),
117
+ )
118
+ expect(response.status).toBe(401)
119
+ })
120
+
121
+ it('returns 404 for an unknown agent id', async () => {
122
+ seedAgentRegistryForTests([
123
+ makeAgent({ id: 'catalog.assistant', moduleId: 'catalog' }),
124
+ ])
125
+ const response = await GET(
126
+ buildRequest(null, 'GET') as any,
127
+ buildParams('catalog.missing'),
128
+ )
129
+ expect(response.status).toBe(404)
130
+ const json = await response.json()
131
+ expect(json.code).toBe('agent_unknown')
132
+ })
133
+
134
+ it('returns { codeDeclared, override: null } when no override exists', async () => {
135
+ seedAgentRegistryForTests([
136
+ makeAgent({
137
+ id: 'catalog.assistant',
138
+ moduleId: 'catalog',
139
+ mutationPolicy: 'confirm-required',
140
+ }),
141
+ ])
142
+ repoGetMock.mockResolvedValueOnce(null)
143
+
144
+ const response = await GET(
145
+ buildRequest(null, 'GET') as any,
146
+ buildParams('catalog.assistant'),
147
+ )
148
+ expect(response.status).toBe(200)
149
+ const json = await response.json()
150
+ expect(json.agentId).toBe('catalog.assistant')
151
+ expect(json.codeDeclared).toBe('confirm-required')
152
+ expect(json.override).toBeNull()
153
+ })
154
+
155
+ it('returns serialized override when one exists', async () => {
156
+ seedAgentRegistryForTests([
157
+ makeAgent({
158
+ id: 'catalog.assistant',
159
+ moduleId: 'catalog',
160
+ mutationPolicy: 'confirm-required',
161
+ }),
162
+ ])
163
+ repoGetMock.mockResolvedValueOnce({
164
+ id: 'row-1',
165
+ agentId: 'catalog.assistant',
166
+ mutationPolicy: 'read-only',
167
+ notes: 'lock it',
168
+ createdByUserId: 'user-1',
169
+ createdAt: new Date('2026-04-17T00:00:00Z'),
170
+ updatedAt: new Date('2026-04-18T00:00:00Z'),
171
+ })
172
+
173
+ const response = await GET(
174
+ buildRequest(null, 'GET') as any,
175
+ buildParams('catalog.assistant'),
176
+ )
177
+ expect(response.status).toBe(200)
178
+ const json = await response.json()
179
+ expect(json.codeDeclared).toBe('confirm-required')
180
+ expect(json.override.mutationPolicy).toBe('read-only')
181
+ })
182
+ })
183
+
184
+ describe('POST', () => {
185
+ it('returns 401 when unauthenticated', async () => {
186
+ authMock.mockResolvedValueOnce(null)
187
+ const response = await POST(
188
+ buildRequest({ mutationPolicy: 'read-only' }) as any,
189
+ buildParams('catalog.assistant'),
190
+ )
191
+ expect(response.status).toBe(401)
192
+ })
193
+
194
+ it('returns 403 when the caller lacks ai_assistant.settings.manage', async () => {
195
+ loadAclMock.mockResolvedValueOnce({
196
+ features: ['ai_assistant.view'],
197
+ isSuperAdmin: false,
198
+ })
199
+ seedAgentRegistryForTests([
200
+ makeAgent({
201
+ id: 'catalog.assistant',
202
+ moduleId: 'catalog',
203
+ mutationPolicy: 'confirm-required',
204
+ }),
205
+ ])
206
+
207
+ const response = await POST(
208
+ buildRequest({ mutationPolicy: 'read-only' }) as any,
209
+ buildParams('catalog.assistant'),
210
+ )
211
+ expect(response.status).toBe(403)
212
+ const json = await response.json()
213
+ expect(json.code).toBe('forbidden')
214
+ })
215
+
216
+ it('returns 404 for an unknown agent id', async () => {
217
+ seedAgentRegistryForTests([
218
+ makeAgent({ id: 'catalog.assistant', moduleId: 'catalog' }),
219
+ ])
220
+ const response = await POST(
221
+ buildRequest({ mutationPolicy: 'read-only' }) as any,
222
+ buildParams('catalog.missing'),
223
+ )
224
+ expect(response.status).toBe(404)
225
+ })
226
+
227
+ it('returns 400 with validation_error when body is malformed', async () => {
228
+ seedAgentRegistryForTests([
229
+ makeAgent({ id: 'catalog.assistant', moduleId: 'catalog' }),
230
+ ])
231
+ const response = await POST(
232
+ buildRequest({ mutationPolicy: 'not-a-valid-policy' }) as any,
233
+ buildParams('catalog.assistant'),
234
+ )
235
+ expect(response.status).toBe(400)
236
+ const json = await response.json()
237
+ expect(json.code).toBe('validation_error')
238
+ })
239
+
240
+ it('rejects escalation (read-only agent → confirm-required override) with escalation_not_allowed', async () => {
241
+ seedAgentRegistryForTests([
242
+ makeAgent({
243
+ id: 'catalog.assistant',
244
+ moduleId: 'catalog',
245
+ mutationPolicy: 'read-only',
246
+ }),
247
+ ])
248
+ const response = await POST(
249
+ buildRequest({ mutationPolicy: 'confirm-required' }) as any,
250
+ buildParams('catalog.assistant'),
251
+ )
252
+ expect(response.status).toBe(400)
253
+ const json = await response.json()
254
+ expect(json.code).toBe('escalation_not_allowed')
255
+ expect(json.codeDeclared).toBe('read-only')
256
+ expect(json.requested).toBe('confirm-required')
257
+ expect(repoSetMock).not.toHaveBeenCalled()
258
+ })
259
+
260
+ it('rejects escalation (destructive-confirm-required agent → confirm-required override)', async () => {
261
+ seedAgentRegistryForTests([
262
+ makeAgent({
263
+ id: 'catalog.assistant',
264
+ moduleId: 'catalog',
265
+ mutationPolicy: 'destructive-confirm-required',
266
+ }),
267
+ ])
268
+ const response = await POST(
269
+ buildRequest({ mutationPolicy: 'confirm-required' }) as any,
270
+ buildParams('catalog.assistant'),
271
+ )
272
+ expect(response.status).toBe(400)
273
+ const json = await response.json()
274
+ expect(json.code).toBe('escalation_not_allowed')
275
+ })
276
+
277
+ it('accepts a downgrade (confirm-required → read-only) with 200', async () => {
278
+ seedAgentRegistryForTests([
279
+ makeAgent({
280
+ id: 'catalog.assistant',
281
+ moduleId: 'catalog',
282
+ mutationPolicy: 'confirm-required',
283
+ }),
284
+ ])
285
+ const response = await POST(
286
+ buildRequest({ mutationPolicy: 'read-only' }) as any,
287
+ buildParams('catalog.assistant'),
288
+ )
289
+ expect(response.status).toBe(200)
290
+ const json = await response.json()
291
+ expect(json.ok).toBe(true)
292
+ expect(json.override.mutationPolicy).toBe('read-only')
293
+ expect(json.codeDeclared).toBe('confirm-required')
294
+ expect(repoSetMock).toHaveBeenCalledTimes(1)
295
+ })
296
+
297
+ it('accepts a same-level save (confirm-required → confirm-required) as a no-op override', async () => {
298
+ seedAgentRegistryForTests([
299
+ makeAgent({
300
+ id: 'catalog.assistant',
301
+ moduleId: 'catalog',
302
+ mutationPolicy: 'confirm-required',
303
+ }),
304
+ ])
305
+ const response = await POST(
306
+ buildRequest({ mutationPolicy: 'confirm-required' }) as any,
307
+ buildParams('catalog.assistant'),
308
+ )
309
+ expect(response.status).toBe(200)
310
+ })
311
+ })
312
+
313
+ describe('DELETE', () => {
314
+ it('returns 401 when unauthenticated', async () => {
315
+ authMock.mockResolvedValueOnce(null)
316
+ const response = await DELETE(
317
+ buildRequest(null, 'DELETE') as any,
318
+ buildParams('catalog.assistant'),
319
+ )
320
+ expect(response.status).toBe(401)
321
+ })
322
+
323
+ it('returns 403 when the caller lacks ai_assistant.settings.manage', async () => {
324
+ loadAclMock.mockResolvedValueOnce({
325
+ features: ['ai_assistant.view'],
326
+ isSuperAdmin: false,
327
+ })
328
+ seedAgentRegistryForTests([
329
+ makeAgent({ id: 'catalog.assistant', moduleId: 'catalog' }),
330
+ ])
331
+ const response = await DELETE(
332
+ buildRequest(null, 'DELETE') as any,
333
+ buildParams('catalog.assistant'),
334
+ )
335
+ expect(response.status).toBe(403)
336
+ })
337
+
338
+ it('clears the override and subsequent GET returns override: null', async () => {
339
+ seedAgentRegistryForTests([
340
+ makeAgent({
341
+ id: 'catalog.assistant',
342
+ moduleId: 'catalog',
343
+ mutationPolicy: 'confirm-required',
344
+ }),
345
+ ])
346
+ repoClearMock.mockResolvedValueOnce(true)
347
+
348
+ const delResponse = await DELETE(
349
+ buildRequest(null, 'DELETE') as any,
350
+ buildParams('catalog.assistant'),
351
+ )
352
+ expect(delResponse.status).toBe(200)
353
+ const delJson = await delResponse.json()
354
+ expect(delJson.ok).toBe(true)
355
+ expect(delJson.cleared).toBe(true)
356
+ expect(delJson.override).toBeNull()
357
+
358
+ repoGetMock.mockResolvedValueOnce(null)
359
+ const getResponse = await GET(
360
+ buildRequest(null, 'GET') as any,
361
+ buildParams('catalog.assistant'),
362
+ )
363
+ const getJson = await getResponse.json()
364
+ expect(getJson.override).toBeNull()
365
+ })
366
+ })
367
+ })