@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,333 @@
1
+ // Phase 1 of spec 2026-04-27-ai-tools-api-backed-dry-refactor.md.
2
+ //
3
+ // In-process API operation runner used by typed AI tools to reuse existing
4
+ // API route handlers without HTTP, fetch, or a second RBAC pass. The runner
5
+ // resolves the matched route entry from the generated `apiRoutes` manifest,
6
+ // validates that the route is documented (`openApi`) and that mutation routes
7
+ // declare `requiredFeatures`, asserts the route's required features are
8
+ // covered by the tool definition, then invokes the route handler directly with
9
+ // a synthetic Request that carries a Symbol-keyed trusted-auth envelope so the
10
+ // shared auth resolver short-circuits cookie/JWT/API-key parsing.
11
+ import {
12
+ attachTrustedAuthContext,
13
+ type AuthContext,
14
+ type TrustedAuthContextEnvelope,
15
+ } from '@open-mercato/shared/lib/auth/server'
16
+ import {
17
+ findApiRouteManifestMatch,
18
+ getApiRouteManifests,
19
+ type ApiRouteManifestEntry,
20
+ type RouteMatchParams,
21
+ } from '@open-mercato/shared/modules/registry'
22
+ import { hasAllFeatures } from '@open-mercato/shared/security/features'
23
+ import type { AiToolDefinition, McpToolContext } from './types'
24
+
25
+ export type AiApiHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
26
+
27
+ const MUTATION_METHODS: ReadonlySet<AiApiHttpMethod> = new Set(['POST', 'PUT', 'PATCH', 'DELETE'])
28
+
29
+ const SYNTHETIC_ORIGIN = 'http://internal.local'
30
+
31
+ export type AiApiOperationRequest = {
32
+ method: AiApiHttpMethod
33
+ path: string
34
+ query?: Record<string, string | number | boolean | null | undefined>
35
+ body?: Record<string, unknown>
36
+ allowFeaturelessMutation?: boolean
37
+ }
38
+
39
+ export type AiApiOperationResponse<T = unknown> = {
40
+ success: boolean
41
+ statusCode: number
42
+ data?: T
43
+ error?: string
44
+ details?: unknown
45
+ }
46
+
47
+ export interface AiToolExecutionContext extends McpToolContext {
48
+ tool: AiToolDefinition
49
+ }
50
+
51
+ export type AiApiOperationRunnerOptions = {
52
+ /** Optional override of the API route manifest (used by tests). */
53
+ apiRoutes?: ApiRouteManifestEntry[]
54
+ /** Custom loader for the API route manifest (used by tests). */
55
+ loadApiRoutes?: () => Promise<ApiRouteManifestEntry[]>
56
+ }
57
+
58
+ export type AiApiOperationRunner = {
59
+ run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>>
60
+ }
61
+
62
+ type ResolvedHandler = (req: Request, ctx?: { params: RouteMatchParams }) => Promise<Response> | Response
63
+
64
+ type LoadedRouteModule = Record<string, unknown>
65
+
66
+ type MethodMetadata = {
67
+ requireAuth?: boolean
68
+ requireFeatures?: string[]
69
+ }
70
+
71
+ function normalizeMethod(method: string): AiApiHttpMethod {
72
+ const upper = method.toUpperCase()
73
+ if (upper === 'GET' || upper === 'POST' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE') {
74
+ return upper
75
+ }
76
+ throw new Error(`Unsupported method "${method}"`)
77
+ }
78
+
79
+ // Exported for unit testing — see __tests__/ai-api-operation-runner.test.ts.
80
+ // `path` arrives from agent tool inputs (LLM-controlled), so trailing-slash
81
+ // stripping is implemented as a linear character-code scan rather than the
82
+ // /\/+$/ regex (CodeQL js/polynomial-redos: regex exhibits polynomial
83
+ // backtracking on long runs of `/`). The loop is O(n) regardless of input.
84
+ export function normalizePath(path: string): string {
85
+ if (typeof path !== 'string' || path.length === 0) return '/'
86
+ const trimmed = path.startsWith('/') ? path : `/${path}`
87
+ let end = trimmed.length
88
+ while (end > 1 && trimmed.charCodeAt(end - 1) === 47 /* '/' */) end--
89
+ return trimmed.slice(0, end)
90
+ }
91
+
92
+ function buildUrl(path: string, query?: AiApiOperationRequest['query']): URL {
93
+ const url = new URL(`${SYNTHETIC_ORIGIN}/api${normalizePath(path)}`)
94
+ if (query) {
95
+ for (const [key, value] of Object.entries(query)) {
96
+ if (value === null || value === undefined) continue
97
+ url.searchParams.append(key, String(value))
98
+ }
99
+ }
100
+ return url
101
+ }
102
+
103
+ function buildAuthEnvelope(ctx: AiToolExecutionContext): TrustedAuthContextEnvelope {
104
+ const userId = ctx.userId
105
+ if (!userId) {
106
+ return { auth: null, status: 'invalid' }
107
+ }
108
+ const auth: AuthContext = {
109
+ sub: userId,
110
+ userId,
111
+ tenantId: ctx.tenantId,
112
+ orgId: ctx.organizationId,
113
+ roles: [],
114
+ isSuperAdmin: ctx.isSuperAdmin,
115
+ }
116
+ return { auth, status: 'authenticated' }
117
+ }
118
+
119
+ function pickHandler(entry: ApiRouteManifestEntry, mod: LoadedRouteModule, method: AiApiHttpMethod): ResolvedHandler | null {
120
+ const direct = mod[method]
121
+ if (typeof direct === 'function') return direct as ResolvedHandler
122
+ if (entry.kind === 'legacy') {
123
+ const fallback = mod.default ?? mod.handler
124
+ if (typeof fallback === 'function') return fallback as ResolvedHandler
125
+ }
126
+ return null
127
+ }
128
+
129
+ function extractMethodMetadata(metadata: unknown, method: AiApiHttpMethod): MethodMetadata | null {
130
+ if (!metadata || typeof metadata !== 'object') return null
131
+ const record = metadata as Record<string, unknown>
132
+ const perMethod = record[method]
133
+ const source: Record<string, unknown> = perMethod && typeof perMethod === 'object'
134
+ ? (perMethod as Record<string, unknown>)
135
+ : record
136
+ const result: MethodMetadata = {}
137
+ if (typeof source.requireAuth === 'boolean') {
138
+ result.requireAuth = source.requireAuth
139
+ }
140
+ if (Array.isArray(source.requireFeatures)) {
141
+ const features = source.requireFeatures.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)
142
+ if (features.length > 0) result.requireFeatures = features
143
+ }
144
+ return result
145
+ }
146
+
147
+ async function readResponseBody(res: Response): Promise<unknown> {
148
+ const contentType = res.headers.get('content-type') ?? ''
149
+ if (contentType.includes('application/json')) {
150
+ try {
151
+ return await res.json()
152
+ } catch {
153
+ return null
154
+ }
155
+ }
156
+ try {
157
+ const text = await res.text()
158
+ if (!text) return null
159
+ try {
160
+ return JSON.parse(text)
161
+ } catch {
162
+ return text
163
+ }
164
+ } catch {
165
+ return null
166
+ }
167
+ }
168
+
169
+ function failure(statusCode: number, error: string, details?: unknown): AiApiOperationResponse {
170
+ const response: AiApiOperationResponse = { success: false, statusCode, error }
171
+ if (details !== undefined) response.details = details
172
+ return response
173
+ }
174
+
175
+ function normalizeError(body: unknown): { error: string; details?: unknown } {
176
+ if (body && typeof body === 'object' && !Array.isArray(body)) {
177
+ const record = body as Record<string, unknown>
178
+ const message = typeof record.error === 'string'
179
+ ? record.error
180
+ : typeof record.message === 'string'
181
+ ? record.message
182
+ : null
183
+ if (message) {
184
+ const { error: _ignored, message: _ignoredMessage, ...rest } = record
185
+ void _ignored
186
+ void _ignoredMessage
187
+ return Object.keys(rest).length > 0 ? { error: message, details: rest } : { error: message }
188
+ }
189
+ }
190
+ if (typeof body === 'string' && body.length > 0) {
191
+ return { error: body }
192
+ }
193
+ return { error: 'Request failed' }
194
+ }
195
+
196
+ export function createAiApiOperationRunner(
197
+ ctx: AiToolExecutionContext,
198
+ options: AiApiOperationRunnerOptions = {},
199
+ ): AiApiOperationRunner {
200
+ let manifestPromise: Promise<ApiRouteManifestEntry[]> | null = null
201
+
202
+ const loadManifest = async (): Promise<ApiRouteManifestEntry[]> => {
203
+ if (options.apiRoutes) return options.apiRoutes
204
+ if (manifestPromise) return manifestPromise
205
+ const loader = options.loadApiRoutes ?? defaultLoadApiRoutes
206
+ manifestPromise = loader()
207
+ try {
208
+ return await manifestPromise
209
+ } catch (error) {
210
+ manifestPromise = null
211
+ throw error
212
+ }
213
+ }
214
+
215
+ return {
216
+ async run<T = unknown>(request: AiApiOperationRequest): Promise<AiApiOperationResponse<T>> {
217
+ let method: AiApiHttpMethod
218
+ try {
219
+ method = normalizeMethod(request.method)
220
+ } catch (error) {
221
+ const message = error instanceof Error ? error.message : 'Invalid method'
222
+ return failure(400, message) as AiApiOperationResponse<T>
223
+ }
224
+ const path = normalizePath(request.path)
225
+
226
+ let routes: ApiRouteManifestEntry[]
227
+ try {
228
+ routes = await loadManifest()
229
+ } catch (error) {
230
+ const message = error instanceof Error ? error.message : 'Failed to load API route manifest'
231
+ return failure(500, `Operation runner manifest unavailable: ${message}`) as AiApiOperationResponse<T>
232
+ }
233
+
234
+ const match = findApiRouteManifestMatch(routes, method, path)
235
+ if (!match) {
236
+ return failure(
237
+ 404,
238
+ `No documented API route matches ${method} ${path}`,
239
+ ) as AiApiOperationResponse<T>
240
+ }
241
+
242
+ let mod: LoadedRouteModule
243
+ try {
244
+ mod = (await match.route.load()) as LoadedRouteModule
245
+ } catch (error) {
246
+ const message = error instanceof Error ? error.message : 'Failed to load route module'
247
+ return failure(500, `Failed to load route module: ${message}`) as AiApiOperationResponse<T>
248
+ }
249
+
250
+ if (!('openApi' in mod) || mod.openApi === undefined || mod.openApi === null) {
251
+ return failure(
252
+ 501,
253
+ `Route ${method} ${path} is undocumented (missing openApi export); refusing to call from AI tool`,
254
+ ) as AiApiOperationResponse<T>
255
+ }
256
+
257
+ const handler = pickHandler(match.route, mod, method)
258
+ if (!handler) {
259
+ return failure(
260
+ 405,
261
+ `Route ${path} does not export a handler for method ${method}`,
262
+ ) as AiApiOperationResponse<T>
263
+ }
264
+
265
+ const methodMetadata = extractMethodMetadata(mod.metadata, method)
266
+ const routeFeatures = methodMetadata?.requireFeatures ?? []
267
+ const isMutation = MUTATION_METHODS.has(method)
268
+
269
+ if (isMutation && routeFeatures.length === 0 && !request.allowFeaturelessMutation) {
270
+ return failure(
271
+ 403,
272
+ `Mutation route ${method} ${path} declares no requiredFeatures; refusing to call without allowFeaturelessMutation opt-in`,
273
+ ) as AiApiOperationResponse<T>
274
+ }
275
+
276
+ const toolFeatures = ctx.tool.requiredFeatures ?? []
277
+ if (routeFeatures.length > 0 && !hasAllFeatures(toolFeatures, routeFeatures)) {
278
+ return failure(
279
+ 403,
280
+ `AI tool "${ctx.tool.name}" requiredFeatures do not cover route ${method} ${path} requiredFeatures`,
281
+ { toolFeatures, routeFeatures },
282
+ ) as AiApiOperationResponse<T>
283
+ }
284
+
285
+ const url = buildUrl(path, request.query)
286
+ const headers = new Headers()
287
+ const requestInit: RequestInit = { method, headers }
288
+ if (request.body !== undefined && method !== 'GET') {
289
+ headers.set('content-type', 'application/json')
290
+ requestInit.body = JSON.stringify(request.body)
291
+ }
292
+
293
+ const syntheticRequest = new Request(url, requestInit)
294
+ attachTrustedAuthContext(syntheticRequest, buildAuthEnvelope(ctx))
295
+
296
+ let response: Response
297
+ try {
298
+ response = await handler(syntheticRequest, { params: match.params })
299
+ } catch (error) {
300
+ const message = error instanceof Error ? error.message : 'Route handler threw'
301
+ return failure(500, message) as AiApiOperationResponse<T>
302
+ }
303
+
304
+ const status = response.status
305
+ const body = await readResponseBody(response)
306
+ if (status >= 200 && status < 300) {
307
+ return {
308
+ success: true,
309
+ statusCode: status,
310
+ data: body as T,
311
+ }
312
+ }
313
+ const normalized = normalizeError(body)
314
+ return {
315
+ success: false,
316
+ statusCode: status,
317
+ error: normalized.error,
318
+ ...(normalized.details !== undefined ? { details: normalized.details } : {}),
319
+ }
320
+ },
321
+ }
322
+ }
323
+
324
+ async function defaultLoadApiRoutes(): Promise<ApiRouteManifestEntry[]> {
325
+ const registered = getApiRouteManifests()
326
+ if (registered.length === 0) {
327
+ throw new Error(
328
+ 'No API route manifest registered. Call registerApiRouteManifests(...) at app bootstrap or pass apiRoutes/loadApiRoutes to createAiApiOperationRunner.',
329
+ )
330
+ }
331
+ return registered
332
+ }
333
+