@hed-hog/core 0.0.387 → 0.0.390

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 (535) hide show
  1. package/README.md +12 -11
  2. package/dist/access-log/access-log.interceptor.d.ts.map +1 -1
  3. package/dist/access-log/access-log.interceptor.js +4 -2
  4. package/dist/access-log/access-log.interceptor.js.map +1 -1
  5. package/dist/ai/ai-attachment.fragments.d.ts +23 -0
  6. package/dist/ai/ai-attachment.fragments.d.ts.map +1 -0
  7. package/dist/ai/ai-attachment.fragments.js +34 -0
  8. package/dist/ai/ai-attachment.fragments.js.map +1 -0
  9. package/dist/ai/ai.controller.d.ts +7 -16
  10. package/dist/ai/ai.controller.d.ts.map +1 -1
  11. package/dist/ai/ai.prompts.d.ts +16 -0
  12. package/dist/ai/ai.prompts.d.ts.map +1 -0
  13. package/dist/ai/ai.prompts.js +37 -0
  14. package/dist/ai/ai.prompts.js.map +1 -0
  15. package/dist/ai/ai.service.d.ts +63 -12
  16. package/dist/ai/ai.service.d.ts.map +1 -1
  17. package/dist/ai/ai.service.js +215 -88
  18. package/dist/ai/ai.service.js.map +1 -1
  19. package/dist/ai/dto/chat.dto.d.ts +4 -1
  20. package/dist/ai/dto/chat.dto.d.ts.map +1 -1
  21. package/dist/ai/dto/chat.dto.js +23 -1
  22. package/dist/ai/dto/chat.dto.js.map +1 -1
  23. package/dist/ai/dto/create-agent.dto.d.ts +1 -1
  24. package/dist/ai/dto/create-agent.dto.d.ts.map +1 -1
  25. package/dist/ai/dto/create-agent.dto.js +1 -1
  26. package/dist/ai/dto/create-agent.dto.js.map +1 -1
  27. package/dist/ai/dto/update-agent.dto.d.ts +1 -1
  28. package/dist/ai/dto/update-agent.dto.d.ts.map +1 -1
  29. package/dist/ai/dto/update-agent.dto.js +1 -1
  30. package/dist/ai/dto/update-agent.dto.js.map +1 -1
  31. package/dist/ai-instruction/ai-instruction.controller.d.ts +61 -7
  32. package/dist/ai-instruction/ai-instruction.controller.d.ts.map +1 -1
  33. package/dist/ai-instruction/ai-instruction.controller.js +63 -20
  34. package/dist/ai-instruction/ai-instruction.controller.js.map +1 -1
  35. package/dist/ai-instruction/ai-instruction.module.d.ts.map +1 -1
  36. package/dist/ai-instruction/ai-instruction.module.js +13 -2
  37. package/dist/ai-instruction/ai-instruction.module.js.map +1 -1
  38. package/dist/ai-instruction/ai-instruction.service.d.ts +131 -6
  39. package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
  40. package/dist/ai-instruction/ai-instruction.service.js +533 -60
  41. package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
  42. package/dist/ai-instruction/ai-prompt-builder.service.d.ts +8 -0
  43. package/dist/ai-instruction/ai-prompt-builder.service.d.ts.map +1 -1
  44. package/dist/ai-instruction/ai-prompt-builder.service.js +10 -1
  45. package/dist/ai-instruction/ai-prompt-builder.service.js.map +1 -1
  46. package/dist/ai-instruction/ai-prompt-registry.d.ts +45 -0
  47. package/dist/ai-instruction/ai-prompt-registry.d.ts.map +1 -0
  48. package/dist/ai-instruction/ai-prompt-registry.js +49 -0
  49. package/dist/ai-instruction/ai-prompt-registry.js.map +1 -0
  50. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +89 -0
  51. package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -0
  52. package/dist/ai-instruction/ai-prompt-resolver.service.js +222 -0
  53. package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -0
  54. package/dist/ai-instruction/ai-prompt-template.util.d.ts +70 -0
  55. package/dist/ai-instruction/ai-prompt-template.util.d.ts.map +1 -0
  56. package/dist/ai-instruction/ai-prompt-template.util.js +154 -0
  57. package/dist/ai-instruction/ai-prompt-template.util.js.map +1 -0
  58. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts +5 -0
  59. package/dist/ai-instruction/dto/create-ai-instruction.dto.d.ts.map +1 -1
  60. package/dist/ai-instruction/dto/create-ai-instruction.dto.js +27 -1
  61. package/dist/ai-instruction/dto/create-ai-instruction.dto.js.map +1 -1
  62. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts +14 -0
  63. package/dist/ai-instruction/dto/preview-ai-instruction.dto.d.ts.map +1 -0
  64. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js +42 -0
  65. package/dist/ai-instruction/dto/preview-ai-instruction.dto.js.map +1 -0
  66. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts +11 -0
  67. package/dist/ai-instruction/dto/update-ai-instruction.dto.d.ts.map +1 -1
  68. package/dist/ai-instruction/dto/update-ai-instruction.dto.js +34 -0
  69. package/dist/ai-instruction/dto/update-ai-instruction.dto.js.map +1 -1
  70. package/dist/ai-instruction/types/ai-instruction.types.d.ts +13 -1
  71. package/dist/ai-instruction/types/ai-instruction.types.d.ts.map +1 -1
  72. package/dist/ai-instruction/types/ai-instruction.types.js +10 -0
  73. package/dist/ai-instruction/types/ai-instruction.types.js.map +1 -1
  74. package/dist/auth/auth.controller.d.ts +24 -9
  75. package/dist/auth/auth.controller.d.ts.map +1 -1
  76. package/dist/auth/auth.controller.js +49 -21
  77. package/dist/auth/auth.controller.js.map +1 -1
  78. package/dist/auth/auth.service.d.ts +33 -8
  79. package/dist/auth/auth.service.d.ts.map +1 -1
  80. package/dist/auth/auth.service.js +78 -29
  81. package/dist/auth/auth.service.js.map +1 -1
  82. package/dist/captcha/captcha.module.d.ts +3 -0
  83. package/dist/captcha/captcha.module.d.ts.map +1 -0
  84. package/dist/captcha/captcha.module.js +23 -0
  85. package/dist/captcha/captcha.module.js.map +1 -0
  86. package/dist/captcha/captcha.service.d.ts +38 -0
  87. package/dist/captcha/captcha.service.d.ts.map +1 -0
  88. package/dist/captcha/captcha.service.js +144 -0
  89. package/dist/captcha/captcha.service.js.map +1 -0
  90. package/dist/challenge/challenge.service.d.ts +16 -7
  91. package/dist/challenge/challenge.service.d.ts.map +1 -1
  92. package/dist/challenge/challenge.service.js +64 -16
  93. package/dist/challenge/challenge.service.js.map +1 -1
  94. package/dist/core.module.d.ts +3 -1
  95. package/dist/core.module.d.ts.map +1 -1
  96. package/dist/core.module.js +29 -2
  97. package/dist/core.module.js.map +1 -1
  98. package/dist/dashboard/dashboard/dashboard.controller.d.ts +15 -15
  99. package/dist/dashboard/dashboard/dashboard.service.d.ts +15 -15
  100. package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +6 -6
  101. package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +6 -6
  102. package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +20 -20
  103. package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +20 -20
  104. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +1 -1
  105. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +1 -1
  106. package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +13 -13
  107. package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +13 -13
  108. package/dist/file/file.service.d.ts +6 -0
  109. package/dist/file/file.service.d.ts.map +1 -1
  110. package/dist/file/file.service.js +44 -4
  111. package/dist/file/file.service.js.map +1 -1
  112. package/dist/incident/incident-notifier.service.d.ts +36 -0
  113. package/dist/incident/incident-notifier.service.d.ts.map +1 -0
  114. package/dist/incident/incident-notifier.service.js +208 -0
  115. package/dist/incident/incident-notifier.service.js.map +1 -0
  116. package/dist/incident/incident.controller.d.ts +23 -0
  117. package/dist/incident/incident.controller.d.ts.map +1 -0
  118. package/dist/incident/incident.controller.js +75 -0
  119. package/dist/incident/incident.controller.js.map +1 -0
  120. package/dist/incident/incident.module.d.ts +7 -0
  121. package/dist/incident/incident.module.d.ts.map +1 -0
  122. package/dist/incident/incident.module.js +32 -0
  123. package/dist/incident/incident.module.js.map +1 -0
  124. package/dist/incident/incident.service.d.ts +72 -0
  125. package/dist/incident/incident.service.d.ts.map +1 -0
  126. package/dist/incident/incident.service.js +184 -0
  127. package/dist/incident/incident.service.js.map +1 -0
  128. package/dist/index.d.ts +26 -0
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +30 -0
  131. package/dist/index.js.map +1 -1
  132. package/dist/integration-profile/dto/test.dto.d.ts +13 -0
  133. package/dist/integration-profile/dto/test.dto.d.ts.map +1 -0
  134. package/dist/integration-profile/dto/test.dto.js +26 -0
  135. package/dist/integration-profile/dto/test.dto.js.map +1 -0
  136. package/dist/integration-profile/integration-profile.controller.d.ts +12 -1
  137. package/dist/integration-profile/integration-profile.controller.d.ts.map +1 -1
  138. package/dist/integration-profile/integration-profile.controller.js +9 -1
  139. package/dist/integration-profile/integration-profile.controller.js.map +1 -1
  140. package/dist/integration-profile/integration-profile.module.d.ts +6 -1
  141. package/dist/integration-profile/integration-profile.module.d.ts.map +1 -1
  142. package/dist/integration-profile/integration-profile.module.js +26 -3
  143. package/dist/integration-profile/integration-profile.module.js.map +1 -1
  144. package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
  145. package/dist/integration-profile/integration-profile.secrets.js +9 -1
  146. package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
  147. package/dist/integration-profile/integration-profile.service.d.ts +26 -7
  148. package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
  149. package/dist/integration-profile/integration-profile.service.js +94 -91
  150. package/dist/integration-profile/integration-profile.service.js.map +1 -1
  151. package/dist/integration-profile/integration-profile.utils.d.ts +13 -1
  152. package/dist/integration-profile/integration-profile.utils.d.ts.map +1 -1
  153. package/dist/integration-profile/integration-profile.utils.js +20 -5
  154. package/dist/integration-profile/integration-profile.utils.js.map +1 -1
  155. package/dist/integration-profile/testers/ai.testers.d.ts +3 -0
  156. package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -0
  157. package/dist/integration-profile/testers/ai.testers.js +125 -0
  158. package/dist/integration-profile/testers/ai.testers.js.map +1 -0
  159. package/dist/integration-profile/testers/captcha.testers.d.ts +3 -0
  160. package/dist/integration-profile/testers/captcha.testers.d.ts.map +1 -0
  161. package/dist/integration-profile/testers/captcha.testers.js +121 -0
  162. package/dist/integration-profile/testers/captcha.testers.js.map +1 -0
  163. package/dist/integration-profile/testers/email.testers.d.ts +3 -0
  164. package/dist/integration-profile/testers/email.testers.d.ts.map +1 -0
  165. package/dist/integration-profile/testers/email.testers.js +128 -0
  166. package/dist/integration-profile/testers/email.testers.js.map +1 -0
  167. package/dist/integration-profile/testers/http-probe.d.ts +57 -0
  168. package/dist/integration-profile/testers/http-probe.d.ts.map +1 -0
  169. package/dist/integration-profile/testers/http-probe.js +140 -0
  170. package/dist/integration-profile/testers/http-probe.js.map +1 -0
  171. package/dist/integration-profile/testers/index.d.ts +12 -0
  172. package/dist/integration-profile/testers/index.d.ts.map +1 -0
  173. package/dist/integration-profile/testers/index.js +45 -0
  174. package/dist/integration-profile/testers/index.js.map +1 -0
  175. package/dist/integration-profile/testers/infrastructure.testers.d.ts +3 -0
  176. package/dist/integration-profile/testers/infrastructure.testers.d.ts.map +1 -0
  177. package/dist/integration-profile/testers/infrastructure.testers.js +105 -0
  178. package/dist/integration-profile/testers/infrastructure.testers.js.map +1 -0
  179. package/dist/integration-profile/testers/integration-tester.registry.d.ts +17 -0
  180. package/dist/integration-profile/testers/integration-tester.registry.d.ts.map +1 -0
  181. package/dist/integration-profile/testers/integration-tester.registry.js +52 -0
  182. package/dist/integration-profile/testers/integration-tester.registry.js.map +1 -0
  183. package/dist/integration-profile/testers/integration-tester.types.d.ts +55 -0
  184. package/dist/integration-profile/testers/integration-tester.types.d.ts.map +1 -0
  185. package/dist/integration-profile/testers/integration-tester.types.js +16 -0
  186. package/dist/integration-profile/testers/integration-tester.types.js.map +1 -0
  187. package/dist/integration-profile/testers/messaging.testers.d.ts +3 -0
  188. package/dist/integration-profile/testers/messaging.testers.d.ts.map +1 -0
  189. package/dist/integration-profile/testers/messaging.testers.js +70 -0
  190. package/dist/integration-profile/testers/messaging.testers.js.map +1 -0
  191. package/dist/integration-profile/testers/oauth.testers.d.ts +3 -0
  192. package/dist/integration-profile/testers/oauth.testers.d.ts.map +1 -0
  193. package/dist/integration-profile/testers/oauth.testers.js +285 -0
  194. package/dist/integration-profile/testers/oauth.testers.js.map +1 -0
  195. package/dist/integration-profile/testers/payment.testers.d.ts +3 -0
  196. package/dist/integration-profile/testers/payment.testers.d.ts.map +1 -0
  197. package/dist/integration-profile/testers/payment.testers.js +169 -0
  198. package/dist/integration-profile/testers/payment.testers.js.map +1 -0
  199. package/dist/integration-profile/testers/storage.testers.d.ts +3 -0
  200. package/dist/integration-profile/testers/storage.testers.d.ts.map +1 -0
  201. package/dist/integration-profile/testers/storage.testers.js +208 -0
  202. package/dist/integration-profile/testers/storage.testers.js.map +1 -0
  203. package/dist/language/en.json +4 -2
  204. package/dist/language/pt.json +4 -2
  205. package/dist/leaked-password/leaked-password.controller.d.ts +24 -0
  206. package/dist/leaked-password/leaked-password.controller.d.ts.map +1 -0
  207. package/dist/leaked-password/leaked-password.controller.js +78 -0
  208. package/dist/leaked-password/leaked-password.controller.js.map +1 -0
  209. package/dist/leaked-password/leaked-password.module.d.ts +8 -0
  210. package/dist/leaked-password/leaked-password.module.d.ts.map +1 -0
  211. package/dist/leaked-password/leaked-password.module.js +31 -0
  212. package/dist/leaked-password/leaked-password.module.js.map +1 -0
  213. package/dist/leaked-password/leaked-password.service.d.ts +64 -0
  214. package/dist/leaked-password/leaked-password.service.d.ts.map +1 -0
  215. package/dist/leaked-password/leaked-password.service.js +218 -0
  216. package/dist/leaked-password/leaked-password.service.js.map +1 -0
  217. package/dist/locale/locale.controller.d.ts +1 -1
  218. package/dist/locale/locale.service.d.ts +1 -1
  219. package/dist/mail/dto/preview.dto.d.ts +18 -0
  220. package/dist/mail/dto/preview.dto.d.ts.map +1 -0
  221. package/dist/mail/dto/preview.dto.js +66 -0
  222. package/dist/mail/dto/preview.dto.js.map +1 -0
  223. package/dist/mail/dto/send.dto.d.ts +7 -0
  224. package/dist/mail/dto/send.dto.d.ts.map +1 -1
  225. package/dist/mail/dto/send.dto.js +10 -0
  226. package/dist/mail/dto/send.dto.js.map +1 -1
  227. package/dist/mail/mail.controller.d.ts +4 -0
  228. package/dist/mail/mail.controller.d.ts.map +1 -1
  229. package/dist/mail/mail.controller.js +16 -2
  230. package/dist/mail/mail.controller.js.map +1 -1
  231. package/dist/mail/mail.service.d.ts +23 -2
  232. package/dist/mail/mail.service.d.ts.map +1 -1
  233. package/dist/mail/mail.service.js +102 -13
  234. package/dist/mail/mail.service.js.map +1 -1
  235. package/dist/mail-layout/dto/update.dto.d.ts +17 -0
  236. package/dist/mail-layout/dto/update.dto.d.ts.map +1 -0
  237. package/dist/mail-layout/dto/update.dto.js +27 -0
  238. package/dist/mail-layout/dto/update.dto.js.map +1 -0
  239. package/dist/mail-layout/mail-layout.controller.d.ts +15 -0
  240. package/dist/mail-layout/mail-layout.controller.d.ts.map +1 -0
  241. package/dist/mail-layout/mail-layout.controller.js +71 -0
  242. package/dist/mail-layout/mail-layout.controller.js.map +1 -0
  243. package/dist/mail-layout/mail-layout.module.d.ts +3 -0
  244. package/dist/mail-layout/mail-layout.module.d.ts.map +1 -0
  245. package/dist/mail-layout/mail-layout.module.js +35 -0
  246. package/dist/mail-layout/mail-layout.module.js.map +1 -0
  247. package/dist/mail-layout/mail-layout.service.d.ts +27 -0
  248. package/dist/mail-layout/mail-layout.service.d.ts.map +1 -0
  249. package/dist/mail-layout/mail-layout.service.js +80 -0
  250. package/dist/mail-layout/mail-layout.service.js.map +1 -0
  251. package/dist/mcp-chat/mcp-chat.controller.d.ts +2 -2
  252. package/dist/mcp-chat/mcp-chat.service.d.ts +24 -2
  253. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  254. package/dist/mcp-chat/mcp-chat.service.js +80 -24
  255. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  256. package/dist/menu/menu.controller.d.ts +3 -3
  257. package/dist/menu/menu.service.d.ts +3 -3
  258. package/dist/notification/notification.controller.d.ts +12 -12
  259. package/dist/notification/notification.service.d.ts +12 -12
  260. package/dist/oauth/oauth-token-broker.service.d.ts +72 -0
  261. package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -0
  262. package/dist/oauth/oauth-token-broker.service.js +258 -0
  263. package/dist/oauth/oauth-token-broker.service.js.map +1 -0
  264. package/dist/oauth/oauth.module.d.ts.map +1 -1
  265. package/dist/oauth/oauth.module.js +3 -1
  266. package/dist/oauth/oauth.module.js.map +1 -1
  267. package/dist/oauth/oauth.service.d.ts +2 -0
  268. package/dist/oauth/oauth.service.d.ts.map +1 -1
  269. package/dist/oauth/oauth.service.js +6 -3
  270. package/dist/oauth/oauth.service.js.map +1 -1
  271. package/dist/pdf/pdf.service.d.ts +8 -0
  272. package/dist/pdf/pdf.service.d.ts.map +1 -1
  273. package/dist/pdf/pdf.service.js +52 -0
  274. package/dist/pdf/pdf.service.js.map +1 -1
  275. package/dist/presence/presence.controller.d.ts +16 -0
  276. package/dist/presence/presence.controller.d.ts.map +1 -0
  277. package/dist/presence/presence.controller.js +60 -0
  278. package/dist/presence/presence.controller.js.map +1 -0
  279. package/dist/presence/presence.listener.d.ts +29 -0
  280. package/dist/presence/presence.listener.d.ts.map +1 -0
  281. package/dist/presence/presence.listener.js +82 -0
  282. package/dist/presence/presence.listener.js.map +1 -0
  283. package/dist/presence/presence.module.d.ts +3 -0
  284. package/dist/presence/presence.module.d.ts.map +1 -0
  285. package/dist/presence/presence.module.js +32 -0
  286. package/dist/presence/presence.module.js.map +1 -0
  287. package/dist/presence/presence.service.d.ts +42 -0
  288. package/dist/presence/presence.service.d.ts.map +1 -0
  289. package/dist/presence/presence.service.js +147 -0
  290. package/dist/presence/presence.service.js.map +1 -0
  291. package/dist/profile/dto/delete-account.dto.d.ts +8 -0
  292. package/dist/profile/dto/delete-account.dto.d.ts.map +1 -0
  293. package/dist/profile/dto/delete-account.dto.js +22 -0
  294. package/dist/profile/dto/delete-account.dto.js.map +1 -0
  295. package/dist/profile/events/profile-account-deleted.event.d.ts +12 -0
  296. package/dist/profile/events/profile-account-deleted.event.d.ts.map +1 -0
  297. package/dist/profile/events/profile-account-deleted.event.js +17 -0
  298. package/dist/profile/events/profile-account-deleted.event.js.map +1 -0
  299. package/dist/profile/profile.controller.d.ts +21 -15
  300. package/dist/profile/profile.controller.d.ts.map +1 -1
  301. package/dist/profile/profile.controller.js +75 -46
  302. package/dist/profile/profile.controller.js.map +1 -1
  303. package/dist/profile/profile.service.d.ts +30 -18
  304. package/dist/profile/profile.service.d.ts.map +1 -1
  305. package/dist/profile/profile.service.js +113 -37
  306. package/dist/profile/profile.service.js.map +1 -1
  307. package/dist/realtime/realtime.gateway.d.ts +48 -0
  308. package/dist/realtime/realtime.gateway.d.ts.map +1 -0
  309. package/dist/realtime/realtime.gateway.js +156 -0
  310. package/dist/realtime/realtime.gateway.js.map +1 -0
  311. package/dist/realtime/realtime.module.d.ts +8 -0
  312. package/dist/realtime/realtime.module.d.ts.map +1 -0
  313. package/dist/realtime/realtime.module.js +29 -0
  314. package/dist/realtime/realtime.module.js.map +1 -0
  315. package/dist/realtime/realtime.service.d.ts +51 -0
  316. package/dist/realtime/realtime.service.d.ts.map +1 -0
  317. package/dist/realtime/realtime.service.js +177 -0
  318. package/dist/realtime/realtime.service.js.map +1 -0
  319. package/dist/redis/redis-pubsub.d.ts +27 -0
  320. package/dist/redis/redis-pubsub.d.ts.map +1 -0
  321. package/dist/redis/redis-pubsub.js +140 -0
  322. package/dist/redis/redis-pubsub.js.map +1 -0
  323. package/dist/role/role.controller.d.ts +3 -3
  324. package/dist/role/role.service.d.ts +3 -3
  325. package/dist/setting/dto/create.dto.d.ts.map +1 -1
  326. package/dist/setting/dto/create.dto.js +9 -2
  327. package/dist/setting/dto/create.dto.js.map +1 -1
  328. package/dist/setting/setting.controller.d.ts +5 -5
  329. package/dist/setting/setting.service.d.ts +8 -5
  330. package/dist/setting/setting.service.d.ts.map +1 -1
  331. package/dist/setting/setting.service.js +25 -1
  332. package/dist/setting/setting.service.js.map +1 -1
  333. package/dist/user/dto/create-with-email-and-password.dto.d.ts +2 -0
  334. package/dist/user/dto/create-with-email-and-password.dto.d.ts.map +1 -1
  335. package/dist/user/dto/create-with-email-and-password.dto.js +5 -0
  336. package/dist/user/dto/create-with-email-and-password.dto.js.map +1 -1
  337. package/dist/user/dto/query-user-mail-list.dto.d.ts +5 -0
  338. package/dist/user/dto/query-user-mail-list.dto.d.ts.map +1 -0
  339. package/dist/user/dto/query-user-mail-list.dto.js +25 -0
  340. package/dist/user/dto/query-user-mail-list.dto.js.map +1 -0
  341. package/dist/user/user-credential.util.d.ts +19 -0
  342. package/dist/user/user-credential.util.d.ts.map +1 -0
  343. package/dist/user/user-credential.util.js +32 -0
  344. package/dist/user/user-credential.util.js.map +1 -0
  345. package/dist/user/user.controller.d.ts +17 -5
  346. package/dist/user/user.controller.d.ts.map +1 -1
  347. package/dist/user/user.controller.js +18 -3
  348. package/dist/user/user.controller.js.map +1 -1
  349. package/dist/user/user.service.d.ts +28 -6
  350. package/dist/user/user.service.d.ts.map +1 -1
  351. package/dist/user/user.service.js +204 -13
  352. package/dist/user/user.service.js.map +1 -1
  353. package/dist/validators/is-strong-password-with-settings.validator.d.ts.map +1 -1
  354. package/dist/validators/is-strong-password-with-settings.validator.js +11 -0
  355. package/dist/validators/is-strong-password-with-settings.validator.js.map +1 -1
  356. package/dist/validators/service-locator.d.ts +9 -0
  357. package/dist/validators/service-locator.d.ts.map +1 -1
  358. package/dist/validators/service-locator.js +12 -0
  359. package/dist/validators/service-locator.js.map +1 -1
  360. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts +3 -0
  361. package/dist/whatsapp-sender/whatsapp-sender.module.d.ts.map +1 -0
  362. package/dist/whatsapp-sender/whatsapp-sender.module.js +23 -0
  363. package/dist/whatsapp-sender/whatsapp-sender.module.js.map +1 -0
  364. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +50 -0
  365. package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -0
  366. package/dist/whatsapp-sender/whatsapp-sender.service.js +224 -0
  367. package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -0
  368. package/hedhog/data/integration_provider.yaml +16 -0
  369. package/hedhog/data/mail.yaml +88 -61
  370. package/hedhog/data/mail_layout.yaml +188 -0
  371. package/hedhog/data/menu.yaml +67 -3
  372. package/hedhog/data/route.yaml +135 -0
  373. package/hedhog/data/setting_group.yaml +139 -1
  374. package/hedhog/frontend/app/account/components/mfa-setup-dialog.tsx.ejs +36 -0
  375. package/hedhog/frontend/app/account/components/two-factor-auth.tsx.ejs +2 -0
  376. package/hedhog/frontend/app/account/hooks/use-mfa-setup.ts.ejs +10 -7
  377. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +7 -4
  378. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +580 -0
  379. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-preview.tsx.ejs +150 -0
  380. package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +199 -0
  381. package/hedhog/frontend/app/ai_instruction/_components/prompt-diff.tsx.ejs +63 -0
  382. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.spec.ts.ejs +59 -0
  383. package/hedhog/frontend/app/ai_instruction/_lib/line-diff.ts.ejs +72 -0
  384. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.spec.ts.ejs +170 -0
  385. package/hedhog/frontend/app/ai_instruction/_lib/prompt-template.ts.ejs +167 -0
  386. package/hedhog/frontend/app/ai_instruction/_lib/types.ts.ejs +99 -0
  387. package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +422 -0
  388. package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +51 -4
  389. package/hedhog/frontend/app/incidents/page.tsx.ejs +400 -0
  390. package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +153 -84
  391. package/hedhog/frontend/app/mail/layout/page.tsx.ejs +344 -0
  392. package/hedhog/frontend/app/mail/template/page.tsx.ejs +155 -121
  393. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +129 -17
  394. package/hedhog/frontend/app/pages/_components/page-delete-dialog.tsx.ejs +343 -0
  395. package/hedhog/frontend/app/pages/_components/page-detail-sheet.tsx.ejs +438 -0
  396. package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1009 -0
  397. package/hedhog/frontend/app/pages/_components/system-page-types.ts.ejs +56 -0
  398. package/hedhog/frontend/app/pages/_components/use-system-pages.ts.ejs +171 -0
  399. package/hedhog/frontend/app/pages/page.tsx.ejs +514 -0
  400. package/hedhog/frontend/app/users/page.tsx.ejs +119 -13
  401. package/hedhog/frontend/app/users/user-activity-timeline.tsx.ejs +231 -0
  402. package/hedhog/frontend/app/users/user-mails.tsx.ejs +399 -0
  403. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +60 -75
  404. package/hedhog/frontend/messages/en.json +499 -3
  405. package/hedhog/frontend/messages/pt.json +499 -3
  406. package/hedhog/table/ai_agent.yaml +1 -0
  407. package/hedhog/table/ai_instruction.yaml +15 -0
  408. package/hedhog/table/leaked_password.yaml +18 -0
  409. package/hedhog/table/mail_layout.yaml +35 -0
  410. package/hedhog/table/mail_var.yaml +4 -0
  411. package/hedhog/table/setting.yaml +1 -0
  412. package/hedhog/table/system_incident.yaml +59 -0
  413. package/hedhog/table/user_presence.yaml +36 -0
  414. package/package.json +8 -4
  415. package/src/access-log/access-log.interceptor.ts +4 -2
  416. package/src/ai/ai-attachment.fragments.spec.ts +319 -0
  417. package/src/ai/ai-attachment.fragments.ts +35 -0
  418. package/src/ai/ai.prompts.ts +38 -0
  419. package/src/ai/ai.service.spec.ts +280 -0
  420. package/src/ai/ai.service.ts +338 -82
  421. package/src/ai/dto/chat.dto.ts +33 -3
  422. package/src/ai/dto/create-agent.dto.ts +2 -2
  423. package/src/ai/dto/update-agent.dto.ts +2 -2
  424. package/src/ai-instruction/ai-instruction.controller.ts +40 -9
  425. package/src/ai-instruction/ai-instruction.module.ts +13 -2
  426. package/src/ai-instruction/ai-instruction.service.spec.ts +658 -0
  427. package/src/ai-instruction/ai-instruction.service.ts +661 -62
  428. package/src/ai-instruction/ai-prompt-builder.service.ts +10 -1
  429. package/src/ai-instruction/ai-prompt-registry.ts +87 -0
  430. package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +375 -0
  431. package/src/ai-instruction/ai-prompt-resolver.service.ts +295 -0
  432. package/src/ai-instruction/ai-prompt-template.util.spec.ts +162 -0
  433. package/src/ai-instruction/ai-prompt-template.util.ts +199 -0
  434. package/src/ai-instruction/dto/create-ai-instruction.dto.ts +39 -3
  435. package/src/ai-instruction/dto/preview-ai-instruction.dto.ts +26 -0
  436. package/src/ai-instruction/dto/update-ai-instruction.dto.ts +42 -1
  437. package/src/ai-instruction/types/ai-instruction.types.ts +24 -1
  438. package/src/auth/auth.controller.ts +31 -5
  439. package/src/auth/auth.service.spec.ts +3 -1
  440. package/src/auth/auth.service.ts +101 -36
  441. package/src/captcha/captcha.module.ts +10 -0
  442. package/src/captcha/captcha.service.spec.ts +210 -0
  443. package/src/captcha/captcha.service.ts +191 -0
  444. package/src/challenge/challenge.service.spec.ts +39 -4
  445. package/src/challenge/challenge.service.ts +72 -17
  446. package/src/core.module.ts +27 -1
  447. package/src/file/file.service.spec.ts +105 -0
  448. package/src/file/file.service.ts +60 -3
  449. package/src/incident/incident-notifier.service.spec.ts +205 -0
  450. package/src/incident/incident-notifier.service.ts +241 -0
  451. package/src/incident/incident.controller.ts +38 -0
  452. package/src/incident/incident.module.ts +19 -0
  453. package/src/incident/incident.service.spec.ts +150 -0
  454. package/src/incident/incident.service.ts +209 -0
  455. package/src/index.ts +37 -0
  456. package/src/integration-profile/dto/test.dto.ts +19 -0
  457. package/src/integration-profile/integration-profile.controller.ts +10 -1
  458. package/src/integration-profile/integration-profile.module.spec.ts +51 -0
  459. package/src/integration-profile/integration-profile.module.ts +23 -4
  460. package/src/integration-profile/integration-profile.secrets.ts +9 -1
  461. package/src/integration-profile/integration-profile.service.spec.ts +279 -0
  462. package/src/integration-profile/integration-profile.service.ts +120 -124
  463. package/src/integration-profile/integration-profile.utils.spec.ts +22 -0
  464. package/src/integration-profile/integration-profile.utils.ts +40 -3
  465. package/src/integration-profile/testers/ai.testers.ts +165 -0
  466. package/src/integration-profile/testers/captcha.testers.spec.ts +92 -0
  467. package/src/integration-profile/testers/captcha.testers.ts +139 -0
  468. package/src/integration-profile/testers/email.testers.ts +161 -0
  469. package/src/integration-profile/testers/http-probe.spec.ts +153 -0
  470. package/src/integration-profile/testers/http-probe.ts +171 -0
  471. package/src/integration-profile/testers/index.ts +30 -0
  472. package/src/integration-profile/testers/infrastructure.testers.ts +122 -0
  473. package/src/integration-profile/testers/integration-tester.registry.spec.ts +75 -0
  474. package/src/integration-profile/testers/integration-tester.registry.ts +43 -0
  475. package/src/integration-profile/testers/integration-tester.types.ts +61 -0
  476. package/src/integration-profile/testers/messaging.testers.ts +102 -0
  477. package/src/integration-profile/testers/oauth.testers.spec.ts +220 -0
  478. package/src/integration-profile/testers/oauth.testers.ts +305 -0
  479. package/src/integration-profile/testers/payment.testers.ts +185 -0
  480. package/src/integration-profile/testers/remaining.testers.spec.ts +401 -0
  481. package/src/integration-profile/testers/storage.testers.spec.ts +185 -0
  482. package/src/integration-profile/testers/storage.testers.ts +226 -0
  483. package/src/integration-profile/testers/tester-coverage.spec.ts +58 -0
  484. package/src/language/en.json +4 -2
  485. package/src/language/pt.json +4 -2
  486. package/src/leaked-password/README.md +83 -0
  487. package/src/leaked-password/leaked-password.controller.ts +52 -0
  488. package/src/leaked-password/leaked-password.module.ts +18 -0
  489. package/src/leaked-password/leaked-password.service.ts +242 -0
  490. package/src/leaked-password/seed/build-seed-sql.mjs +180 -0
  491. package/src/leaked-password/seed/common-passwords.txt +335 -0
  492. package/src/mail/dto/preview.dto.ts +50 -0
  493. package/src/mail/dto/send.dto.ts +14 -1
  494. package/src/mail/mail-template.spec.ts +197 -0
  495. package/src/mail/mail.controller.ts +9 -2
  496. package/src/mail/mail.service.spec.ts +116 -1
  497. package/src/mail/mail.service.ts +118 -12
  498. package/src/mail-layout/dto/update.dto.ts +19 -0
  499. package/src/mail-layout/mail-layout.controller.ts +47 -0
  500. package/src/mail-layout/mail-layout.module.ts +22 -0
  501. package/src/mail-layout/mail-layout.service.ts +94 -0
  502. package/src/mcp-chat/mcp-chat.service.spec.ts +236 -0
  503. package/src/mcp-chat/mcp-chat.service.ts +122 -26
  504. package/src/oauth/oauth-token-broker.service.spec.ts +172 -0
  505. package/src/oauth/oauth-token-broker.service.ts +363 -0
  506. package/src/oauth/oauth.module.ts +3 -1
  507. package/src/oauth/oauth.service.ts +8 -2
  508. package/src/pdf/pdf.service.ts +75 -0
  509. package/src/presence/presence.controller.ts +29 -0
  510. package/src/presence/presence.listener.ts +53 -0
  511. package/src/presence/presence.module.ts +19 -0
  512. package/src/presence/presence.service.spec.ts +97 -0
  513. package/src/presence/presence.service.ts +160 -0
  514. package/src/profile/dto/delete-account.dto.ts +11 -0
  515. package/src/profile/events/profile-account-deleted.event.ts +13 -0
  516. package/src/profile/profile.controller.ts +46 -34
  517. package/src/profile/profile.service.ts +138 -38
  518. package/src/realtime/realtime.gateway.ts +138 -0
  519. package/src/realtime/realtime.module.ts +16 -0
  520. package/src/realtime/realtime.service.spec.ts +50 -0
  521. package/src/realtime/realtime.service.ts +187 -0
  522. package/src/redis/redis-pubsub.ts +179 -0
  523. package/src/setting/dto/create.dto.ts +13 -2
  524. package/src/setting/setting.service.spec.ts +56 -0
  525. package/src/setting/setting.service.ts +29 -1
  526. package/src/user/dto/create-with-email-and-password.dto.ts +6 -1
  527. package/src/user/dto/query-user-mail-list.dto.ts +10 -0
  528. package/src/user/user-credential.util.ts +35 -0
  529. package/src/user/user.controller.ts +17 -2
  530. package/src/user/user.service.spec.ts +153 -0
  531. package/src/user/user.service.ts +255 -12
  532. package/src/validators/is-strong-password-with-settings.validator.ts +12 -0
  533. package/src/validators/service-locator.ts +15 -0
  534. package/src/whatsapp-sender/whatsapp-sender.module.ts +10 -0
  535. package/src/whatsapp-sender/whatsapp-sender.service.ts +313 -0
