@hed-hog/core 0.0.349 → 0.0.351

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 (350) hide show
  1. package/dist/access-log/access-log.controller.d.ts +16 -0
  2. package/dist/access-log/access-log.controller.d.ts.map +1 -0
  3. package/dist/access-log/access-log.controller.js +44 -0
  4. package/dist/access-log/access-log.controller.js.map +1 -0
  5. package/dist/access-log/access-log.interceptor.d.ts +9 -0
  6. package/dist/access-log/access-log.interceptor.d.ts.map +1 -0
  7. package/dist/access-log/access-log.interceptor.js +46 -0
  8. package/dist/access-log/access-log.interceptor.js.map +1 -0
  9. package/dist/access-log/access-log.module.d.ts +3 -0
  10. package/dist/access-log/access-log.module.d.ts.map +1 -0
  11. package/dist/access-log/access-log.module.js +29 -0
  12. package/dist/access-log/access-log.module.js.map +1 -0
  13. package/dist/access-log/access-log.service.d.ts +47 -0
  14. package/dist/access-log/access-log.service.d.ts.map +1 -0
  15. package/dist/access-log/access-log.service.js +113 -0
  16. package/dist/access-log/access-log.service.js.map +1 -0
  17. package/dist/access-log/dto/query-access-log.dto.d.ts +8 -0
  18. package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -0
  19. package/dist/access-log/dto/query-access-log.dto.js +42 -0
  20. package/dist/access-log/dto/query-access-log.dto.js.map +1 -0
  21. package/dist/auth/auth.controller.d.ts +12 -12
  22. package/dist/auth/auth.service.d.ts +27 -27
  23. package/dist/auth/auth.service.d.ts.map +1 -1
  24. package/dist/auth/auth.service.js +0 -4
  25. package/dist/auth/auth.service.js.map +1 -1
  26. package/dist/challenge/challenge.service.d.ts +2 -2
  27. package/dist/challenge/challenge.service.d.ts.map +1 -1
  28. package/dist/challenge/challenge.service.js +0 -1
  29. package/dist/challenge/challenge.service.js.map +1 -1
  30. package/dist/core/system.module.d.ts.map +1 -1
  31. package/dist/core/system.module.js +1 -0
  32. package/dist/core/system.module.js.map +1 -1
  33. package/dist/core.module.d.ts.map +1 -1
  34. package/dist/core.module.js +15 -0
  35. package/dist/core.module.js.map +1 -1
  36. package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
  37. package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
  38. package/dist/dashboard/dashboard.module.d.ts.map +1 -1
  39. package/dist/dashboard/dashboard.module.js +4 -1
  40. package/dist/dashboard/dashboard.module.js.map +1 -1
  41. package/dist/file/file.controller.js +0 -1
  42. package/dist/file/file.controller.js.map +1 -1
  43. package/dist/file/file.service.d.ts +65 -0
  44. package/dist/file/file.service.d.ts.map +1 -1
  45. package/dist/file/file.service.js +151 -3
  46. package/dist/file/file.service.js.map +1 -1
  47. package/dist/file/provider/abstract.provider.d.ts +8 -0
  48. package/dist/file/provider/abstract.provider.d.ts.map +1 -1
  49. package/dist/file/provider/abstract.provider.js.map +1 -1
  50. package/dist/file/provider/azure.provider.d.ts +4 -0
  51. package/dist/file/provider/azure.provider.d.ts.map +1 -1
  52. package/dist/file/provider/azure.provider.js +14 -0
  53. package/dist/file/provider/azure.provider.js.map +1 -1
  54. package/dist/file/provider/gcs.provider.d.ts +4 -0
  55. package/dist/file/provider/gcs.provider.d.ts.map +1 -1
  56. package/dist/file/provider/gcs.provider.js +14 -0
  57. package/dist/file/provider/gcs.provider.js.map +1 -1
  58. package/dist/file/provider/local.provider.d.ts +4 -0
  59. package/dist/file/provider/local.provider.d.ts.map +1 -1
  60. package/dist/file/provider/local.provider.js +19 -0
  61. package/dist/file/provider/local.provider.js.map +1 -1
  62. package/dist/file/provider/provider.factory.d.ts.map +1 -1
  63. package/dist/file/provider/provider.factory.js +3 -0
  64. package/dist/file/provider/provider.factory.js.map +1 -1
  65. package/dist/file/provider/s3.provider.d.ts +4 -0
  66. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  67. package/dist/file/provider/s3.provider.js +17 -0
  68. package/dist/file/provider/s3.provider.js.map +1 -1
  69. package/dist/index.d.ts +3 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +4 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/mcp/guards/mcp-auth.guard.d.ts +6 -1
  74. package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
  75. package/dist/mcp/guards/mcp-auth.guard.js +29 -2
  76. package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
  77. package/dist/mcp/mcp-api-key.controller.d.ts +32 -0
  78. package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -0
  79. package/dist/mcp/mcp-api-key.controller.js +64 -0
  80. package/dist/mcp/mcp-api-key.controller.js.map +1 -0
  81. package/dist/mcp/mcp-api-key.service.d.ts +27 -0
  82. package/dist/mcp/mcp-api-key.service.d.ts.map +1 -0
  83. package/dist/mcp/mcp-api-key.service.js +74 -0
  84. package/dist/mcp/mcp-api-key.service.js.map +1 -0
  85. package/dist/mcp/mcp-audit.service.d.ts +3 -1
  86. package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
  87. package/dist/mcp/mcp-audit.service.js +14 -2
  88. package/dist/mcp/mcp-audit.service.js.map +1 -1
  89. package/dist/mcp/mcp-registry.service.d.ts +1 -2
  90. package/dist/mcp/mcp-registry.service.d.ts.map +1 -1
  91. package/dist/mcp/mcp-registry.service.js +6 -2
  92. package/dist/mcp/mcp-registry.service.js.map +1 -1
  93. package/dist/mcp/mcp.controller.d.ts +3 -1
  94. package/dist/mcp/mcp.controller.d.ts.map +1 -1
  95. package/dist/mcp/mcp.controller.js +10 -2
  96. package/dist/mcp/mcp.controller.js.map +1 -1
  97. package/dist/mcp/mcp.module.d.ts.map +1 -1
  98. package/dist/mcp/mcp.module.js +80 -1
  99. package/dist/mcp/mcp.module.js.map +1 -1
  100. package/dist/mcp/tools/core-ai.mcp-tools.d.ts +45 -0
  101. package/dist/mcp/tools/core-ai.mcp-tools.d.ts.map +1 -0
  102. package/dist/mcp/tools/core-ai.mcp-tools.js +214 -0
  103. package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -0
  104. package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts +21 -0
  105. package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts.map +1 -0
  106. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +89 -0
  107. package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -0
  108. package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts +29 -0
  109. package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts.map +1 -0
  110. package/dist/mcp/tools/core-dashboard.mcp-tools.js +149 -0
  111. package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -0
  112. package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts +30 -0
  113. package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -0
  114. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +185 -0
  115. package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -0
  116. package/dist/mcp/tools/core-files.mcp-tools.d.ts +26 -0
  117. package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -0
  118. package/dist/mcp/tools/core-files.mcp-tools.js +140 -0
  119. package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -0
  120. package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts +26 -0
  121. package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts.map +1 -0
  122. package/dist/mcp/tools/core-integration-events.mcp-tools.js +168 -0
  123. package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -0
  124. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +32 -0
  125. package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -0
  126. package/dist/mcp/tools/core-mail-profile.mcp-tools.js +178 -0
  127. package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -0
  128. package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts +14 -0
  129. package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts.map +1 -0
  130. package/dist/mcp/tools/core-mail-sent.mcp-tools.js +106 -0
  131. package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -0
  132. package/dist/mcp/tools/core-mail.mcp-tools.d.ts +36 -0
  133. package/dist/mcp/tools/core-mail.mcp-tools.d.ts.map +1 -0
  134. package/dist/mcp/tools/core-mail.mcp-tools.js +184 -0
  135. package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -0
  136. package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts +21 -0
  137. package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts.map +1 -0
  138. package/dist/mcp/tools/core-mcp-chat.mcp-tools.js +118 -0
  139. package/dist/mcp/tools/core-mcp-chat.mcp-tools.js.map +1 -0
  140. package/dist/mcp/tools/core-menus.mcp-tools.d.ts +40 -0
  141. package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -0
  142. package/dist/mcp/tools/core-menus.mcp-tools.js +268 -0
  143. package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -0
  144. package/dist/mcp/tools/core-notifications.mcp-tools.d.ts +31 -0
  145. package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -0
  146. package/dist/mcp/tools/core-notifications.mcp-tools.js +178 -0
  147. package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -0
  148. package/dist/mcp/tools/core-profile.mcp-tools.d.ts +20 -0
  149. package/dist/mcp/tools/core-profile.mcp-tools.d.ts.map +1 -0
  150. package/dist/mcp/tools/core-profile.mcp-tools.js +111 -0
  151. package/dist/mcp/tools/core-profile.mcp-tools.js.map +1 -0
  152. package/dist/mcp/tools/core-roles.mcp-tools.d.ts +70 -0
  153. package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -0
  154. package/dist/mcp/tools/core-roles.mcp-tools.js +355 -0
  155. package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -0
  156. package/dist/mcp/tools/core-routes.mcp-tools.d.ts +52 -0
  157. package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -0
  158. package/dist/mcp/tools/core-routes.mcp-tools.js +254 -0
  159. package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -0
  160. package/dist/mcp/tools/core-screens.mcp-tools.d.ts +47 -0
  161. package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -0
  162. package/dist/mcp/tools/core-screens.mcp-tools.js +250 -0
  163. package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -0
  164. package/dist/mcp/tools/core-sessions.mcp-tools.d.ts +20 -0
  165. package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -0
  166. package/dist/mcp/tools/core-sessions.mcp-tools.js +128 -0
  167. package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -0
  168. package/dist/mcp/tools/core-settings.mcp-tools.d.ts +25 -0
  169. package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
  170. package/dist/mcp/tools/core-settings.mcp-tools.js +138 -0
  171. package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
  172. package/dist/mcp/tools/core-system.mcp-tools.d.ts +8 -0
  173. package/dist/mcp/tools/core-system.mcp-tools.d.ts.map +1 -0
  174. package/dist/mcp/tools/core-system.mcp-tools.js +40 -0
  175. package/dist/mcp/tools/core-system.mcp-tools.js.map +1 -0
  176. package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts +46 -0
  177. package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -0
  178. package/dist/mcp/tools/core-webhooks.mcp-tools.js +266 -0
  179. package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -0
  180. package/dist/mcp-chat/mcp-chat.controller.d.ts +5 -1
  181. package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -1
  182. package/dist/mcp-chat/mcp-chat.controller.js +46 -0
  183. package/dist/mcp-chat/mcp-chat.controller.js.map +1 -1
  184. package/dist/mcp-chat/mcp-chat.service.d.ts +31 -3
  185. package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
  186. package/dist/mcp-chat/mcp-chat.service.js +776 -38
  187. package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
  188. package/dist/notification/dto/create-notification.dto.d.ts +26 -0
  189. package/dist/notification/dto/create-notification.dto.d.ts.map +1 -0
  190. package/dist/notification/dto/create-notification.dto.js +86 -0
  191. package/dist/notification/dto/create-notification.dto.js.map +1 -0
  192. package/dist/notification/dto/update-progress.dto.d.ts +6 -0
  193. package/dist/notification/dto/update-progress.dto.d.ts.map +1 -0
  194. package/dist/notification/dto/update-progress.dto.js +33 -0
  195. package/dist/notification/dto/update-progress.dto.js.map +1 -0
  196. package/dist/notification/notification.controller.d.ts +112 -0
  197. package/dist/notification/notification.controller.d.ts.map +1 -0
  198. package/dist/notification/notification.controller.js +130 -0
  199. package/dist/notification/notification.controller.js.map +1 -0
  200. package/dist/notification/notification.module.d.ts +3 -0
  201. package/dist/notification/notification.module.d.ts.map +1 -0
  202. package/dist/notification/notification.module.js +29 -0
  203. package/dist/notification/notification.module.js.map +1 -0
  204. package/dist/notification/notification.service.d.ts +112 -0
  205. package/dist/notification/notification.service.d.ts.map +1 -0
  206. package/dist/notification/notification.service.js +269 -0
  207. package/dist/notification/notification.service.js.map +1 -0
  208. package/dist/pdf/pdf.service.js +1 -1
  209. package/dist/pdf/pdf.service.js.map +1 -1
  210. package/dist/profile/profile.controller.d.ts +4 -4
  211. package/dist/profile/profile.controller.js +0 -1
  212. package/dist/profile/profile.controller.js.map +1 -1
  213. package/dist/profile/profile.module.d.ts.map +1 -1
  214. package/dist/profile/profile.module.js +1 -0
  215. package/dist/profile/profile.module.js.map +1 -1
  216. package/dist/profile/profile.service.d.ts +4 -4
  217. package/dist/session/session.controller.d.ts +3 -3
  218. package/dist/session/session.service.d.ts +9 -9
  219. package/dist/setting/dto/update-setting-list.dto.d.ts +9 -0
  220. package/dist/setting/dto/update-setting-list.dto.d.ts.map +1 -0
  221. package/dist/setting/dto/update-setting-list.dto.js +44 -0
  222. package/dist/setting/dto/update-setting-list.dto.js.map +1 -0
  223. package/dist/setting/setting.controller.d.ts +20 -1
  224. package/dist/setting/setting.controller.d.ts.map +1 -1
  225. package/dist/setting/setting.controller.js +12 -0
  226. package/dist/setting/setting.controller.js.map +1 -1
  227. package/dist/setting/setting.service.d.ts +20 -1
  228. package/dist/setting/setting.service.d.ts.map +1 -1
  229. package/dist/setting/setting.service.js +80 -4
  230. package/dist/setting/setting.service.js.map +1 -1
  231. package/dist/task/task.service.d.ts +13 -0
  232. package/dist/task/task.service.d.ts.map +1 -1
  233. package/dist/task/task.service.js +85 -0
  234. package/dist/task/task.service.js.map +1 -1
  235. package/dist/token/token.service.d.ts.map +1 -1
  236. package/dist/token/token.service.js +0 -1
  237. package/dist/token/token.service.js.map +1 -1
  238. package/dist/user/user.controller.d.ts +11 -11
  239. package/dist/user/user.service.d.ts +27 -27
  240. package/dist/webhook-integration/dto/webhook-action.dto.d.ts +22 -0
  241. package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -0
  242. package/dist/webhook-integration/dto/webhook-action.dto.js +120 -0
  243. package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -0
  244. package/dist/webhook-integration/webhook-integration.controller.d.ts +7 -5
  245. package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
  246. package/dist/webhook-integration/webhook-integration.controller.js +18 -5
  247. package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
  248. package/dist/webhook-integration/webhook-integration.service.d.ts +18 -5
  249. package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
  250. package/dist/webhook-integration/webhook-integration.service.js +342 -59
  251. package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
  252. package/dist/webhook-integration/webhook-utils.d.ts +1 -0
  253. package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
  254. package/dist/webhook-integration/webhook-utils.js +38 -0
  255. package/dist/webhook-integration/webhook-utils.js.map +1 -1
  256. package/hedhog/data/menu.yaml +63 -4
  257. package/hedhog/data/route.yaml +1437 -0
  258. package/hedhog/data/setting_group.yaml +112 -0
  259. package/hedhog/data/setting_subgroup.yaml +32 -0
  260. package/hedhog/frontend/app/access-log/page.tsx.ejs +772 -0
  261. package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +285 -0
  262. package/hedhog/frontend/app/account/layout.tsx.ejs +32 -55
  263. package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +5 -0
  264. package/hedhog/frontend/app/ai_agent/page.tsx.ejs +10 -3
  265. package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +33 -13
  266. package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +12 -5
  267. package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +12 -5
  268. package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +3559 -1835
  269. package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +633 -0
  270. package/hedhog/frontend/app/mcp_chat/chat-types.ts.ejs +16 -0
  271. package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +583 -384
  272. package/hedhog/frontend/app/menu/page.tsx.ejs +9 -3
  273. package/hedhog/frontend/app/roles/page.tsx.ejs +18 -6
  274. package/hedhog/frontend/app/routes/page.tsx.ejs +9 -3
  275. package/hedhog/frontend/app/setting-list/page.tsx.ejs +822 -0
  276. package/hedhog/frontend/app/users/page.tsx.ejs +445 -203
  277. package/hedhog/frontend/app/users/user-access-sheet.tsx.ejs +310 -304
  278. package/hedhog/frontend/app/users/user-sheet.tsx.ejs +41 -44
  279. package/hedhog/frontend/messages/en.json +343 -3
  280. package/hedhog/frontend/messages/pt.json +343 -3
  281. package/hedhog/table/access_log.yaml +31 -0
  282. package/hedhog/table/mcp_api_key.yaml +30 -0
  283. package/hedhog/table/notification.yaml +72 -0
  284. package/hedhog/table/webhook_action_log.yaml +49 -0
  285. package/package.json +5 -4
  286. package/src/access-log/access-log.controller.ts +29 -0
  287. package/src/access-log/access-log.interceptor.ts +38 -0
  288. package/src/access-log/access-log.module.ts +16 -0
  289. package/src/access-log/access-log.service.ts +129 -0
  290. package/src/access-log/dto/query-access-log.dto.ts +23 -0
  291. package/src/auth/auth.service.ts +0 -7
  292. package/src/challenge/challenge.service.ts +0 -2
  293. package/src/core/system.module.ts +1 -0
  294. package/src/core.module.ts +15 -0
  295. package/src/dashboard/dashboard.module.ts +4 -1
  296. package/src/file/file.controller.ts +14 -14
  297. package/src/file/file.service.ts +198 -4
  298. package/src/file/provider/abstract.provider.ts +10 -0
  299. package/src/file/provider/azure.provider.ts +24 -0
  300. package/src/file/provider/gcs.provider.ts +20 -0
  301. package/src/file/provider/local.provider.ts +30 -2
  302. package/src/file/provider/provider.factory.ts +3 -0
  303. package/src/file/provider/s3.provider.ts +22 -0
  304. package/src/index.ts +5 -0
  305. package/src/mcp/guards/mcp-auth.guard.ts +64 -32
  306. package/src/mcp/mcp-api-key.controller.ts +42 -0
  307. package/src/mcp/mcp-api-key.service.ts +66 -0
  308. package/src/mcp/mcp-audit.service.ts +47 -36
  309. package/src/mcp/mcp-registry.service.ts +75 -69
  310. package/src/mcp/mcp.controller.ts +40 -30
  311. package/src/mcp/mcp.module.ts +115 -36
  312. package/src/mcp/tools/core-ai.mcp-tools.ts +156 -0
  313. package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +63 -0
  314. package/src/mcp/tools/core-dashboard.mcp-tools.ts +103 -0
  315. package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +134 -0
  316. package/src/mcp/tools/core-files.mcp-tools.ts +105 -0
  317. package/src/mcp/tools/core-integration-events.mcp-tools.ts +118 -0
  318. package/src/mcp/tools/core-mail-profile.mcp-tools.ts +128 -0
  319. package/src/mcp/tools/core-mail-sent.mcp-tools.ts +76 -0
  320. package/src/mcp/tools/core-mail.mcp-tools.ts +130 -0
  321. package/src/mcp/tools/core-mcp-chat.mcp-tools.ts +81 -0
  322. package/src/mcp/tools/core-menus.mcp-tools.ts +197 -0
  323. package/src/mcp/tools/core-notifications.mcp-tools.ts +128 -0
  324. package/src/mcp/tools/core-profile.mcp-tools.ts +74 -0
  325. package/src/mcp/tools/core-roles.mcp-tools.ts +288 -0
  326. package/src/mcp/tools/core-routes.mcp-tools.ts +196 -0
  327. package/src/mcp/tools/core-screens.mcp-tools.ts +186 -0
  328. package/src/mcp/tools/core-sessions.mcp-tools.ts +97 -0
  329. package/src/mcp/tools/core-settings.mcp-tools.ts +171 -53
  330. package/src/mcp/tools/core-system.mcp-tools.ts +19 -0
  331. package/src/mcp/tools/core-webhooks.mcp-tools.ts +199 -0
  332. package/src/mcp-chat/mcp-chat.controller.ts +113 -60
  333. package/src/mcp-chat/mcp-chat.service.ts +1343 -332
  334. package/src/notification/dto/create-notification.dto.ts +71 -0
  335. package/src/notification/dto/update-progress.dto.ts +16 -0
  336. package/src/notification/notification.controller.ts +83 -0
  337. package/src/notification/notification.module.ts +16 -0
  338. package/src/notification/notification.service.ts +324 -0
  339. package/src/pdf/pdf.service.ts +1 -1
  340. package/src/profile/profile.controller.ts +1 -1
  341. package/src/profile/profile.module.ts +1 -0
  342. package/src/setting/dto/update-setting-list.dto.ts +32 -0
  343. package/src/setting/setting.controller.ts +9 -0
  344. package/src/setting/setting.service.ts +99 -11
  345. package/src/task/task.service.ts +103 -0
  346. package/src/token/token.service.ts +0 -2
  347. package/src/webhook-integration/dto/webhook-action.dto.ts +96 -0
  348. package/src/webhook-integration/webhook-integration.controller.ts +124 -103
  349. package/src/webhook-integration/webhook-integration.service.ts +1137 -735
  350. package/src/webhook-integration/webhook-utils.ts +136 -79
