@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.
- package/dist/access-log/access-log.controller.d.ts +16 -0
- package/dist/access-log/access-log.controller.d.ts.map +1 -0
- package/dist/access-log/access-log.controller.js +44 -0
- package/dist/access-log/access-log.controller.js.map +1 -0
- package/dist/access-log/access-log.interceptor.d.ts +9 -0
- package/dist/access-log/access-log.interceptor.d.ts.map +1 -0
- package/dist/access-log/access-log.interceptor.js +46 -0
- package/dist/access-log/access-log.interceptor.js.map +1 -0
- package/dist/access-log/access-log.module.d.ts +3 -0
- package/dist/access-log/access-log.module.d.ts.map +1 -0
- package/dist/access-log/access-log.module.js +29 -0
- package/dist/access-log/access-log.module.js.map +1 -0
- package/dist/access-log/access-log.service.d.ts +47 -0
- package/dist/access-log/access-log.service.d.ts.map +1 -0
- package/dist/access-log/access-log.service.js +113 -0
- package/dist/access-log/access-log.service.js.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts +8 -0
- package/dist/access-log/dto/query-access-log.dto.d.ts.map +1 -0
- package/dist/access-log/dto/query-access-log.dto.js +42 -0
- package/dist/access-log/dto/query-access-log.dto.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +12 -12
- package/dist/auth/auth.service.d.ts +27 -27
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +0 -4
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/challenge/challenge.service.d.ts.map +1 -1
- package/dist/challenge/challenge.service.js +0 -1
- package/dist/challenge/challenge.service.js.map +1 -1
- package/dist/core/system.module.d.ts.map +1 -1
- package/dist/core/system.module.js +1 -0
- package/dist/core/system.module.js.map +1 -1
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +15 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard-user/dashboard-user.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-user/dashboard-user.service.d.ts +3 -3
- package/dist/dashboard/dashboard.module.d.ts.map +1 -1
- package/dist/dashboard/dashboard.module.js +4 -1
- package/dist/dashboard/dashboard.module.js.map +1 -1
- package/dist/file/file.controller.js +0 -1
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.service.d.ts +65 -0
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +151 -3
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/provider/abstract.provider.d.ts +8 -0
- package/dist/file/provider/abstract.provider.d.ts.map +1 -1
- package/dist/file/provider/abstract.provider.js.map +1 -1
- package/dist/file/provider/azure.provider.d.ts +4 -0
- package/dist/file/provider/azure.provider.d.ts.map +1 -1
- package/dist/file/provider/azure.provider.js +14 -0
- package/dist/file/provider/azure.provider.js.map +1 -1
- package/dist/file/provider/gcs.provider.d.ts +4 -0
- package/dist/file/provider/gcs.provider.d.ts.map +1 -1
- package/dist/file/provider/gcs.provider.js +14 -0
- package/dist/file/provider/gcs.provider.js.map +1 -1
- package/dist/file/provider/local.provider.d.ts +4 -0
- package/dist/file/provider/local.provider.d.ts.map +1 -1
- package/dist/file/provider/local.provider.js +19 -0
- package/dist/file/provider/local.provider.js.map +1 -1
- package/dist/file/provider/provider.factory.d.ts.map +1 -1
- package/dist/file/provider/provider.factory.js +3 -0
- package/dist/file/provider/provider.factory.js.map +1 -1
- package/dist/file/provider/s3.provider.d.ts +4 -0
- package/dist/file/provider/s3.provider.d.ts.map +1 -1
- package/dist/file/provider/s3.provider.js +17 -0
- package/dist/file/provider/s3.provider.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts +6 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +29 -2
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/mcp-api-key.controller.d.ts +32 -0
- package/dist/mcp/mcp-api-key.controller.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.controller.js +64 -0
- package/dist/mcp/mcp-api-key.controller.js.map +1 -0
- package/dist/mcp/mcp-api-key.service.d.ts +27 -0
- package/dist/mcp/mcp-api-key.service.d.ts.map +1 -0
- package/dist/mcp/mcp-api-key.service.js +74 -0
- package/dist/mcp/mcp-api-key.service.js.map +1 -0
- package/dist/mcp/mcp-audit.service.d.ts +3 -1
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
- package/dist/mcp/mcp-audit.service.js +14 -2
- package/dist/mcp/mcp-audit.service.js.map +1 -1
- package/dist/mcp/mcp-registry.service.d.ts +1 -2
- package/dist/mcp/mcp-registry.service.d.ts.map +1 -1
- package/dist/mcp/mcp-registry.service.js +6 -2
- package/dist/mcp/mcp-registry.service.js.map +1 -1
- package/dist/mcp/mcp.controller.d.ts +3 -1
- package/dist/mcp/mcp.controller.d.ts.map +1 -1
- package/dist/mcp/mcp.controller.js +10 -2
- package/dist/mcp/mcp.controller.js.map +1 -1
- package/dist/mcp/mcp.module.d.ts.map +1 -1
- package/dist/mcp/mcp.module.js +80 -1
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts +45 -0
- package/dist/mcp/tools/core-ai.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js +214 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +89 -0
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts +29 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js +149 -0
- package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts +30 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +185 -0
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-files.mcp-tools.js +140 -0
- package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts +26 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js +168 -0
- package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts +32 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-mail-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts +14 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js +106 -0
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts +36 -0
- package/dist/mcp/tools/core-mail.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js +184 -0
- package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts +21 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js +118 -0
- package/dist/mcp/tools/core-mcp-chat.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts +40 -0
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js +268 -0
- package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts +31 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js +178 -0
- package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-profile.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js +111 -0
- package/dist/mcp/tools/core-profile.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts +70 -0
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js +355 -0
- package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts +52 -0
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js +254 -0
- package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts +47 -0
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js +250 -0
- package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts +20 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js +128 -0
- package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts +25 -0
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.js +138 -0
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-system.mcp-tools.d.ts +8 -0
- package/dist/mcp/tools/core-system.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-system.mcp-tools.js +40 -0
- package/dist/mcp/tools/core-system.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts +46 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js +266 -0
- package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -0
- package/dist/mcp-chat/mcp-chat.controller.d.ts +5 -1
- package/dist/mcp-chat/mcp-chat.controller.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.controller.js +46 -0
- package/dist/mcp-chat/mcp-chat.controller.js.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts +31 -3
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +776 -38
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/notification/dto/create-notification.dto.d.ts +26 -0
- package/dist/notification/dto/create-notification.dto.d.ts.map +1 -0
- package/dist/notification/dto/create-notification.dto.js +86 -0
- package/dist/notification/dto/create-notification.dto.js.map +1 -0
- package/dist/notification/dto/update-progress.dto.d.ts +6 -0
- package/dist/notification/dto/update-progress.dto.d.ts.map +1 -0
- package/dist/notification/dto/update-progress.dto.js +33 -0
- package/dist/notification/dto/update-progress.dto.js.map +1 -0
- package/dist/notification/notification.controller.d.ts +112 -0
- package/dist/notification/notification.controller.d.ts.map +1 -0
- package/dist/notification/notification.controller.js +130 -0
- package/dist/notification/notification.controller.js.map +1 -0
- package/dist/notification/notification.module.d.ts +3 -0
- package/dist/notification/notification.module.d.ts.map +1 -0
- package/dist/notification/notification.module.js +29 -0
- package/dist/notification/notification.module.js.map +1 -0
- package/dist/notification/notification.service.d.ts +112 -0
- package/dist/notification/notification.service.d.ts.map +1 -0
- package/dist/notification/notification.service.js +269 -0
- package/dist/notification/notification.service.js.map +1 -0
- package/dist/pdf/pdf.service.js +1 -1
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +4 -4
- package/dist/profile/profile.controller.js +0 -1
- package/dist/profile/profile.controller.js.map +1 -1
- package/dist/profile/profile.module.d.ts.map +1 -1
- package/dist/profile/profile.module.js +1 -0
- package/dist/profile/profile.module.js.map +1 -1
- package/dist/profile/profile.service.d.ts +4 -4
- package/dist/session/session.controller.d.ts +3 -3
- package/dist/session/session.service.d.ts +9 -9
- package/dist/setting/dto/update-setting-list.dto.d.ts +9 -0
- package/dist/setting/dto/update-setting-list.dto.d.ts.map +1 -0
- package/dist/setting/dto/update-setting-list.dto.js +44 -0
- package/dist/setting/dto/update-setting-list.dto.js.map +1 -0
- package/dist/setting/setting.controller.d.ts +20 -1
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.controller.js +12 -0
- package/dist/setting/setting.controller.js.map +1 -1
- package/dist/setting/setting.service.d.ts +20 -1
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +80 -4
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +13 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +85 -0
- package/dist/task/task.service.js.map +1 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +0 -1
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user.controller.d.ts +11 -11
- package/dist/user/user.service.d.ts +27 -27
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts +22 -0
- package/dist/webhook-integration/dto/webhook-action.dto.d.ts.map +1 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js +120 -0
- package/dist/webhook-integration/dto/webhook-action.dto.js.map +1 -0
- package/dist/webhook-integration/webhook-integration.controller.d.ts +7 -5
- package/dist/webhook-integration/webhook-integration.controller.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.controller.js +18 -5
- package/dist/webhook-integration/webhook-integration.controller.js.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.d.ts +18 -5
- package/dist/webhook-integration/webhook-integration.service.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-integration.service.js +342 -59
- package/dist/webhook-integration/webhook-integration.service.js.map +1 -1
- package/dist/webhook-integration/webhook-utils.d.ts +1 -0
- package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-utils.js +38 -0
- package/dist/webhook-integration/webhook-utils.js.map +1 -1
- package/hedhog/data/menu.yaml +63 -4
- package/hedhog/data/route.yaml +1437 -0
- package/hedhog/data/setting_group.yaml +112 -0
- package/hedhog/data/setting_subgroup.yaml +32 -0
- package/hedhog/frontend/app/access-log/page.tsx.ejs +772 -0
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +285 -0
- package/hedhog/frontend/app/account/layout.tsx.ejs +32 -55
- package/hedhog/frontend/app/account/mcp-tokens/page.tsx.ejs +5 -0
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +10 -3
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +33 -13
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +12 -5
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +3559 -1835
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +633 -0
- package/hedhog/frontend/app/mcp_chat/chat-types.ts.ejs +16 -0
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +583 -384
- package/hedhog/frontend/app/menu/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/roles/page.tsx.ejs +18 -6
- package/hedhog/frontend/app/routes/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +822 -0
- package/hedhog/frontend/app/users/page.tsx.ejs +445 -203
- package/hedhog/frontend/app/users/user-access-sheet.tsx.ejs +310 -304
- package/hedhog/frontend/app/users/user-sheet.tsx.ejs +41 -44
- package/hedhog/frontend/messages/en.json +343 -3
- package/hedhog/frontend/messages/pt.json +343 -3
- package/hedhog/table/access_log.yaml +31 -0
- package/hedhog/table/mcp_api_key.yaml +30 -0
- package/hedhog/table/notification.yaml +72 -0
- package/hedhog/table/webhook_action_log.yaml +49 -0
- package/package.json +5 -4
- package/src/access-log/access-log.controller.ts +29 -0
- package/src/access-log/access-log.interceptor.ts +38 -0
- package/src/access-log/access-log.module.ts +16 -0
- package/src/access-log/access-log.service.ts +129 -0
- package/src/access-log/dto/query-access-log.dto.ts +23 -0
- package/src/auth/auth.service.ts +0 -7
- package/src/challenge/challenge.service.ts +0 -2
- package/src/core/system.module.ts +1 -0
- package/src/core.module.ts +15 -0
- package/src/dashboard/dashboard.module.ts +4 -1
- package/src/file/file.controller.ts +14 -14
- package/src/file/file.service.ts +198 -4
- package/src/file/provider/abstract.provider.ts +10 -0
- package/src/file/provider/azure.provider.ts +24 -0
- package/src/file/provider/gcs.provider.ts +20 -0
- package/src/file/provider/local.provider.ts +30 -2
- package/src/file/provider/provider.factory.ts +3 -0
- package/src/file/provider/s3.provider.ts +22 -0
- package/src/index.ts +5 -0
- package/src/mcp/guards/mcp-auth.guard.ts +64 -32
- package/src/mcp/mcp-api-key.controller.ts +42 -0
- package/src/mcp/mcp-api-key.service.ts +66 -0
- package/src/mcp/mcp-audit.service.ts +47 -36
- package/src/mcp/mcp-registry.service.ts +75 -69
- package/src/mcp/mcp.controller.ts +40 -30
- package/src/mcp/mcp.module.ts +115 -36
- package/src/mcp/tools/core-ai.mcp-tools.ts +156 -0
- package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +63 -0
- package/src/mcp/tools/core-dashboard.mcp-tools.ts +103 -0
- package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +134 -0
- package/src/mcp/tools/core-files.mcp-tools.ts +105 -0
- package/src/mcp/tools/core-integration-events.mcp-tools.ts +118 -0
- package/src/mcp/tools/core-mail-profile.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-mail-sent.mcp-tools.ts +76 -0
- package/src/mcp/tools/core-mail.mcp-tools.ts +130 -0
- package/src/mcp/tools/core-mcp-chat.mcp-tools.ts +81 -0
- package/src/mcp/tools/core-menus.mcp-tools.ts +197 -0
- package/src/mcp/tools/core-notifications.mcp-tools.ts +128 -0
- package/src/mcp/tools/core-profile.mcp-tools.ts +74 -0
- package/src/mcp/tools/core-roles.mcp-tools.ts +288 -0
- package/src/mcp/tools/core-routes.mcp-tools.ts +196 -0
- package/src/mcp/tools/core-screens.mcp-tools.ts +186 -0
- package/src/mcp/tools/core-sessions.mcp-tools.ts +97 -0
- package/src/mcp/tools/core-settings.mcp-tools.ts +171 -53
- package/src/mcp/tools/core-system.mcp-tools.ts +19 -0
- package/src/mcp/tools/core-webhooks.mcp-tools.ts +199 -0
- package/src/mcp-chat/mcp-chat.controller.ts +113 -60
- package/src/mcp-chat/mcp-chat.service.ts +1343 -332
- package/src/notification/dto/create-notification.dto.ts +71 -0
- package/src/notification/dto/update-progress.dto.ts +16 -0
- package/src/notification/notification.controller.ts +83 -0
- package/src/notification/notification.module.ts +16 -0
- package/src/notification/notification.service.ts +324 -0
- package/src/pdf/pdf.service.ts +1 -1
- package/src/profile/profile.controller.ts +1 -1
- package/src/profile/profile.module.ts +1 -0
- package/src/setting/dto/update-setting-list.dto.ts +32 -0
- package/src/setting/setting.controller.ts +9 -0
- package/src/setting/setting.service.ts +99 -11
- package/src/task/task.service.ts +103 -0
- package/src/token/token.service.ts +0 -2
- package/src/webhook-integration/dto/webhook-action.dto.ts +96 -0
- package/src/webhook-integration/webhook-integration.controller.ts +124 -103
- package/src/webhook-integration/webhook-integration.service.ts +1137 -735
- 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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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;
|
|
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
|
|
272
|
-
const settings = await this.setting.getSettingValues([
|
|
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
|
|
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
|
|
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))),
|