@@ -0,0 +1,236 @@
1
+ import axios from 'axios';
2
+ import { McpChatService } from './mcp-chat.service';
3
+
4
+ jest.mock('axios');
5
+
6
+ const mockedAxios = axios as jest.Mocked<typeof axios>;
7
+
8
+ type ProfileConfig = Record<string, unknown>;
9
+
10
+ /**
11
+ * O serviço é instanciado à mão em vez de por `Test.createTestingModule` para
12
+ * não arrastar os `forwardRef` do módulo — o que está sob teste é a resolução
13
+ * do modelo, não a injeção.
14
+ */
15
+ function buildService(params: {
16
+ providerSlug: string;
17
+ config: ProfileConfig;
18
+ clarification?: string;
19
+ }) {
20
+ const recordStep = jest.fn();
21
+ const finish = jest.fn();
22
+
23
+ const prisma = {
24
+ mcp_conversation: {
25
+ findUnique: jest.fn().mockResolvedValue({ user_id: 1, title: 'conversa' }),
26
+ update: jest.fn().mockResolvedValue({}),
27
+ },
28
+ mcp_conversation_message: {
29
+ create: jest.fn().mockResolvedValue({}),
30
+ findMany: jest.fn().mockResolvedValue([]),
31
+ },
32
+ integration_profile: {
33
+ findUnique: jest.fn().mockResolvedValue({
34
+ config: { api_key: 'chave-secreta', ...params.config },
35
+ integration_provider: { slug: params.providerSlug },
36
+ }),
37
+ },
38
+ route: { findMany: jest.fn().mockResolvedValue([]) },
39
+ };
40
+
41
+ const setting = {
42
+ getSettingValues: jest.fn(async (keys: string[]) => {
43
+ const values: Record<string, unknown> = {
44
+ 'mcp-enabled': true,
45
+ 'mcp-ai-profile-id': 'perfil-mcp',
46
+ };
47
+ return Object.fromEntries(keys.map((key) => [key, values[key]]));
48
+ }),
49
+ };
50
+
51
+ // Sem ferramentas registradas o loop encerra na primeira resposta, e
52
+ // `tools`/`tool_choice` continuam `undefined` no corpo enviado.
53
+ const registry = { getAll: jest.fn().mockReturnValue([]) };
54
+
55
+ const promptBuilder = {
56
+ build: jest.fn().mockResolvedValue({
57
+ systemPrompt: 'prompt de sistema',
58
+ layers: [],
59
+ layerNames: [],
60
+ }),
61
+ };
62
+
63
+ const aiExecution = {
64
+ start: jest.fn().mockResolvedValue(7),
65
+ recordStep,
66
+ finish,
67
+ };
68
+
69
+ const service = new McpChatService(
70
+ prisma as any,
71
+ setting as any,
72
+ registry as any,
73
+ promptBuilder as any,
74
+ aiExecution as any,
75
+ );
76
+
77
+ if (params.clarification) {
78
+ jest
79
+ .spyOn(service as any, 'selectOpenAiTools')
80
+ .mockResolvedValue({ tools: [], clarification: params.clarification });
81
+ }
82
+
83
+ return { service, recordStep, finish, prisma };
84
+ }
85
+
86
+ function mockOpenAiReply() {
87
+ mockedAxios.post.mockResolvedValue({
88
+ data: {
89
+ choices: [{ message: { content: 'resposta' } }],
90
+ usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
91
+ },
92
+ } as any);
93
+ }
94
+
95
+ function mockGeminiReply() {
96
+ mockedAxios.post.mockResolvedValue({
97
+ data: {
98
+ candidates: [{ content: { parts: [{ text: 'resposta' }] } }],
99
+ usageMetadata: {
100
+ promptTokenCount: 10,
101
+ candidatesTokenCount: 5,
102
+ totalTokenCount: 15,
103
+ },
104
+ },
105
+ } as any);
106
+ }
107
+
108
+ const send = (service: McpChatService) =>
109
+ service.sendMessage(1, 1, 'pt-BR', 'olá');
110
+
111
+ describe('McpChatService — modelo vindo do integration_profile', () => {
112
+ beforeEach(() => {
113
+ jest.clearAllMocks();
114
+ });
115
+
116
+ describe('OpenAI', () => {
117
+ it('sem model no perfil, envia o corpo histórico intacto', async () => {
118
+ const { service, recordStep } = buildService({
119
+ providerSlug: 'openai',
120
+ config: {},
121
+ });
122
+ mockOpenAiReply();
123
+
124
+ await send(service);
125
+
126
+ const [url, body, options] = mockedAxios.post.mock.calls[0];
127
+ expect(url).toBe('https://api.openai.com/v1/chat/completions');
128
+ expect(body).toEqual({
129
+ model: 'gpt-4o-mini',
130
+ messages: [
131
+ { role: 'system', content: 'prompt de sistema' },
132
+ ],
133
+ tools: undefined,
134
+ tool_choice: undefined,
135
+ });
136
+ expect(options).toEqual({
137
+ headers: {
138
+ Authorization: 'Bearer chave-secreta',
139
+ 'Content-Type': 'application/json',
140
+ },
141
+ });
142
+ expect(recordStep).toHaveBeenCalledWith(
143
+ expect.objectContaining({ provider: 'openai', model: 'gpt-4o-mini' }),
144
+ );
145
+ });
146
+
147
+ it('usa o model do perfil no corpo e no registro de custo', async () => {
148
+ const { service, recordStep } = buildService({
149
+ providerSlug: 'openai',
150
+ config: { model: 'gpt-4o' },
151
+ });
152
+ mockOpenAiReply();
153
+
154
+ await send(service);
155
+
156
+ expect(mockedAxios.post.mock.calls[0][1]).toEqual(
157
+ expect.objectContaining({ model: 'gpt-4o' }),
158
+ );
159
+ expect(recordStep).toHaveBeenCalledWith(
160
+ expect.objectContaining({ provider: 'openai', model: 'gpt-4o' }),
161
+ );
162
+ });
163
+ });
164
+
165
+ describe('Gemini', () => {
166
+ it('sem model no perfil, mantém a URL e o custo históricos', async () => {
167
+ const { service, recordStep } = buildService({
168
+ providerSlug: 'gemini',
169
+ config: {},
170
+ });
171
+ mockGeminiReply();
172
+
173
+ await send(service);
174
+
175
+ expect(mockedAxios.post.mock.calls[0][0]).toBe(
176
+ 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=chave-secreta',
177
+ );
178
+ expect(recordStep).toHaveBeenCalledWith(
179
+ expect.objectContaining({
180
+ provider: 'gemini',
181
+ model: 'gemini-2.0-flash',
182
+ }),
183
+ );
184
+ });
185
+
186
+ it('usa o model do perfil na URL e no registro de custo', async () => {
187
+ const { service, recordStep } = buildService({
188
+ providerSlug: 'gemini',
189
+ config: { model: 'gemini-2.5-flash' },
190
+ });
191
+ mockGeminiReply();
192
+
193
+ await send(service);
194
+
195
+ expect(mockedAxios.post.mock.calls[0][0]).toContain(
196
+ '/models/gemini-2.5-flash:generateContent',
197
+ );
198
+ expect(recordStep).toHaveBeenCalledWith(
199
+ expect.objectContaining({
200
+ provider: 'gemini',
201
+ model: 'gemini-2.5-flash',
202
+ }),
203
+ );
204
+ });
205
+
206
+ it('aceita o model no formato "models/<id>" sem duplicar o segmento', async () => {
207
+ const { service, recordStep } = buildService({
208
+ providerSlug: 'gemini',
209
+ config: { model: 'models/gemini-2.5-flash' },
210
+ });
211
+ mockGeminiReply();
212
+
213
+ await send(service);
214
+
215
+ const url = mockedAxios.post.mock.calls[0][0];
216
+ expect(url).toContain('/v1beta/models/gemini-2.5-flash:generateContent');
217
+ expect(url).not.toContain('models/models/');
218
+ expect(recordStep).toHaveBeenCalledWith(
219
+ expect.objectContaining({ model: 'gemini-2.5-flash' }),
220
+ );
221
+ });
222
+ });
223
+
224
+ it('fecha a execução quando o caminho OpenAI devolve pedido de esclarecimento', async () => {
225
+ const { service, finish } = buildService({
226
+ providerSlug: 'openai',
227
+ config: {},
228
+ clarification: 'Qual conta você quer consultar?',
229
+ });
230
+
231
+ await send(service);
232
+
233
+ expect(mockedAxios.post).not.toHaveBeenCalled();
234
+ expect(finish).toHaveBeenCalledWith(7, 'completed');
235
+ });
236
+ });
@@ -12,13 +12,27 @@ import {
12
12
  } from '@nestjs/common';
