@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,98 @@
1
+ import { ObjectType } from '@nestjs/graphql';
2
+ import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
+ import { Document } from 'mongoose';
4
+
5
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
6
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
7
+ import { RoleEnum } from '../../../common/enums/role.enum';
8
+ import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
9
+
10
+ export type AiPromptHintDocument = CoreAiPromptHint & Document;
11
+
12
+ /**
13
+ * A learned prompt hint produced by the governed self-improvement loop
14
+ * ({@link CoreAiPromptFeedbackService}). When a recurring failure pattern is detected
15
+ * (tool errors, denied actions, parse failures, claimed-but-not-executed actions),
16
+ * a hint is recorded and, once **approved** (or auto-approved when
17
+ * `ai.promptLearning.autoApply` is on), injected into the system prompt so the model
18
+ * avoids the same mistake next time.
19
+ *
20
+ * Hints only ever ADD guidance — they can never relax the security core (permissions,
21
+ * tool gating), which is always enforced backend-side independently of the prompt.
22
+ */
23
+ @MongooseSchema({ collection: 'aiPromptHints', timestamps: true })
24
+ @ObjectType({ description: 'Learned AI prompt hint from the governed self-improvement loop' })
25
+ @Restricted(RoleEnum.ADMIN)
26
+ export class CoreAiPromptHint extends CorePersistenceModel {
27
+ /**
28
+ * The guidance text injected into the prompt when approved + enabled.
29
+ */
30
+ @UnifiedField({
31
+ description: 'Guidance text added to the prompt when approved',
32
+ mongoose: true,
33
+ roles: RoleEnum.ADMIN,
34
+ })
35
+ content: string = undefined;
36
+
37
+ /**
38
+ * Whether the hint is active (independent of approval status).
39
+ */
40
+ @UnifiedField({
41
+ description: 'Whether the hint is active',
42
+ isOptional: true,
43
+ mongoose: { default: true },
44
+ roles: RoleEnum.ADMIN,
45
+ type: () => Boolean,
46
+ })
47
+ enabled?: boolean = undefined;
48
+
49
+ /**
50
+ * How often the underlying failure pattern was observed.
51
+ */
52
+ @UnifiedField({
53
+ description: 'Number of times the failure pattern was observed',
54
+ isOptional: true,
55
+ mongoose: { default: 1 },
56
+ roles: RoleEnum.ADMIN,
57
+ type: () => Number,
58
+ })
59
+ occurrences?: number = undefined;
60
+
61
+ /**
62
+ * Optional scope the hint applies to (e.g. a tool name); empty = global.
63
+ */
64
+ @UnifiedField({
65
+ description: 'Scope the hint applies to (e.g. a tool name); empty = global',
66
+ isOptional: true,
67
+ mongoose: { index: true },
68
+ roles: RoleEnum.ADMIN,
69
+ })
70
+ scope?: string = undefined;
71
+
72
+ /**
73
+ * Governance status: 'suggested' (default), 'approved' or 'rejected'. Only
74
+ * 'approved' + enabled hints reach the prompt.
75
+ */
76
+ @UnifiedField({
77
+ description: "Governance status: 'suggested', 'approved' or 'rejected'",
78
+ isOptional: true,
79
+ mongoose: { default: 'suggested', index: true },
80
+ roles: RoleEnum.ADMIN,
81
+ })
82
+ status?: string = undefined;
83
+
84
+ /**
85
+ * Failure-pattern identifier that produced this hint (e.g. 'tool_error',
86
+ * 'hallucinated_execution', 'parse_failure', 'denied').
87
+ */
88
+ @UnifiedField({
89
+ description: 'Failure-pattern identifier that produced the hint',
90
+ mongoose: { index: true },
91
+ roles: RoleEnum.ADMIN,
92
+ })
93
+ trigger: string = undefined;
94
+ }
95
+
96
+ export const AiPromptHintSchema = SchemaFactory.createForClass(CoreAiPromptHint);
97
+ // One aggregated hint per (trigger, scope).
98
+ AiPromptHintSchema.index({ scope: 1, trigger: 1 }, { unique: true });
@@ -0,0 +1,120 @@
1
+ import { ObjectType } from '@nestjs/graphql';
2
+ import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
+ import { Document } from 'mongoose';
4
+
5
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
6
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
7
+ import { RoleEnum } from '../../../common/enums/role.enum';
8
+ import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
9
+
10
+ export type AiPromptDocument = CoreAiPrompt & Document;
11
+
12
+ /**
13
+ * User-facing prompt — a short, named piece of text the user can insert into
14
+ * the chat input with one click. Different from the {@link CoreAiPromptInput}
15
+ * mutation payload (which carries a single user question to the AI) and from
16
+ * {@link CoreAiSlot} (the admin-edited building blocks of the SYSTEM prompt).
17
+ *
18
+ * Visibility (enforced in {@link CoreAiPromptService.listVisible} + this
19
+ * model's {@link securityCheck}):
20
+ * - `scope: 'user'` → only the `ownerId` user sees it ("private").
21
+ * - `scope: 'tenant'` → all members of `tenantId` see it ("public" within
22
+ * the tenant; without multi-tenancy this is effectively workspace-wide).
23
+ *
24
+ * Mutations are owner-only.
25
+ */
26
+ @MongooseSchema({ collection: 'aiPrompts', timestamps: true })
27
+ @ObjectType({ description: 'User-facing AI prompt (re-usable user prompt)' })
28
+ @Restricted(RoleEnum.S_USER)
29
+ export class CoreAiPrompt extends CorePersistenceModel {
30
+ /** The text inserted into the chat input. May contain `{{placeholders}}`. */
31
+ @UnifiedField({ description: 'The prompt text', mongoose: true, roles: RoleEnum.S_USER })
32
+ content: string = undefined;
33
+
34
+ /** Optional description. */
35
+ @UnifiedField({ description: 'Description', isOptional: true, mongoose: true, roles: RoleEnum.S_USER })
36
+ description?: string = undefined;
37
+
38
+ /** Whether the prompt is active (disabled prompts are hidden from the picker). */
39
+ @UnifiedField({
40
+ description: 'Whether the prompt is active',
41
+ isOptional: true,
42
+ mongoose: { default: true },
43
+ roles: RoleEnum.S_USER,
44
+ type: () => Boolean,
45
+ })
46
+ enabled?: boolean = undefined;
47
+
48
+ /** Optional icon hint for the UI (lucide name or single emoji). */
49
+ @UnifiedField({
50
+ description: 'Icon hint (e.g. lucide name or emoji)',
51
+ isOptional: true,
52
+ mongoose: true,
53
+ roles: RoleEnum.S_USER,
54
+ })
55
+ icon?: string = undefined;
56
+
57
+ /** Display label shown in the prompt picker. */
58
+ @UnifiedField({ description: 'Display label', mongoose: { index: true }, roles: RoleEnum.S_USER })
59
+ name: string = undefined;
60
+
61
+ /** Owner user id (the creator). Set automatically on create. */
62
+ @UnifiedField({
63
+ description: 'Owner user id',
64
+ mongoose: { index: true },
65
+ roles: RoleEnum.S_USER,
66
+ })
67
+ ownerId: string = undefined;
68
+
69
+ /** Sort order in the picker (ascending). */
70
+ @UnifiedField({
71
+ description: 'Sort order',
72
+ isOptional: true,
73
+ mongoose: { default: 100 },
74
+ roles: RoleEnum.S_USER,
75
+ type: () => Number,
76
+ })
77
+ order?: number = undefined;
78
+
79
+ /**
80
+ * Visibility scope: `'user'` (only the owner — "private") or `'tenant'`
81
+ * (members of the owner's tenant — "public").
82
+ */
83
+ @UnifiedField({
84
+ description: "Visibility scope ('user' = private, 'tenant' = public)",
85
+ mongoose: { default: 'user', index: true },
86
+ roles: RoleEnum.S_USER,
87
+ })
88
+ scope: string = undefined;
89
+
90
+ /** Tenant id when scope = 'tenant' (set from the creator's tenant at create time). */
91
+ @UnifiedField({
92
+ description: 'Tenant id (when scope = "tenant")',
93
+ isOptional: true,
94
+ mongoose: { index: true },
95
+ roles: RoleEnum.S_USER,
96
+ })
97
+ tenantId?: string = undefined;
98
+
99
+ /**
100
+ * Filter prompts out of read responses the current user is not allowed to see.
101
+ * Update/delete authorization is enforced by the service layer.
102
+ */
103
+ override securityCheck(user: any, _force?: boolean): this {
104
+ if (!user) {
105
+ return undefined as any;
106
+ }
107
+ if (this.scope === 'tenant') {
108
+ const userTenantId = user.tenantId || user.currentTenantId || (user.tenantIds || [])[0];
109
+ if (this.ownerId === user.id || (this.tenantId && this.tenantId === String(userTenantId))) {
110
+ return this;
111
+ }
112
+ return undefined as any;
113
+ }
114
+ return this.ownerId === user.id ? this : (undefined as any);
115
+ }
116
+ }
117
+
118
+ export const AiPromptSchema = SchemaFactory.createForClass(CoreAiPrompt);
119
+ // One prompt per (owner, name) — keeps the picker tidy.
120
+ AiPromptSchema.index({ ownerId: 1, name: 1 }, { unique: true });
@@ -0,0 +1,119 @@
1
+ import { Field, Int, ObjectType } from '@nestjs/graphql';
2
+
3
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
4
+ import { RoleEnum } from '../../../common/enums/role.enum';
5
+ import { JSON } from '../../../common/scalars/json.scalar';
6
+ import { CoreAiAction } from './core-ai-action.model';
7
+ import { CoreAiBudgetSummary } from './core-ai-usage-info.model';
8
+ import { CoreAiUsage } from './core-ai-usage.model';
9
+
10
+ /**
11
+ * Structured response of an AI prompt.
12
+ *
13
+ * The frontend renders {@link text} as the natural-language answer, may render
14
+ * {@link data} as structured output (tables/cards), and can show {@link actions}
15
+ * for transparency about what the assistant did.
16
+ */
17
+ @ObjectType({ description: 'Structured response of an AI prompt' })
18
+ @Restricted(RoleEnum.S_EVERYONE)
19
+ export class CoreAiResponse {
20
+ /**
21
+ * Tool actions executed while answering.
22
+ */
23
+ @Field(() => [CoreAiAction], { description: 'Tool actions executed while answering', nullable: true })
24
+ actions?: CoreAiAction[];
25
+
26
+ /**
27
+ * Compact token-budget summary (this prompt's cost, remaining/used, reset time).
28
+ */
29
+ @Field(() => CoreAiBudgetSummary, { description: 'Compact token-budget summary', nullable: true })
30
+ budget?: CoreAiBudgetSummary;
31
+
32
+ /**
33
+ * Id of the AI connection used.
34
+ */
35
+ @Field(() => String, { description: 'Id of the AI connection used', nullable: true })
36
+ connectionId?: string;
37
+
38
+ /**
39
+ * Conversation id for multi-turn continuation.
40
+ */
41
+ @Field(() => String, { description: 'Conversation id for multi-turn continuation', nullable: true })
42
+ conversationId?: string;
43
+
44
+ /**
45
+ * Whether the run was aborted because the user lacked permission for at least
46
+ * one planned action (plan mode, all-or-nothing). Nothing was executed.
47
+ */
48
+ @Field(() => Boolean, { description: 'Whether the run was aborted due to missing permissions', nullable: true })
49
+ denied?: boolean;
50
+
51
+ /**
52
+ * Planned actions the user is NOT permitted to perform (when `denied`).
53
+ */
54
+ @Field(() => [CoreAiAction], { description: 'Planned actions the user may not perform', nullable: true })
55
+ deniedActions?: CoreAiAction[];
56
+
57
+ /**
58
+ * Optional structured data the frontend can render.
59
+ */
60
+ @Field(() => JSON, { description: 'Optional structured data for the frontend to render', nullable: true })
61
+ data?: unknown;
62
+
63
+ /**
64
+ * Number of agent-loop iterations performed.
65
+ */
66
+ @Field(() => Int, { description: 'Number of agent-loop iterations performed', nullable: true })
67
+ iterations?: number;
68
+
69
+ /**
70
+ * The planned actions (plan mode), for transparency.
71
+ */
72
+ @Field(() => [CoreAiAction], { description: 'Planned actions (plan mode)', nullable: true })
73
+ plan?: CoreAiAction[];
74
+
75
+ /**
76
+ * Mutating/destructive tool actions awaiting confirmation. Re-send the prompt
77
+ * with `confirm: true` to execute them.
78
+ */
79
+ @Field(() => [CoreAiAction], {
80
+ description: 'Actions awaiting confirmation',
81
+ nullable: true,
82
+ })
83
+ pendingActions?: CoreAiAction[];
84
+
85
+ /**
86
+ * Optional clarifying question raised by the assistant via the built-in
87
+ * `ask_user_question` tool. When set, the run paused to collect more input from
88
+ * the user instead of guessing — the client should render this and send the user's
89
+ * answer as the next prompt to continue the conversation.
90
+ */
91
+ @Field(() => JSON, { description: 'Pending clarifying question from the assistant', nullable: true })
92
+ pendingQuestion?: { options?: { label: string; value: string }[]; question: string };
93
+
94
+ /**
95
+ * Whether the response is awaiting confirmation of destructive actions.
96
+ */
97
+ @Field(() => Boolean, { description: 'Whether confirmation of destructive actions is required', nullable: true })
98
+ requiresConfirmation?: boolean;
99
+
100
+ /**
101
+ * Natural-language answer for the user.
102
+ */
103
+ @Field(() => String, { description: 'Natural-language answer for the user' })
104
+ text: string;
105
+
106
+ /**
107
+ * Token usage (best effort).
108
+ */
109
+ @Field(() => CoreAiUsage, { description: 'Token usage (best effort)', nullable: true })
110
+ usage?: CoreAiUsage;
111
+
112
+ /**
113
+ * Context-window utilization at the end of the run. Used by frontends to render
114
+ * a "closing-circle" indicator when the conversation approaches the model's limit.
115
+ * `total` is the model's window size; `used` is the assembled-messages token estimate.
116
+ */
117
+ @Field(() => JSON, { description: 'Context-window utilization (used/total tokens)', nullable: true })
118
+ contextWindow?: { total: number; used: number };
119
+ }
@@ -0,0 +1,146 @@
1
+ import { ObjectType } from '@nestjs/graphql';
2
+ import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
+ import { Document } from 'mongoose';
4
+
5
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
6
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
7
+ import { RoleEnum } from '../../../common/enums/role.enum';
8
+ import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
9
+
10
+ export type AiSlotDocument = CoreAiSlot & Document;
11
+
12
+ /**
13
+ * Admin-editable building block of the SYSTEM prompt.
14
+ *
15
+ * The system prompt is assembled from keyed slots (see `CoreAiPromptBuilderService`):
16
+ * each {@link key} is a logical slot (e.g. `base`, `permissions`, `anti_hallucination`,
17
+ * `output_contract`, `tool_protocol_emulated`). The framework ships sensible built-in
18
+ * defaults for every key, so the module works with zero rows; a row here **overrides**
19
+ * the default for its key (optionally scoped by `locale`/`capability`).
20
+ *
21
+ * Tenancy: when multi-tenancy is active, an admin's slot is tenant-scoped — it only
22
+ * applies to prompts running in that admin's tenant. Without multi-tenancy, slots are
23
+ * effectively system-wide. The framework's built-in (`isSystem = true`) defaults are
24
+ * NOT stored in this collection; admin "overrides" of a built-in are regular rows
25
+ * matching the key.
26
+ *
27
+ * `content` may contain `{{placeholders}}` (see {@link CoreAiPlaceholderRegistry} for
28
+ * the runtime-resolved list).
29
+ */
30
+ @MongooseSchema({ collection: 'aiSlots', timestamps: true })
31
+ @ObjectType({ description: 'Admin-editable building block (fragment) of the AI system prompt' })
32
+ @Restricted(RoleEnum.ADMIN)
33
+ export class CoreAiSlot extends CorePersistenceModel {
34
+ /**
35
+ * Capability filter: 'all' (default), 'native' or 'emulated' — limits the slot
36
+ * to runs with that tool-calling mode.
37
+ */
38
+ @UnifiedField({
39
+ description: "Capability scope: 'all', 'native' or 'emulated'",
40
+ isOptional: true,
41
+ mongoose: true,
42
+ roles: RoleEnum.ADMIN,
43
+ })
44
+ capability?: string = undefined;
45
+
46
+ /**
47
+ * Slot text. May contain `{{placeholders}}` (see placeholder registry).
48
+ */
49
+ @UnifiedField({
50
+ description: 'Slot text — supports placeholder tokens; the active registry is served by GET /ai/placeholders',
51
+ mongoose: true,
52
+ roles: RoleEnum.ADMIN,
53
+ })
54
+ content: string = undefined;
55
+
56
+ /**
57
+ * Admin-facing description of what this slot does.
58
+ */
59
+ @UnifiedField({
60
+ description: 'Admin-facing description of the slot',
61
+ isOptional: true,
62
+ mongoose: true,
63
+ roles: RoleEnum.ADMIN,
64
+ })
65
+ description?: string = undefined;
66
+
67
+ /**
68
+ * Whether the slot is active (disabled slots are skipped — used to "hide" a
69
+ * built-in default for a specific tenant without losing the row).
70
+ */
71
+ @UnifiedField({
72
+ description: 'Whether the slot is included in the prompt',
73
+ isOptional: true,
74
+ mongoose: { default: true },
75
+ roles: RoleEnum.ADMIN,
76
+ type: () => Boolean,
77
+ })
78
+ enabled?: boolean = undefined;
79
+
80
+ /**
81
+ * Logical slot key (e.g. `base`, `permissions`, `anti_hallucination`).
82
+ * A row whose `key` matches a built-in system slot overrides it for the slot's tenant.
83
+ */
84
+ @UnifiedField({
85
+ description: "Logical prompt slot key (e.g. 'base', 'permissions', 'anti_hallucination')",
86
+ mongoose: { index: true },
87
+ roles: RoleEnum.ADMIN,
88
+ })
89
+ key: string = undefined;
90
+
91
+ /**
92
+ * Optional locale ('en', 'de', …). When set, the slot is only used for that
93
+ * language; otherwise it applies to all languages.
94
+ */
95
+ @UnifiedField({
96
+ description: "Locale (e.g. 'en', 'de'); empty = all languages",
97
+ isOptional: true,
98
+ mongoose: true,
99
+ roles: RoleEnum.ADMIN,
100
+ })
101
+ locale?: string = undefined;
102
+
103
+ /**
104
+ * Assembly order (ascending). Lower numbers appear earlier in the prompt.
105
+ */
106
+ @UnifiedField({
107
+ description: 'Assembly order (ascending)',
108
+ isOptional: true,
109
+ mongoose: { default: 100 },
110
+ roles: RoleEnum.ADMIN,
111
+ type: () => Number,
112
+ })
113
+ order?: number = undefined;
114
+
115
+ /**
116
+ * Optional scope-filter this slot applies to. Empty/undefined = always applies.
117
+ * Recognized prefixes: `tool:<name>` (only when that tool is in scope), `role:<name>`
118
+ * (only when the user has that role), `mode:<name>` (only when running in this named
119
+ * mode — see {@link CoreAiMode}). Multiple filters can be expressed by creating
120
+ * multiple rows with the same key.
121
+ */
122
+ @UnifiedField({
123
+ description: "Scope filter (e.g. 'tool:get_user', 'role:admin', 'mode:support'); empty = always",
124
+ isOptional: true,
125
+ mongoose: { index: true },
126
+ roles: RoleEnum.ADMIN,
127
+ })
128
+ scope?: string = undefined;
129
+
130
+ /**
131
+ * Tenant id the slot applies to. Auto-set from the creating admin's tenant when
132
+ * multi-tenancy is active. Without multi-tenancy this stays undefined and the
133
+ * slot is effectively system-wide.
134
+ */
135
+ @UnifiedField({
136
+ description: 'Tenant id the slot applies to (auto-set; undefined = system-wide)',
137
+ isOptional: true,
138
+ mongoose: { index: true },
139
+ roles: RoleEnum.ADMIN,
140
+ })
141
+ tenantId?: string = undefined;
142
+ }
143
+
144
+ export const AiSlotSchema = SchemaFactory.createForClass(CoreAiSlot);
145
+ // Compound index for the common lookup (effective slots by key + locale + capability + tenant).
146
+ AiSlotSchema.index({ key: 1, locale: 1, capability: 1, tenantId: 1 });
@@ -0,0 +1,87 @@
1
+ import { ObjectType } from '@nestjs/graphql';
2
+ import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
+ import { Document } from 'mongoose';
4
+
5
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
6
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
7
+ import { RoleEnum } from '../../../common/enums/role.enum';
8
+ import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
9
+
10
+ export type AiToolGrantDocument = CoreAiToolGrant & Document;
11
+
12
+ /**
13
+ * Persistent permission decision so end users don't have to re-confirm the same
14
+ * mutating action over and over. When the user confirms a mutating tool with
15
+ * `prompt.input.rememberDecision: 'user' | 'tenant' | 'conversation'`, the
16
+ * orchestrator persists a grant here. Subsequent calls to the same tool by the
17
+ * same scope skip the confirmation gate — until the grant expires or an admin
18
+ * revokes it.
19
+ *
20
+ * Grants only ever say "skip the confirmation gate" — they never relax the
21
+ * permission model itself (`@Restricted`, `@Roles`, `authorize()` and scoped
22
+ * tool-policies still apply). `destructive` tools are excluded from grants by
23
+ * convention: irreversible actions always confirm.
24
+ */
25
+ @MongooseSchema({ collection: 'aiToolGrants', timestamps: true })
26
+ @ObjectType({ description: 'Persistent permission decision for a mutating tool' })
27
+ @Restricted(RoleEnum.ADMIN)
28
+ export class CoreAiToolGrant extends CorePersistenceModel {
29
+ /** Decision: only 'allow' is persisted today; 'deny' is reserved for future use. */
30
+ @UnifiedField({
31
+ description: "Decision ('allow' or 'deny')",
32
+ isOptional: true,
33
+ mongoose: { default: 'allow' },
34
+ roles: RoleEnum.ADMIN,
35
+ })
36
+ decision?: string = undefined;
37
+
38
+ /** Whether the grant is active (an admin can deactivate without deleting). */
39
+ @UnifiedField({
40
+ description: 'Whether the grant is active',
41
+ isOptional: true,
42
+ mongoose: { default: true },
43
+ roles: RoleEnum.ADMIN,
44
+ type: () => Boolean,
45
+ })
46
+ enabled?: boolean = undefined;
47
+
48
+ /** Optional TTL — when set, the grant auto-expires via a Mongo TTL index. */
49
+ @UnifiedField({
50
+ description: 'Optional expiry timestamp',
51
+ isOptional: true,
52
+ mongoose: { index: { expireAfterSeconds: 0 } },
53
+ roles: RoleEnum.ADMIN,
54
+ type: () => Date,
55
+ })
56
+ expiresAt?: Date = undefined;
57
+
58
+ /**
59
+ * Reference id for the scope: user id, tenant id, or conversation id.
60
+ */
61
+ @UnifiedField({
62
+ description: 'Reference id for the scope (user/tenant/conversation id)',
63
+ mongoose: { index: true },
64
+ roles: RoleEnum.ADMIN,
65
+ })
66
+ refId: string = undefined;
67
+
68
+ /** Scope: 'user' (this user, anywhere), 'tenant' (this tenant), 'conversation' (just this thread). */
69
+ @UnifiedField({
70
+ description: "Scope: 'user', 'tenant' or 'conversation'",
71
+ mongoose: { index: true },
72
+ roles: RoleEnum.ADMIN,
73
+ })
74
+ scope: string = undefined;
75
+
76
+ /** The tool name this grant applies to. */
77
+ @UnifiedField({
78
+ description: 'Tool name the grant applies to',
79
+ mongoose: { index: true },
80
+ roles: RoleEnum.ADMIN,
81
+ })
82
+ tool: string = undefined;
83
+ }
84
+
85
+ export const AiToolGrantSchema = SchemaFactory.createForClass(CoreAiToolGrant);
86
+ // One active grant per (scope, refId, tool).
87
+ AiToolGrantSchema.index({ scope: 1, refId: 1, tool: 1 }, { unique: true });
@@ -0,0 +1,115 @@
1
+ import { Field, ObjectType } from '@nestjs/graphql';
2
+ import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
3
+ import { Document } from 'mongoose';
4
+
5
+ import { Restricted } from '../../../common/decorators/restricted.decorator';
6
+ import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
7
+ import { RoleEnum } from '../../../common/enums/role.enum';
8
+ import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
9
+ import { JSON } from '../../../common/scalars/json.scalar';
10
+
11
+ export type AiToolPolicyDocument = CoreAiToolPolicy & Document;
12
+
13
+ /**
14
+ * A fine-grained allow/deny/ask rule against a tool's arguments. See
15
+ * {@link CoreAiToolPolicy}.
16
+ */
17
+ @ObjectType({ description: 'A scoped allow/deny/ask rule for a tool call' })
18
+ export class CoreAiToolPolicyRule {
19
+ /** 'allow' (run without gate), 'deny' (refuse), or 'ask' (route through the confirmation gate). */
20
+ @Field(() => String, { description: "Decision: 'allow', 'deny' or 'ask'" })
21
+ action: string;
22
+
23
+ /** Which argument key the pattern matches against (e.g. `sql`, `collection`). */
24
+ @Field(() => String, { description: 'Argument key the pattern matches against' })
25
+ argument: string;
26
+
27
+ /** RegExp source matched against `String(arguments[argument])`. */
28
+ @Field(() => String, { description: 'RegExp source matched against the argument value' })
29
+ pattern: string;
30
+
31
+ /** Optional flags for the RegExp (e.g. 'i'). */
32
+ @Field(() => String, { description: 'Optional RegExp flags', nullable: true })
33
+ flags?: string;
34
+
35
+ /** Optional human-readable reason — surfaced as the deny/ask message. */
36
+ @Field(() => String, { description: 'Optional human-readable reason', nullable: true })
37
+ reason?: string;
38
+ }
39
+
40
+ /**
41
+ * Admin-editable, fine-grained allow/deny/ask rules against tool calls. The
42
+ * confirmation/permission model stays as-is on top — this layer ADDS extra
43
+ * gating against the arguments of an otherwise-permitted call, without forcing
44
+ * a project to wrap their tools in custom logic.
45
+ *
46
+ * Evaluation order per matching policy: every `deny` rule wins (immediately),
47
+ * then `ask`, then `allow`. No matching rule → default = behave as before
48
+ * (tool's own `mutating`/`destructive` flags decide).
49
+ *
50
+ * Scope chain: `tool` (always) optionally narrowed by `role`, `tenant` or
51
+ * `user`. A more specific scope wins over a more generic one. Hints only ever
52
+ * tighten or relax the confirmation gate; the underlying permission model
53
+ * (`@Restricted`, `@Roles`, `authorize()`) is enforced regardless.
54
+ */
55
+ @MongooseSchema({ collection: 'aiToolPolicies', timestamps: true })
56
+ @ObjectType({ description: 'Admin-editable scoped policy for a tool call' })
57
+ @Restricted(RoleEnum.ADMIN)
58
+ export class CoreAiToolPolicy extends CorePersistenceModel {
59
+ /** Whether the policy is active. */
60
+ @UnifiedField({
61
+ description: 'Whether the policy is active',
62
+ isOptional: true,
63
+ mongoose: { default: true },
64
+ roles: RoleEnum.ADMIN,
65
+ type: () => Boolean,
66
+ })
67
+ enabled?: boolean = undefined;
68
+
69
+ /** Admin-facing label for the policy (just for UX, never read by code). */
70
+ @UnifiedField({
71
+ description: 'Admin-facing label',
72
+ isOptional: true,
73
+ mongoose: true,
74
+ roles: RoleEnum.ADMIN,
75
+ })
76
+ label?: string = undefined;
77
+
78
+ /** Reference id for the scope: empty when scope is 'global' or 'tool'. */
79
+ @UnifiedField({
80
+ description: 'Reference id for the scope (user/tenant id or role name)',
81
+ isOptional: true,
82
+ mongoose: { index: true },
83
+ roles: RoleEnum.ADMIN,
84
+ })
85
+ refId?: string = undefined;
86
+
87
+ /** The rule set evaluated against the call's arguments. */
88
+ @UnifiedField({
89
+ description: 'Rule set',
90
+ isOptional: true,
91
+ mongoose: { default: [] },
92
+ roles: RoleEnum.ADMIN,
93
+ type: () => JSON,
94
+ })
95
+ rules?: { action: string; argument: string; flags?: string; pattern: string; reason?: string }[] = undefined;
96
+
97
+ /** Scope: 'tool' (any user), 'role', 'tenant' or 'user'. */
98
+ @UnifiedField({
99
+ description: "Scope: 'tool', 'role', 'tenant' or 'user'",
100
+ mongoose: { index: true },
101
+ roles: RoleEnum.ADMIN,
102
+ })
103
+ scope: string = undefined;
104
+
105
+ /** The tool name this policy applies to. */
106
+ @UnifiedField({
107
+ description: 'Tool name the policy applies to',
108
+ mongoose: { index: true },
109
+ roles: RoleEnum.ADMIN,
110
+ })
111
+ tool: string = undefined;
112
+ }
113
+
114
+ export const AiToolPolicySchema = SchemaFactory.createForClass(CoreAiToolPolicy);
115
+ AiToolPolicySchema.index({ scope: 1, refId: 1, tool: 1 });