@lenne.tech/nest-server 11.25.6 → 11.26.0

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 (335) hide show
  1. package/.claude/rules/configurable-features.md +2 -0
  2. package/CLAUDE.md +18 -0
  3. package/FRAMEWORK-API.md +48 -1
  4. package/dist/config.env.js +35 -1
  5. package/dist/config.env.js.map +1 -1
  6. package/dist/core/common/helpers/config.helper.js +2 -2
  7. package/dist/core/common/helpers/config.helper.js.map +1 -1
  8. package/dist/core/common/interceptors/check-security.interceptor.js +9 -2
  9. package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
  10. package/dist/core/common/interfaces/server-options.interface.d.ts +89 -0
  11. package/dist/core/modules/ai/core-ai-mcp.controller.d.ts +21 -0
  12. package/dist/core/modules/ai/core-ai-mcp.controller.js +191 -0
  13. package/dist/core/modules/ai/core-ai-mcp.controller.js.map +1 -0
  14. package/dist/core/modules/ai/core-ai.controller.d.ts +90 -0
  15. package/dist/core/modules/ai/core-ai.controller.js +576 -0
  16. package/dist/core/modules/ai/core-ai.controller.js.map +1 -0
  17. package/dist/core/modules/ai/core-ai.module.d.ts +43 -0
  18. package/dist/core/modules/ai/core-ai.module.js +164 -0
  19. package/dist/core/modules/ai/core-ai.module.js.map +1 -0
  20. package/dist/core/modules/ai/core-ai.resolver.d.ts +84 -0
  21. package/dist/core/modules/ai/core-ai.resolver.js +530 -0
  22. package/dist/core/modules/ai/core-ai.resolver.js.map +1 -0
  23. package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.d.ts +7 -0
  24. package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js +16 -0
  25. package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js.map +1 -0
  26. package/dist/core/modules/ai/hooks/ai-hook.base.d.ts +10 -0
  27. package/dist/core/modules/ai/hooks/ai-hook.base.js +30 -0
  28. package/dist/core/modules/ai/hooks/ai-hook.base.js.map +1 -0
  29. package/dist/core/modules/ai/hooks/ai-hook.registry.d.ts +22 -0
  30. package/dist/core/modules/ai/hooks/ai-hook.registry.js +98 -0
  31. package/dist/core/modules/ai/hooks/ai-hook.registry.js.map +1 -0
  32. package/dist/core/modules/ai/index.d.ts +69 -0
  33. package/dist/core/modules/ai/index.js +86 -0
  34. package/dist/core/modules/ai/index.js.map +1 -0
  35. package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.d.ts +5 -0
  36. package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.js +43 -0
  37. package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.js.map +1 -0
  38. package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.d.ts +7 -0
  39. package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.js +74 -0
  40. package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.js.map +1 -0
  41. package/dist/core/modules/ai/inputs/core-ai-connection-create.input.d.ts +6 -0
  42. package/dist/core/modules/ai/inputs/core-ai-connection-create.input.js +49 -0
  43. package/dist/core/modules/ai/inputs/core-ai-connection-create.input.js.map +1 -0
  44. package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.d.ts +6 -0
  45. package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.js +60 -0
  46. package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.js.map +1 -0
  47. package/dist/core/modules/ai/inputs/core-ai-connection.input.d.ts +23 -0
  48. package/dist/core/modules/ai/inputs/core-ai-connection.input.js +229 -0
  49. package/dist/core/modules/ai/inputs/core-ai-connection.input.js.map +1 -0
  50. package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.d.ts +3 -0
  51. package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.js +21 -0
  52. package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.js.map +1 -0
  53. package/dist/core/modules/ai/inputs/core-ai-conversation.input.d.ts +4 -0
  54. package/dist/core/modules/ai/inputs/core-ai-conversation.input.js +42 -0
  55. package/dist/core/modules/ai/inputs/core-ai-conversation.input.js.map +1 -0
  56. package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.d.ts +10 -0
  57. package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.js +74 -0
  58. package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.js.map +1 -0
  59. package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.d.ts +5 -0
  60. package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.js +41 -0
  61. package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.js.map +1 -0
  62. package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.d.ts +6 -0
  63. package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.js +63 -0
  64. package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.js.map +1 -0
  65. package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.d.ts +10 -0
  66. package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.js +70 -0
  67. package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.js.map +1 -0
  68. package/dist/core/modules/ai/inputs/core-ai-prompt.input.d.ts +18 -0
  69. package/dist/core/modules/ai/inputs/core-ai-prompt.input.js +131 -0
  70. package/dist/core/modules/ai/inputs/core-ai-prompt.input.js.map +1 -0
  71. package/dist/core/modules/ai/inputs/core-ai-slot-create.input.d.ts +5 -0
  72. package/dist/core/modules/ai/inputs/core-ai-slot-create.input.js +41 -0
  73. package/dist/core/modules/ai/inputs/core-ai-slot-create.input.js.map +1 -0
  74. package/dist/core/modules/ai/inputs/core-ai-slot-update.input.d.ts +9 -0
  75. package/dist/core/modules/ai/inputs/core-ai-slot-update.input.js +91 -0
  76. package/dist/core/modules/ai/inputs/core-ai-slot-update.input.js.map +1 -0
  77. package/dist/core/modules/ai/interfaces/ai-hook.interface.d.ts +28 -0
  78. package/dist/core/modules/ai/interfaces/ai-hook.interface.js +3 -0
  79. package/dist/core/modules/ai/interfaces/ai-hook.interface.js.map +1 -0
  80. package/dist/core/modules/ai/interfaces/ai-placeholder.interface.d.ts +21 -0
  81. package/dist/core/modules/ai/interfaces/ai-placeholder.interface.js +3 -0
  82. package/dist/core/modules/ai/interfaces/ai-placeholder.interface.js.map +1 -0
  83. package/dist/core/modules/ai/interfaces/ai-tool.interface.d.ts +30 -0
  84. package/dist/core/modules/ai/interfaces/ai-tool.interface.js +3 -0
  85. package/dist/core/modules/ai/interfaces/ai-tool.interface.js.map +1 -0
  86. package/dist/core/modules/ai/interfaces/llm-provider.interface.d.ts +55 -0
  87. package/dist/core/modules/ai/interfaces/llm-provider.interface.js +3 -0
  88. package/dist/core/modules/ai/interfaces/llm-provider.interface.js.map +1 -0
  89. package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.d.ts +16 -0
  90. package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.js +3 -0
  91. package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.js.map +1 -0
  92. package/dist/core/modules/ai/models/core-ai-action.model.d.ts +6 -0
  93. package/dist/core/modules/ai/models/core-ai-action.model.js +44 -0
  94. package/dist/core/modules/ai/models/core-ai-action.model.js.map +1 -0
  95. package/dist/core/modules/ai/models/core-ai-available-connection.model.d.ts +8 -0
  96. package/dist/core/modules/ai/models/core-ai-available-connection.model.js +53 -0
  97. package/dist/core/modules/ai/models/core-ai-available-connection.model.js.map +1 -0
  98. package/dist/core/modules/ai/models/core-ai-budget-limit.model.d.ts +97 -0
  99. package/dist/core/modules/ai/models/core-ai-budget-limit.model.js +79 -0
  100. package/dist/core/modules/ai/models/core-ai-budget-limit.model.js.map +1 -0
  101. package/dist/core/modules/ai/models/core-ai-connection-preference.model.d.ts +91 -0
  102. package/dist/core/modules/ai/models/core-ai-connection-preference.model.js +67 -0
  103. package/dist/core/modules/ai/models/core-ai-connection-preference.model.js.map +1 -0
  104. package/dist/core/modules/ai/models/core-ai-connection.model.d.ts +200 -0
  105. package/dist/core/modules/ai/models/core-ai-connection.model.js +263 -0
  106. package/dist/core/modules/ai/models/core-ai-connection.model.js.map +1 -0
  107. package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +93 -0
  108. package/dist/core/modules/ai/models/core-ai-conversation.model.js +82 -0
  109. package/dist/core/modules/ai/models/core-ai-conversation.model.js.map +1 -0
  110. package/dist/core/modules/ai/models/core-ai-interaction.model.d.ts +133 -0
  111. package/dist/core/modules/ai/models/core-ai-interaction.model.js +137 -0
  112. package/dist/core/modules/ai/models/core-ai-interaction.model.js.map +1 -0
  113. package/dist/core/modules/ai/models/core-ai-message.model.d.ts +5 -0
  114. package/dist/core/modules/ai/models/core-ai-message.model.js +38 -0
  115. package/dist/core/modules/ai/models/core-ai-message.model.js.map +1 -0
  116. package/dist/core/modules/ai/models/core-ai-mode.model.d.ts +109 -0
  117. package/dist/core/modules/ai/models/core-ai-mode.model.js +100 -0
  118. package/dist/core/modules/ai/models/core-ai-mode.model.js.map +1 -0
  119. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.d.ts +103 -0
  120. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js +89 -0
  121. package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js.map +1 -0
  122. package/dist/core/modules/ai/models/core-ai-prompt.model.d.ts +122 -0
  123. package/dist/core/modules/ai/models/core-ai-prompt.model.js +117 -0
  124. package/dist/core/modules/ai/models/core-ai-prompt.model.js.map +1 -0
  125. package/dist/core/modules/ai/models/core-ai-response.model.d.ts +29 -0
  126. package/dist/core/modules/ai/models/core-ai-response.model.js +105 -0
  127. package/dist/core/modules/ai/models/core-ai-response.model.js.map +1 -0
  128. package/dist/core/modules/ai/models/core-ai-slot.model.d.ts +121 -0
  129. package/dist/core/modules/ai/models/core-ai-slot.model.js +119 -0
  130. package/dist/core/modules/ai/models/core-ai-slot.model.js.map +1 -0
  131. package/dist/core/modules/ai/models/core-ai-tool-grant.model.d.ts +103 -0
  132. package/dist/core/modules/ai/models/core-ai-tool-grant.model.js +88 -0
  133. package/dist/core/modules/ai/models/core-ai-tool-grant.model.js.map +1 -0
  134. package/dist/core/modules/ai/models/core-ai-tool-policy.model.d.ts +122 -0
  135. package/dist/core/modules/ai/models/core-ai-tool-policy.model.js +121 -0
  136. package/dist/core/modules/ai/models/core-ai-tool-policy.model.js.map +1 -0
  137. package/dist/core/modules/ai/models/core-ai-usage-info.model.d.ts +24 -0
  138. package/dist/core/modules/ai/models/core-ai-usage-info.model.js +127 -0
  139. package/dist/core/modules/ai/models/core-ai-usage-info.model.js.map +1 -0
  140. package/dist/core/modules/ai/models/core-ai-usage.model.d.ts +5 -0
  141. package/dist/core/modules/ai/models/core-ai-usage.model.js +38 -0
  142. package/dist/core/modules/ai/models/core-ai-usage.model.js.map +1 -0
  143. package/dist/core/modules/ai/providers/claude-cli.provider.d.ts +16 -0
  144. package/dist/core/modules/ai/providers/claude-cli.provider.js +151 -0
  145. package/dist/core/modules/ai/providers/claude-cli.provider.js.map +1 -0
  146. package/dist/core/modules/ai/providers/llm-provider.factory.d.ts +10 -0
  147. package/dist/core/modules/ai/providers/llm-provider.factory.js +45 -0
  148. package/dist/core/modules/ai/providers/llm-provider.factory.js.map +1 -0
  149. package/dist/core/modules/ai/providers/openai-compatible.provider.d.ts +32 -0
  150. package/dist/core/modules/ai/providers/openai-compatible.provider.js +236 -0
  151. package/dist/core/modules/ai/providers/openai-compatible.provider.js.map +1 -0
  152. package/dist/core/modules/ai/services/ai-crypto.service.d.ts +11 -0
  153. package/dist/core/modules/ai/services/ai-crypto.service.js +84 -0
  154. package/dist/core/modules/ai/services/ai-crypto.service.js.map +1 -0
  155. package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +42 -0
  156. package/dist/core/modules/ai/services/core-ai-budget.service.js +211 -0
  157. package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -0
  158. package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +18 -0
  159. package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +53 -0
  160. package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -0
  161. package/dist/core/modules/ai/services/core-ai-connection-resolver.service.d.ts +55 -0
  162. package/dist/core/modules/ai/services/core-ai-connection-resolver.service.js +177 -0
  163. package/dist/core/modules/ai/services/core-ai-connection-resolver.service.js.map +1 -0
  164. package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +43 -0
  165. package/dist/core/modules/ai/services/core-ai-connection.service.js +272 -0
  166. package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -0
  167. package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +26 -0
  168. package/dist/core/modules/ai/services/core-ai-conversation.service.js +72 -0
  169. package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -0
  170. package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +13 -0
  171. package/dist/core/modules/ai/services/core-ai-interaction.service.js +52 -0
  172. package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -0
  173. package/dist/core/modules/ai/services/core-ai-mcp-client.service.d.ts +51 -0
  174. package/dist/core/modules/ai/services/core-ai-mcp-client.service.js +123 -0
  175. package/dist/core/modules/ai/services/core-ai-mcp-client.service.js.map +1 -0
  176. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.d.ts +68 -0
  177. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js +279 -0
  178. package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js.map +1 -0
  179. package/dist/core/modules/ai/services/core-ai-mcp.service.d.ts +22 -0
  180. package/dist/core/modules/ai/services/core-ai-mcp.service.js +59 -0
  181. package/dist/core/modules/ai/services/core-ai-mcp.service.js.map +1 -0
  182. package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +14 -0
  183. package/dist/core/modules/ai/services/core-ai-mode.service.js +56 -0
  184. package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -0
  185. package/dist/core/modules/ai/services/core-ai-placeholder.registry.d.ts +15 -0
  186. package/dist/core/modules/ai/services/core-ai-placeholder.registry.js +102 -0
  187. package/dist/core/modules/ai/services/core-ai-placeholder.registry.js.map +1 -0
  188. package/dist/core/modules/ai/services/core-ai-prompt-builder.service.d.ts +42 -0
  189. package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js +136 -0
  190. package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js.map +1 -0
  191. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +29 -0
  192. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +98 -0
  193. package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -0
  194. package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +21 -0
  195. package/dist/core/modules/ai/services/core-ai-prompt.service.js +143 -0
  196. package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -0
  197. package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +51 -0
  198. package/dist/core/modules/ai/services/core-ai-slot.service.js +372 -0
  199. package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -0
  200. package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +22 -0
  201. package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +97 -0
  202. package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -0
  203. package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +23 -0
  204. package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +102 -0
  205. package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -0
  206. package/dist/core/modules/ai/services/core-ai.service.d.ts +144 -0
  207. package/dist/core/modules/ai/services/core-ai.service.js +991 -0
  208. package/dist/core/modules/ai/services/core-ai.service.js.map +1 -0
  209. package/dist/core/modules/ai/tools/ai-tool.base.d.ts +15 -0
  210. package/dist/core/modules/ai/tools/ai-tool.base.js +30 -0
  211. package/dist/core/modules/ai/tools/ai-tool.base.js.map +1 -0
  212. package/dist/core/modules/ai/tools/ai-tool.registry.d.ts +19 -0
  213. package/dist/core/modules/ai/tools/ai-tool.registry.js +71 -0
  214. package/dist/core/modules/ai/tools/ai-tool.registry.js.map +1 -0
  215. package/dist/core/modules/ai/tools/ask-user-question.tool.d.ts +38 -0
  216. package/dist/core/modules/ai/tools/ask-user-question.tool.js +65 -0
  217. package/dist/core/modules/ai/tools/ask-user-question.tool.js.map +1 -0
  218. package/dist/core/modules/ai/tools/search-tools.tool.d.ts +24 -0
  219. package/dist/core/modules/ai/tools/search-tools.tool.js +68 -0
  220. package/dist/core/modules/ai/tools/search-tools.tool.js.map +1 -0
  221. package/dist/core/modules/error-code/error-codes.d.ts +81 -0
  222. package/dist/core/modules/error-code/error-codes.js +72 -0
  223. package/dist/core/modules/error-code/error-codes.js.map +1 -1
  224. package/dist/core.module.js +8 -0
  225. package/dist/core.module.js.map +1 -1
  226. package/dist/index.d.ts +1 -0
  227. package/dist/index.js +1 -0
  228. package/dist/index.js.map +1 -1
  229. package/dist/server/modules/ai/ai-tools.module.d.ts +5 -0
  230. package/dist/server/modules/ai/ai-tools.module.js +36 -0
  231. package/dist/server/modules/ai/ai-tools.module.js.map +1 -0
  232. package/dist/server/modules/ai/tools/delete-user.tool.d.ts +30 -0
  233. package/dist/server/modules/ai/tools/delete-user.tool.js +49 -0
  234. package/dist/server/modules/ai/tools/delete-user.tool.js.map +1 -0
  235. package/dist/server/modules/ai/tools/find-users.tool.d.ts +30 -0
  236. package/dist/server/modules/ai/tools/find-users.tool.js +52 -0
  237. package/dist/server/modules/ai/tools/find-users.tool.js.map +1 -0
  238. package/dist/server/modules/ai/tools/get-user.tool.d.ts +26 -0
  239. package/dist/server/modules/ai/tools/get-user.tool.js +48 -0
  240. package/dist/server/modules/ai/tools/get-user.tool.js.map +1 -0
  241. package/dist/server/modules/ai/tools/update-user-job-title.tool.d.ts +32 -0
  242. package/dist/server/modules/ai/tools/update-user-job-title.tool.js +54 -0
  243. package/dist/server/modules/ai/tools/update-user-job-title.tool.js.map +1 -0
  244. package/dist/server/modules/error-code/error-codes.d.ts +9 -0
  245. package/dist/server/server.module.js +2 -0
  246. package/dist/server/server.module.js.map +1 -1
  247. package/dist/tsconfig.build.tsbuildinfo +1 -1
  248. package/docs/REQUEST-LIFECYCLE.md +10 -0
  249. package/migration-guides/11.25.x-to-11.26.0.md +278 -0
  250. package/package.json +2 -1
  251. package/src/config.env.ts +48 -1
  252. package/src/core/common/helpers/config.helper.ts +5 -2
  253. package/src/core/common/interceptors/check-security.interceptor.ts +13 -3
  254. package/src/core/common/interfaces/server-options.interface.ts +312 -0
  255. package/src/core/modules/ai/INTEGRATION-CHECKLIST.md +220 -0
  256. package/src/core/modules/ai/README.md +526 -0
  257. package/src/core/modules/ai/core-ai-mcp.controller.ts +223 -0
  258. package/src/core/modules/ai/core-ai.controller.ts +547 -0
  259. package/src/core/modules/ai/core-ai.module.ts +269 -0
  260. package/src/core/modules/ai/core-ai.resolver.ts +526 -0
  261. package/src/core/modules/ai/helpers/ai-mcp-oauth.helper.ts +35 -0
  262. package/src/core/modules/ai/hooks/ai-hook.base.ts +23 -0
  263. package/src/core/modules/ai/hooks/ai-hook.registry.ts +119 -0
  264. package/src/core/modules/ai/index.ts +70 -0
  265. package/src/core/modules/ai/inputs/core-ai-budget-limit-create.input.ts +27 -0
  266. package/src/core/modules/ai/inputs/core-ai-budget-limit.input.ts +52 -0
  267. package/src/core/modules/ai/inputs/core-ai-connection-create.input.ts +32 -0
  268. package/src/core/modules/ai/inputs/core-ai-connection-preference.input.ts +42 -0
  269. package/src/core/modules/ai/inputs/core-ai-connection.input.ts +235 -0
  270. package/src/core/modules/ai/inputs/core-ai-conversation-create.input.ts +13 -0
  271. package/src/core/modules/ai/inputs/core-ai-conversation.input.ts +33 -0
  272. package/src/core/modules/ai/inputs/core-ai-prompt-create.input.ts +50 -0
  273. package/src/core/modules/ai/inputs/core-ai-prompt-hint-create.input.ts +26 -0
  274. package/src/core/modules/ai/inputs/core-ai-prompt-hint.input.ts +43 -0
  275. package/src/core/modules/ai/inputs/core-ai-prompt-update.input.ts +42 -0
  276. package/src/core/modules/ai/inputs/core-ai-prompt.input.ts +144 -0
  277. package/src/core/modules/ai/inputs/core-ai-slot-create.input.ts +26 -0
  278. package/src/core/modules/ai/inputs/core-ai-slot-update.input.ts +65 -0
  279. package/src/core/modules/ai/interfaces/ai-hook.interface.ts +74 -0
  280. package/src/core/modules/ai/interfaces/ai-placeholder.interface.ts +49 -0
  281. package/src/core/modules/ai/interfaces/ai-tool.interface.ts +112 -0
  282. package/src/core/modules/ai/interfaces/llm-provider.interface.ts +187 -0
  283. package/src/core/modules/ai/interfaces/resolved-ai-connection.interface.ts +55 -0
  284. package/src/core/modules/ai/models/core-ai-action.model.ts +37 -0
  285. package/src/core/modules/ai/models/core-ai-available-connection.model.ts +42 -0
  286. package/src/core/modules/ai/models/core-ai-budget-limit.model.ts +82 -0
  287. package/src/core/modules/ai/models/core-ai-connection-preference.model.ts +72 -0
  288. package/src/core/modules/ai/models/core-ai-connection.model.ts +330 -0
  289. package/src/core/modules/ai/models/core-ai-conversation.model.ts +87 -0
  290. package/src/core/modules/ai/models/core-ai-interaction.model.ts +145 -0
  291. package/src/core/modules/ai/models/core-ai-message.model.ts +29 -0
  292. package/src/core/modules/ai/models/core-ai-mode.model.ts +93 -0
  293. package/src/core/modules/ai/models/core-ai-prompt-hint.model.ts +98 -0
  294. package/src/core/modules/ai/models/core-ai-prompt.model.ts +120 -0
  295. package/src/core/modules/ai/models/core-ai-response.model.ts +119 -0
  296. package/src/core/modules/ai/models/core-ai-slot.model.ts +146 -0
  297. package/src/core/modules/ai/models/core-ai-tool-grant.model.ts +87 -0
  298. package/src/core/modules/ai/models/core-ai-tool-policy.model.ts +115 -0
  299. package/src/core/modules/ai/models/core-ai-usage-info.model.ts +107 -0
  300. package/src/core/modules/ai/models/core-ai-usage.model.ts +29 -0
  301. package/src/core/modules/ai/providers/claude-cli.provider.ts +240 -0
  302. package/src/core/modules/ai/providers/llm-provider.factory.ts +63 -0
  303. package/src/core/modules/ai/providers/openai-compatible.provider.ts +329 -0
  304. package/src/core/modules/ai/services/ai-crypto.service.ts +120 -0
  305. package/src/core/modules/ai/services/core-ai-budget.service.ts +297 -0
  306. package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +74 -0
  307. package/src/core/modules/ai/services/core-ai-connection-resolver.service.ts +308 -0
  308. package/src/core/modules/ai/services/core-ai-connection.service.ts +387 -0
  309. package/src/core/modules/ai/services/core-ai-conversation.service.ts +105 -0
  310. package/src/core/modules/ai/services/core-ai-interaction.service.ts +56 -0
  311. package/src/core/modules/ai/services/core-ai-mcp-client.service.ts +169 -0
  312. package/src/core/modules/ai/services/core-ai-mcp-oauth.service.ts +445 -0
  313. package/src/core/modules/ai/services/core-ai-mcp.service.ts +94 -0
  314. package/src/core/modules/ai/services/core-ai-mode.service.ts +43 -0
  315. package/src/core/modules/ai/services/core-ai-placeholder.registry.ts +123 -0
  316. package/src/core/modules/ai/services/core-ai-prompt-builder.service.ts +228 -0
  317. package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +133 -0
  318. package/src/core/modules/ai/services/core-ai-prompt.service.ts +164 -0
  319. package/src/core/modules/ai/services/core-ai-slot.service.ts +526 -0
  320. package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +107 -0
  321. package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +124 -0
  322. package/src/core/modules/ai/services/core-ai.service.ts +1396 -0
  323. package/src/core/modules/ai/tools/ai-tool.base.ts +46 -0
  324. package/src/core/modules/ai/tools/ai-tool.registry.ts +124 -0
  325. package/src/core/modules/ai/tools/ask-user-question.tool.ts +76 -0
  326. package/src/core/modules/ai/tools/search-tools.tool.ts +70 -0
  327. package/src/core/modules/error-code/error-codes.ts +86 -0
  328. package/src/core.module.ts +12 -0
  329. package/src/index.ts +6 -0
  330. package/src/server/modules/ai/ai-tools.module.ts +33 -0
  331. package/src/server/modules/ai/tools/delete-user.tool.ts +44 -0
  332. package/src/server/modules/ai/tools/find-users.tool.ts +49 -0
  333. package/src/server/modules/ai/tools/get-user.tool.ts +43 -0
  334. package/src/server/modules/ai/tools/update-user-job-title.tool.ts +62 -0
  335. package/src/server/server.module.ts +5 -0