13
13
  import axios from 'axios';
14
14
  import { AiExecutionService } from '../ai-instruction/ai-execution.service';
15
+ import { FALLBACK_SYSTEM_PROMPT } from '../ai-instruction/ai-instruction.service';
15
16
  import { AiPromptBuilderService } from '../ai-instruction/ai-prompt-builder.service';
16
- import { buildAiConfigFromIntegration } from '../integration-profile/integration-profile.utils';
17
+ import {
18
+ buildAiConfigFromIntegration,
19
+ DEEPSEEK_API_BASE_URL,
20
+ DEEPSEEK_DEFAULT_MODEL,
21
+ } from '../integration-profile/integration-profile.utils';
17
22
  import { McpRegistryService, McpToolEntry } from '../mcp/mcp-registry.service';
18
23
  import { McpContext } from '../mcp/types/mcp-context.type';
19
24
  import { SettingService } from '../setting/setting.service';
20
25
  import { CreateConversationDTO } from './dto/create-conversation.dto';
21
26
 
27
+ const OPENAI_API_BASE_URL = 'https://api.openai.com/v1';
28
+ /**
29
+ * Modelos usados quando o perfil de integração não declara `config.model`.
30
+ * São o comportamento histórico do chat MCP, de quando o modelo era literal:
31
+ * mudar aqui muda o padrão de toda instalação que ainda não preencheu o campo.
32
+ */
33
+ const OPENAI_CHAT_MODEL = 'gpt-4o-mini';
34
+ const GEMINI_CHAT_MODEL = 'gemini-2.0-flash';
35
+
22
36
  type OpenAiMessage =