@@ -14,23 +14,167 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14
14
  var __importDefault = (this && this.__importDefault) || function (mod) {
15
15
  return (mod && mod.__esModule) ? mod : { "default": mod };
16
16
  };
17
+ var McpChatService_1;
17
18
  Object.defineProperty(exports, "__esModule", { value: true });
18
19
  exports.McpChatService = void 0;
19
20
  const api_prisma_1 = require("@hed-hog/api-prisma");
20
21
  const common_1 = require("@nestjs/common");
21
22
  const axios_1 = __importDefault(require("axios"));
22
- const setting_service_1 = require("../setting/setting.service");
23
23
  const mcp_registry_service_1 = require("../mcp/mcp-registry.service");
24
+ const setting_service_1 = require("../setting/setting.service");
25
+ const MAX_OPENAI_TOOLS = 128;
26
+ const TARGET_SELECTED_TOOLS = 112;
27
+ const MAX_ITERATIONS = 20;
28
+ const FORCE_FINISH_THRESHOLD = 2;
29
+ const MIN_DOMAIN_CONFIDENCE = 2;
30
+ const AMBIGUOUS_DOMAIN_DELTA = 1;
24
31
  const SYSTEM_PROMPT = 'You are a helpful assistant with access to tools from the HedHog system. ' +