@@ -0,0 +1,26 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+
3
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
4
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
5
+ import { RoleEnum } from '../../../common/enums/role.enum';
6
+ import { CoreAiPromptHintInput } from './core-ai-prompt-hint.input';
7
+
8
+ /**
9
+ * Input to create a learned AI prompt hint manually. `content` and `trigger` are
10
+ * required (the learning loop normally creates these automatically).
11
+ */
12
+ @InputType({ description: 'Input to create a learned AI prompt hint', isAbstract: true })
13
+ @Restricted(RoleEnum.ADMIN)
14
+ export class CoreAiPromptHintCreateInput extends CoreAiPromptHintInput {
15
+ @UnifiedField({
16
+ description: 'Guidance text added to the prompt when approved',
17
+ roles: RoleEnum.ADMIN,
18
+ })
19
+ override content: string = undefined;
20
+
21
+ @UnifiedField({
22
+ description: 'Failure-pattern identifier that produced the hint',
23
+ roles: RoleEnum.ADMIN,
24
+ })
25
+ trigger: string = undefined;
26
+ }
@@ -0,0 +1,43 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+ import { IsIn } from 'class-validator';
3
+
4
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
5
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
6
+ import { RoleEnum } from '../../../common/enums/role.enum';
7
+
8
+ /**
9
+ * Input to update a learned AI prompt hint (admins typically approve/reject or edit).
10
+ */
11
+ @InputType({ description: 'Input to update a learned AI prompt hint', isAbstract: true })
12
+ @Restricted(RoleEnum.ADMIN)
13
+ export class CoreAiPromptHintInput {
14
+ @UnifiedField({
15
+ description: 'Guidance text added to the prompt when approved',
16
+ isOptional: true,
17
+ roles: RoleEnum.ADMIN,
18
+ })
19
+ content?: string = undefined;
20
+
21
+ @UnifiedField({
22
+ description: 'Whether the hint is active',
23
+ isOptional: true,
24
+ roles: RoleEnum.ADMIN,
25
+ type: () => Boolean,
26
+ })
27
+ enabled?: boolean = undefined;
28
+
29
+ @UnifiedField({
30
+ description: 'Scope the hint applies to (e.g. a tool name); empty = global',
31
+ isOptional: true,
32
+ roles: RoleEnum.ADMIN,
33
+ })
34
+ scope?: string = undefined;
35
+
36
+ @UnifiedField({
37
+ description: "Governance status: 'suggested', 'approved' or 'rejected'",
38
+ isOptional: true,
39
+ roles: RoleEnum.ADMIN,
40
+ validator: () => [IsIn(['approved', 'rejected', 'suggested'])],
41
+ })
42
+ status?: string = undefined;
43
+ }
@@ -0,0 +1,42 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+
3
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
4
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
5
+ import { CoreInput } from '../../../common/inputs/core-input.input';
6
+ import { RoleEnum } from '../../../common/enums/role.enum';
7
+
8
+ /** Input for updating a {@link CoreAiPrompt}. All fields optional. */
9
+ @InputType({ description: 'Input to update a user prompt' })
10
+ @Restricted(RoleEnum.S_USER)
11
+ export class CoreAiPromptUpdateInput extends CoreInput {
12
+ @UnifiedField({ description: 'The prompt text', isOptional: true, roles: RoleEnum.S_USER })
13
+ content?: string = undefined;
14
+
15
+ @UnifiedField({ description: 'Description', isOptional: true, roles: RoleEnum.S_USER })
16
+ description?: string = undefined;
17
+
18
+ @UnifiedField({
19
+ description: 'Whether the prompt is active',
20
+ isOptional: true,
21
+ roles: RoleEnum.S_USER,
22
+ type: () => Boolean,
23
+ })
24
+ enabled?: boolean = undefined;
25
+
26
+ @UnifiedField({ description: 'Icon hint', isOptional: true, roles: RoleEnum.S_USER })
27
+ icon?: string = undefined;
28
+
29
+ @UnifiedField({ description: 'Display label', isOptional: true, roles: RoleEnum.S_USER })
30
+ name?: string = undefined;
31
+
32
+ @UnifiedField({
33
+ description: 'Sort order',
34
+ isOptional: true,
35
+ roles: RoleEnum.S_USER,
36
+ type: () => Number,
37
+ })
38
+ order?: number = undefined;
39
+
40
+ @UnifiedField({ description: 'Visibility scope', isOptional: true, roles: RoleEnum.S_USER })
41
+ scope?: string = undefined;
42
+ }
@@ -0,0 +1,144 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+ import { IsIn, IsString, MaxLength } from 'class-validator';
3
+
4
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
5
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
6
+ import { RoleEnum } from '../../../common/enums/role.enum';
7
+ import { JSON } from '../../../common/scalars/json.scalar';
8
+
9
+ /**
10
+ * Input for an AI prompt sent from the frontend.
11
+ */
12
+ @InputType({ description: 'Input for an AI prompt', isAbstract: true })
13
+ @Restricted(RoleEnum.S_USER)
14
+ export class CoreAiPromptInput {
15
+ /**
16
+ * Optional id of the AI connection to use (defaults to the configured default).
17
+ */
18
+ @UnifiedField({
19
+ description: 'Id of the AI connection to use (defaults to the configured default)',
20
+ isOptional: true,
21
+ roles: RoleEnum.S_USER,
22
+ })
23
+ connectionId?: string = undefined;
24
+
25
+ /**
26
+ * Confirm execution of destructive tool actions requested in a previous turn.
27
+ */
28
+ @UnifiedField({
29
+ description: 'Confirm execution of destructive tool actions',
30
+ isOptional: true,
31
+ roles: RoleEnum.S_USER,
32
+ type: () => Boolean,
33
+ })
34
+ confirm?: boolean = undefined;
35
+
36
+ /**
37
+ * Optional conversation id for multi-turn continuation.
38
+ */
39
+ @UnifiedField({
40
+ description: 'Conversation id for multi-turn continuation',
41
+ isOptional: true,
42
+ roles: RoleEnum.S_USER,
43
+ })
44
+ conversationId?: string = undefined;
45
+
46
+ /**
47
+ * Optional structured context the frontend wants the assistant to consider.
48
+ */
49
+ @UnifiedField({
50
+ description: 'Optional structured context for the assistant',
51
+ isOptional: true,
52
+ roles: RoleEnum.S_USER,
53
+ type: () => JSON,
54
+ })
55
+ context?: Record<string, any> = undefined;
56
+
57
+ /**
58
+ * Optional client metadata giving the assistant more situational context, e.g.
59
+ * current URL, previous navigation steps, console logs. Treated as UNTRUSTED
60
+ * input (size-capped, clearly delimited) to limit prompt-injection risk.
61
+ */
62
+ @UnifiedField({
63
+ description: 'Optional client metadata (current URL, navigation steps, console logs, …)',
64
+ isOptional: true,
65
+ roles: RoleEnum.S_USER,
66
+ type: () => JSON,
67
+ })
68
+ metadata?: Record<string, any> = undefined;
69
+
70
+ /**
71
+ * Execution mode. `auto` (default) runs the reactive agent loop; `plan` first
72
+ * produces a complete plan, validates ALL action permissions up front, and only
73
+ * then executes (all-or-nothing).
74
+ */
75
+ @UnifiedField({
76
+ description: "Execution mode: 'auto' (reactive loop) or 'plan' (validate all permissions, then execute atomically)",
77
+ isOptional: true,
78
+ roles: RoleEnum.S_USER,
79
+ validator: () => [IsIn(['auto', 'plan'])],
80
+ })
81
+ mode?: string = undefined;
82
+
83
+ /**
84
+ * The user's prompt text.
85
+ */
86
+ @UnifiedField({
87
+ description: 'The user prompt text',
88
+ roles: RoleEnum.S_USER,
89
+ // IsNotEmpty is auto-applied for required fields by @UnifiedField; only IsString
90
+ // + MaxLength need to be declared here (the custom validator replaces built-ins).
91
+ validator: () => [IsString(), MaxLength(50000)],
92
+ })
93
+ prompt: string = undefined;
94
+
95
+ /**
96
+ * Client override of the admin confirmation-for-mutating-actions default.
97
+ * Ignored when the admin has enforced the policy.
98
+ */
99
+ @UnifiedField({
100
+ description: 'Override the admin default for requiring confirmation of mutating actions (ignored when enforced)',
101
+ isOptional: true,
102
+ roles: RoleEnum.S_USER,
103
+ type: () => Boolean,
104
+ })
105
+ requireConfirmation?: boolean = undefined;
106
+
107
+ /**
108
+ * When confirming a mutating action (`confirm: true`), persist the consent so the
109
+ * user does not have to re-confirm the same tool next time. Scope: `'conversation'`
110
+ * (this thread only), `'user'` (this user, all conversations), `'tenant'` (whole
111
+ * tenant). Destructive tools are never grantable — they always confirm.
112
+ */
113
+ @UnifiedField({
114
+ description: "Remember the confirmation as a grant: 'conversation', 'user' or 'tenant'",
115
+ isOptional: true,
116
+ roles: RoleEnum.S_USER,
117
+ })
118
+ rememberDecision?: string = undefined;
119
+
120
+ /**
121
+ * Named agent mode (admin-defined). Restricts the assistant to a curated tool set
122
+ * and optional model/prompt override for this run (e.g. `'support'`, `'audit'`).
123
+ * See {@link CoreAiMode}.
124
+ */
125
+ @UnifiedField({
126
+ description: 'Named agent mode (admin-defined; restricts tools / prompts / model)',
127
+ isOptional: true,
128
+ roles: RoleEnum.S_USER,
129
+ })
130
+ agentMode?: string = undefined;
131
+
132
+ /**
133
+ * Multi-modal attachments for the user prompt (e.g. screenshots, documents).
134
+ * Forwarded to vision-capable providers; ignored by providers without vision
135
+ * support. Items are `{ mimeType, dataUrl|url, name? }`.
136
+ */
137
+ @UnifiedField({
138
+ description: 'Multi-modal attachments (images, documents) for the prompt',
139
+ isOptional: true,
140
+ roles: RoleEnum.S_USER,
141
+ type: () => JSON,
142
+ })
143
+ attachments?: { dataUrl?: string; mimeType: string; name?: string; url?: string }[] = undefined;
144
+ }
@@ -0,0 +1,26 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+
3
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
4
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
5
+ import { RoleEnum } from '../../../common/enums/role.enum';
6
+ import { CoreAiSlotUpdateInput } from './core-ai-slot-update.input';
7
+
8
+ /**
9
+ * Input to create an AI slot (system-prompt building block). `key` and `content`
10
+ * are required.
11
+ */
12
+ @InputType({ description: 'Input to create an AI slot (system-prompt building block)', isAbstract: true })
13
+ @Restricted(RoleEnum.ADMIN)
14
+ export class CoreAiSlotCreateInput extends CoreAiSlotUpdateInput {
15
+ @UnifiedField({
16
+ description: 'Slot text — supports placeholder tokens; the active registry is served by GET /ai/placeholders',
17
+ roles: RoleEnum.ADMIN,
18
+ })
19
+ override content: string = undefined;
20
+
21
+ @UnifiedField({
22
+ description: "Logical prompt slot key (e.g. 'base', 'permissions', 'anti_hallucination')",
23
+ roles: RoleEnum.ADMIN,
24
+ })
25
+ override key: string = undefined;
26
+ }
@@ -0,0 +1,65 @@
1
+ import { InputType } from '@nestjs/graphql';
2
+ import { IsIn } from 'class-validator';
3
+
4
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
5
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
6
+ import { RoleEnum } from '../../../common/enums/role.enum';
7
+
8
+ /**
9
+ * Input to update an AI slot (system-prompt building block). All fields optional.
10
+ */
11
+ @InputType({ description: 'Input to update an AI slot', isAbstract: true })
12
+ @Restricted(RoleEnum.ADMIN)
13
+ export class CoreAiSlotUpdateInput {
14
+ @UnifiedField({
15
+ description: "Capability scope: 'all', 'native' or 'emulated'",
16
+ isOptional: true,
17
+ roles: RoleEnum.ADMIN,
18
+ validator: () => [IsIn(['all', 'emulated', 'native'])],
19
+ })
20
+ capability?: string = undefined;
21
+
22
+ @UnifiedField({
23
+ description: 'Slot text — supports placeholder tokens; the active registry is served by GET /ai/placeholders',
24
+ isOptional: true,
25
+ roles: RoleEnum.ADMIN,
26
+ })
27
+ content?: string = undefined;
28
+
29
+ @UnifiedField({
30
+ description: 'Admin-facing description of the slot',
31
+ isOptional: true,
32
+ roles: RoleEnum.ADMIN,
33
+ })
34
+ description?: string = undefined;
35
+
36
+ @UnifiedField({
37
+ description: 'Whether the slot is included in the prompt',
38
+ isOptional: true,
39
+ roles: RoleEnum.ADMIN,
40
+ type: () => Boolean,
41
+ })
42
+ enabled?: boolean = undefined;
43
+
44
+ @UnifiedField({
45
+ description: "Logical prompt slot key (e.g. 'base', 'permissions', 'anti_hallucination')",
46
+ isOptional: true,
47
+ roles: RoleEnum.ADMIN,
48
+ })
49
+ key?: string = undefined;
50
+
51
+ @UnifiedField({
52
+ description: "Locale (e.g. 'en', 'de'); empty = all languages",
53
+ isOptional: true,
54
+ roles: RoleEnum.ADMIN,
55
+ })
56
+ locale?: string = undefined;
57
+
58
+ @UnifiedField({
59
+ description: 'Assembly order (ascending)',
60
+ isOptional: true,
61
+ roles: RoleEnum.ADMIN,
62
+ type: () => Number,
63
+ })
64
+ order?: number = undefined;
65
+ }
@@ -0,0 +1,74 @@
1
+ import type { AiToolContext, IAiTool } from './ai-tool.interface';
2
+ import type { CoreAiPromptInput } from '../inputs/core-ai-prompt.input';
3
+ import type { CoreAiResponse } from '../models/core-ai-response.model';
4
+
5
+ /**
6
+ * Decision returned by a `preToolUse` hook. `block: true` aborts the tool call
7
+ * with a translated error; `block: false` (or undefined) lets it run. Returning
8
+ * `args` replaces the original tool arguments — useful for input sanitization or
9
+ * PII redaction. Returning nothing is equivalent to `{ block: false }`.
10
+ */
11
+ export interface AiHookPreDecision {
12
+ /** Replace the tool arguments before execution. */
13
+ args?: Record<string, any>;
14
+ /** Block the tool call entirely. */
15
+ block?: boolean;
16
+ /** Human-readable reason for blocking — surfaced as the tool error. */
17
+ reason?: string;
18
+ }
19
+
20
+ /**
21
+ * Lifecycle event payload passed to all hook methods.
22
+ */
23
+ export interface AiHookEvent {
24
+ /** The full prompt input the orchestrator is running. */
25
+ input: CoreAiPromptInput;
26
+ /** The user context (currentUser, serviceOptions, language). */
27
+ toolContext: AiToolContext;
28
+ }
29
+
30
+ /**
31
+ * Lifecycle hook a project can register to observe or gate the agent loop without
32
+ * forking the orchestrator. Hooks are dispatched in registration order; the first
33
+ * hook returning `{ block: true }` aborts the tool call.
34
+ *
35
+ * Implement any subset of the methods. Register the hook as a NestJS provider that
36
+ * extends {@link AiHookBase} — it self-registers in the global {@link AiHookRegistry}
37
+ * on module init.
38
+ *
39
+ * **Security:** hooks can only ADD restrictions (block calls, redact args) — they
40
+ * cannot relax the permission system. A hook returning no block does not bypass
41
+ * `@Restricted`/`@Roles`/`authorize()`; those still apply.
42
+ */
43
+ export interface IAiHook {
44
+ /** Unique hook name (for diagnostics and deterministic ordering). */
45
+ readonly name: string;
46
+
47
+ /**
48
+ * Called BEFORE a tool runs. Can block the call, modify the args, or just
49
+ * observe (return undefined). Errors thrown here are swallowed — hooks are
50
+ * best-effort and must not crash a prompt run.
51
+ */
52
+ preToolUse?(
53
+ call: { arguments: Record<string, any>; name: string },
54
+ tool: IAiTool,
55
+ event: AiHookEvent,
56
+ ): Promise<AiHookPreDecision | undefined> | AiHookPreDecision | undefined;
57
+
58
+ /**
59
+ * Called AFTER a tool ran (success or failure). Pure notification — the result
60
+ * is not modifiable. Useful for audit/webhook/metrics integration.
61
+ */
62
+ postToolUse?(
63
+ call: { arguments: Record<string, any>; name: string },
64
+ tool: IAiTool,
65
+ result: { result: unknown; success: boolean },
66
+ event: AiHookEvent,
67
+ ): Promise<void> | void;
68
+
69
+ /** Called at the start of a prompt run, before any LLM call. */
70
+ sessionStart?(event: AiHookEvent): Promise<void> | void;
71
+
72
+ /** Called at the end of a prompt run, with the final response (or partial state). */
73
+ stop?(response: CoreAiResponse, event: AiHookEvent): Promise<void> | void;
74
+ }
@@ -0,0 +1,49 @@
1
+ import { IAiTool } from './ai-tool.interface';
2
+
3
+ /**
4
+ * Runtime context passed to every placeholder resolver. Mirrors the data a
5
+ * prompt build has on hand (current user, in-scope tools, etc.) — keep it
6
+ * narrow on purpose so resolvers stay testable and don't reach into the
7
+ * orchestrator's internals.
8
+ */
9
+ export interface AiPlaceholderContext {
10
+ /** Pre-computed catalog string (formatted tool list with parameter schema). */
11
+ toolCatalog?: string;
12
+ /** Tools the current user is allowed to use this turn. */
13
+ tools?: IAiTool[];
14
+ /** Current user (may be undefined for system contexts). */
15
+ user?: { id?: string; roles?: string[]; [key: string]: any };
16
+ }
17
+
18
+ /**
19
+ * A placeholder registered with {@link CoreAiPlaceholderRegistry}.
20
+ *
21
+ * Placeholders are referenced in slot / prompt content via `{{name}}`. At
22
+ * render time the registry calls each placeholder's {@link resolve} with the
23
+ * current context and inlines the returned string. Unknown placeholder names
24
+ * render as the empty string (forward-compatible — old content survives
25
+ * placeholder removal without crashing).
26
+ */
27
+ export interface IAiPlaceholder {
28
+ /**
29
+ * Human-readable description for the admin UI (shown next to the name in
30
+ * the placeholder helper sidebar). Keep it short — one sentence.
31
+ */
32
+ description: string;
33
+ /** Optional example value rendered in the UI tooltip. */
34
+ example?: string;
35
+ /** Placeholder name without curly braces (e.g. `'roles'` matches `{{roles}}`). */
36
+ name: string;
37
+ /**
38
+ * Compute the placeholder's string value for the current context. Sync or
39
+ * async; missing context values should yield `''` rather than throw.
40
+ */
41
+ resolve(ctx: AiPlaceholderContext): Promise<string> | string;
42
+ }
43
+
44
+ /** Public metadata shape returned by the placeholders API (no `resolve`). */
45
+ export interface AiPlaceholderInfo {
46
+ description: string;
47
+ example?: string;
48
+ name: string;
49
+ }
@@ -0,0 +1,112 @@
1
+ import { RoleEnum } from '../../../common/enums/role.enum';
2
+ import { ServiceOptions } from '../../../common/interfaces/service-options.interface';
3
+
4
+ /**
5
+ * Execution context handed to a tool when the LLM invokes it.
6
+ *
7
+ * The {@link serviceOptions} carry the authenticated user, so tools that call a
8
+ * {@link CrudService} run with the caller's permissions — the LLM can never
9
+ * escalate beyond what the user is allowed to do.
10
+ */
11
+ export interface AiToolContext {
12
+ /** Authenticated user (shortcut for `serviceOptions.currentUser`). */
13
+ currentUser?: { [key: string]: any; id: string; roles?: string[] };
14
+
15
+ /** Accept-Language of the original request. */
16
+ language?: string;
17
+
18
+ /**
19
+ * ServiceOptions to forward to downstream services. Contains `currentUser`,
20
+ * so authorization, field filtering and tenant context are preserved.
21
+ */
22
+ serviceOptions: ServiceOptions;
23
+ }
24
+
25
+ /**
26
+ * Result of a tool's pre-flight authorization check ({@link IAiTool.authorize}).
27
+ */
28
+ export interface AiToolAuthorization {
29
+ /** Whether the user may run the tool with these arguments. */
30
+ allowed: boolean;
31
+
32
+ /** Optional human-readable reason when not allowed. */
33
+ reason?: string;
34
+ }
35
+
36
+ /**
37
+ * Normalized result of a tool execution that is fed back to the LLM.
38
+ */
39
+ export interface AiToolResult {
40
+ /** Structured payload returned to the model (and optionally the frontend). */
41
+ data?: unknown;
42
+
43
+ /** Optional human-readable message. */
44
+ message?: string;
45
+
46
+ /** Whether the tool ran successfully. */
47
+ success: boolean;
48
+ }
49
+
50
+ /**
51
+ * A backend capability the LLM may call — the "MCP-like" building block.
52
+ *
53
+ * Tools self-register in the global {@link AiToolRegistry} (typically from
54
+ * `onModuleInit`), so projects can add or override tools from any module without
55
+ * DI-scope constraints. Implement this interface directly or extend the
56
+ * convenience base class {@link AiTool}.
57
+ *
58
+ * ## Security
59
+ *
60
+ * - {@link roles} is a first-line visibility filter: tools the user may not use
61
+ * are never even offered to the LLM.
62
+ * - The TRUE authorization gate is {@link execute}: tools must route data access
63
+ * through a {@link CrudService} using `context.serviceOptions` so `@Restricted`,
64
+ * `securityCheck()` and field filtering still apply.
65
+ */
66
+ export interface IAiTool {
67
+ /** Description shown to the LLM — the primary signal for when to use the tool. */
68
+ readonly description: string;
69
+
70
+ /**
71
+ * Whether the tool performs a destructive/irreversible action (delete, bulk
72
+ * update, payment, …). Destructive tools always require confirmation: they are
73
+ * NOT executed until the prompt is re-sent with `confirm: true`; the first
74
+ * response lists them as `pendingActions` with `requiresConfirmation: true`.
75
+ */
76
+ readonly destructive?: boolean;
77
+
78
+ /**
79
+ * Whether the tool changes data (create/update/delete). Confirmation for
80
+ * mutating tools is governed by the `ai.confirmation` policy (admin default,
81
+ * optionally client-overridable, optionally enforced). `destructive` is the
82
+ * stronger flag and always requires confirmation regardless of policy.
83
+ */
84
+ readonly mutating?: boolean;
85
+
86
+ /**
87
+ * Optional pre-flight authorization check used by plan mode (and recommended
88
+ * for data-level checks). MUST NOT mutate anything — it only decides whether
89
+ * the user may run the tool with these arguments (e.g. load the target record
90
+ * and verify ownership). When omitted, only the registry role filter applies.
91
+ */
92
+ authorize?(args: Record<string, any>, context: AiToolContext): Promise<AiToolAuthorization | boolean>;
93
+
94
+ /** Unique tool name (snake_case recommended, stable across versions). */
95
+ readonly name: string;
96
+
97
+ /** JSON schema of the tool's input arguments (JSON-schema shape). */
98
+ readonly parameters: Record<string, any>;
99
+
100
+ /**
101
+ * Roles required to see and run the tool. Use {@link RoleEnum.S_EVERYONE} for
102
+ * public tools, {@link RoleEnum.S_USER} for any authenticated user, or real
103
+ * roles (e.g. `RoleEnum.ADMIN`) for privileged tools.
104
+ */
105
+ readonly roles: (RoleEnum | string)[];
106
+
107
+ /**
108
+ * Execute the tool. MUST enforce real authorization by routing through a
109
+ * service with `context.serviceOptions`.
110
+ */
111
+ execute(args: Record<string, any>, context: AiToolContext): Promise<AiToolResult | unknown>;
112
+ }