23
37
  | { role: 'system'; content: string }
24
38
  | { role: 'user'; content: string }
@@ -90,13 +104,6 @@ const FORCE_FINISH_THRESHOLD = 2;
90
104
  const MIN_DOMAIN_CONFIDENCE = 2;
91
105
  const AMBIGUOUS_DOMAIN_DELTA = 1;
92
106
 
93
- // SYSTEM_PROMPT is now managed via AiInstructionService (slug: system.global).
94
- // This fallback is used only if the DB is unreachable during startup.
95
- const SYSTEM_PROMPT_FALLBACK =
96
- 'You are a helpful assistant with access to tools from the HedHog system. ' +
97
- "Use the available tools to answer the user's questions accurately. " +
98
- 'Always respond in the same language the user writes in.';
99
-
100
107
  const sanitize = (n: string) => n.replace(/\./g, '__');
101
108
  const restore = (n: string) => n.replace(/__/g, '.');
102
109
 
@@ -300,7 +307,7 @@ export class McpChatService {
300
307
 
301
308
  await this.assertOwnership(conversationId, userId);
302
309
 
303
- const { provider, apiKey } = await this.getProviderKey();
310
+ const { provider, apiKey, baseUrl, model } = await this.getProviderKey();
304
311
 
305
312
  // Save user message
306
313
  await this.prisma.mcp_conversation_message.create({
@@ -331,28 +338,65 @@ export class McpChatService {
331
338
 
332
339
  try {
333
340
  if (provider === 'gemini') {
334
- return await this.runGeminiLoop(conversationId, userId, locale, message, apiKey, executionId);
341
+ return await this.runGeminiLoop(
342
+ conversationId,
343
+ userId,
344
+ locale,
345
+ message,
346
+ apiKey,
347
+ executionId,
348
+ model,
349
+ );
335
350
  }
336
- return await this.runOpenAiLoop(conversationId, userId, locale, message, apiKey, executionId);
351
+ return await this.runOpenAiLoop(
352
+ conversationId,
353
+ userId,
354
+ locale,
355
+ message,
356
+ apiKey,
357
+ executionId,
358
+ provider,
359
+ baseUrl,
360
+ model,
361
+ );
337
362
  } catch (err) {
338
363
  await this.aiExecution.finish(executionId, 'failed', String(err));
339
364
  throw err;
340
365
  }
341
366
  }
342
367
 
343
- private async getSystemPrompt(locale?: string): Promise<string> {
368
+ /**
369
+ * Composes the system prompt from the stored layers.
370
+ *
371
+ * `moduleSlug`/`agentSlug` activate the L3/L4 layers; without them the seeded
372
+ * `module.*` and `agent.*` instructions are never read. `SYSTEM_PROMPT_FALLBACK`
373
+ * used to be duplicated here — it now comes from `AiInstructionService`, which
374
+ * already falls back internally, so this only guards against the whole build
375
+ * throwing.
376
+ */
377
+ private async getSystemPrompt(
378
+ locale?: string,
379
+ context?: { moduleSlug?: string; agentSlug?: string },
380
+ ): Promise<string> {
344
381
  try {
345
382
  const built = await this.promptBuilder.build({
346
383
  locale,
384
+ moduleSlug: context?.moduleSlug,
385
+ agentSlug: context?.agentSlug,
347
386
  });
348
- return built.systemPrompt || SYSTEM_PROMPT_FALLBACK;
387
+ return built.systemPrompt || FALLBACK_SYSTEM_PROMPT;
349
388
  } catch {
350
- return SYSTEM_PROMPT_FALLBACK;
389
+ return FALLBACK_SYSTEM_PROMPT;
351
390
  }
352
391
  }
353
392
 
354
393
  // ── OpenAI loop ──────────────────────────────────────────────────────────
355
394
 
395
+ /**
396
+ * Loop de tool calling no formato OpenAI. Serve tanto para a OpenAI quanto
397
+ * para o DeepSeek, que expõe a mesma API de `/chat/completions` (inclusive
398
+ * `tools`/`tool_calls`) — muda só a base URL, o modelo e a chave.
399
+ */
356
400
  private async runOpenAiLoop(
357
401
  conversationId: number,
358
402
  userId: number,
@@ -360,6 +404,9 @@ export class McpChatService {
360
404
  message: string,
361
405
  apiKey: string,
362
406
  executionId: number,
407
+ provider: 'openai' | 'deepseek' = 'openai',
408
+ baseUrl = OPENAI_API_BASE_URL,
409
+ model = OPENAI_CHAT_MODEL,
363
410
  ) {
364
411
  const systemPrompt = await this.getSystemPrompt(locale);
365
412
 
@@ -385,6 +432,9 @@ export class McpChatService {
385
432
  history,
386
433
  );
387
434
  if (toolSelection.clarification) {
435
+ // Sem o finish a execução fica presa em `running` para sempre — o caminho
436
+ // Gemini já fechava aqui.
437
+ await this.aiExecution.finish(executionId, 'completed');
388
438
  return this.recordAssistantAndReturnHistory(
389
439
  conversationId,
390
440
  toolSelection.clarification,
@@ -401,9 +451,9 @@ export class McpChatService {
401
451
  const stepStart = Date.now();
402
452
  try {
403
453
  response = await axios.post(
404
- 'https://api.openai.com/v1/chat/completions',
454
+ `${baseUrl}/chat/completions`,
405
455
  {
406
- model: 'gpt-4o-mini',
456
+ model,
407
457
  messages: openAiMessages,
408
458
  tools: !forceFinish && tools.length > 0 ? tools : undefined,
409
459
  tool_choice: !forceFinish && tools.length > 0 ? 'auto' : undefined,
@@ -418,17 +468,19 @@ export class McpChatService {
418
468
  } catch (err: any) {
419
469
  const status = err?.response?.status;
420
470
  const errBody = err?.response?.data?.error;
471
+ const providerName = provider === 'deepseek' ? 'DeepSeek' : 'OpenAI';
421
472
  if (status === 429) {
422
473
  throw new HttpException(
423
- errBody?.message ?? 'OpenAI rate limit exceeded. Please try again later.',
474
+ errBody?.message ??
475
+ `${providerName} rate limit exceeded. Please try again later.`,
424
476
  HttpStatus.TOO_MANY_REQUESTS,
425
477
  );
426
478
  }
427
479
  if (status === 401) {
428
- throw new BadRequestException('Invalid OpenAI API key.');
480
+ throw new BadRequestException(`Invalid ${providerName} API key.`);
429
481
  }
430
482
  throw new HttpException(
431
- errBody?.message ?? 'OpenAI API error.',
483
+ errBody?.message ?? `${providerName} API error.`,
432
484
  status ?? HttpStatus.BAD_GATEWAY,
433
485
  );
434
486
  }
@@ -438,8 +490,8 @@ export class McpChatService {
438
490
  executionId,
439
491
  stepOrder: stepOrder++,
440
492
  type: 'prompt',
441
- provider: 'openai',
442
- model: 'gpt-4o-mini',
493
+ provider,
494
+ model,
443
495
  durationMs: Date.now() - stepStart,
444
496
  usage: usage
445
497
  ? { input: usage.prompt_tokens ?? 0, output: usage.completion_tokens ?? 0, total: usage.total_tokens ?? 0 }
@@ -571,7 +623,11 @@ export class McpChatService {
571
623
  message: string,
572
624
  apiKey: string,
573
625
  executionId: number,
626
+ model = GEMINI_CHAT_MODEL,
574
627
  ) {
628
+ // O perfil pode trazer o nome no formato da API ("models/gemini-2.0-flash");
629
+ // a URL abaixo já inclui o segmento `/models/`.
630
+ const modelId = model.replace(/^models\//, '');
575
631
  const systemPrompt = await this.getSystemPrompt(locale);
576
632
 
577
633
  const allHistory = await this.prisma.mcp_conversation_message.findMany({
@@ -608,7 +664,7 @@ export class McpChatService {
608
664
  const stepStart = Date.now();
609
665
  try {
610
666
  response = await axios.post(
611
- `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`,
667
+ `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(modelId)}:generateContent?key=${apiKey}`,
612
668
  {
613
669
  systemInstruction: { parts: [{ text: systemPrompt }] },
614
670
  contents: geminiContents,
@@ -648,7 +704,7 @@ export class McpChatService {
648
704
  stepOrder: stepOrder++,
649
705
  type: 'prompt',
650
706
  provider: 'gemini',
651
- model: 'gemini-2.0-flash',
707
+ model: modelId,
652
708
  durationMs: Date.now() - stepStart,
653
709
  usage: geminiUsage
654
710
  ? { input: geminiUsage.promptTokenCount ?? 0, output: geminiUsage.candidatesTokenCount ?? 0, total: geminiUsage.totalTokenCount ?? 0 }
@@ -858,7 +914,21 @@ export class McpChatService {
858
914
  }
859
915
  }
860
916
 
861
- private async getProviderKey(): Promise<{ provider: 'openai' | 'gemini'; apiKey: string }> {
917
+ /**
918
+ * Resolve credenciais e modelo do chat MCP a partir do perfil de integração
919
+ * apontado pela setting `mcp-ai-profile-id`.
920
+ *
921
+ * O `model` segue a mesma precedência do resto do codebase — aqui sem o degrau
922
+ * de `ai_instruction`, porque este fluxo não tem prompt de task próprio:
923
+ * `integration_profile.config.model` > constante de default do provider.
924
+ */
925
+ private async getProviderKey(): Promise<{
926
+ provider: 'openai' | 'gemini' | 'deepseek';
927
+ apiKey: string;
928
+ /** Base URL só se aplica aos providers no formato OpenAI; o Gemini leva o modelo na URL. */
929
+ baseUrl: string;
930
+ model: string;
931
+ }> {
862
932
  const settings = await this.setting.getSettingValues(['mcp-ai-profile-id']);
863
933
  const profileSlug = String(settings['mcp-ai-profile-id'] ?? '').trim();
864
934
 
@@ -878,13 +948,39 @@ export class McpChatService {
878
948
  }
879
949
 
880
950
  const providerSlug = profile.integration_provider.slug;
881
- const { apiKey } = buildAiConfigFromIntegration(providerSlug, profile.config);
951
+ const { apiKey, model, baseUrl } = buildAiConfigFromIntegration(
952
+ providerSlug,
953
+ profile.config,
954
+ );
882
955
 
883
956
  if (!apiKey) {
884
957
  throw new BadRequestException(`MCP AI profile "${profileSlug}" has no API key configured.`);
885
958
  }
886
959
 
887
- return { provider: providerSlug === 'gemini' ? 'gemini' : 'openai', apiKey };
960
+ if (providerSlug === 'gemini') {
961
+ return {
962
+ provider: 'gemini',
963
+ apiKey,
964
+ baseUrl: '',
965
+ model: model || GEMINI_CHAT_MODEL,
966
+ };
967
+ }
968
+
969
+ if (providerSlug === 'deepseek') {
970
+ return {
971
+ provider: 'deepseek',
972
+ apiKey,
973
+ baseUrl: baseUrl || DEEPSEEK_API_BASE_URL,
974
+ model: model || DEEPSEEK_DEFAULT_MODEL,
975
+ };
976
+ }
977
+
978
+ return {
979
+ provider: 'openai',
980
+ apiKey,
981
+ baseUrl: OPENAI_API_BASE_URL,
982
+ model: model || OPENAI_CHAT_MODEL,
983
+ };
888
984
  }
889
985
 
890
986
  private async buildOpenAiTools(
@@ -0,0 +1,172 @@
1
+ import { describe, it, expect, beforeEach, jest } from '@jest/globals';
2
+ import { of, throwError } from 'rxjs';
3
+ import { SecurityService } from '../security/security.service';
4
+ import {
5
+ OAuthTokenBrokerError,
6
+ OAuthTokenBrokerService,
7
+ } from './oauth-token-broker.service';
8
+
9
+ const ENCRYPTION_SECRET = 'test-encryption-secret-0123456789';
10
+
11
+ const makeSecurity = () =>
12
+ new SecurityService({
13
+ get: (key: string) =>
14
+ key === 'ENCRYPTION_SECRET' ? ENCRYPTION_SECRET : undefined,
15
+ } as any);
16
+
17
+ const makeDeps = () => {
18
+ const security = makeSecurity();
19
+ const http = { post: jest.fn() };
20
+ const prisma = {
21
+ integration_profile: { findUnique: jest.fn() },
22
+ user_account: { findFirst: jest.fn(), update: jest.fn() },
23
+ };
24
+ const setting = { getSettingValues: jest.fn() };
25
+ return { security, http, prisma, setting };
26
+ };
27
+
28
+ const makeService = (deps = makeDeps()) => ({
29
+ service: new OAuthTokenBrokerService(
30
+ deps.http as any,
31
+ deps.setting as any,
32
+ deps.prisma as any,
33
+ deps.security,
34
+ ),
35
+ deps,
36
+ });
37
+
38
+ const PROVIDER = 'microsoft-entra-id';
39
+
40
+ const primeConfig = (deps: ReturnType<typeof makeDeps>) => {
41
+ deps.setting.getSettingValues.mockResolvedValue({
42
+ 'oauth-microsoft-entra-id-profile-id': 'ms-profile',
43
+ } as any);
44
+ deps.prisma.integration_profile.findUnique.mockResolvedValue({
45
+ slug: 'ms-profile',
46
+ config: {
47
+ client_id: 'CID',
48
+ client_secret: 'SECRET',
49
+ tenant_id: 'TENANT',
50
+ },
51
+ integration_provider: { slug: 'microsoft-entra-id-oauth' },
52
+ } as any);
53
+ };
54
+
55
+ describe('OAuthTokenBrokerService', () => {
56
+ let deps: ReturnType<typeof makeDeps>;
57
+ let service: OAuthTokenBrokerService;
58
+
59
+ beforeEach(() => {
60
+ const built = makeService();
61
+ deps = built.deps;
62
+ service = built.service;
63
+ primeConfig(deps);
64
+ });
65
+
66
+ const storedRefreshTokenRow = (security: SecurityService, plain: string) => ({
67
+ id: 42,
68
+ refresh_token: Buffer.from(security.encrypt(plain)),
69
+ scopes: 'openid,offline_access,Calendars.Read',
70
+ token_expires_at: new Date('2020-01-01T00:00:00Z'),
71
+ });
72
+
73
+ it('decrypts the stored refresh token, exchanges it, and returns an access token', async () => {
74
+ deps.prisma.user_account.findFirst.mockResolvedValue(
75
+ storedRefreshTokenRow(deps.security, 'refresh-original') as any,
76
+ );
77
+ deps.http.post.mockReturnValue(
78
+ of({
79
+ data: {
80
+ access_token: 'ACCESS-1',
81
+ refresh_token: 'refresh-rotated',
82
+ expires_in: 3600,
83
+ },
84
+ }) as any,
85
+ );
86
+
87
+ const result = await service.getAccessToken(1, PROVIDER);
88
+
89
+ expect(result.accessToken).toBe('ACCESS-1');
90
+ expect(result.expiresAt.getTime()).toBeGreaterThan(Date.now());
91
+
92
+ // The token endpoint received the DECRYPTED refresh token, not the ciphertext.
93
+ const [, body] = deps.http.post.mock.calls[0] as [string, string, unknown];
94
+ expect(body).toContain('grant_type=refresh_token');
95
+ expect(body).toContain('refresh_token=refresh-original');
96
+ });
97
+
98
+ it('persists the rotated refresh token re-encrypted (never in plaintext)', async () => {
99
+ deps.prisma.user_account.findFirst.mockResolvedValue(
100
+ storedRefreshTokenRow(deps.security, 'refresh-original') as any,
101
+ );
102
+ deps.http.post.mockReturnValue(
103
+ of({
104
+ data: {
105
+ access_token: 'ACCESS-1',
106
+ refresh_token: 'refresh-rotated',
107
+ expires_in: 3600,
108
+ },
109
+ }) as any,
110
+ );
111
+
112
+ await service.getAccessToken(1, PROVIDER);
113
+
114
+ expect(deps.prisma.user_account.update).toHaveBeenCalledTimes(1);
115
+ const updateArg = deps.prisma.user_account.update.mock.calls[0][0] as any;
116
+ const storedBuffer = updateArg.data.refresh_token as Buffer;
117
+ // Round-trips back to the rotated token, and is not the plaintext itself.
118
+ expect(storedBuffer.toString()).not.toContain('refresh-rotated');
119
+ expect(deps.security.decrypt(storedBuffer.toString())).toBe('refresh-rotated');
120
+ });
121
+
122
+ it('serves a cached access token without a second token exchange', async () => {
123
+ deps.prisma.user_account.findFirst.mockResolvedValue(
124
+ storedRefreshTokenRow(deps.security, 'refresh-original') as any,
125
+ );
126
+ deps.http.post.mockReturnValue(
127
+ of({
128
+ data: { access_token: 'ACCESS-1', expires_in: 3600 },
129
+ }) as any,
130
+ );
131
+
132
+ await service.getAccessToken(1, PROVIDER);
133
+ await service.getAccessToken(1, PROVIDER);
134
+
135
+ expect(deps.http.post).toHaveBeenCalledTimes(1);
136
+ });
137
+
138
+ it('throws not_connected when the user has no linked account', async () => {
139
+ deps.prisma.user_account.findFirst.mockResolvedValue(null as any);
140
+
141
+ await expect(service.getAccessToken(1, PROVIDER)).rejects.toMatchObject({
142
+ reason: 'not_connected',
143
+ });
144
+ });
145
+
146
+ it('throws refresh_revoked on invalid_grant from the provider', async () => {
147
+ deps.prisma.user_account.findFirst.mockResolvedValue(
148
+ storedRefreshTokenRow(deps.security, 'refresh-original') as any,
149
+ );
150
+ deps.http.post.mockReturnValue(
151
+ throwError(() => ({
152
+ response: { data: { error: 'invalid_grant' }, status: 400 },
153
+ })) as any,
154
+ );
155
+
156
+ await expect(service.getAccessToken(1, PROVIDER)).rejects.toBeInstanceOf(
157
+ OAuthTokenBrokerError,
158
+ );
159
+ await expect(service.getAccessToken(1, PROVIDER)).rejects.toMatchObject({
160
+ reason: 'refresh_revoked',
161
+ });
162
+ });
163
+
164
+ it('parses granted scopes from the stored account', async () => {
165
+ deps.prisma.user_account.findFirst.mockResolvedValue({
166
+ scopes: 'openid, Calendars.Read offline_access',
167
+ } as any);
168
+
169
+ const scopes = await service.getGrantedScopes(1, PROVIDER);
170
+ expect(scopes).toEqual(['openid', 'Calendars.Read', 'offline_access']);
171
+ });
172
+ });