25
32
  'Use the available tools to answer the user\'s questions accurately. ' +
26
33
  'Always respond in the same language the user writes in.';
27
34
  const sanitize = (n) => n.replace(/\./g, '__');
28
35
  const restore = (n) => n.replace(/__/g, '.');
29
- let McpChatService = class McpChatService {
36
+ const DOMAIN_KEYWORDS = {
37
+ finance: [
38
+ 'finance',
39
+ 'financeiro',
40
+ 'financeira',
41
+ 'financas',
42
+ 'finanças',
43
+ 'banco',
44
+ 'bancos',
45
+ 'bank',
46
+ 'banks',
47
+ 'conta',
48
+ 'contas',
49
+ 'account',
50
+ 'accounts',
51
+ 'conta bancaria',
52
+ 'contas bancarias',
53
+ 'conta bancária',
54
+ 'contas bancárias',
55
+ 'extrato',
56
+ 'extratos',
57
+ 'statement',
58
+ 'statements',
59
+ 'pagamento',
60
+ 'pagamentos',
61
+ 'payment',
62
+ 'payments',
63
+ 'recebimento',
64
+ 'recebimentos',
65
+ 'receivable',
66
+ 'payable',
67
+ 'currency',
68
+ 'moeda',
69
+ 'transferencia',
70
+ 'transferência',
71
+ ],
72
+ operations: [
73
+ 'operations',
74
+ 'operacoes',
75
+ 'operações',
76
+ 'tarefa',
77
+ 'tarefas',
78
+ 'task',
79
+ 'tasks',
80
+ 'projeto',
81
+ 'projetos',
82
+ 'project',
83
+ 'projects',
84
+ 'timesheet',
85
+ 'apontamento',
86
+ 'aprovacao',
87
+ 'aprovação',
88
+ 'approval',
89
+ 'colaborador',
90
+ 'collaborator',
91
+ ],
92
+ lms: [
93
+ 'lms',
94
+ 'curso',
95
+ 'cursos',
96
+ 'course',
97
+ 'courses',
98
+ 'aula',
99
+ 'aulas',
100
+ 'lesson',
101
+ 'lessons',
102
+ 'treinamento',
103
+ 'training',
104
+ 'turma',
105
+ 'class',
106
+ 'aluno',
107
+ 'student',
108
+ 'prova',
109
+ 'exam',
110
+ ],
111
+ core: [
112
+ 'core',
113
+ 'usuario',
114
+ 'usuário',
115
+ 'usuarios',
116
+ 'usuários',
117
+ 'user',
118
+ 'users',
119
+ 'perfil',
120
+ 'profile',
121
+ 'role',
122
+ 'roles',
123
+ 'menu',
124
+ 'menus',
125
+ 'rota',
126
+ 'rotas',
127
+ 'route',
128
+ 'routes',
129
+ 'configuracao',
130
+ 'configuração',
131
+ 'setting',
132
+ 'settings',
133
+ ],
134
+ contact: [
135
+ 'contato',
136
+ 'contatos',
137
+ 'contact',
138
+ 'contacts',
139
+ 'pessoa',
140
+ 'pessoas',
141
+ 'person',
142
+ 'proposal',
143
+ 'proposta',
144
+ ],
145
+ };
146
+ const ACTION_KEYWORDS = [
147
+ 'listar',
148
+ 'lista',
149
+ 'buscar',
150
+ 'procurar',
151
+ 'consultar',
152
+ 'mostrar',
153
+ 'ver',
154
+ 'criar',
155
+ 'adicionar',
156
+ 'atualizar',
157
+ 'alterar',
158
+ 'remover',
159
+ 'deletar',
160
+ 'excluir',
161
+ 'list',
162
+ 'search',
163
+ 'find',
164
+ 'show',
165
+ 'get',
166
+ 'create',
167
+ 'add',
168
+ 'update',
169
+ 'delete',
170
+ 'remove',
171
+ ];
172
+ let McpChatService = McpChatService_1 = class McpChatService {
30
173
  constructor(prisma, setting, registry) {
31
174
  this.prisma = prisma;
32
175
  this.setting = setting;
33
176
  this.registry = registry;
177
+ this.logger = new common_1.Logger(McpChatService_1.name);
34
178
  }
35
179
  async listConversations(userId) {
36
180
  return this.prisma.mcp_conversation.findMany({
@@ -62,9 +206,12 @@ let McpChatService = class McpChatService {
62
206
  });
63
207
  }
64
208
  async sendMessage(conversationId, userId, locale, message) {
65
- var _a, _b, _c, _d, _e, _f, _g, _h;
209
+ const cfg = await this.setting.getSettingValues(['mcp-enabled']);
210
+ if (cfg['mcp-enabled'] === false) {
211
+ throw new common_1.BadRequestException('MCP server is disabled.');
212
+ }
66
213
  await this.assertOwnership(conversationId, userId);
67
- const apiKey = await this.getOpenAiKey();
214
+ const { provider, apiKey } = await this.getProviderKey();
68
215
  // Save user message
69
216
  await this.prisma.mcp_conversation_message.create({
70
217
  data: {
@@ -83,7 +230,14 @@ let McpChatService = class McpChatService {
83
230
  data: { title: message.slice(0, 60) },
84
231
  });
85
232
  }
86
- // Build OpenAI messages from history
233
+ if (provider === 'gemini') {
234
+ return this.runGeminiLoop(conversationId, userId, locale, message, apiKey);
235
+ }
236
+ return this.runOpenAiLoop(conversationId, userId, locale, message, apiKey);
237
+ }
238
+ // ── OpenAI loop ──────────────────────────────────────────────────────────
239
+ async runOpenAiLoop(conversationId, userId, locale, message, apiKey) {
240
+ var _a, _b, _c, _d, _e, _f, _g, _h;
87
241
  const history = await this.prisma.mcp_conversation_message.findMany({
88
242
  where: { conversation_id: conversationId },
89
243
  orderBy: { created_at: 'asc' },
@@ -92,31 +246,22 @@ let McpChatService = class McpChatService {
92
246
  { role: 'system', content: SYSTEM_PROMPT },
93
247
  ...this.toOpenAiMessages(history),
94
248
  ];
95
- // Build tool definitions
96
- const tools = this.registry.getAll().map((entry) => {
97
- var _a;
98
- return ({
99
- type: 'function',
100
- function: {
101
- name: sanitize(entry.definition.name),
102
- description: entry.definition.description,
103
- parameters: (_a = entry.definition.inputSchema) !== null && _a !== void 0 ? _a : {
104
- type: 'object',
105
- properties: {},
106
- },
107
- },
108
- });
109
- });
110
- // Tool-calling loop
111
- let maxIterations = 10;
249
+ const toolSelection = await this.buildOpenAiTools(message, conversationId, userId, history);
250
+ if (toolSelection.clarification) {
251
+ return this.recordAssistantAndReturnHistory(conversationId, toolSelection.clarification);
252
+ }
253
+ const tools = toolSelection.tools;
254
+ const callSignatures = new Set();
255
+ let maxIterations = MAX_ITERATIONS;
112
256
  while (maxIterations-- > 0) {
257
+ const forceFinish = maxIterations < FORCE_FINISH_THRESHOLD;
113
258
  let response;
114
259
  try {
115
260
  response = await axios_1.default.post('https://api.openai.com/v1/chat/completions', {
116
261
  model: 'gpt-4o-mini',
117
262
  messages: openAiMessages,
118
- tools: tools.length > 0 ? tools : undefined,
119
- tool_choice: tools.length > 0 ? 'auto' : undefined,
263
+ tools: !forceFinish && tools.length > 0 ? tools : undefined,
264
+ tool_choice: !forceFinish && tools.length > 0 ? 'auto' : undefined,
120
265
  }, {
121
266
  headers: {
122
267
  Authorization: `Bearer ${apiKey}`,
@@ -137,14 +282,12 @@ let McpChatService = class McpChatService {
137
282
  }
138
283
  const choice = (_g = (_f = response.data) === null || _f === void 0 ? void 0 : _f.choices) === null || _g === void 0 ? void 0 : _g[0];
139
284
  const assistantMsg = choice === null || choice === void 0 ? void 0 : choice.message;
140
- if ((_h = assistantMsg === null || assistantMsg === void 0 ? void 0 : assistantMsg.tool_calls) === null || _h === void 0 ? void 0 : _h.length) {
141
- // Add assistant tool-call message to context
285
+ if (((_h = assistantMsg === null || assistantMsg === void 0 ? void 0 : assistantMsg.tool_calls) === null || _h === void 0 ? void 0 : _h.length) && !forceFinish) {
142
286
  openAiMessages.push({
143
287
  role: 'assistant',
144
288
  content: null,
145
289
  tool_calls: assistantMsg.tool_calls,
146
290
  });
147
- // Execute each tool call
148
291
  for (const toolCall of assistantMsg.tool_calls) {
149
292
  const originalName = restore(toolCall.function.name);
150
293
  const argsJson = toolCall.function.arguments;
@@ -155,7 +298,6 @@ let McpChatService = class McpChatService {
155
298
  catch (_j) {
156
299
  args = {};
157
300
  }
158
- // Persist tool_call message
159
301
  await this.prisma.mcp_conversation_message.create({
160
302
  data: {
161
303
  conversation_id: conversationId,
@@ -165,7 +307,28 @@ let McpChatService = class McpChatService {
165
307
  tool_call_id: toolCall.id,
166
308
  },
167
309
  });
168
- // Execute the tool
310
+ const sig = `${toolCall.function.name}:${argsJson}`;
311
+ if (callSignatures.has(sig)) {
312
+ this.logger.warn(`MCP chat duplicate tool call detected — aborting re-execution. ` +
313
+ `conversationId=${conversationId} tool=${originalName}`);
314
+ const dupResult = JSON.stringify({ error: 'Duplicate tool call detected, aborting loop.' });
315
+ await this.prisma.mcp_conversation_message.create({
316
+ data: {
317
+ conversation_id: conversationId,
318
+ role: 'tool_result',
319
+ content: dupResult,
320
+ tool_name: originalName,
321
+ tool_call_id: toolCall.id,
322
+ },
323
+ });
324
+ openAiMessages.push({
325
+ role: 'tool',
326
+ tool_call_id: toolCall.id,
327
+ content: dupResult,
328
+ });
329
+ continue;
330
+ }
331
+ callSignatures.add(sig);
169
332
  let resultContent;
170
333
  const entry = this.registry.get(originalName);
171
334
  if (entry) {
@@ -186,7 +349,6 @@ let McpChatService = class McpChatService {
186
349
  else {
187
350
  resultContent = JSON.stringify({ error: `Tool '${originalName}' not found` });
188
351
  }
189
- // Persist tool_result message
190
352
  await this.prisma.mcp_conversation_message.create({
191
353
  data: {
192
354
  conversation_id: conversationId,
@@ -196,16 +358,14 @@ let McpChatService = class McpChatService {
196
358
  tool_call_id: toolCall.id,
197
359
  },
198
360
  });
199
- // Add tool result to context for next iteration
200
361
  openAiMessages.push({
201
362
  role: 'tool',
202
363
  tool_call_id: toolCall.id,
203
364
  content: resultContent,
204
365
  });
205
366
  }
206
- continue; // next iteration with tool results
367
+ continue;
207
368
  }
208
- // Final assistant response
209
369
  const finalContent = (assistantMsg === null || assistantMsg === void 0 ? void 0 : assistantMsg.content) || '';
210
370
  await this.prisma.mcp_conversation_message.create({
211
371
  data: {
@@ -221,6 +381,123 @@ let McpChatService = class McpChatService {
221
381
  }
222
382
  throw new common_1.BadRequestException('Maximum tool call iterations exceeded.');
223
383
  }
384
+ // ── Gemini loop ──────────────────────────────────────────────────────────
385
+ async runGeminiLoop(conversationId, userId, locale, message, apiKey) {
386
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
387
+ const history = await this.prisma.mcp_conversation_message.findMany({
388
+ where: { conversation_id: conversationId },
389
+ orderBy: { created_at: 'asc' },
390
+ });
391
+ const geminiContents = this.toGeminiContents(history);
392
+ const toolSelection = await this.buildGeminiTools(message, conversationId, userId, history);
393
+ if (toolSelection.clarification) {
394
+ return this.recordAssistantAndReturnHistory(conversationId, toolSelection.clarification);
395
+ }
396
+ const functionDeclarations = toolSelection.tools;
397
+ let maxIterations = MAX_ITERATIONS;
398
+ let callIndex = 0;
399
+ while (maxIterations-- > 0) {
400
+ const forceFinish = maxIterations < FORCE_FINISH_THRESHOLD;
401
+ let response;
402
+ try {
403
+ response = await axios_1.default.post(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`, {
404
+ systemInstruction: { parts: [{ text: SYSTEM_PROMPT }] },
405
+ contents: geminiContents,
406
+ tools: !forceFinish && functionDeclarations.length > 0
407
+ ? [{ functionDeclarations }]
408
+ : undefined,
409
+ }, { headers: { 'Content-Type': 'application/json' } });
410
+ }
411
+ catch (err) {
412
+ const status = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.status;
413
+ const errData = (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.data;
414
+ if (status === 429) {
415
+ throw new common_1.HttpException((_d = (_c = errData === null || errData === void 0 ? void 0 : errData.error) === null || _c === void 0 ? void 0 : _c.message) !== null && _d !== void 0 ? _d : 'Gemini rate limit exceeded. Please try again later.', common_1.HttpStatus.TOO_MANY_REQUESTS);
416
+ }
417
+ if (status === 400) {
418
+ throw new common_1.BadRequestException((_f = (_e = errData === null || errData === void 0 ? void 0 : errData.error) === null || _e === void 0 ? void 0 : _e.message) !== null && _f !== void 0 ? _f : 'Invalid Gemini API request.');
419
+ }
420
+ if (status === 401 || status === 403) {
421
+ throw new common_1.BadRequestException('Invalid Gemini API key.');
422
+ }
423
+ throw new common_1.HttpException((_h = (_g = errData === null || errData === void 0 ? void 0 : errData.error) === null || _g === void 0 ? void 0 : _g.message) !== null && _h !== void 0 ? _h : 'Gemini API error.', status !== null && status !== void 0 ? status : common_1.HttpStatus.BAD_GATEWAY);
424
+ }
425
+ const candidate = (_k = (_j = response.data) === null || _j === void 0 ? void 0 : _j.candidates) === null || _k === void 0 ? void 0 : _k[0];
426
+ const parts = (_m = (_l = candidate === null || candidate === void 0 ? void 0 : candidate.content) === null || _l === void 0 ? void 0 : _l.parts) !== null && _m !== void 0 ? _m : [];
427
+ const functionCallParts = parts.filter((p) => p.functionCall);
428
+ const textParts = parts.filter((p) => p.text);
429
+ if (functionCallParts.length > 0 && !forceFinish) {
430
+ geminiContents.push({ role: 'model', parts: functionCallParts });
431
+ const functionResponseParts = [];
432
+ for (const part of functionCallParts) {
433
+ const { name, args } = part.functionCall;
434
+ const originalName = restore(name);
435
+ const argsJson = JSON.stringify(args !== null && args !== void 0 ? args : {});
436
+ const toolCallId = `gemini-${callIndex++}`;
437
+ await this.prisma.mcp_conversation_message.create({
438
+ data: {
439
+ conversation_id: conversationId,
440
+ role: 'tool_call',
441
+ content: argsJson,
442
+ tool_name: originalName,
443
+ tool_call_id: toolCallId,
444
+ },
445
+ });
446
+ let resultContent;
447
+ const entry = this.registry.get(originalName);
448
+ if (entry) {
449
+ const context = {
450
+ userId,
451
+ sessionId: '',
452
+ locale,
453
+ toolName: originalName,
454
+ };
455
+ try {
456
+ const result = await entry.handler(args !== null && args !== void 0 ? args : {}, context);
457
+ resultContent = JSON.stringify(result);
458
+ }
459
+ catch (e) {
460
+ resultContent = JSON.stringify({ error: e.message });
461
+ }
462
+ }
463
+ else {
464
+ resultContent = JSON.stringify({ error: `Tool '${originalName}' not found` });
465
+ }
466
+ await this.prisma.mcp_conversation_message.create({
467
+ data: {
468
+ conversation_id: conversationId,
469
+ role: 'tool_result',
470
+ content: resultContent,
471
+ tool_name: originalName,
472
+ tool_call_id: toolCallId,
473
+ },
474
+ });
475
+ functionResponseParts.push({
476
+ functionResponse: {
477
+ name,
478
+ response: { output: resultContent },
479
+ },
480
+ });
481
+ }
482
+ geminiContents.push({ role: 'user', parts: functionResponseParts });
483
+ continue;
484
+ }
485
+ const finalContent = textParts.map((p) => p.text).join('');
486
+ await this.prisma.mcp_conversation_message.create({
487
+ data: {
488
+ conversation_id: conversationId,
489
+ role: 'assistant',
490
+ content: finalContent,
491
+ },
492
+ });
493
+ return this.prisma.mcp_conversation_message.findMany({
494
+ where: { conversation_id: conversationId },
495
+ orderBy: { created_at: 'asc' },
496
+ });
497
+ }
498
+ throw new common_1.BadRequestException('Maximum tool call iterations exceeded.');
499
+ }
500
+ // ── Helpers ──────────────────────────────────────────────────────────────
224
501
  toOpenAiMessages(history) {
225
502
  const messages = [];
226
503
  const toolCallMap = new Map(); // tool_call_id → sanitized name
@@ -256,6 +533,58 @@ let McpChatService = class McpChatService {
256
533
  }
257
534
  return messages;
258
535
  }
536
+ toGeminiContents(history) {
537
+ var _a, _b;
538
+ const contents = [];
539
+ let i = 0;
540
+ while (i < history.length) {
541
+ const msg = history[i];
542
+ if (msg.role === 'user') {
543
+ contents.push({ role: 'user', parts: [{ text: msg.content }] });
544
+ i++;
545
+ }
546
+ else if (msg.role === 'assistant') {
547
+ contents.push({ role: 'model', parts: [{ text: msg.content }] });
548
+ i++;
549
+ }
550
+ else if (msg.role === 'tool_call') {
551
+ const functionCallParts = [];
552
+ while (i < history.length && history[i].role === 'tool_call') {
553
+ const m = history[i];
554
+ let args = {};
555
+ try {
556
+ args = JSON.parse(m.content);
557
+ }
558
+ catch (_c) {
559
+ args = {};
560
+ }
561
+ functionCallParts.push({
562
+ functionCall: { name: sanitize((_a = m.tool_name) !== null && _a !== void 0 ? _a : ''), args },
563
+ });
564
+ i++;
565
+ }
566
+ contents.push({ role: 'model', parts: functionCallParts });
567
+ }
568
+ else if (msg.role === 'tool_result') {
569
+ const functionResponseParts = [];
570
+ while (i < history.length && history[i].role === 'tool_result') {
571
+ const m = history[i];
572
+ functionResponseParts.push({
573
+ functionResponse: {
574
+ name: sanitize((_b = m.tool_name) !== null && _b !== void 0 ? _b : ''),
575
+ response: { output: m.content },
576
+ },
577
+ });
578
+ i++;
579
+ }
580
+ contents.push({ role: 'user', parts: functionResponseParts });
581
+ }
582
+ else {
583
+ i++;
584
+ }
585
+ }
586
+ return contents;
587
+ }
259
588
  async assertOwnership(conversationId, userId) {
260
589
  const conv = await this.prisma.mcp_conversation.findUnique({
261
590
  where: { id: conversationId },
@@ -268,17 +597,426 @@ let McpChatService = class McpChatService {
268
597
  throw new common_1.ForbiddenException('Access denied to this conversation.');
269
598
  }
270
599
  }
271
- async getOpenAiKey() {
272
- const settings = await this.setting.getSettingValues(['ai-openai-api-key']);
600
+ async getProviderKey() {
601
+ const settings = await this.setting.getSettingValues([
602
+ 'mcp-ai-provider',
603
+ 'ai-openai-api-key',
604
+ 'ai-gemini-api-key',
605
+ ]);
606
+ const provider = (settings['mcp-ai-provider'] || 'openai');
607
+ if (provider === 'gemini') {
608
+ const key = settings['ai-gemini-api-key'];
609
+ if (!key) {
610
+ throw new common_1.BadRequestException('Gemini API key is not configured. Please set it in Settings → AI → Gemini API Key.');
611
+ }
612
+ return { provider: 'gemini', apiKey: key };
613
+ }
273
614
  const key = settings['ai-openai-api-key'];
274
615
  if (!key) {
275
- throw new common_1.BadRequestException('OpenAI API key is not configured (setting "ai-openai-api-key").');
616
+ throw new common_1.BadRequestException('OpenAI API key is not configured. Please set it in Settings → AI → OpenAI API Key.');
617
+ }
618
+ return { provider: 'openai', apiKey: key };
619
+ }
620
+ async buildOpenAiTools(message, conversationId, userId, history) {
621
+ return this.selectOpenAiTools(message, conversationId, userId, history);
622
+ }
623
+ async buildGeminiTools(message, conversationId, userId, history) {
624
+ const selection = await this.selectOpenAiTools(message, conversationId, userId, history);
625
+ return {
626
+ clarification: selection.clarification,
627
+ tools: selection.tools.map((t) => t.function),
628
+ };
629
+ }
630
+ async selectOpenAiTools(message, conversationId, userId, history) {
631
+ var _a;
632
+ const allEntries = this.registry.getAll();
633
+ const allowedToolNames = await this.getAllowedMcpToolNames(userId);
634
+ const allowedEntries = allEntries.filter((entry) => allowedToolNames.has(entry.definition.name));
635
+ const dedupedBySanitized = new Map();
636
+ const excludedDuplicates = [];
637
+ const routerText = this.buildToolRouterText(message, history);
638
+ const normalizedMessage = this.normalizeText(routerText);
639
+ const messageTerms = this.getMessageKeywordSet(normalizedMessage);
640
+ const domainScores = this.scoreToolDomains(normalizedMessage, allowedEntries);
641
+ const candidateDomains = this.getCandidateDomains(domainScores);
642
+ const clarification = this.getToolSelectionClarification(message, normalizedMessage, domainScores, candidateDomains, allowedEntries);
643
+ if (clarification) {
644
+ this.logger.log(`MCP tools need clarification: conversationId=${conversationId} userId=${userId} ` +
645
+ `registered=${allEntries.length} authorized=${allowedEntries.length} ` +
646
+ `domains=${this.formatDomainScores(domainScores)} selected=0`);
647
+ return { tools: [], clarification };
648
+ }
649
+ const entriesForRanking = candidateDomains.length > 0
650
+ ? allowedEntries.filter((entry) => candidateDomains.includes(this.getToolDomain(entry.definition.name)))
651
+ : allowedEntries;
652
+ for (const [index, entry] of entriesForRanking.entries()) {
653
+ const originalName = entry.definition.name;
654
+ const sanitizedName = sanitize(originalName);
655
+ const readOnly = Boolean(entry.definition.readOnly);
656
+ const domain = this.getToolDomain(originalName);
657
+ const matchScore = this.scoreToolMatch(normalizedMessage, messageTerms, entry, candidateDomains);
658
+ if (dedupedBySanitized.has(sanitizedName)) {
659
+ excludedDuplicates.push(originalName);
660
+ continue;
661
+ }
662
+ const scored = {
663
+ name: originalName,
664
+ domain,
665
+ readOnly,
666
+ priorityBucket: this.getDomainPriorityBucket(originalName, candidateDomains),
667
+ keywordBoost: this.getKeywordBoost(normalizedMessage, originalName),
668
+ matchScore,
669
+ index,
670
+ tool: {
671
+ type: 'function',
672
+ function: {
673
+ name: sanitizedName,
674
+ description: entry.definition.description,
675
+ parameters: (_a = entry.definition.inputSchema) !== null && _a !== void 0 ? _a : {
676
+ type: 'object',
677
+ properties: {},
678
+ },
679
+ },
680
+ },
681
+ };
682
+ dedupedBySanitized.set(sanitizedName, scored);
683
+ }
684
+ const scoredTools = Array.from(dedupedBySanitized.values());
685
+ scoredTools.sort((a, b) => {
686
+ if (a.matchScore !== b.matchScore) {
687
+ return b.matchScore - a.matchScore;
688
+ }
689
+ if (a.priorityBucket !== b.priorityBucket) {
690
+ return a.priorityBucket - b.priorityBucket;
691
+ }
692
+ if (a.keywordBoost !== b.keywordBoost) {
693
+ return b.keywordBoost - a.keywordBoost;
694
+ }
695
+ if (a.readOnly !== b.readOnly) {
696
+ return a.readOnly ? -1 : 1;
697
+ }
698
+ return a.index - b.index;
699
+ });
700
+ const selected = scoredTools.slice(0, TARGET_SELECTED_TOOLS);
701
+ const excludedByLimit = scoredTools
702
+ .slice(TARGET_SELECTED_TOOLS)
703
+ .map((tool) => tool.name);
704
+ if (excludedDuplicates.length > 0) {
705
+ this.logger.warn(`MCP tools duplicate sanitize names ignored: ${excludedDuplicates.length}. ` +
706
+ `Examples: ${excludedDuplicates.slice(0, 10).join(', ')}`);
707
+ }
708
+ if (excludedByLimit.length > 0) {
709
+ this.logger.warn(`MCP tools truncated for provider budget (${TARGET_SELECTED_TOOLS}/${MAX_OPENAI_TOOLS}). ` +
710
+ `conversationId=${conversationId} userId=${userId} ` +
711
+ `available=${scoredTools.length} selected=${selected.length} excluded=${excludedByLimit.length}. ` +
712
+ `Top excluded: ${excludedByLimit.slice(0, 12).join(', ')}`);
713
+ }
714
+ this.logger.log(`MCP tools prepared: conversationId=${conversationId} userId=${userId} ` +
715
+ `registered=${allEntries.length} authorized=${allowedEntries.length} ` +
716
+ `domains=${this.formatDomainScores(domainScores)} ranked=${scoredTools.length} ` +
717
+ `selected=${selected.length}`);
718
+ return { tools: selected.map((entry) => entry.tool) };
719
+ }
720
+ async getAllowedMcpToolNames(userId) {
721
+ const routes = await this.prisma.route.findMany({
722
+ where: {
723
+ type: 'MCP',
724
+ tool_name: { not: null },
725
+ role_route: {
726
+ some: {
727
+ role: {
728
+ role_user: {
729
+ some: { user_id: userId },
730
+ },
731
+ },
732
+ },
733
+ },
734
+ },
735
+ select: { tool_name: true },
736
+ });
737
+ return new Set(routes
738
+ .map((route) => route.tool_name)
739
+ .filter((toolName) => typeof toolName === 'string'));
740
+ }
741
+ getDomainPriorityBucket(toolName, candidateDomains) {
742
+ const domain = this.getToolDomain(toolName);
743
+ const candidateIndex = candidateDomains.indexOf(domain);
744
+ if (candidateIndex >= 0) {
745
+ return candidateIndex;
746
+ }
747
+ if (toolName.startsWith('operations.'))
748
+ return 10;
749
+ if (toolName.startsWith('finance.'))
750
+ return 11;
751
+ if (toolName.startsWith('lms.'))
752
+ return 12;
753
+ if (toolName.startsWith('core.'))
754
+ return 13;
755
+ return 99;
756
+ }
757
+ getKeywordBoost(message, toolName) {
758
+ const terms = this.getMessageKeywordSet(message);
759
+ if (terms.size === 0) {
760
+ return 0;
761
+ }
762
+ let boost = 0;
763
+ if (terms.has('task') &&
764
+ (toolName.includes('.task') || toolName.includes('.tasks.'))) {
765
+ boost += 4;
766
+ }
767
+ if (terms.has('project') &&
768
+ (toolName.includes('.project') || toolName.includes('.projects.'))) {
769
+ boost += 3;
770
+ }
771
+ if (terms.has('class') &&
772
+ (toolName.includes('.class') ||
773
+ toolName.includes('.course') ||
774
+ toolName.includes('.training'))) {
775
+ boost += 3;
776
+ }
777
+ if (terms.has('pending') &&
778
+ (toolName.includes('.task') ||
779
+ toolName.includes('.approval') ||
780
+ toolName.includes('.time-off'))) {
781
+ boost += 2;
782
+ }
783
+ return boost;
784
+ }
785
+ buildToolRouterText(message, history) {
786
+ const recentContext = history
787
+ .slice(-8)
788
+ .map((item) => [item.role === 'user' ? item.content : undefined, item.tool_name]
789
+ .filter(Boolean)
790
+ .join(' '))
791
+ .join(' ');
792
+ return `${recentContext} ${message}`;
793
+ }
794
+ normalizeText(value) {
795
+ return value
796
+ .toLowerCase()
797
+ .normalize('NFD')
798
+ .replace(/[\u0300-\u036f]/g, '')
799
+ .replace(/[^a-z0-9]+/g, ' ')
800
+ .replace(/\s+/g, ' ')
801
+ .trim();
802
+ }
803
+ getToolDomain(toolName) {
804
+ return toolName.split('.')[0] || 'unknown';
805
+ }
806
+ scoreToolDomains(normalizedMessage, entries) {
807
+ var _a, _b;
808
+ const scores = new Map();
809
+ for (const [domain, keywords] of Object.entries(DOMAIN_KEYWORDS)) {
810
+ let score = 0;
811
+ if (this.hasTerm(normalizedMessage, domain)) {
812
+ score += 3;
813
+ }
814
+ for (const keyword of keywords) {
815
+ const normalizedKeyword = this.normalizeText(keyword);
816
+ if (normalizedKeyword && normalizedMessage.includes(normalizedKeyword)) {
817
+ score += normalizedKeyword.includes(' ') ? 3 : 2;
818
+ }
819
+ }
820
+ if (score > 0 && entries.some((entry) => this.getToolDomain(entry.definition.name) === domain)) {
821
+ scores.set(domain, score);
822
+ }
823
+ }
824
+ for (const entry of entries) {
825
+ const domain = this.getToolDomain(entry.definition.name);
826
+ const toolText = this.normalizeText(`${entry.definition.name} ${(_a = entry.definition.description) !== null && _a !== void 0 ? _a : ''}`);
827
+ let score = (_b = scores.get(domain)) !== null && _b !== void 0 ? _b : 0;
828
+ for (const term of normalizedMessage.split(' ')) {
829
+ if (term.length >= 4 && toolText.includes(term)) {
830
+ score += 1;
831
+ }
832
+ }
833
+ if (score > 0) {
834
+ scores.set(domain, score);
835
+ }
836
+ }
837
+ return scores;
838
+ }
839
+ getCandidateDomains(domainScores) {
840
+ const ranked = Array.from(domainScores.entries())
841
+ .filter(([, score]) => score >= MIN_DOMAIN_CONFIDENCE)
842
+ .sort((a, b) => b[1] - a[1]);
843
+ if (ranked.length === 0) {
844
+ return [];
845
+ }
846
+ const topScore = ranked[0][1];
847
+ return ranked
848
+ .filter(([, score]) => topScore - score <= AMBIGUOUS_DOMAIN_DELTA)
849
+ .map(([domain]) => domain);
850
+ }
851
+ getToolSelectionClarification(originalMessage, normalizedMessage, domainScores, candidateDomains, entries) {
852
+ if (!this.messageLooksLikeToolRequest(normalizedMessage)) {
853
+ return undefined;
854
+ }
855
+ const rankedDomains = Array.from(domainScores.entries()).sort((a, b) => b[1] - a[1]);
856
+ if (rankedDomains.length === 0 || rankedDomains[0][1] < MIN_DOMAIN_CONFIDENCE) {
857
+ return this.isLikelyPortuguese(originalMessage)
858
+ ? 'Você quer consultar qual área do sistema? Por exemplo: financeiro, operações, LMS ou configurações.'
859
+ : 'Which system area do you want to query? For example: finance, operations, LMS, or settings.';
860
+ }
861
+ if (candidateDomains.length > 1) {
862
+ const options = candidateDomains
863
+ .slice(0, 3)
864
+ .map((domain) => this.getDomainLabel(domain, originalMessage))
865
+ .join(', ');
866
+ return this.isLikelyPortuguese(originalMessage)
867
+ ? `Você quer consultar qual área: ${options}?`
868
+ : `Which area do you want to query: ${options}?`;
869
+ }
870
+ if (candidateDomains[0] === 'finance' &&
871
+ this.isAmbiguousFinanceAccountsRequest(normalizedMessage, entries)) {
872
+ return this.isLikelyPortuguese(originalMessage)
873
+ ? 'Você quer consultar contas bancárias, contas a pagar ou contas a receber?'
874
+ : 'Do you want bank accounts, accounts payable, or accounts receivable?';
875
+ }
876
+ return undefined;
877
+ }
878
+ scoreToolMatch(normalizedMessage, terms, entry, candidateDomains) {
879
+ var _a;
880
+ const toolName = entry.definition.name;
881
+ const toolText = this.normalizeText(`${toolName} ${(_a = entry.definition.description) !== null && _a !== void 0 ? _a : ''} ${this.getSchemaText(entry.definition.inputSchema)}`);
882
+ const domain = this.getToolDomain(toolName);
883
+ let score = candidateDomains.includes(domain) ? 8 : 0;
884
+ for (const term of normalizedMessage.split(' ')) {
885
+ if (term.length < 3)
886
+ continue;
887
+ if (toolText.includes(term)) {
888
+ score += term.length >= 5 ? 2 : 1;
889
+ }
890
+ }
891
+ if (terms.has('list') && entry.definition.readOnly)
892
+ score += 4;
893
+ if (terms.has('write') && !entry.definition.readOnly)
894
+ score += 4;
895
+ score += this.getFinanceSpecificBoost(normalizedMessage, toolName);
896
+ score += this.getKeywordBoost(normalizedMessage, toolName);
897
+ return score;
898
+ }
899
+ getSchemaText(schema) {
900
+ if (!schema || typeof schema !== 'object') {
901
+ return '';
902
+ }
903
+ const properties = schema.properties;
904
+ if (!properties || typeof properties !== 'object') {
905
+ return '';
906
+ }
907
+ return Object.keys(properties).join(' ');
908
+ }
909
+ getFinanceSpecificBoost(message, toolName) {
910
+ if (!toolName.startsWith('finance.')) {
911
+ return 0;
912
+ }
913
+ let boost = 0;
914
+ if (/banco|bancaria|bancarias|bank/.test(message) &&
915
+ toolName.includes('bank-accounts')) {
916
+ boost += 10;
917
+ }
918
+ if (/extrato|statement/.test(message) && toolName.includes('statements')) {
919
+ boost += 10;
920
+ }
921
+ if (/pagar|payable/.test(message) && toolName.includes('accounts-payable')) {
922
+ boost += 10;
923
+ }
924
+ if (/receber|receivable/.test(message) && toolName.includes('accounts-receivable')) {
925
+ boost += 10;
926
+ }
927
+ if (/moeda|currency/.test(message) && toolName.includes('currencies')) {
928
+ boost += 8;
929
+ }
930
+ if (/transferencia|transfer|transferencias/.test(message) && toolName.includes('transfers')) {
931
+ boost += 8;
932
+ }
933
+ return boost;
934
+ }
935
+ messageLooksLikeToolRequest(normalizedMessage) {
936
+ return ACTION_KEYWORDS.some((keyword) => this.hasTerm(normalizedMessage, this.normalizeText(keyword)));
937
+ }
938
+ isAmbiguousFinanceAccountsRequest(normalizedMessage, entries) {
939
+ const mentionsGenericAccounts = /\b(conta|contas|account|accounts)\b/.test(normalizedMessage);
940
+ const hasQualifier = /banco|bancaria|bancarias|bank|extrato|statement|pagar|payable|receber|receivable/.test(normalizedMessage);
941
+ if (!mentionsGenericAccounts || hasQualifier) {
942
+ return false;
943
+ }
944
+ const financeToolNames = entries
945
+ .map((entry) => entry.definition.name)
946
+ .filter((name) => name.startsWith('finance.'));
947
+ return (financeToolNames.some((name) => name.includes('bank-accounts')) &&
948
+ (financeToolNames.some((name) => name.includes('accounts-payable')) ||
949
+ financeToolNames.some((name) => name.includes('accounts-receivable'))));
950
+ }
951
+ hasTerm(text, term) {
952
+ return new RegExp(`(^|\\s)${this.escapeRegex(term)}($|\\s)`).test(text);
953
+ }
954
+ escapeRegex(value) {
955
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
956
+ }
957
+ getDomainLabel(domain, message) {
958
+ const labels = {
959
+ finance: { pt: 'financeiro', en: 'finance' },
960
+ operations: { pt: 'operações', en: 'operations' },
961
+ lms: { pt: 'LMS/cursos', en: 'LMS/courses' },
962
+ core: { pt: 'configurações/core', en: 'settings/core' },
963
+ contact: { pt: 'contatos', en: 'contacts' },
964
+ };
965
+ const label = labels[domain];
966
+ if (!label) {
967
+ return domain;
968
+ }
969
+ return this.isLikelyPortuguese(message) ? label.pt : label.en;
970
+ }
971
+ isLikelyPortuguese(message) {
972
+ return /(voce|você|qual|consultar|listar|conta|contas|bancaria|bancária|extrato|tarefas|curso|cursos)/i.test(message);
973
+ }
974
+ formatDomainScores(domainScores) {
975
+ const formatted = Array.from(domainScores.entries())
976
+ .sort((a, b) => b[1] - a[1])
977
+ .slice(0, 5)
978
+ .map(([domain, score]) => `${domain}:${score}`)
979
+ .join(',');
980
+ return formatted || 'none';
981
+ }
982
+ async recordAssistantAndReturnHistory(conversationId, content) {
983
+ await this.prisma.mcp_conversation_message.create({
984
+ data: {
985
+ conversation_id: conversationId,
986
+ role: 'assistant',
987
+ content,
988
+ },
989
+ });
990
+ return this.prisma.mcp_conversation_message.findMany({
991
+ where: { conversation_id: conversationId },
992
+ orderBy: { created_at: 'asc' },
993
+ });
994
+ }
995
+ getMessageKeywordSet(message) {
996
+ const keywords = new Set();
997
+ if (/(tarefa|tarefas|task|tasks)/i.test(message)) {
998
+ keywords.add('task');
999
+ }
1000
+ if (/(projeto|projetos|project|projects)/i.test(message)) {
1001
+ keywords.add('project');
1002
+ }
1003
+ if (/(turma|class|curso|cursos|course|training)/i.test(message)) {
1004
+ keywords.add('class');
1005
+ }
1006
+ if (/(pendente|pendentes|pending|open|aberta|abertas)/i.test(message)) {
1007
+ keywords.add('pending');
1008
+ }
1009
+ if (/(listar|lista|buscar|procurar|consultar|mostrar|ver|list|search|find|show|get)/i.test(message)) {
1010
+ keywords.add('list');
1011
+ }
1012
+ if (/(criar|adicionar|atualizar|alterar|remover|deletar|excluir|create|add|update|delete|remove)/i.test(message)) {
1013
+ keywords.add('write');
276
1014
  }
277
- return key;
1015
+ return keywords;
278
1016
  }
279
1017
  };
280
1018
  exports.McpChatService = McpChatService;
281
- exports.McpChatService = McpChatService = __decorate([
1019
+ exports.McpChatService = McpChatService = McpChatService_1 = __decorate([
282
1020
  (0, common_1.Injectable)(),
283
1021
  __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => api_prisma_1.PrismaService))),
284
1022
  __param(1, (0, common_1.Inject)((0, common_1.forwardRef)(() => setting_service_1.SettingService))),