@hed-hog/core 0.0.399 → 0.0.401
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/ai/ai-agent.sort.d.ts +6 -0
- package/dist/ai/ai-agent.sort.d.ts.map +1 -0
- package/dist/ai/ai-agent.sort.js +21 -0
- package/dist/ai/ai-agent.sort.js.map +1 -0
- package/dist/ai/ai.controller.d.ts +6 -4
- package/dist/ai/ai.controller.d.ts.map +1 -1
- package/dist/ai/ai.service.d.ts +121 -6
- package/dist/ai/ai.service.d.ts.map +1 -1
- package/dist/ai/ai.service.js +355 -160
- package/dist/ai/ai.service.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-instruction.service.js +26 -23
- package/dist/ai-instruction/ai-instruction.service.js.map +1 -1
- package/dist/ai-instruction/ai-instruction.sort.d.ts +16 -0
- package/dist/ai-instruction/ai-instruction.sort.d.ts.map +1 -0
- package/dist/ai-instruction/ai-instruction.sort.js +32 -0
- package/dist/ai-instruction/ai-instruction.sort.js.map +1 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts +12 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.d.ts.map +1 -1
- package/dist/ai-instruction/ai-prompt-resolver.service.js +26 -0
- package/dist/ai-instruction/ai-prompt-resolver.service.js.map +1 -1
- package/dist/auth/auth.controller.d.ts +24 -8
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +8 -1
- package/dist/auth/auth.module.js.map +1 -1
- package/dist/auth/auth.service.d.ts +72 -25
- package/dist/auth/auth.service.d.ts.map +1 -1
- package/dist/auth/auth.service.js +41 -4
- package/dist/auth/auth.service.js.map +1 -1
- package/dist/auth/guards/auth.guard.d.ts +3 -1
- package/dist/auth/guards/auth.guard.d.ts.map +1 -1
- package/dist/auth/guards/auth.guard.js +12 -3
- package/dist/auth/guards/auth.guard.js.map +1 -1
- package/dist/authorize/authorize.controller.d.ts +29 -5
- package/dist/authorize/authorize.controller.d.ts.map +1 -1
- package/dist/authorize/authorize.controller.js +120 -13
- package/dist/authorize/authorize.controller.js.map +1 -1
- package/dist/authorize/authorize.errors.d.ts +34 -0
- package/dist/authorize/authorize.errors.d.ts.map +1 -0
- package/dist/authorize/authorize.errors.js +37 -0
- package/dist/authorize/authorize.errors.js.map +1 -0
- package/dist/authorize/authorize.module.d.ts.map +1 -1
- package/dist/authorize/authorize.module.js +6 -1
- package/dist/authorize/authorize.module.js.map +1 -1
- package/dist/authorize/authorize.service.d.ts +77 -3
- package/dist/authorize/authorize.service.d.ts.map +1 -1
- package/dist/authorize/authorize.service.js +212 -21
- package/dist/authorize/authorize.service.js.map +1 -1
- package/dist/authorize/dto/authorize-info.dto.d.ts +10 -1
- package/dist/authorize/dto/authorize-info.dto.d.ts.map +1 -1
- package/dist/authorize/dto/authorize-info.dto.js +16 -1
- package/dist/authorize/dto/authorize-info.dto.js.map +1 -1
- package/dist/authorize/dto/consent.dto.d.ts +10 -1
- package/dist/authorize/dto/consent.dto.d.ts.map +1 -1
- package/dist/authorize/dto/consent.dto.js +16 -1
- package/dist/authorize/dto/consent.dto.js.map +1 -1
- package/dist/authorize/dto/token.dto.d.ts +12 -0
- package/dist/authorize/dto/token.dto.d.ts.map +1 -1
- package/dist/authorize/dto/token.dto.js +21 -1
- package/dist/authorize/dto/token.dto.js.map +1 -1
- package/dist/authorize/oauth-exception.filter.d.ts +17 -0
- package/dist/authorize/oauth-exception.filter.d.ts.map +1 -0
- package/dist/authorize/oauth-exception.filter.js +54 -0
- package/dist/authorize/oauth-exception.filter.js.map +1 -0
- package/dist/authorize/oauth-metadata.service.d.ts +39 -0
- package/dist/authorize/oauth-metadata.service.d.ts.map +1 -0
- package/dist/authorize/oauth-metadata.service.js +81 -0
- package/dist/authorize/oauth-metadata.service.js.map +1 -0
- package/dist/authorize/well-known.controller.d.ts +67 -0
- package/dist/authorize/well-known.controller.d.ts.map +1 -0
- package/dist/authorize/well-known.controller.js +126 -0
- package/dist/authorize/well-known.controller.js.map +1 -0
- package/dist/captcha/captcha.service.d.ts +32 -2
- package/dist/captcha/captcha.service.d.ts.map +1 -1
- package/dist/captcha/captcha.service.js +85 -12
- package/dist/captcha/captcha.service.js.map +1 -1
- package/dist/challenge/challenge.service.d.ts +2 -2
- package/dist/core.module.d.ts.map +1 -1
- package/dist/core.module.js +9 -0
- package/dist/core.module.js.map +1 -1
- package/dist/dashboard/dashboard/dashboard.controller.d.ts +9 -9
- package/dist/dashboard/dashboard/dashboard.service.d.ts +9 -9
- package/dist/dashboard/dashboard-component/dashboard-component.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-component/dashboard-component.service.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts +3 -3
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js +2 -4
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.service.js.map +1 -1
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts +8 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js +18 -0
- package/dist/dashboard/dashboard-component-role/dashboard-component-role.sort.js.map +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.service.js +2 -4
- package/dist/dashboard/dashboard-item/dashboard-item.service.js.map +1 -1
- package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts +9 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.js +19 -0
- package/dist/dashboard/dashboard-item/dashboard-item.sort.js.map +1 -0
- package/dist/dashboard/dashboard-role/dashboard-role.controller.d.ts +3 -3
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts +3 -3
- package/dist/dashboard/dashboard-role/dashboard-role.service.d.ts.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.service.js +2 -4
- package/dist/dashboard/dashboard-role/dashboard-role.service.js.map +1 -1
- package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts +8 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.d.ts.map +1 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.js +16 -0
- package/dist/dashboard/dashboard-role/dashboard-role.sort.js.map +1 -0
- package/dist/document-kit/document-kit.module.d.ts +3 -0
- package/dist/document-kit/document-kit.module.d.ts.map +1 -0
- package/dist/document-kit/document-kit.module.js +24 -0
- package/dist/document-kit/document-kit.module.js.map +1 -0
- package/dist/document-kit/document-kit.registry.d.ts +55 -0
- package/dist/document-kit/document-kit.registry.d.ts.map +1 -0
- package/dist/document-kit/document-kit.registry.js +91 -0
- package/dist/document-kit/document-kit.registry.js.map +1 -0
- package/dist/document-kit/document-kit.service.d.ts +49 -0
- package/dist/document-kit/document-kit.service.d.ts.map +1 -0
- package/dist/document-kit/document-kit.service.js +135 -0
- package/dist/document-kit/document-kit.service.js.map +1 -0
- package/dist/file/file-upload-ticket.service.d.ts +160 -0
- package/dist/file/file-upload-ticket.service.d.ts.map +1 -0
- package/dist/file/file-upload-ticket.service.js +382 -0
- package/dist/file/file-upload-ticket.service.js.map +1 -0
- package/dist/file/file.controller.d.ts +24 -1
- package/dist/file/file.controller.d.ts.map +1 -1
- package/dist/file/file.controller.js +63 -2
- package/dist/file/file.controller.js.map +1 -1
- package/dist/file/file.module.d.ts.map +1 -1
- package/dist/file/file.module.js +14 -2
- package/dist/file/file.module.js.map +1 -1
- package/dist/file/file.service.d.ts +197 -7
- package/dist/file/file.service.d.ts.map +1 -1
- package/dist/file/file.service.js +438 -78
- package/dist/file/file.service.js.map +1 -1
- package/dist/file/filename-encoding.util.d.ts +24 -0
- package/dist/file/filename-encoding.util.d.ts.map +1 -0
- package/dist/file/filename-encoding.util.js +63 -0
- package/dist/file/filename-encoding.util.js.map +1 -0
- package/dist/file/image-optimization.service.d.ts +27 -0
- package/dist/file/image-optimization.service.d.ts.map +1 -1
- package/dist/file/image-optimization.service.js +63 -14
- package/dist/file/image-optimization.service.js.map +1 -1
- package/dist/file/mcp-file-source.schema.d.ts +33 -0
- package/dist/file/mcp-file-source.schema.d.ts.map +1 -0
- package/dist/file/mcp-file-source.schema.js +78 -0
- package/dist/file/mcp-file-source.schema.js.map +1 -0
- package/dist/file/mcp-file-source.service.d.ts +124 -0
- package/dist/file/mcp-file-source.service.d.ts.map +1 -0
- package/dist/file/mcp-file-source.service.js +262 -0
- package/dist/file/mcp-file-source.service.js.map +1 -0
- package/dist/file/mimetype-sniff.util.d.ts +62 -0
- package/dist/file/mimetype-sniff.util.d.ts.map +1 -0
- package/dist/file/mimetype-sniff.util.js +226 -0
- package/dist/file/mimetype-sniff.util.js.map +1 -0
- package/dist/file/remote-fetch.util.d.ts +35 -0
- package/dist/file/remote-fetch.util.d.ts.map +1 -0
- package/dist/file/remote-fetch.util.js +236 -0
- package/dist/file/remote-fetch.util.js.map +1 -0
- package/dist/impersonation/dto/start-impersonation.dto.d.ts +4 -1
- package/dist/impersonation/dto/start-impersonation.dto.d.ts.map +1 -1
- package/dist/impersonation/dto/start-impersonation.dto.js +1 -1
- package/dist/impersonation/dto/start-impersonation.dto.js.map +1 -1
- package/dist/impersonation/impersonation.service.d.ts +8 -3
- package/dist/impersonation/impersonation.service.d.ts.map +1 -1
- package/dist/impersonation/impersonation.service.js +14 -4
- package/dist/impersonation/impersonation.service.js.map +1 -1
- package/dist/incident/incident.controller.d.ts +2 -1
- package/dist/incident/incident.controller.d.ts.map +1 -1
- package/dist/incident/incident.controller.js +10 -6
- package/dist/incident/incident.controller.js.map +1 -1
- package/dist/incident/incident.service.d.ts +2 -0
- package/dist/incident/incident.service.d.ts.map +1 -1
- package/dist/incident/incident.service.js +4 -0
- package/dist/incident/incident.service.js.map +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.secrets.js +28 -0
- package/dist/integration-profile/integration-profile.secrets.js.map +1 -1
- package/dist/integration-profile/integration-profile.service.d.ts +0 -13
- package/dist/integration-profile/integration-profile.service.d.ts.map +1 -1
- package/dist/integration-profile/integration-profile.service.js +5 -40
- package/dist/integration-profile/integration-profile.service.js.map +1 -1
- package/dist/integration-profile/integration-profile.utils.js +5 -5
- package/dist/integration-profile/integration-profile.utils.js.map +1 -1
- package/dist/integration-profile/testers/ai.testers.d.ts.map +1 -1
- package/dist/integration-profile/testers/ai.testers.js +46 -8
- package/dist/integration-profile/testers/ai.testers.js.map +1 -1
- package/dist/integration-profile/testers/index.d.ts.map +1 -1
- package/dist/integration-profile/testers/index.js +2 -0
- package/dist/integration-profile/testers/index.js.map +1 -1
- package/dist/integration-profile/testers/shipping.testers.d.ts +3 -0
- package/dist/integration-profile/testers/shipping.testers.d.ts.map +1 -0
- package/dist/integration-profile/testers/shipping.testers.js +71 -0
- package/dist/integration-profile/testers/shipping.testers.js.map +1 -0
- package/dist/locale/locale.controller.d.ts +1 -1
- package/dist/locale/locale.service.d.ts +1 -1
- package/dist/mail/dto/send.dto.d.ts +6 -1
- package/dist/mail/dto/send.dto.d.ts.map +1 -1
- package/dist/mail/dto/send.dto.js.map +1 -1
- package/dist/mail/mail.service.d.ts +9 -0
- package/dist/mail/mail.service.d.ts.map +1 -1
- package/dist/mail/mail.service.js +34 -14
- package/dist/mail/mail.service.js.map +1 -1
- package/dist/mail-sent/mail-sent.controller.d.ts +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts +1 -1
- package/dist/mail-sent/mail-sent.service.d.ts.map +1 -1
- package/dist/mail-sent/mail-sent.service.js +2 -1
- package/dist/mail-sent/mail-sent.service.js.map +1 -1
- package/dist/mail-sent/mail-sent.sort.d.ts +9 -0
- package/dist/mail-sent/mail-sent.sort.d.ts.map +1 -0
- package/dist/mail-sent/mail-sent.sort.js +19 -0
- package/dist/mail-sent/mail-sent.sort.js.map +1 -0
- package/dist/mcp/filters/mcp-challenge.filter.d.ts +20 -0
- package/dist/mcp/filters/mcp-challenge.filter.d.ts.map +1 -0
- package/dist/mcp/filters/mcp-challenge.filter.js +69 -0
- package/dist/mcp/filters/mcp-challenge.filter.js.map +1 -0
- package/dist/mcp/guards/mcp-auth.guard.d.ts +4 -1
- package/dist/mcp/guards/mcp-auth.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-auth.guard.js +19 -5
- package/dist/mcp/guards/mcp-auth.guard.js.map +1 -1
- package/dist/mcp/guards/mcp-permission.guard.d.ts +25 -3
- package/dist/mcp/guards/mcp-permission.guard.d.ts.map +1 -1
- package/dist/mcp/guards/mcp-permission.guard.js +46 -26
- package/dist/mcp/guards/mcp-permission.guard.js.map +1 -1
- package/dist/mcp/mcp-audit.service.d.ts +17 -0
- package/dist/mcp/mcp-audit.service.d.ts.map +1 -1
- package/dist/mcp/mcp-audit.service.js +32 -3
- package/dist/mcp/mcp-audit.service.js.map +1 -1
- package/dist/mcp/mcp-permission.service.d.ts +64 -0
- package/dist/mcp/mcp-permission.service.d.ts.map +1 -0
- package/dist/mcp/mcp-permission.service.js +178 -0
- package/dist/mcp/mcp-permission.service.js.map +1 -0
- package/dist/mcp/mcp-server.service.d.ts +3 -1
- package/dist/mcp/mcp-server.service.d.ts.map +1 -1
- package/dist/mcp/mcp-server.service.js +36 -15
- package/dist/mcp/mcp-server.service.js.map +1 -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 +7 -1
- package/dist/mcp/mcp.module.js.map +1 -1
- package/dist/mcp/tools/core-access-log.mcp-tools.d.ts +17 -0
- package/dist/mcp/tools/core-access-log.mcp-tools.d.ts.map +1 -0
- package/dist/mcp/tools/core-access-log.mcp-tools.js +74 -0
- package/dist/mcp/tools/core-access-log.mcp-tools.js.map +1 -0
- package/dist/mcp/tools/core-ai.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-ai.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js +1 -1
- package/dist/mcp/tools/core-dashboard-items.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-dashboard.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-dashboard.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-event-webhooks.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-files.mcp-tools.d.ts +17 -5
- package/dist/mcp/tools/core-files.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-files.mcp-tools.js +186 -24
- package/dist/mcp/tools/core-files.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-integration-events.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-integration-events.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js +2 -14
- package/dist/mcp/tools/core-mail-sent.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-mail.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-mail.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-menus.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-menus.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-menus.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.js +0 -1
- package/dist/mcp/tools/core-notifications.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-roles.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-roles.mcp-tools.js +2 -13
- package/dist/mcp/tools/core-roles.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-routes.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-routes.mcp-tools.js +2 -11
- package/dist/mcp/tools/core-routes.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-screens.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-screens.mcp-tools.js +2 -11
- package/dist/mcp/tools/core-screens.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-sessions.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-sessions.mcp-tools.js +0 -2
- package/dist/mcp/tools/core-sessions.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-settings.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-settings.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-users.mcp-tools.js +2 -9
- package/dist/mcp/tools/core-users.mcp-tools.js.map +1 -1
- package/dist/mcp/tools/core-webhooks.mcp-tools.d.ts.map +1 -1
- package/dist/mcp/tools/core-webhooks.mcp-tools.js +2 -10
- package/dist/mcp/tools/core-webhooks.mcp-tools.js.map +1 -1
- package/dist/mcp/types/mcp-context.type.d.ts +9 -0
- package/dist/mcp/types/mcp-context.type.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.d.ts.map +1 -1
- package/dist/mcp-chat/mcp-chat.service.js +8 -0
- package/dist/mcp-chat/mcp-chat.service.js.map +1 -1
- package/dist/meeting/meeting-provider.registry.d.ts +187 -0
- package/dist/meeting/meeting-provider.registry.d.ts.map +1 -1
- package/dist/meeting/meeting-provider.registry.js.map +1 -1
- package/dist/meeting/meeting.constants.d.ts +70 -0
- package/dist/meeting/meeting.constants.d.ts.map +1 -1
- package/dist/meeting/meeting.constants.js +9 -1
- package/dist/meeting/meeting.constants.js.map +1 -1
- package/dist/menu/menu.service.d.ts.map +1 -1
- package/dist/menu/menu.service.js +29 -9
- package/dist/menu/menu.service.js.map +1 -1
- package/dist/message-template/dto/update-message-template.dto.d.ts +18 -0
- package/dist/message-template/dto/update-message-template.dto.d.ts.map +1 -0
- package/dist/message-template/dto/update-message-template.dto.js +38 -0
- package/dist/message-template/dto/update-message-template.dto.js.map +1 -0
- package/dist/message-template/message-template-admin.service.d.ts +70 -0
- package/dist/message-template/message-template-admin.service.d.ts.map +1 -0
- package/dist/message-template/message-template-admin.service.js +226 -0
- package/dist/message-template/message-template-admin.service.js.map +1 -0
- package/dist/message-template/message-template.controller.d.ts +29 -0
- package/dist/message-template/message-template.controller.d.ts.map +1 -0
- package/dist/message-template/message-template.controller.js +101 -0
- package/dist/message-template/message-template.controller.js.map +1 -0
- package/dist/message-template/message-template.module.d.ts +10 -0
- package/dist/message-template/message-template.module.d.ts.map +1 -0
- package/dist/message-template/message-template.module.js +33 -0
- package/dist/message-template/message-template.module.js.map +1 -0
- package/dist/message-template/message-template.registry.d.ts +55 -0
- package/dist/message-template/message-template.registry.d.ts.map +1 -0
- package/dist/message-template/message-template.registry.js +64 -0
- package/dist/message-template/message-template.registry.js.map +1 -0
- package/dist/message-template/message-template.service.d.ts +59 -0
- package/dist/message-template/message-template.service.d.ts.map +1 -0
- package/dist/message-template/message-template.service.js +166 -0
- package/dist/message-template/message-template.service.js.map +1 -0
- package/dist/notification/notification.constants.d.ts +11 -0
- package/dist/notification/notification.constants.d.ts.map +1 -0
- package/dist/notification/notification.constants.js +14 -0
- package/dist/notification/notification.constants.js.map +1 -0
- package/dist/notification/notification.controller.d.ts +20 -20
- package/dist/notification/notification.module.d.ts.map +1 -1
- package/dist/notification/notification.module.js +3 -0
- package/dist/notification/notification.module.js.map +1 -1
- package/dist/notification/notification.service.d.ts +33 -21
- package/dist/notification/notification.service.d.ts.map +1 -1
- package/dist/notification/notification.service.js +36 -2
- package/dist/notification/notification.service.js.map +1 -1
- package/dist/oauth/oauth-token-broker.service.d.ts +50 -1
- package/dist/oauth/oauth-token-broker.service.d.ts.map +1 -1
- package/dist/oauth/oauth-token-broker.service.js +105 -3
- package/dist/oauth/oauth-token-broker.service.js.map +1 -1
- package/dist/oauth/oauth.controller.d.ts +4 -6
- package/dist/oauth/oauth.controller.d.ts.map +1 -1
- package/dist/oauth/oauth.controller.js +0 -1
- package/dist/oauth/oauth.controller.js.map +1 -1
- package/dist/oauth/oauth.errors.d.ts +15 -1
- package/dist/oauth/oauth.errors.d.ts.map +1 -1
- package/dist/oauth/oauth.errors.js +9 -1
- package/dist/oauth/oauth.errors.js.map +1 -1
- package/dist/oauth/oauth.module.d.ts.map +1 -1
- package/dist/oauth/oauth.module.js +6 -1
- package/dist/oauth/oauth.module.js.map +1 -1
- package/dist/oauth/oauth.service.d.ts +25 -5
- package/dist/oauth/oauth.service.d.ts.map +1 -1
- package/dist/oauth/oauth.service.js +63 -27
- package/dist/oauth/oauth.service.js.map +1 -1
- package/dist/oauth/providers/abstract.provider.d.ts +10 -0
- package/dist/oauth/providers/abstract.provider.d.ts.map +1 -1
- package/dist/oauth/providers/abstract.provider.js +39 -12
- package/dist/oauth/providers/abstract.provider.js.map +1 -1
- package/dist/oauth/providers/github.provider.d.ts +1 -1
- package/dist/oauth/providers/github.provider.d.ts.map +1 -1
- package/dist/oauth/providers/github.provider.js +48 -22
- package/dist/oauth/providers/github.provider.js.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts +6 -0
- package/dist/oauth/providers/microsoft-entra-id.provider.d.ts.map +1 -1
- package/dist/oauth/providers/microsoft-entra-id.provider.js +36 -4
- package/dist/oauth/providers/microsoft-entra-id.provider.js.map +1 -1
- package/dist/observability/monitored-cron.d.ts +29 -12
- package/dist/observability/monitored-cron.d.ts.map +1 -1
- package/dist/observability/monitored-cron.js +131 -46
- package/dist/observability/monitored-cron.js.map +1 -1
- package/dist/pairing/pairing.service.d.ts +6 -2
- package/dist/pairing/pairing.service.d.ts.map +1 -1
- package/dist/pdf/document/charts/chart-bar.d.ts +24 -0
- package/dist/pdf/document/charts/chart-bar.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-bar.js +117 -0
- package/dist/pdf/document/charts/chart-bar.js.map +1 -0
- package/dist/pdf/document/charts/chart-donut.d.ts +16 -0
- package/dist/pdf/document/charts/chart-donut.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-donut.js +89 -0
- package/dist/pdf/document/charts/chart-donut.js.map +1 -0
- package/dist/pdf/document/charts/chart-gauge.d.ts +15 -0
- package/dist/pdf/document/charts/chart-gauge.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-gauge.js +60 -0
- package/dist/pdf/document/charts/chart-gauge.js.map +1 -0
- package/dist/pdf/document/charts/chart-line.d.ts +29 -0
- package/dist/pdf/document/charts/chart-line.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-line.js +89 -0
- package/dist/pdf/document/charts/chart-line.js.map +1 -0
- package/dist/pdf/document/charts/chart-primitives.d.ts +64 -0
- package/dist/pdf/document/charts/chart-primitives.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-primitives.js +110 -0
- package/dist/pdf/document/charts/chart-primitives.js.map +1 -0
- package/dist/pdf/document/charts/chart-radar.d.ts +13 -0
- package/dist/pdf/document/charts/chart-radar.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-radar.js +83 -0
- package/dist/pdf/document/charts/chart-radar.js.map +1 -0
- package/dist/pdf/document/charts/chart-scale.d.ts +39 -0
- package/dist/pdf/document/charts/chart-scale.d.ts.map +1 -0
- package/dist/pdf/document/charts/chart-scale.js +118 -0
- package/dist/pdf/document/charts/chart-scale.js.map +1 -0
- package/dist/pdf/document/charts/index.d.ts +8 -0
- package/dist/pdf/document/charts/index.d.ts.map +1 -0
- package/dist/pdf/document/charts/index.js +24 -0
- package/dist/pdf/document/charts/index.js.map +1 -0
- package/dist/pdf/document/index.d.ts +8 -0
- package/dist/pdf/document/index.d.ts.map +1 -0
- package/dist/pdf/document/index.js +24 -0
- package/dist/pdf/document/index.js.map +1 -0
- package/dist/pdf/document/pdf-document.chrome.d.ts +20 -0
- package/dist/pdf/document/pdf-document.chrome.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.chrome.js +36 -0
- package/dist/pdf/document/pdf-document.chrome.js.map +1 -0
- package/dist/pdf/document/pdf-document.css.d.ts +20 -0
- package/dist/pdf/document/pdf-document.css.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.css.js +239 -0
- package/dist/pdf/document/pdf-document.css.js.map +1 -0
- package/dist/pdf/document/pdf-document.renderer.d.ts +10 -0
- package/dist/pdf/document/pdf-document.renderer.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.renderer.js +153 -0
- package/dist/pdf/document/pdf-document.renderer.js.map +1 -0
- package/dist/pdf/document/pdf-document.service.d.ts +27 -0
- package/dist/pdf/document/pdf-document.service.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.service.js +81 -0
- package/dist/pdf/document/pdf-document.service.js.map +1 -0
- package/dist/pdf/document/pdf-document.theme.d.ts +41 -0
- package/dist/pdf/document/pdf-document.theme.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.theme.js +105 -0
- package/dist/pdf/document/pdf-document.theme.js.map +1 -0
- package/dist/pdf/document/pdf-document.types.d.ts +108 -0
- package/dist/pdf/document/pdf-document.types.d.ts.map +1 -0
- package/dist/pdf/document/pdf-document.types.js +18 -0
- package/dist/pdf/document/pdf-document.types.js.map +1 -0
- package/dist/pdf/pdf.module.d.ts.map +1 -1
- package/dist/pdf/pdf.module.js +3 -2
- package/dist/pdf/pdf.module.js.map +1 -1
- package/dist/pdf/pdf.service.d.ts +69 -1
- package/dist/pdf/pdf.service.d.ts.map +1 -1
- package/dist/pdf/pdf.service.js +164 -63
- package/dist/pdf/pdf.service.js.map +1 -1
- package/dist/pdf/templates/commercial-proposal.template.d.ts +96 -0
- package/dist/pdf/templates/commercial-proposal.template.d.ts.map +1 -0
- package/dist/pdf/templates/commercial-proposal.template.js +276 -0
- package/dist/pdf/templates/commercial-proposal.template.js.map +1 -0
- package/dist/profile/dto/change-password.dto.d.ts.map +1 -1
- package/dist/profile/dto/change-password.dto.js +4 -6
- package/dist/profile/dto/change-password.dto.js.map +1 -1
- package/dist/profile/profile.controller.d.ts +1 -1
- package/dist/profile/profile.service.d.ts +1 -1
- package/dist/profile/profile.service.d.ts.map +1 -1
- package/dist/profile/profile.service.js +9 -3
- package/dist/profile/profile.service.js.map +1 -1
- package/dist/realtime/realtime-tick.coalescer.d.ts +34 -0
- package/dist/realtime/realtime-tick.coalescer.d.ts.map +1 -0
- package/dist/realtime/realtime-tick.coalescer.js +60 -0
- package/dist/realtime/realtime-tick.coalescer.js.map +1 -0
- package/dist/realtime/realtime.service.d.ts +2 -0
- package/dist/realtime/realtime.service.d.ts.map +1 -1
- package/dist/realtime/realtime.service.js +22 -2
- package/dist/realtime/realtime.service.js.map +1 -1
- package/dist/redis/redis-kv.service.d.ts +90 -0
- package/dist/redis/redis-kv.service.d.ts.map +1 -0
- package/dist/redis/redis-kv.service.js +247 -0
- package/dist/redis/redis-kv.service.js.map +1 -0
- package/dist/redis/redis-master.d.ts +29 -0
- package/dist/redis/redis-master.d.ts.map +1 -0
- package/dist/redis/redis-master.js +81 -0
- package/dist/redis/redis-master.js.map +1 -0
- package/dist/redis/redis-pubsub.d.ts +12 -0
- package/dist/redis/redis-pubsub.d.ts.map +1 -1
- package/dist/redis/redis-pubsub.js +25 -2
- package/dist/redis/redis-pubsub.js.map +1 -1
- package/dist/redis/redis.module.d.ts +11 -0
- package/dist/redis/redis.module.d.ts.map +1 -0
- package/dist/redis/redis.module.js +30 -0
- package/dist/redis/redis.module.js.map +1 -0
- package/dist/session/session.controller.d.ts +6 -2
- package/dist/session/session.controller.d.ts.map +1 -1
- package/dist/session/session.service.d.ts +118 -15
- package/dist/session/session.service.d.ts.map +1 -1
- package/dist/session/session.service.js +251 -77
- package/dist/session/session.service.js.map +1 -1
- package/dist/setting/favicon.controller.d.ts +26 -0
- package/dist/setting/favicon.controller.d.ts.map +1 -0
- package/dist/setting/favicon.controller.js +130 -0
- package/dist/setting/favicon.controller.js.map +1 -0
- package/dist/setting/setting.controller.d.ts +5 -0
- package/dist/setting/setting.controller.d.ts.map +1 -1
- package/dist/setting/setting.module.d.ts.map +1 -1
- package/dist/setting/setting.module.js +2 -1
- package/dist/setting/setting.module.js.map +1 -1
- package/dist/setting/setting.service.d.ts +7 -0
- package/dist/setting/setting.service.d.ts.map +1 -1
- package/dist/setting/setting.service.js +38 -3
- package/dist/setting/setting.service.js.map +1 -1
- package/dist/task/task.service.d.ts +17 -0
- package/dist/task/task.service.d.ts.map +1 -1
- package/dist/task/task.service.js +48 -13
- package/dist/task/task.service.js.map +1 -1
- package/dist/token/token.service.d.ts +19 -1
- package/dist/token/token.service.d.ts.map +1 -1
- package/dist/token/token.service.js +39 -2
- package/dist/token/token.service.js.map +1 -1
- package/dist/user/user-credential.util.d.ts +10 -0
- package/dist/user/user-credential.util.d.ts.map +1 -1
- package/dist/user/user-credential.util.js +14 -1
- package/dist/user/user-credential.util.js.map +1 -1
- package/dist/user/user.service.d.ts +12 -4
- package/dist/user/user.service.d.ts.map +1 -1
- package/dist/user/user.service.js +2 -11
- package/dist/user/user.service.js.map +1 -1
- package/dist/user/user.sort.d.ts +16 -0
- package/dist/user/user.sort.d.ts.map +1 -0
- package/dist/user/user.sort.js +25 -0
- package/dist/user/user.sort.js.map +1 -0
- package/dist/utils/abbreviate-name.d.ts +13 -0
- package/dist/utils/abbreviate-name.d.ts.map +1 -0
- package/dist/utils/abbreviate-name.js +42 -0
- package/dist/utils/abbreviate-name.js.map +1 -0
- package/dist/utils/date-range-query.dto.d.ts +11 -0
- package/dist/utils/date-range-query.dto.d.ts.map +1 -0
- package/dist/utils/date-range-query.dto.js +63 -0
- package/dist/utils/date-range-query.dto.js.map +1 -0
- package/dist/utils/date-range.d.ts +96 -0
- package/dist/utils/date-range.d.ts.map +1 -0
- package/dist/utils/date-range.js +172 -0
- package/dist/utils/date-range.js.map +1 -0
- package/dist/webhook-integration/webhook-utils.d.ts.map +1 -1
- package/dist/webhook-integration/webhook-utils.js +24 -0
- package/dist/webhook-integration/webhook-utils.js.map +1 -1
- package/dist/whatsapp-sender/whatsapp-recipients.d.ts +49 -0
- package/dist/whatsapp-sender/whatsapp-recipients.d.ts.map +1 -0
- package/dist/whatsapp-sender/whatsapp-recipients.js +66 -0
- package/dist/whatsapp-sender/whatsapp-recipients.js.map +1 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts +25 -0
- package/dist/whatsapp-sender/whatsapp-sender.service.d.ts.map +1 -1
- package/dist/whatsapp-sender/whatsapp-sender.service.js +71 -7
- package/dist/whatsapp-sender/whatsapp-sender.service.js.map +1 -1
- package/hedhog/data/integration_provider.yaml +9 -0
- package/hedhog/data/integration_type.yaml +12 -0
- package/hedhog/data/locale.yaml +0 -1
- package/hedhog/data/mail.yaml +2 -2
- package/hedhog/data/mail_layout.yaml +6 -3
- package/hedhog/data/menu.yaml +25 -5
- package/hedhog/data/route.yaml +148 -0
- package/hedhog/data/setting_group.yaml +189 -3
- package/hedhog/frontend/app/access-log/page.tsx.ejs +47 -53
- package/hedhog/frontend/app/account/components/active-sessions.tsx.ejs +33 -8
- package/hedhog/frontend/app/account/components/mcp-tokens.tsx.ejs +54 -13
- package/hedhog/frontend/app/account/components/mfa-method-card.tsx.ejs +7 -1
- package/hedhog/frontend/app/account/components/recovery-codes-dialog.tsx.ejs +1 -0
- package/hedhog/frontend/app/account/components/tokens.tsx.ejs +47 -17
- package/hedhog/frontend/app/ai_agent/page.tsx.ejs +46 -5
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-form.tsx.ejs +101 -30
- package/hedhog/frontend/app/ai_instruction/_components/ai-instruction-versions.tsx.ejs +24 -8
- package/hedhog/frontend/app/ai_instruction/page.tsx.ejs +80 -15
- package/hedhog/frontend/app/configurations/[slug]/components/image-optimization-action.tsx.ejs +166 -0
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.test.tsx.ejs +145 -45
- package/hedhog/frontend/app/configurations/[slug]/components/setting-field.tsx.ejs +99 -219
- package/hedhog/frontend/app/configurations/[slug]/page.tsx.ejs +19 -1
- package/hedhog/frontend/app/configurations/layout.tsx.ejs +19 -5
- package/hedhog/frontend/app/dashboard/[slug]/widget-renderer.tsx.ejs +2 -8
- package/hedhog/frontend/app/dashboard/components/dynamic-widget.tsx.ejs +3 -0
- package/hedhog/frontend/app/dashboard/components/widget-wrapper.tsx.ejs +4 -0
- package/hedhog/frontend/app/dashboard/dashboard-home-tabs.tsx.ejs +43 -44
- package/hedhog/frontend/app/dashboard/management/tabs/component-roles-tab.tsx.ejs +41 -3
- package/hedhog/frontend/app/dashboard/management/tabs/components-tab.tsx.ejs +42 -2
- package/hedhog/frontend/app/dashboard/management/tabs/dashboard-roles-tab.tsx.ejs +41 -3
- package/hedhog/frontend/app/dashboard/management/tabs/dashboards-tab.tsx.ejs +39 -4
- package/hedhog/frontend/app/dashboard/management/tabs/items-tab.tsx.ejs +42 -3
- package/hedhog/frontend/app/incidents/page.tsx.ejs +60 -31
- package/hedhog/frontend/app/integration/profiles/page.tsx.ejs +45 -5
- package/hedhog/frontend/app/integrations-webhooks/page.tsx.ejs +92 -15
- package/hedhog/frontend/app/mail/log/page.tsx.ejs +109 -61
- package/hedhog/frontend/app/mail/template/page.tsx.ejs +125 -23
- package/hedhog/frontend/app/mcp_chat/chat-components.tsx.ejs +13 -15
- package/hedhog/frontend/app/mcp_chat/page.tsx.ejs +116 -110
- package/hedhog/frontend/app/message-templates/_components/message-template-sheet.tsx.ejs +245 -0
- package/hedhog/frontend/app/message-templates/_lib/types.ts.ejs +24 -0
- package/hedhog/frontend/app/message-templates/page.tsx.ejs +182 -0
- package/hedhog/frontend/app/pages/_components/page-wizard-sheet.tsx.ejs +1 -0
- package/hedhog/frontend/app/pages/page.tsx.ejs +94 -9
- package/hedhog/frontend/app/roles/menus.tsx.ejs +4 -4
- package/hedhog/frontend/app/roles/routes.tsx.ejs +4 -4
- package/hedhog/frontend/app/roles/users.tsx.ejs +4 -4
- package/hedhog/frontend/app/setting-list/page.tsx.ejs +71 -9
- package/hedhog/frontend/app/users/page.tsx.ejs +77 -67
- package/hedhog/frontend/messages/en.json +237 -37
- package/hedhog/frontend/messages/pt.json +237 -37
- package/hedhog/table/cron_lock.yaml +17 -0
- package/hedhog/table/file.yaml +13 -1
- package/hedhog/table/file_upload_chunk.yaml +23 -0
- package/hedhog/table/file_upload_ticket.yaml +67 -0
- package/hedhog/table/mcp_tool_call_log.yaml +30 -22
- package/hedhog/table/message_template.yaml +33 -0
- package/hedhog/table/setting.yaml +8 -0
- package/hedhog/table/user_session.yaml +36 -1
- package/package.json +5 -3
- package/src/ai/ai-agent.sort.ts +21 -0
- package/src/ai/ai-attachment.fragments.spec.ts +56 -3
- package/src/ai/ai.service.responses.spec.ts +429 -0
- package/src/ai/ai.service.spec.ts +173 -1
- package/src/ai/ai.service.ts +473 -220
- package/src/ai-instruction/ai-instruction.service.ts +32 -28
- package/src/ai-instruction/ai-instruction.sort.ts +32 -0
- package/src/ai-instruction/ai-prompt-resolver.service.spec.ts +44 -0
- package/src/ai-instruction/ai-prompt-resolver.service.ts +29 -0
- package/src/auth/auth.module.ts +8 -1
- package/src/auth/auth.service.spec.ts +108 -1
- package/src/auth/auth.service.ts +59 -5
- package/src/auth/guards/auth.guard.ts +9 -1
- package/src/authorize/authorize.controller.ts +126 -11
- package/src/authorize/authorize.errors.ts +55 -0
- package/src/authorize/authorize.module.ts +6 -1
- package/src/authorize/authorize.service.spec.ts +379 -7
- package/src/authorize/authorize.service.ts +309 -23
- package/src/authorize/dto/authorize-info.dto.ts +21 -3
- package/src/authorize/dto/consent.dto.ts +21 -3
- package/src/authorize/dto/token.dto.ts +24 -2
- package/src/authorize/oauth-exception.filter.ts +58 -0
- package/src/authorize/oauth-metadata.service.ts +67 -0
- package/src/authorize/well-known.controller.spec.ts +84 -0
- package/src/authorize/well-known.controller.ts +96 -0
- package/src/captcha/captcha.service.spec.ts +211 -4
- package/src/captcha/captcha.service.ts +127 -10
- package/src/core.module.ts +9 -0
- package/src/dashboard/dashboard-component-role/dashboard-component-role.service.ts +2 -3
- package/src/dashboard/dashboard-component-role/dashboard-component-role.sort.ts +18 -0
- package/src/dashboard/dashboard-item/dashboard-item.service.ts +2 -3
- package/src/dashboard/dashboard-item/dashboard-item.sort.ts +19 -0
- package/src/dashboard/dashboard-role/dashboard-role.service.ts +2 -3
- package/src/dashboard/dashboard-role/dashboard-role.sort.ts +16 -0
- package/src/document-kit/document-kit.module.ts +12 -0
- package/src/document-kit/document-kit.registry.ts +125 -0
- package/src/document-kit/document-kit.service.spec.ts +156 -0
- package/src/document-kit/document-kit.service.ts +173 -0
- package/src/file/file-upload-ticket.service.spec.ts +422 -0
- package/src/file/file-upload-ticket.service.ts +513 -0
- package/src/file/file.controller.ts +65 -0
- package/src/file/file.module.ts +14 -2
- package/src/file/file.service.spec.ts +262 -1
- package/src/file/file.service.ts +505 -87
- package/src/file/filename-encoding.util.spec.ts +54 -0
- package/src/file/filename-encoding.util.ts +67 -0
- package/src/file/image-optimization.service.spec.ts +156 -19
- package/src/file/image-optimization.service.ts +106 -21
- package/src/file/mcp-file-source.schema.ts +86 -0
- package/src/file/mcp-file-source.service.spec.ts +473 -0
- package/src/file/mcp-file-source.service.ts +445 -0
- package/src/file/mimetype-sniff.util.spec.ts +126 -0
- package/src/file/mimetype-sniff.util.ts +265 -0
- package/src/file/remote-fetch.util.spec.ts +117 -0
- package/src/file/remote-fetch.util.ts +330 -0
- package/src/impersonation/dto/start-impersonation.dto.ts +5 -2
- package/src/impersonation/impersonation.service.spec.ts +24 -1
- package/src/impersonation/impersonation.service.ts +14 -4
- package/src/incident/incident.controller.ts +9 -1
- package/src/incident/incident.service.ts +7 -0
- package/src/index.ts +23 -1
- package/src/integration-profile/integration-profile.secrets.ts +28 -0
- package/src/integration-profile/integration-profile.service.ts +7 -64
- package/src/integration-profile/integration-profile.utils.spec.ts +9 -0
- package/src/integration-profile/integration-profile.utils.ts +5 -5
- package/src/integration-profile/testers/ai.testers.ts +70 -5
- package/src/integration-profile/testers/index.ts +2 -0
- package/src/integration-profile/testers/remaining.testers.spec.ts +144 -1
- package/src/integration-profile/testers/shipping.testers.ts +94 -0
- package/src/integration-profile/testers/tester-coverage.spec.ts +10 -0
- package/src/mail/dto/send.dto.ts +6 -1
- package/src/mail/mail-template.spec.ts +58 -1
- package/src/mail/mail.service.spec.ts +112 -0
- package/src/mail/mail.service.ts +42 -4
- package/src/mail-sent/mail-sent.service.ts +3 -0
- package/src/mail-sent/mail-sent.sort.ts +19 -0
- package/src/mcp/filters/mcp-challenge.filter.spec.ts +76 -0
- package/src/mcp/filters/mcp-challenge.filter.ts +70 -0
- package/src/mcp/guards/mcp-auth.guard.spec.ts +51 -2
- package/src/mcp/guards/mcp-auth.guard.ts +24 -1
- package/src/mcp/guards/mcp-permission.guard.spec.ts +109 -15
- package/src/mcp/guards/mcp-permission.guard.ts +76 -51
- package/src/mcp/mcp-audit.service.spec.ts +107 -0
- package/src/mcp/mcp-audit.service.ts +37 -1
- package/src/mcp/mcp-permission.service.spec.ts +197 -0
- package/src/mcp/mcp-permission.service.ts +184 -0
- package/src/mcp/mcp-server.service.spec.ts +84 -2
- package/src/mcp/mcp-server.service.ts +111 -87
- package/src/mcp/mcp.controller.ts +8 -1
- package/src/mcp/mcp.module.ts +7 -1
- package/src/mcp/tools/core-access-log.mcp-tools.ts +66 -0
- package/src/mcp/tools/core-ai.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-dashboard-items.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-dashboard.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-event-webhooks.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-files.mcp-tools.ts +202 -22
- package/src/mcp/tools/core-integration-events.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-mail-sent.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-mail.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-menus.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-notifications.mcp-tools.ts +0 -1
- package/src/mcp/tools/core-roles.mcp-tools.ts +1 -5
- package/src/mcp/tools/core-routes.mcp-tools.ts +1 -3
- package/src/mcp/tools/core-screens.mcp-tools.ts +1 -3
- package/src/mcp/tools/core-sessions.mcp-tools.ts +0 -2
- package/src/mcp/tools/core-settings.mcp-tools.ts +1 -2
- package/src/mcp/tools/core-users.mcp-tools.ts +1 -1
- package/src/mcp/tools/core-webhooks.mcp-tools.ts +1 -2
- package/src/mcp/types/mcp-context.type.ts +15 -6
- package/src/mcp-chat/mcp-chat.service.ts +8 -0
- package/src/meeting/meeting-provider.registry.ts +201 -0
- package/src/meeting/meeting.constants.ts +74 -0
- package/src/menu/menu.service.spec.ts +89 -0
- package/src/menu/menu.service.ts +29 -11
- package/src/message-template/dto/update-message-template.dto.ts +22 -0
- package/src/message-template/message-template-admin.service.spec.ts +163 -0
- package/src/message-template/message-template-admin.service.ts +239 -0
- package/src/message-template/message-template.controller.ts +52 -0
- package/src/message-template/message-template.module.ts +21 -0
- package/src/message-template/message-template.registry.spec.ts +62 -0
- package/src/message-template/message-template.registry.ts +125 -0
- package/src/message-template/message-template.service.spec.ts +149 -0
- package/src/message-template/message-template.service.ts +149 -0
- package/src/notification/notification.constants.ts +10 -0
- package/src/notification/notification.module.ts +3 -0
- package/src/notification/notification.service.spec.ts +75 -1
- package/src/notification/notification.service.ts +39 -1
- package/src/oauth/oauth-token-broker.service.spec.ts +108 -0
- package/src/oauth/oauth-token-broker.service.ts +129 -2
- package/src/oauth/oauth.controller.ts +0 -1
- package/src/oauth/oauth.errors.ts +7 -0
- package/src/oauth/oauth.module.ts +6 -1
- package/src/oauth/oauth.service.spec.ts +58 -7
- package/src/oauth/oauth.service.ts +71 -32
- package/src/oauth/providers/abstract.provider.spec.ts +192 -0
- package/src/oauth/providers/abstract.provider.ts +46 -14
- package/src/oauth/providers/github.provider.ts +57 -34
- package/src/oauth/providers/microsoft-entra-id.provider.spec.ts +133 -0
- package/src/oauth/providers/microsoft-entra-id.provider.ts +37 -3
- package/src/observability/monitored-cron.spec.ts +164 -31
- package/src/observability/monitored-cron.ts +154 -62
- package/src/pdf/document/charts/chart-bar.ts +217 -0
- package/src/pdf/document/charts/chart-donut.ts +163 -0
- package/src/pdf/document/charts/chart-gauge.ts +94 -0
- package/src/pdf/document/charts/chart-line.ts +159 -0
- package/src/pdf/document/charts/chart-primitives.ts +188 -0
- package/src/pdf/document/charts/chart-radar.ts +136 -0
- package/src/pdf/document/charts/chart-scale.spec.ts +93 -0
- package/src/pdf/document/charts/chart-scale.ts +141 -0
- package/src/pdf/document/charts/charts.spec.ts +157 -0
- package/src/pdf/document/charts/index.ts +7 -0
- package/src/pdf/document/index.ts +7 -0
- package/src/pdf/document/pdf-document.chrome.ts +38 -0
- package/src/pdf/document/pdf-document.css.ts +238 -0
- package/src/pdf/document/pdf-document.renderer.spec.ts +129 -0
- package/src/pdf/document/pdf-document.renderer.ts +215 -0
- package/src/pdf/document/pdf-document.service.ts +77 -0
- package/src/pdf/document/pdf-document.theme.ts +146 -0
- package/src/pdf/document/pdf-document.types.ts +97 -0
- package/src/pdf/pdf.module.ts +3 -2
- package/src/pdf/pdf.service.spec.ts +131 -0
- package/src/pdf/pdf.service.ts +245 -82
- package/src/pdf/templates/commercial-proposal.template.spec.ts +177 -0
- package/src/pdf/templates/commercial-proposal.template.ts +400 -0
- package/src/profile/dto/change-password.dto.ts +25 -7
- package/src/profile/profile.service.spec.ts +97 -0
- package/src/profile/profile.service.ts +9 -3
- package/src/realtime/realtime-tick.coalescer.spec.ts +92 -0
- package/src/realtime/realtime-tick.coalescer.ts +60 -0
- package/src/realtime/realtime.service.spec.ts +33 -0
- package/src/realtime/realtime.service.ts +28 -2
- package/src/redis/redis-kv.service.ts +261 -0
- package/src/redis/redis-master.spec.ts +111 -0
- package/src/redis/redis-master.ts +86 -0
- package/src/redis/redis-pubsub.ts +27 -3
- package/src/redis/redis.module.ts +17 -0
- package/src/session/session.service.spec.ts +121 -42
- package/src/session/session.service.ts +279 -82
- package/src/setting/favicon.controller.spec.ts +92 -0
- package/src/setting/favicon.controller.ts +135 -0
- package/src/setting/setting.module.ts +2 -1
- package/src/setting/setting.service.ts +44 -3
- package/src/task/task.service.spec.ts +41 -0
- package/src/task/task.service.ts +53 -13
- package/src/token/token.service.spec.ts +90 -0
- package/src/token/token.service.ts +48 -2
- package/src/user/user-credential.util.ts +14 -5
- package/src/user/user.service.ts +2 -12
- package/src/user/user.sort.ts +25 -0
- package/src/utils/abbreviate-name.spec.ts +50 -0
- package/src/utils/abbreviate-name.ts +44 -0
- package/src/utils/date-range-query.dto.ts +56 -0
- package/src/utils/date-range.spec.ts +175 -0
- package/src/utils/date-range.ts +246 -0
- package/src/webhook-integration/webhook-utils.spec.ts +67 -0
- package/src/webhook-integration/webhook-utils.ts +26 -0
- package/src/whatsapp-sender/whatsapp-recipients.spec.ts +89 -0
- package/src/whatsapp-sender/whatsapp-recipients.ts +83 -0
- package/src/whatsapp-sender/whatsapp-sender.service.spec.ts +185 -0
- package/src/whatsapp-sender/whatsapp-sender.service.ts +90 -7
- package/hedhog/query/device_pairing_request.sql +0 -46
- package/hedhog/query/impersonation_grant.sql +0 -71
- package/hedhog/query/oauth_authorize_pkce.sql +0 -58
- package/hedhog/query/oauth_mobile_state_token.sql +0 -30
- package/hedhog/query/oauth_web_ref_token.sql +0 -25
package/src/ai/ai.service.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
AiPromptResolverService,
|
|
18
18
|
applyGeminiModelParams,
|
|
19
19
|
applyOpenAiModelParams,
|
|
20
|
+
applyOpenAiResponsesParams,
|
|
20
21
|
mergeModelParams,
|
|
21
22
|
type PromptSource,
|
|
22
23
|
} from '../ai-instruction/ai-prompt-resolver.service';
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
DEEPSEEK_DEFAULT_MODEL,
|
|
30
31
|
} from '../integration-profile/integration-profile.utils';
|
|
31
32
|
import { SettingService } from '../setting/setting.service';
|
|
33
|
+
import { AI_AGENT_SORT } from './ai-agent.sort';
|
|
32
34
|
import {
|
|
33
35
|
attachedFileBlock,
|
|
34
36
|
binaryAttachmentMarker,
|
|
@@ -96,6 +98,56 @@ type AiAttachment = {
|
|
|
96
98
|
buffer: Buffer;
|
|
97
99
|
};
|
|
98
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Como o anexo efetivamente chegou ao modelo na última chamada.
|
|
103
|
+
*
|
|
104
|
+
* Sem isso quem chama só consegue adivinhar — foi exatamente o que o extrator
|
|
105
|
+
* de notas fiscais fazia, deduzindo pelo tamanho do texto do PDF, e por isso
|
|
106
|
+
* insistia em reperguntar ao modelo sobre um anexo que ele nunca recebeu.
|
|
107
|
+
* `unreadable-pdf` e `binary` são os dois casos em que o modelo recebeu um
|
|
108
|
+
* marcador no lugar do documento.
|
|
109
|
+
*/
|
|
110
|
+
export type AiAttachmentDelivery =
|
|
111
|
+
| 'none'
|
|
112
|
+
| 'image'
|
|
113
|
+
| 'pdf-document'
|
|
114
|
+
| 'pdf-text'
|
|
115
|
+
| 'text'
|
|
116
|
+
| 'unreadable-pdf'
|
|
117
|
+
| 'binary';
|
|
118
|
+
|
|
119
|
+
/** Anexo que o modelo realmente leu, em vez de um marcador dizendo que não deu. */
|
|
120
|
+
const DELIVERED_TO_MODEL: ReadonlySet<AiAttachmentDelivery> = new Set([
|
|
121
|
+
'image',
|
|
122
|
+
'pdf-document',
|
|
123
|
+
'pdf-text',
|
|
124
|
+
'text',
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
/** Entregas em que o modelo enxergou os pixels da página, não só texto. */
|
|
128
|
+
const DELIVERED_AS_PIXELS: ReadonlySet<AiAttachmentDelivery> = new Set([
|
|
129
|
+
'image',
|
|
130
|
+
'pdf-document',
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
export function isAttachmentDeliveredToModel(
|
|
134
|
+
delivery?: AiAttachmentDelivery | null,
|
|
135
|
+
): boolean {
|
|
136
|
+
return !!delivery && DELIVERED_TO_MODEL.has(delivery);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function isAttachmentDeliveredAsPixels(
|
|
140
|
+
delivery?: AiAttachmentDelivery | null,
|
|
141
|
+
): boolean {
|
|
142
|
+
return !!delivery && DELIVERED_AS_PIXELS.has(delivery);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type AiChatResult = {
|
|
146
|
+
content: string;
|
|
147
|
+
usage?: { input: number; output: number; total: number; cached?: number };
|
|
148
|
+
delivery?: AiAttachmentDelivery;
|
|
149
|
+
};
|
|
150
|
+
|
|
99
151
|
type AiProfileCredentials = {
|
|
100
152
|
apiKey: string;
|
|
101
153
|
organization?: string;
|
|
@@ -104,6 +156,29 @@ type AiProfileCredentials = {
|
|
|
104
156
|
baseUrl?: string;
|
|
105
157
|
};
|
|
106
158
|
|
|
159
|
+
/**
|
|
160
|
+
* O setting de um provider aponta para o perfil de outro provider.
|
|
161
|
+
*
|
|
162
|
+
* Classe própria, e não um `BadRequestException` solto, para uma escada de
|
|
163
|
+
* fallback conseguir parar antes de disparar chamadas que vão dar 4xx com
|
|
164
|
+
* certeza — era o que o extrator de notas fiscais fazia oito vezes por upload,
|
|
165
|
+
* engolindo cada uma delas.
|
|
166
|
+
*/
|
|
167
|
+
export class AiProfileProviderMismatchError extends BadRequestException {
|
|
168
|
+
constructor(
|
|
169
|
+
readonly requestedProvider: string,
|
|
170
|
+
readonly profileSlug: string,
|
|
171
|
+
readonly profileProviderSlug: string,
|
|
172
|
+
readonly settingSlug: string,
|
|
173
|
+
) {
|
|
174
|
+
super(
|
|
175
|
+
`AI profile "${profileSlug}" (setting "${settingSlug}") belongs to provider ` +
|
|
176
|
+
`"${profileProviderSlug}", not "${requestedProvider}". ` +
|
|
177
|
+
`Point Settings → AI → "${settingSlug}" at a ${requestedProvider} profile, or leave it empty.`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
107
182
|
@Injectable()
|
|
108
183
|
export class AiService implements OnModuleInit {
|
|
109
184
|
private readonly logger = new Logger(AiService.name);
|
|
@@ -147,7 +222,7 @@ export class AiService implements OnModuleInit {
|
|
|
147
222
|
const stepStart = Date.now();
|
|
148
223
|
|
|
149
224
|
try {
|
|
150
|
-
const { content, usage } = await this.withTimeout(
|
|
225
|
+
const { content, usage, delivery } = await this.withTimeout(
|
|
151
226
|
this.chatWithProvider(provider, {
|
|
152
227
|
message: data.message,
|
|
153
228
|
model,
|
|
@@ -156,6 +231,7 @@ export class AiService implements OnModuleInit {
|
|
|
156
231
|
apiKey: aiProfile.apiKey,
|
|
157
232
|
baseUrl: aiProfile.baseUrl,
|
|
158
233
|
params,
|
|
234
|
+
timeoutMs,
|
|
159
235
|
}),
|
|
160
236
|
timeoutMs,
|
|
161
237
|
);
|
|
@@ -172,7 +248,12 @@ export class AiService implements OnModuleInit {
|
|
|
172
248
|
});
|
|
173
249
|
await this.aiExecution.finish(executionId, 'completed');
|
|
174
250
|
|
|
175
|
-
return {
|
|
251
|
+
return {
|
|
252
|
+
provider,
|
|
253
|
+
model,
|
|
254
|
+
content,
|
|
255
|
+
attachmentDelivery: delivery ?? 'none',
|
|
256
|
+
};
|
|
176
257
|
} catch (err) {
|
|
177
258
|
await this.aiExecution.finish(executionId, 'failed', String(err));
|
|
178
259
|
throw err;
|
|
@@ -200,6 +281,15 @@ export class AiService implements OnModuleInit {
|
|
|
200
281
|
* sistema. Mesmo padrão que `sendTemplatedMail` já usa para e-mail.
|
|
201
282
|
*/
|
|
202
283
|
profileSlug?: string;
|
|
284
|
+
/**
|
|
285
|
+
* Modelo a usar, no lugar do que o perfil define.
|
|
286
|
+
*
|
|
287
|
+
* Existe para o chamador que tem a própria configuração de modelo — o SAC
|
|
288
|
+
* lê `sac.ai.model` do operador e não tinha por onde entregá-la. Vence a
|
|
289
|
+
* linha de `ai_instruction` e o perfil, na precedência que
|
|
290
|
+
* `mergeModelParams` documenta: argumento explícito primeiro.
|
|
291
|
+
*/
|
|
292
|
+
model?: string;
|
|
203
293
|
params?: AiChatModelParams;
|
|
204
294
|
contextSlug?: string;
|
|
205
295
|
}): Promise<{
|
|
@@ -207,6 +297,14 @@ export class AiService implements OnModuleInit {
|
|
|
207
297
|
model: string;
|
|
208
298
|
content: string;
|
|
209
299
|
promptSources: Record<string, PromptSource>;
|
|
300
|
+
/**
|
|
301
|
+
* Linha de `ai_execution` desta chamada, onde o custo estimado é registrado.
|
|
302
|
+
*
|
|
303
|
+
* `null` quando o registro não pôde ser aberto: `AiExecutionService.start`
|
|
304
|
+
* devolve `0` nesse caso, e quem grava esse id numa coluna própria estaria
|
|
305
|
+
* apontando para uma execução que não existe.
|
|
306
|
+
*/
|
|
307
|
+
executionId: number | null;
|
|
210
308
|
}> {
|
|
211
309
|
const slugs = input.systemPromptSlug
|
|
212
310
|
? [input.systemPromptSlug, input.userPromptSlug]
|
|
@@ -233,7 +331,10 @@ export class AiService implements OnModuleInit {
|
|
|
233
331
|
const provider = target.provider;
|
|
234
332
|
const aiProfile = target.profile;
|
|
235
333
|
const model =
|
|
236
|
-
|
|
334
|
+
input.model?.trim() ||
|
|
335
|
+
stored.model ||
|
|
336
|
+
aiProfile.model ||
|
|
337
|
+
this.getDefaultModel(provider);
|
|
237
338
|
const timeoutMs = aiProfile.timeoutMs ?? DEFAULT_AI_CALL_TIMEOUT_MS;
|
|
238
339
|
|
|
239
340
|
const params: AiChatModelParams = {
|
|
@@ -277,32 +378,44 @@ export class AiService implements OnModuleInit {
|
|
|
277
378
|
Object.entries(resolved).map(([slug, prompt]) => [slug, prompt.source]),
|
|
278
379
|
);
|
|
279
380
|
|
|
280
|
-
|
|
381
|
+
// `executionId || null`: `start` devolve 0 quando não conseguiu abrir a
|
|
382
|
+
// linha, e quem guarda esse id (o SAC, em `ai_execution_id`) ficaria
|
|
383
|
+
// apontando para uma execução inexistente — a coluna não tem FK para
|
|
384
|
+
// barrar isso.
|
|
385
|
+
return { provider, model, content, promptSources, executionId: executionId || null };
|
|
281
386
|
} catch (err) {
|
|
282
387
|
await this.aiExecution.finish(executionId, 'failed', String(err));
|
|
283
388
|
throw err;
|
|
284
389
|
}
|
|
285
390
|
}
|
|
286
391
|
|
|
392
|
+
/**
|
|
393
|
+
* `external_agent_id` nasce nulo: a Assistants API da OpenAI, que devolvia o
|
|
394
|
+
* `asst_...` guardado nessa coluna, foi desligada em 26/08/2026 e todo
|
|
395
|
+
* `POST /v1/assistants` passou a responder 404. As instruções do agente viram
|
|
396
|
+
* system prompt do `chat/completions` em `chatWithAgent`, então elas precisam
|
|
397
|
+
* estar na linha — daí resolver aqui a instrução padrão que antes ia embutida
|
|
398
|
+
* no assistant remoto, em vez de deixar o agente sem prompt nenhum.
|
|
399
|
+
*/
|
|
287
400
|
async createAgent(data: CreateAgentDTO) {
|
|
288
401
|
const slug = data.slug.trim();
|
|
289
402
|
const provider = data.provider || 'openai';
|
|
290
403
|
const model = data.model || this.getDefaultModel(provider);
|
|
291
|
-
const instructions = data.instructions?.trim() || null;
|
|
292
404
|
|
|
293
405
|
const existing = await this.findAgentBySlug(slug);
|
|
294
406
|
if (existing) {
|
|
295
407
|
return existing;
|
|
296
408
|
}
|
|
297
409
|
|
|
298
|
-
let
|
|
410
|
+
let instructions = data.instructions?.trim() || null;
|
|
299
411
|
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
slug,
|
|
303
|
-
|
|
304
|
-
instructions,
|
|
412
|
+
if (!instructions) {
|
|
413
|
+
const defaultInstructions = await this.promptResolver.resolve({
|
|
414
|
+
slug: CORE_AI_PROMPT_SLUGS.agentDefaultInstructions,
|
|
415
|
+
variables: { slug },
|
|
305
416
|
});
|
|
417
|
+
|
|
418
|
+
instructions = defaultInstructions.content;
|
|
306
419
|
}
|
|
307
420
|
|
|
308
421
|
await this.prismaService.$executeRaw`
|
|
@@ -312,7 +425,7 @@ export class AiService implements OnModuleInit {
|
|
|
312
425
|
CAST(${provider} AS ai_agent_provider_7cb93b1143_enum),
|
|
313
426
|
${model},
|
|
314
427
|
${instructions},
|
|
315
|
-
|
|
428
|
+
NULL
|
|
316
429
|
)
|
|
317
430
|
`;
|
|
318
431
|
|
|
@@ -358,29 +471,22 @@ export class AiService implements OnModuleInit {
|
|
|
358
471
|
Math.max(Number(paginationParams?.pageSize || 10), 1),
|
|
359
472
|
100,
|
|
360
473
|
);
|
|
361
|
-
const
|
|
474
|
+
const skip = (page - 1) * pageSize;
|
|
362
475
|
const search = String(paginationParams?.search || '').trim();
|
|
363
476
|
|
|
364
|
-
const
|
|
365
|
-
?
|
|
366
|
-
:
|
|
367
|
-
|
|
368
|
-
const data = await this.prismaService.$queryRaw<AiAgentRecord[]>(Prisma.sql`
|
|
369
|
-
SELECT id, slug, provider, model, instructions, external_agent_id, created_at, updated_at
|
|
370
|
-
FROM ai_agent
|
|
371
|
-
${whereClause}
|
|
372
|
-
ORDER BY id DESC
|
|
373
|
-
LIMIT ${pageSize}
|
|
374
|
-
OFFSET ${offset}
|
|
375
|
-
`);
|
|
376
|
-
|
|
377
|
-
const totalResult = await this.prismaService.$queryRaw<Array<{ total: bigint | number | string }>>(Prisma.sql`
|
|
378
|
-
SELECT COUNT(*) AS total
|
|
379
|
-
FROM ai_agent
|
|
380
|
-
${whereClause}
|
|
381
|
-
`);
|
|
477
|
+
const where: Prisma.ai_agentWhereInput = search
|
|
478
|
+
? { slug: { contains: search, mode: 'insensitive' } }
|
|
479
|
+
: {};
|
|
382
480
|
|
|
383
|
-
const total =
|
|
481
|
+
const [data, total] = await Promise.all([
|
|
482
|
+
this.prismaService.ai_agent.findMany({
|
|
483
|
+
where,
|
|
484
|
+
orderBy: AI_AGENT_SORT.toPrismaOrderBy(paginationParams),
|
|
485
|
+
skip,
|
|
486
|
+
take: pageSize,
|
|
487
|
+
}),
|
|
488
|
+
this.prismaService.ai_agent.count({ where }),
|
|
489
|
+
]);
|
|
384
490
|
|
|
385
491
|
return {
|
|
386
492
|
data,
|
|
@@ -420,25 +526,15 @@ export class AiService implements OnModuleInit {
|
|
|
420
526
|
}
|
|
421
527
|
}
|
|
422
528
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (provider !== 'openai') {
|
|
426
|
-
externalAgentId = null;
|
|
427
|
-
} else if (!externalAgentId) {
|
|
428
|
-
externalAgentId = await this.createOpenAiAssistant({
|
|
429
|
-
slug,
|
|
430
|
-
model,
|
|
431
|
-
instructions,
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
|
|
529
|
+
// Zera o `asst_...` legado: a coluna deixou de ser alimentada quando a
|
|
530
|
+
// Assistants API foi desligada, e valor antigo aqui não tem mais para onde ir.
|
|
435
531
|
await this.prismaService.$executeRaw`
|
|
436
532
|
UPDATE ai_agent
|
|
437
533
|
SET slug = ${slug},
|
|
438
534
|
provider = CAST(${provider} AS ai_agent_provider_7cb93b1143_enum),
|
|
439
535
|
model = ${model},
|
|
440
536
|
instructions = ${instructions},
|
|
441
|
-
external_agent_id =
|
|
537
|
+
external_agent_id = NULL,
|
|
442
538
|
updated_at = NOW()
|
|
443
539
|
WHERE id = ${agentId}
|
|
444
540
|
`;
|
|
@@ -479,36 +575,36 @@ export class AiService implements OnModuleInit {
|
|
|
479
575
|
throw new NotFoundException(`AI agent with slug "${slug}" was not found.`);
|
|
480
576
|
}
|
|
481
577
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
return {
|
|
489
|
-
slug: agent.slug,
|
|
490
|
-
provider: agent.provider,
|
|
491
|
-
model: agent.model,
|
|
492
|
-
content,
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
|
|
578
|
+
// Um único caminho para todo agente, com ou sem anexo: as instruções da
|
|
579
|
+
// linha viram system prompt do provider. Até 26/08/2026 o agente da OpenAI
|
|
580
|
+
// com `external_agent_id` e sem anexo era atendido por thread + run da
|
|
581
|
+
// Assistants API — que a OpenAI desligou, e que já ignorava model e
|
|
582
|
+
// instructions do banco porque só mandava o `assistant_id`.
|
|
496
583
|
const aiProfile = await this.getAiProfile(agent.provider);
|
|
584
|
+
const timeoutMs = aiProfile.timeoutMs ?? DEFAULT_AI_CALL_TIMEOUT_MS;
|
|
497
585
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
586
|
+
// Sem o `withTimeout` este era o único ponto público sem prazo nenhum: uma
|
|
587
|
+
// chamada travada no provider segurava a requisição HTTP de quem chamou
|
|
588
|
+
// indefinidamente.
|
|
589
|
+
const { content, delivery } = await this.withTimeout(
|
|
590
|
+
this.chatWithProvider(agent.provider, {
|
|
591
|
+
message: data.message,
|
|
592
|
+
model: agent.model || this.getDefaultModel(agent.provider),
|
|
593
|
+
systemPrompt: agent.instructions || undefined,
|
|
594
|
+
attachment,
|
|
595
|
+
apiKey: aiProfile.apiKey,
|
|
596
|
+
baseUrl: aiProfile.baseUrl,
|
|
597
|
+
timeoutMs,
|
|
598
|
+
}),
|
|
599
|
+
timeoutMs,
|
|
600
|
+
);
|
|
506
601
|
|
|
507
602
|
return {
|
|
508
603
|
slug: agent.slug,
|
|
509
604
|
provider: agent.provider,
|
|
510
605
|
model: agent.model,
|
|
511
606
|
content,
|
|
607
|
+
attachmentDelivery: delivery ?? 'none',
|
|
512
608
|
};
|
|
513
609
|
}
|
|
514
610
|
|
|
@@ -580,7 +676,7 @@ export class AiService implements OnModuleInit {
|
|
|
580
676
|
sha256: createHash('sha256').update(attachment.buffer).digest('hex'),
|
|
581
677
|
};
|
|
582
678
|
|
|
583
|
-
this.logger.
|
|
679
|
+
this.logger.debug(
|
|
584
680
|
`[AI-ATTACHMENT-DEBUG] fileId=${fileId || 'upload'} filename="${result.filename}" mime=${result.mimeType} mode=${result.mode} bytes=${result.bytes} textLength=${result.textLength}`,
|
|
585
681
|
);
|
|
586
682
|
|
|
@@ -649,8 +745,9 @@ export class AiService implements OnModuleInit {
|
|
|
649
745
|
apiKey?: string;
|
|
650
746
|
baseUrl?: string;
|
|
651
747
|
params?: AiChatModelParams;
|
|
748
|
+
timeoutMs?: number;
|
|
652
749
|
},
|
|
653
|
-
) {
|
|
750
|
+
): Promise<AiChatResult> {
|
|
654
751
|
if (provider === 'gemini') {
|
|
655
752
|
return this.chatWithGemini(input);
|
|
656
753
|
}
|
|
@@ -721,7 +818,49 @@ export class AiService implements OnModuleInit {
|
|
|
721
818
|
);
|
|
722
819
|
}
|
|
723
820
|
|
|
724
|
-
|
|
821
|
+
const loaded = await this.loadAiProfileBySlug(profileSlug);
|
|
822
|
+
const mapped = PROVIDER_BY_INTEGRATION_SLUG[loaded.providerSlug];
|
|
823
|
+
|
|
824
|
+
// `resolveProviderAndProfile` já protegia o caminho do perfil explícito
|
|
825
|
+
// ("pedir openai e apontar um perfil Claude bateria na API errada com a
|
|
826
|
+
// chave errada"); o caminho do setting global ficara de fora. Sem isso, um
|
|
827
|
+
// perfil OpenAI no campo do Gemini fazia o serviço postar a chave da OpenAI
|
|
828
|
+
// no endpoint do Google e engolir o 4xx de cada modelo tentado.
|
|
829
|
+
if (mapped !== provider) {
|
|
830
|
+
this.logger.error(
|
|
831
|
+
`[AI-PROFILE] "${slug}" = "${profileSlug}" é um perfil ${loaded.providerSlug}, ` +
|
|
832
|
+
`mas ${provider} foi pedido.`,
|
|
833
|
+
);
|
|
834
|
+
throw new AiProfileProviderMismatchError(
|
|
835
|
+
provider,
|
|
836
|
+
profileSlug,
|
|
837
|
+
loaded.providerSlug,
|
|
838
|
+
slug,
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return loaded.config;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* "Este provider dá para usar?", sem lançar.
|
|
847
|
+
*
|
|
848
|
+
* Existe para uma escada de fallback perguntar antes de tentar, em vez de
|
|
849
|
+
* gastar uma requisição HTTP por modelo só para descobrir que a credencial
|
|
850
|
+
* nem é daquele provider.
|
|
851
|
+
*/
|
|
852
|
+
async isProviderConfigured(
|
|
853
|
+
provider: AiProvider,
|
|
854
|
+
): Promise<{ ok: boolean; reason?: string }> {
|
|
855
|
+
try {
|
|
856
|
+
await this.getAiProfile(provider);
|
|
857
|
+
return { ok: true };
|
|
858
|
+
} catch (error) {
|
|
859
|
+
return {
|
|
860
|
+
ok: false,
|
|
861
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
862
|
+
};
|
|
863
|
+
}
|
|
725
864
|
}
|
|
726
865
|
|
|
727
866
|
private async loadAiProfileBySlug(profileSlug: string): Promise<{
|
|
@@ -776,6 +915,7 @@ export class AiService implements OnModuleInit {
|
|
|
776
915
|
provider = 'openai',
|
|
777
916
|
baseUrl = 'https://api.openai.com/v1',
|
|
778
917
|
supportsImages = true,
|
|
918
|
+
timeoutMs,
|
|
779
919
|
}: {
|
|
780
920
|
message: string;
|
|
781
921
|
model: string;
|
|
@@ -787,16 +927,44 @@ export class AiService implements OnModuleInit {
|
|
|
787
927
|
provider?: AiProvider;
|
|
788
928
|
baseUrl?: string;
|
|
789
929
|
supportsImages?: boolean;
|
|
790
|
-
|
|
930
|
+
timeoutMs?: number;
|
|
931
|
+
}): Promise<AiChatResult> {
|
|
791
932
|
const openai = apiKey ?? (await this.getAiApiKey(provider));
|
|
792
933
|
|
|
934
|
+
if (this.shouldUseOpenAiResponses({ provider, baseUrl, model, attachment })) {
|
|
935
|
+
try {
|
|
936
|
+
return await this.chatWithOpenAiResponses({
|
|
937
|
+
message,
|
|
938
|
+
model,
|
|
939
|
+
systemPrompt,
|
|
940
|
+
attachment: attachment!,
|
|
941
|
+
apiKey: openai,
|
|
942
|
+
baseUrl,
|
|
943
|
+
params,
|
|
944
|
+
timeoutMs,
|
|
945
|
+
});
|
|
946
|
+
} catch (error) {
|
|
947
|
+
const status = Number((error as any)?.response?.status);
|
|
948
|
+
// 400/404/422 = este modelo ou esta conta não aceita `input_file`;
|
|
949
|
+
// cair para o chat/completions é melhor que falhar. Qualquer outra
|
|
950
|
+
// coisa (401, 429, 5xx, timeout) é falha de verdade e não pode ser
|
|
951
|
+
// mascarada por uma segunda chamada mais fraca, que só reproduziria o
|
|
952
|
+
// marcador de PDF ilegível e devolveria "não achei nada".
|
|
953
|
+
if (![400, 404, 422].includes(status)) throw error;
|
|
954
|
+
this.logger.warn(
|
|
955
|
+
`[AI-RESPONSES] /v1/responses recusou (status=${status}); usando chat/completions. ` +
|
|
956
|
+
`apiError=${(error as any)?.response?.data?.error?.message ?? 'n/a'}`,
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
793
961
|
const messages: Array<any> = [];
|
|
794
962
|
|
|
795
963
|
if (systemPrompt) {
|
|
796
964
|
messages.push({ role: 'system', content: systemPrompt });
|
|
797
965
|
}
|
|
798
966
|
|
|
799
|
-
const userContent = await this.buildOpenAiUserContent(
|
|
967
|
+
const { content: userContent, delivery } = await this.buildOpenAiUserContent(
|
|
800
968
|
message,
|
|
801
969
|
attachment,
|
|
802
970
|
supportsImages,
|
|
@@ -823,10 +991,200 @@ export class AiService implements OnModuleInit {
|
|
|
823
991
|
const u = response.data?.usage;
|
|
824
992
|
return {
|
|
825
993
|
content: response.data?.choices?.[0]?.message?.content || '',
|
|
994
|
+
delivery,
|
|
826
995
|
usage: u ? { input: u.prompt_tokens ?? 0, output: u.completion_tokens ?? 0, total: u.total_tokens ?? 0 } : undefined,
|
|
827
996
|
};
|
|
828
997
|
}
|
|
829
998
|
|
|
999
|
+
/**
|
|
1000
|
+
* Bytes crus de PDF acima disto não vão inline: base64 infla ~1,37x e a
|
|
1001
|
+
* OpenAI limita a requisição a 50 MB.
|
|
1002
|
+
*/
|
|
1003
|
+
private static readonly OPENAI_RESPONSES_MAX_PDF_BYTES = 20 * 1024 * 1024;
|
|
1004
|
+
|
|
1005
|
+
/** Acima disto a conta de tokens das páginas renderizadas deixa de compensar. */
|
|
1006
|
+
private static readonly OPENAI_RESPONSES_MAX_PDF_PAGES = 20;
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Modelos que renderizam as páginas do PDF como imagem na Responses API.
|
|
1010
|
+
*
|
|
1011
|
+
* Um modelo sem visão recebendo `input_file` só recebe a camada de texto de
|
|
1012
|
+
* volta — o mesmo nada do chat/completions, num endpoint diferente. Deixá-lo
|
|
1013
|
+
* no caminho antigo mantém a falha conhecida em vez de criar uma nova.
|
|
1014
|
+
*/
|
|
1015
|
+
private static readonly OPENAI_DOCUMENT_MODEL_RE =
|
|
1016
|
+
/^(gpt-4o|gpt-4\.1|gpt-4-turbo|gpt-5|o3|o4)/i;
|
|
1017
|
+
|
|
1018
|
+
private shouldUseOpenAiResponses(input: {
|
|
1019
|
+
provider: AiProvider;
|
|
1020
|
+
baseUrl: string;
|
|
1021
|
+
model: string;
|
|
1022
|
+
attachment?: AiAttachment | null;
|
|
1023
|
+
}): boolean {
|
|
1024
|
+
// O DeepSeek reusa o formato da OpenAI, mas não tem /v1/responses; e um
|
|
1025
|
+
// gateway apontado por `base_url` pode simplesmente não repassar a rota.
|
|
1026
|
+
if (input.provider !== 'openai') return false;
|
|
1027
|
+
if (!input.baseUrl.startsWith('https://api.openai.com')) return false;
|
|
1028
|
+
if (!input.attachment) return false;
|
|
1029
|
+
// Imagem já funciona pelo bloco de visão do chat/completions.
|
|
1030
|
+
if (!this.isPdfMime(input.attachment.mimeType)) return false;
|
|
1031
|
+
if (
|
|
1032
|
+
input.attachment.buffer.length > AiService.OPENAI_RESPONSES_MAX_PDF_BYTES
|
|
1033
|
+
) {
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
return AiService.OPENAI_DOCUMENT_MODEL_RE.test(input.model);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
private buildOpenAiResponsesBody(input: {
|
|
1040
|
+
message: string;
|
|
1041
|
+
model: string;
|
|
1042
|
+
systemPrompt?: string;
|
|
1043
|
+
attachment: AiAttachment;
|
|
1044
|
+
params?: AiChatModelParams;
|
|
1045
|
+
}): Record<string, unknown> {
|
|
1046
|
+
const base64 = input.attachment.buffer.toString('base64');
|
|
1047
|
+
|
|
1048
|
+
// Arquivo antes da instrução, como no exemplo da própria OpenAI: o modelo
|
|
1049
|
+
// lê o documento antes de saber o que tirar dele.
|
|
1050
|
+
const body: Record<string, unknown> = {
|
|
1051
|
+
input: [
|
|
1052
|
+
{
|
|
1053
|
+
role: 'user',
|
|
1054
|
+
content: [
|
|
1055
|
+
{
|
|
1056
|
+
type: 'input_file',
|
|
1057
|
+
filename: input.attachment.filename,
|
|
1058
|
+
file_data: `data:${input.attachment.mimeType};base64,${base64}`,
|
|
1059
|
+
},
|
|
1060
|
+
{ type: 'input_text', text: input.message },
|
|
1061
|
+
],
|
|
1062
|
+
},
|
|
1063
|
+
],
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
// `instructions` é o equivalente do `messages[0].role === 'system'`.
|
|
1067
|
+
if (input.systemPrompt) body.instructions = input.systemPrompt;
|
|
1068
|
+
|
|
1069
|
+
return applyOpenAiResponsesParams(
|
|
1070
|
+
body,
|
|
1071
|
+
{
|
|
1072
|
+
model: null,
|
|
1073
|
+
temperature: input.params?.temperature ?? null,
|
|
1074
|
+
maxTokens: input.params?.maxTokens ?? null,
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
model: input.model,
|
|
1078
|
+
jsonObject: input.params?.responseFormat === 'json_object',
|
|
1079
|
+
},
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Texto da resposta da Responses API.
|
|
1085
|
+
*
|
|
1086
|
+
* `output_text` é conveniência do SDK — o JSON HTTP cru normalmente não traz.
|
|
1087
|
+
* O texto mora no array `output`, ao lado de itens `reasoning` que não têm
|
|
1088
|
+
* `content` nenhum. Percorrer o array é o caminho real; o atalho pelo
|
|
1089
|
+
* `output_text` só vale para quando o campo por acaso estiver lá.
|
|
1090
|
+
*/
|
|
1091
|
+
private readOpenAiResponsesText(data: any): string {
|
|
1092
|
+
if (typeof data?.output_text === 'string' && data.output_text.trim()) {
|
|
1093
|
+
return data.output_text;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const output: any[] = Array.isArray(data?.output) ? data.output : [];
|
|
1097
|
+
const chunks: string[] = [];
|
|
1098
|
+
|
|
1099
|
+
for (const item of output) {
|
|
1100
|
+
if (item?.type && item.type !== 'message') continue;
|
|
1101
|
+
for (const part of item?.content ?? []) {
|
|
1102
|
+
if (part?.type === 'output_text' && typeof part.text === 'string') {
|
|
1103
|
+
chunks.push(part.text);
|
|
1104
|
+
} else if (part?.type === 'refusal' && typeof part.refusal === 'string') {
|
|
1105
|
+
this.logger.warn(
|
|
1106
|
+
`[AI-RESPONSES] modelo recusou: ${part.refusal.slice(0, 200)}`,
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
return chunks.join('');
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* PDF como documento, via `POST /v1/responses`.
|
|
1117
|
+
*
|
|
1118
|
+
* É o único caminho em que um PDF escaneado chega ao modelo: para modelos com
|
|
1119
|
+
* visão a API extrai o texto e renderiza cada página como imagem. O
|
|
1120
|
+
* chat/completions, mesmo aceitando um content part de PDF, só extrai texto —
|
|
1121
|
+
* não serviria para um scan.
|
|
1122
|
+
*/
|
|
1123
|
+
private async chatWithOpenAiResponses(input: {
|
|
1124
|
+
message: string;
|
|
1125
|
+
model: string;
|
|
1126
|
+
systemPrompt?: string;
|
|
1127
|
+
attachment: AiAttachment;
|
|
1128
|
+
apiKey: string;
|
|
1129
|
+
baseUrl: string;
|
|
1130
|
+
params?: AiChatModelParams;
|
|
1131
|
+
timeoutMs?: number;
|
|
1132
|
+
}): Promise<AiChatResult> {
|
|
1133
|
+
const pages = await this.countPdfPages(input.attachment.buffer);
|
|
1134
|
+
|
|
1135
|
+
if (pages > AiService.OPENAI_RESPONSES_MAX_PDF_PAGES) {
|
|
1136
|
+
this.logger.warn(
|
|
1137
|
+
`[AI-RESPONSES] "${input.attachment.filename}" tem ${pages} páginas ` +
|
|
1138
|
+
`(máx. ${AiService.OPENAI_RESPONSES_MAX_PDF_PAGES}); usando chat/completions.`,
|
|
1139
|
+
);
|
|
1140
|
+
// 422 é o status que o chamador trata como "degrade", e não como falha.
|
|
1141
|
+
throw Object.assign(new Error('PDF acima do limite de páginas'), {
|
|
1142
|
+
response: { status: 422, data: { error: { message: 'too many pages' } } },
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
const response = await axios.post(
|
|
1147
|
+
`${input.baseUrl.replace(/\/+$/, '')}/responses`,
|
|
1148
|
+
this.buildOpenAiResponsesBody(input),
|
|
1149
|
+
{
|
|
1150
|
+
headers: {
|
|
1151
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
1152
|
+
'Content-Type': 'application/json',
|
|
1153
|
+
},
|
|
1154
|
+
// O corpo é o PDF em base64, na casa dos megabytes, e a renderização
|
|
1155
|
+
// das páginas é lenta: com os padrões do axios isso trunca ou trava.
|
|
1156
|
+
timeout: input.timeoutMs ?? DEFAULT_AI_CALL_TIMEOUT_MS,
|
|
1157
|
+
maxBodyLength: Infinity,
|
|
1158
|
+
maxContentLength: Infinity,
|
|
1159
|
+
},
|
|
1160
|
+
);
|
|
1161
|
+
|
|
1162
|
+
if (response.data?.status && response.data.status !== 'completed') {
|
|
1163
|
+
this.logger.warn(
|
|
1164
|
+
`[AI-RESPONSES] status=${response.data.status} ` +
|
|
1165
|
+
`reason=${response.data?.incomplete_details?.reason ?? 'n/a'} ` +
|
|
1166
|
+
`model=${input.model} file="${input.attachment.filename}"`,
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
const u = response.data?.usage;
|
|
1171
|
+
return {
|
|
1172
|
+
content: this.readOpenAiResponsesText(response.data),
|
|
1173
|
+
delivery: 'pdf-document',
|
|
1174
|
+
usage: u
|
|
1175
|
+
? {
|
|
1176
|
+
input: u.input_tokens ?? 0,
|
|
1177
|
+
output: u.output_tokens ?? 0,
|
|
1178
|
+
total:
|
|
1179
|
+
u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0),
|
|
1180
|
+
...(u.input_tokens_details?.cached_tokens
|
|
1181
|
+
? { cached: u.input_tokens_details.cached_tokens }
|
|
1182
|
+
: {}),
|
|
1183
|
+
}
|
|
1184
|
+
: undefined,
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
|
|
830
1188
|
/**
|
|
831
1189
|
* Anthropic (Claude).
|
|
832
1190
|
*
|
|
@@ -851,7 +1209,7 @@ export class AiService implements OnModuleInit {
|
|
|
851
1209
|
systemPrompt?: string;
|
|
852
1210
|
apiKey?: string;
|
|
853
1211
|
params?: AiChatModelParams;
|
|
854
|
-
}): Promise<
|
|
1212
|
+
}): Promise<AiChatResult> {
|
|
855
1213
|
const key = apiKey ?? (await this.getAiApiKey('claude'));
|
|
856
1214
|
|
|
857
1215
|
const body: Record<string, unknown> = {
|
|
@@ -887,138 +1245,6 @@ export class AiService implements OnModuleInit {
|
|
|
887
1245
|
};
|
|
888
1246
|
}
|
|
889
1247
|
|
|
890
|
-
private async createOpenAiAssistant({
|
|
891
|
-
slug,
|
|
892
|
-
model,
|
|
893
|
-
instructions,
|
|
894
|
-
}: {
|
|
895
|
-
slug: string;
|
|
896
|
-
model: string;
|
|
897
|
-
instructions: string | null;
|
|
898
|
-
}): Promise<string> {
|
|
899
|
-
const openai = await this.getAiApiKey('openai');
|
|
900
|
-
|
|
901
|
-
const defaultInstructions = await this.promptResolver.resolve({
|
|
902
|
-
slug: CORE_AI_PROMPT_SLUGS.agentDefaultInstructions,
|
|
903
|
-
variables: { slug },
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
const response = await axios.post(
|
|
907
|
-
'https://api.openai.com/v1/assistants',
|
|
908
|
-
{
|
|
909
|
-
name: slug,
|
|
910
|
-
model,
|
|
911
|
-
instructions: instructions || defaultInstructions.content,
|
|
912
|
-
},
|
|
913
|
-
{
|
|
914
|
-
headers: {
|
|
915
|
-
Authorization: `Bearer ${openai}`,
|
|
916
|
-
'Content-Type': 'application/json',
|
|
917
|
-
'OpenAI-Beta': 'assistants=v2',
|
|
918
|
-
},
|
|
919
|
-
},
|
|
920
|
-
);
|
|
921
|
-
|
|
922
|
-
const assistantId = response.data?.id;
|
|
923
|
-
|
|
924
|
-
if (!assistantId) {
|
|
925
|
-
throw new BadRequestException('OpenAI assistant creation failed.');
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
return assistantId;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
private async chatWithOpenAiAssistant(
|
|
932
|
-
assistantId: string,
|
|
933
|
-
message: string,
|
|
934
|
-
): Promise<string> {
|
|
935
|
-
const openai = await this.getAiApiKey('openai');
|
|
936
|
-
|
|
937
|
-
const threadResponse = await axios.post(
|
|
938
|
-
'https://api.openai.com/v1/threads',
|
|
939
|
-
{
|
|
940
|
-
messages: [{ role: 'user', content: message }],
|
|
941
|
-
},
|
|
942
|
-
{
|
|
943
|
-
headers: {
|
|
944
|
-
Authorization: `Bearer ${openai}`,
|
|
945
|
-
'Content-Type': 'application/json',
|
|
946
|
-
'OpenAI-Beta': 'assistants=v2',
|
|
947
|
-
},
|
|
948
|
-
},
|
|
949
|
-
);
|
|
950
|
-
|
|
951
|
-
const threadId = threadResponse.data?.id;
|
|
952
|
-
|
|
953
|
-
if (!threadId) {
|
|
954
|
-
throw new BadRequestException('OpenAI thread creation failed.');
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
const runResponse = await axios.post(
|
|
958
|
-
`https://api.openai.com/v1/threads/${threadId}/runs`,
|
|
959
|
-
{
|
|
960
|
-
assistant_id: assistantId,
|
|
961
|
-
},
|
|
962
|
-
{
|
|
963
|
-
headers: {
|
|
964
|
-
Authorization: `Bearer ${openai}`,
|
|
965
|
-
'Content-Type': 'application/json',
|
|
966
|
-
'OpenAI-Beta': 'assistants=v2',
|
|
967
|
-
},
|
|
968
|
-
},
|
|
969
|
-
);
|
|
970
|
-
|
|
971
|
-
const runId = runResponse.data?.id;
|
|
972
|
-
|
|
973
|
-
if (!runId) {
|
|
974
|
-
throw new BadRequestException('OpenAI assistant run failed to start.');
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
for (let i = 0; i < 30; i++) {
|
|
978
|
-
const runStatusResponse = await axios.get(
|
|
979
|
-
`https://api.openai.com/v1/threads/${threadId}/runs/${runId}`,
|
|
980
|
-
{
|
|
981
|
-
headers: {
|
|
982
|
-
Authorization: `Bearer ${openai}`,
|
|
983
|
-
'OpenAI-Beta': 'assistants=v2',
|
|
984
|
-
},
|
|
985
|
-
},
|
|
986
|
-
);
|
|
987
|
-
|
|
988
|
-
const status = runStatusResponse.data?.status;
|
|
989
|
-
|
|
990
|
-
if (status === 'completed') {
|
|
991
|
-
break;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
if (['cancelled', 'failed', 'expired'].includes(status)) {
|
|
995
|
-
throw new BadRequestException(
|
|
996
|
-
`OpenAI assistant run did not complete successfully (status: ${status}).`,
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
await this.sleep(1000);
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
const messagesResponse = await axios.get(
|
|
1004
|
-
`https://api.openai.com/v1/threads/${threadId}/messages`,
|
|
1005
|
-
{
|
|
1006
|
-
headers: {
|
|
1007
|
-
Authorization: `Bearer ${openai}`,
|
|
1008
|
-
'OpenAI-Beta': 'assistants=v2',
|
|
1009
|
-
},
|
|
1010
|
-
},
|
|
1011
|
-
);
|
|
1012
|
-
|
|
1013
|
-
const assistantMessage = messagesResponse.data?.data?.find(
|
|
1014
|
-
(item: any) => item.role === 'assistant',
|
|
1015
|
-
);
|
|
1016
|
-
|
|
1017
|
-
const output = assistantMessage?.content?.[0]?.text?.value;
|
|
1018
|
-
|
|
1019
|
-
return output || '';
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
1248
|
private async chatWithGemini({
|
|
1023
1249
|
message,
|
|
1024
1250
|
model,
|
|
@@ -1033,24 +1259,27 @@ export class AiService implements OnModuleInit {
|
|
|
1033
1259
|
attachment?: AiAttachment | null;
|
|
1034
1260
|
apiKey?: string;
|
|
1035
1261
|
params?: AiChatModelParams;
|
|
1036
|
-
}): Promise<
|
|
1262
|
+
}): Promise<AiChatResult> {
|
|
1037
1263
|
const gemini = apiKey ?? (await this.getAiApiKey('gemini'));
|
|
1038
1264
|
|
|
1039
1265
|
const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${gemini}`;
|
|
1040
1266
|
|
|
1041
1267
|
const userParts: any[] = [{ text: message }];
|
|
1268
|
+
let delivery: AiAttachmentDelivery = 'none';
|
|
1042
1269
|
|
|
1043
1270
|
if (attachment) {
|
|
1044
1271
|
if (this.isTextMime(attachment.mimeType)) {
|
|
1045
1272
|
userParts.push({
|
|
1046
1273
|
text: attachedFileBlock(attachment.filename, this.toUtf8Text(attachment.buffer)),
|
|
1047
1274
|
});
|
|
1275
|
+
delivery = 'text';
|
|
1048
1276
|
} else if (this.isPdfMime(attachment.mimeType)) {
|
|
1049
1277
|
const pdfText = await this.extractPdfText(attachment.buffer);
|
|
1050
1278
|
if (pdfText) {
|
|
1051
1279
|
userParts.push({
|
|
1052
1280
|
text: attachedFileBlock(attachment.filename, pdfText),
|
|
1053
1281
|
});
|
|
1282
|
+
delivery = 'pdf-text';
|
|
1054
1283
|
} else {
|
|
1055
1284
|
userParts.push({
|
|
1056
1285
|
inline_data: {
|
|
@@ -1058,6 +1287,7 @@ export class AiService implements OnModuleInit {
|
|
|
1058
1287
|
data: attachment.buffer.toString('base64'),
|
|
1059
1288
|
},
|
|
1060
1289
|
});
|
|
1290
|
+
delivery = 'pdf-document';
|
|
1061
1291
|
}
|
|
1062
1292
|
} else {
|
|
1063
1293
|
userParts.push({
|
|
@@ -1066,6 +1296,7 @@ export class AiService implements OnModuleInit {
|
|
|
1066
1296
|
data: attachment.buffer.toString('base64'),
|
|
1067
1297
|
},
|
|
1068
1298
|
});
|
|
1299
|
+
delivery = this.isImageMime(attachment.mimeType) ? 'image' : 'binary';
|
|
1069
1300
|
}
|
|
1070
1301
|
}
|
|
1071
1302
|
|
|
@@ -1096,14 +1327,11 @@ export class AiService implements OnModuleInit {
|
|
|
1096
1327
|
const u = response.data?.usageMetadata;
|
|
1097
1328
|
return {
|
|
1098
1329
|
content,
|
|
1330
|
+
delivery,
|
|
1099
1331
|
usage: u ? { input: u.promptTokenCount ?? 0, output: u.candidatesTokenCount ?? 0, total: u.totalTokenCount ?? 0 } : undefined,
|
|
1100
1332
|
};
|
|
1101
1333
|
}
|
|
1102
1334
|
|
|
1103
|
-
private async sleep(ms: number) {
|
|
1104
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
1335
|
private async resolveAttachment(
|
|
1108
1336
|
uploadFile?: MulterFile,
|
|
1109
1337
|
fileId?: number,
|
|
@@ -1136,40 +1364,56 @@ export class AiService implements OnModuleInit {
|
|
|
1136
1364
|
return null;
|
|
1137
1365
|
}
|
|
1138
1366
|
|
|
1367
|
+
/**
|
|
1368
|
+
* Conteúdo da mensagem do usuário no chat/completions, mais como o anexo foi
|
|
1369
|
+
* parar lá dentro.
|
|
1370
|
+
*
|
|
1371
|
+
* O `delivery` sai daqui porque é aqui que a decisão acontece: um PDF sem
|
|
1372
|
+
* camada de texto vira o marcador de ilegível, e só este método sabe disso.
|
|
1373
|
+
*/
|
|
1139
1374
|
private async buildOpenAiUserContent(
|
|
1140
1375
|
message: string,
|
|
1141
1376
|
attachment?: AiAttachment | null,
|
|
1142
1377
|
supportsImages = true,
|
|
1143
|
-
) {
|
|
1378
|
+
): Promise<{ content: unknown; delivery: AiAttachmentDelivery }> {
|
|
1144
1379
|
if (!attachment) {
|
|
1145
|
-
return message;
|
|
1380
|
+
return { content: message, delivery: 'none' };
|
|
1146
1381
|
}
|
|
1147
1382
|
|
|
1148
1383
|
if (supportsImages && this.isImageMime(attachment.mimeType)) {
|
|
1149
1384
|
const dataUri = `data:${attachment.mimeType};base64,${attachment.buffer.toString('base64')}`;
|
|
1150
|
-
return
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1385
|
+
return {
|
|
1386
|
+
content: [
|
|
1387
|
+
{ type: 'text', text: message },
|
|
1388
|
+
{ type: 'image_url', image_url: { url: dataUri } },
|
|
1389
|
+
],
|
|
1390
|
+
delivery: 'image',
|
|
1391
|
+
};
|
|
1154
1392
|
}
|
|
1155
1393
|
|
|
1156
1394
|
let text: string;
|
|
1395
|
+
let delivery: AiAttachmentDelivery;
|
|
1157
1396
|
|
|
1158
1397
|
if (this.isTextMime(attachment.mimeType)) {
|
|
1159
1398
|
text = this.toUtf8Text(attachment.buffer);
|
|
1399
|
+
delivery = 'text';
|
|
1160
1400
|
} else if (this.isPdfMime(attachment.mimeType)) {
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1401
|
+
const pdfText = await this.extractPdfText(attachment.buffer);
|
|
1402
|
+
text = pdfText || unreadablePdfMarker(attachment.filename);
|
|
1403
|
+
delivery = pdfText ? 'pdf-text' : 'unreadable-pdf';
|
|
1164
1404
|
} else {
|
|
1165
1405
|
text = binaryAttachmentMarker(
|
|
1166
1406
|
attachment.filename,
|
|
1167
1407
|
attachment.mimeType,
|
|
1168
1408
|
attachment.buffer.length,
|
|
1169
1409
|
);
|
|
1410
|
+
delivery = 'binary';
|
|
1170
1411
|
}
|
|
1171
1412
|
|
|
1172
|
-
return
|
|
1413
|
+
return {
|
|
1414
|
+
content: `${message}${attachedFileBlock(attachment.filename, text)}`,
|
|
1415
|
+
delivery,
|
|
1416
|
+
};
|
|
1173
1417
|
}
|
|
1174
1418
|
|
|
1175
1419
|
private isImageMime(mimeType: string) {
|
|
@@ -1229,6 +1473,15 @@ export class AiService implements OnModuleInit {
|
|
|
1229
1473
|
}
|
|
1230
1474
|
}
|
|
1231
1475
|
|
|
1476
|
+
/** Páginas do PDF, ou 0 quando ele não abre — nesse caso o teto não barra. */
|
|
1477
|
+
private async countPdfPages(buffer: Buffer): Promise<number> {
|
|
1478
|
+
try {
|
|
1479
|
+
return (await pdfParse(buffer))?.numpages ?? 0;
|
|
1480
|
+
} catch {
|
|
1481
|
+
return 0;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1232
1485
|
private toUtf8Text(buffer: Buffer) {
|
|
1233
1486
|
return buffer.toString('utf8');
|
|
1234
1487
|
}
|