@lenne.tech/nest-server 11.25.6 → 11.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/configurable-features.md +2 -0
- package/CLAUDE.md +18 -0
- package/FRAMEWORK-API.md +48 -1
- package/dist/config.env.js +35 -1
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/helpers/config.helper.js +2 -2
- package/dist/core/common/helpers/config.helper.js.map +1 -1
- package/dist/core/common/interceptors/check-security.interceptor.js +9 -2
- package/dist/core/common/interceptors/check-security.interceptor.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +89 -0
- package/dist/core/modules/ai/core-ai-mcp.controller.d.ts +21 -0
- package/dist/core/modules/ai/core-ai-mcp.controller.js +191 -0
- package/dist/core/modules/ai/core-ai-mcp.controller.js.map +1 -0
- package/dist/core/modules/ai/core-ai.controller.d.ts +90 -0
- package/dist/core/modules/ai/core-ai.controller.js +576 -0
- package/dist/core/modules/ai/core-ai.controller.js.map +1 -0
- package/dist/core/modules/ai/core-ai.module.d.ts +43 -0
- package/dist/core/modules/ai/core-ai.module.js +164 -0
- package/dist/core/modules/ai/core-ai.module.js.map +1 -0
- package/dist/core/modules/ai/core-ai.resolver.d.ts +84 -0
- package/dist/core/modules/ai/core-ai.resolver.js +530 -0
- package/dist/core/modules/ai/core-ai.resolver.js.map +1 -0
- package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.d.ts +7 -0
- package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js +16 -0
- package/dist/core/modules/ai/helpers/ai-mcp-oauth.helper.js.map +1 -0
- package/dist/core/modules/ai/hooks/ai-hook.base.d.ts +10 -0
- package/dist/core/modules/ai/hooks/ai-hook.base.js +30 -0
- package/dist/core/modules/ai/hooks/ai-hook.base.js.map +1 -0
- package/dist/core/modules/ai/hooks/ai-hook.registry.d.ts +22 -0
- package/dist/core/modules/ai/hooks/ai-hook.registry.js +98 -0
- package/dist/core/modules/ai/hooks/ai-hook.registry.js.map +1 -0
- package/dist/core/modules/ai/index.d.ts +69 -0
- package/dist/core/modules/ai/index.js +86 -0
- package/dist/core/modules/ai/index.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.d.ts +5 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.js +43 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.d.ts +7 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.js +74 -0
- package/dist/core/modules/ai/inputs/core-ai-budget-limit.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-create.input.d.ts +6 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-create.input.js +49 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.d.ts +6 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.js +60 -0
- package/dist/core/modules/ai/inputs/core-ai-connection-preference.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-connection.input.d.ts +23 -0
- package/dist/core/modules/ai/inputs/core-ai-connection.input.js +229 -0
- package/dist/core/modules/ai/inputs/core-ai-connection.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.d.ts +3 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.js +21 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation.input.d.ts +4 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation.input.js +42 -0
- package/dist/core/modules/ai/inputs/core-ai-conversation.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.d.ts +10 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.js +74 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.d.ts +5 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.js +41 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.d.ts +6 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.js +63 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-hint.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.d.ts +10 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.js +70 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt-update.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt.input.d.ts +18 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt.input.js +131 -0
- package/dist/core/modules/ai/inputs/core-ai-prompt.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-create.input.d.ts +5 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-create.input.js +41 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-create.input.js.map +1 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-update.input.d.ts +9 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-update.input.js +91 -0
- package/dist/core/modules/ai/inputs/core-ai-slot-update.input.js.map +1 -0
- package/dist/core/modules/ai/interfaces/ai-hook.interface.d.ts +28 -0
- package/dist/core/modules/ai/interfaces/ai-hook.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/ai-hook.interface.js.map +1 -0
- package/dist/core/modules/ai/interfaces/ai-placeholder.interface.d.ts +21 -0
- package/dist/core/modules/ai/interfaces/ai-placeholder.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/ai-placeholder.interface.js.map +1 -0
- package/dist/core/modules/ai/interfaces/ai-tool.interface.d.ts +30 -0
- package/dist/core/modules/ai/interfaces/ai-tool.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/ai-tool.interface.js.map +1 -0
- package/dist/core/modules/ai/interfaces/llm-provider.interface.d.ts +55 -0
- package/dist/core/modules/ai/interfaces/llm-provider.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/llm-provider.interface.js.map +1 -0
- package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.d.ts +16 -0
- package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.js +3 -0
- package/dist/core/modules/ai/interfaces/resolved-ai-connection.interface.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-action.model.d.ts +6 -0
- package/dist/core/modules/ai/models/core-ai-action.model.js +44 -0
- package/dist/core/modules/ai/models/core-ai-action.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-available-connection.model.d.ts +8 -0
- package/dist/core/modules/ai/models/core-ai-available-connection.model.js +53 -0
- package/dist/core/modules/ai/models/core-ai-available-connection.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.d.ts +97 -0
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.js +79 -0
- package/dist/core/modules/ai/models/core-ai-budget-limit.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.d.ts +91 -0
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.js +67 -0
- package/dist/core/modules/ai/models/core-ai-connection-preference.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-connection.model.d.ts +200 -0
- package/dist/core/modules/ai/models/core-ai-connection.model.js +263 -0
- package/dist/core/modules/ai/models/core-ai-connection.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +93 -0
- package/dist/core/modules/ai/models/core-ai-conversation.model.js +82 -0
- package/dist/core/modules/ai/models/core-ai-conversation.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-interaction.model.d.ts +133 -0
- package/dist/core/modules/ai/models/core-ai-interaction.model.js +137 -0
- package/dist/core/modules/ai/models/core-ai-interaction.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-message.model.d.ts +5 -0
- package/dist/core/modules/ai/models/core-ai-message.model.js +38 -0
- package/dist/core/modules/ai/models/core-ai-message.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-mode.model.d.ts +109 -0
- package/dist/core/modules/ai/models/core-ai-mode.model.js +100 -0
- package/dist/core/modules/ai/models/core-ai-mode.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.d.ts +103 -0
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js +89 -0
- package/dist/core/modules/ai/models/core-ai-prompt-hint.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-prompt.model.d.ts +122 -0
- package/dist/core/modules/ai/models/core-ai-prompt.model.js +117 -0
- package/dist/core/modules/ai/models/core-ai-prompt.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-response.model.d.ts +29 -0
- package/dist/core/modules/ai/models/core-ai-response.model.js +105 -0
- package/dist/core/modules/ai/models/core-ai-response.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-slot.model.d.ts +121 -0
- package/dist/core/modules/ai/models/core-ai-slot.model.js +119 -0
- package/dist/core/modules/ai/models/core-ai-slot.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.d.ts +103 -0
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.js +88 -0
- package/dist/core/modules/ai/models/core-ai-tool-grant.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.d.ts +122 -0
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.js +121 -0
- package/dist/core/modules/ai/models/core-ai-tool-policy.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-usage-info.model.d.ts +24 -0
- package/dist/core/modules/ai/models/core-ai-usage-info.model.js +127 -0
- package/dist/core/modules/ai/models/core-ai-usage-info.model.js.map +1 -0
- package/dist/core/modules/ai/models/core-ai-usage.model.d.ts +5 -0
- package/dist/core/modules/ai/models/core-ai-usage.model.js +38 -0
- package/dist/core/modules/ai/models/core-ai-usage.model.js.map +1 -0
- package/dist/core/modules/ai/providers/claude-cli.provider.d.ts +16 -0
- package/dist/core/modules/ai/providers/claude-cli.provider.js +151 -0
- package/dist/core/modules/ai/providers/claude-cli.provider.js.map +1 -0
- package/dist/core/modules/ai/providers/llm-provider.factory.d.ts +10 -0
- package/dist/core/modules/ai/providers/llm-provider.factory.js +45 -0
- package/dist/core/modules/ai/providers/llm-provider.factory.js.map +1 -0
- package/dist/core/modules/ai/providers/openai-compatible.provider.d.ts +32 -0
- package/dist/core/modules/ai/providers/openai-compatible.provider.js +236 -0
- package/dist/core/modules/ai/providers/openai-compatible.provider.js.map +1 -0
- package/dist/core/modules/ai/services/ai-crypto.service.d.ts +11 -0
- package/dist/core/modules/ai/services/ai-crypto.service.js +84 -0
- package/dist/core/modules/ai/services/ai-crypto.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-budget.service.d.ts +42 -0
- package/dist/core/modules/ai/services/core-ai-budget.service.js +211 -0
- package/dist/core/modules/ai/services/core-ai-budget.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.d.ts +18 -0
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js +53 -0
- package/dist/core/modules/ai/services/core-ai-connection-preference.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-connection-resolver.service.d.ts +55 -0
- package/dist/core/modules/ai/services/core-ai-connection-resolver.service.js +177 -0
- package/dist/core/modules/ai/services/core-ai-connection-resolver.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-connection.service.d.ts +43 -0
- package/dist/core/modules/ai/services/core-ai-connection.service.js +272 -0
- package/dist/core/modules/ai/services/core-ai-connection.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +26 -0
- package/dist/core/modules/ai/services/core-ai-conversation.service.js +72 -0
- package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-interaction.service.d.ts +13 -0
- package/dist/core/modules/ai/services/core-ai-interaction.service.js +52 -0
- package/dist/core/modules/ai/services/core-ai-interaction.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-mcp-client.service.d.ts +51 -0
- package/dist/core/modules/ai/services/core-ai-mcp-client.service.js +123 -0
- package/dist/core/modules/ai/services/core-ai-mcp-client.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.d.ts +68 -0
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js +279 -0
- package/dist/core/modules/ai/services/core-ai-mcp-oauth.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-mcp.service.d.ts +22 -0
- package/dist/core/modules/ai/services/core-ai-mcp.service.js +59 -0
- package/dist/core/modules/ai/services/core-ai-mcp.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-mode.service.d.ts +14 -0
- package/dist/core/modules/ai/services/core-ai-mode.service.js +56 -0
- package/dist/core/modules/ai/services/core-ai-mode.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-placeholder.registry.d.ts +15 -0
- package/dist/core/modules/ai/services/core-ai-placeholder.registry.js +102 -0
- package/dist/core/modules/ai/services/core-ai-placeholder.registry.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-prompt-builder.service.d.ts +42 -0
- package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js +136 -0
- package/dist/core/modules/ai/services/core-ai-prompt-builder.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.d.ts +29 -0
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js +98 -0
- package/dist/core/modules/ai/services/core-ai-prompt-hint.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-prompt.service.d.ts +21 -0
- package/dist/core/modules/ai/services/core-ai-prompt.service.js +143 -0
- package/dist/core/modules/ai/services/core-ai-prompt.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-slot.service.d.ts +51 -0
- package/dist/core/modules/ai/services/core-ai-slot.service.js +372 -0
- package/dist/core/modules/ai/services/core-ai-slot.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.d.ts +22 -0
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js +97 -0
- package/dist/core/modules/ai/services/core-ai-tool-grant.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.d.ts +23 -0
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js +102 -0
- package/dist/core/modules/ai/services/core-ai-tool-policy.service.js.map +1 -0
- package/dist/core/modules/ai/services/core-ai.service.d.ts +144 -0
- package/dist/core/modules/ai/services/core-ai.service.js +991 -0
- package/dist/core/modules/ai/services/core-ai.service.js.map +1 -0
- package/dist/core/modules/ai/tools/ai-tool.base.d.ts +15 -0
- package/dist/core/modules/ai/tools/ai-tool.base.js +30 -0
- package/dist/core/modules/ai/tools/ai-tool.base.js.map +1 -0
- package/dist/core/modules/ai/tools/ai-tool.registry.d.ts +19 -0
- package/dist/core/modules/ai/tools/ai-tool.registry.js +71 -0
- package/dist/core/modules/ai/tools/ai-tool.registry.js.map +1 -0
- package/dist/core/modules/ai/tools/ask-user-question.tool.d.ts +38 -0
- package/dist/core/modules/ai/tools/ask-user-question.tool.js +65 -0
- package/dist/core/modules/ai/tools/ask-user-question.tool.js.map +1 -0
- package/dist/core/modules/ai/tools/search-tools.tool.d.ts +24 -0
- package/dist/core/modules/ai/tools/search-tools.tool.js +68 -0
- package/dist/core/modules/ai/tools/search-tools.tool.js.map +1 -0
- package/dist/core/modules/error-code/error-codes.d.ts +81 -0
- package/dist/core/modules/error-code/error-codes.js +72 -0
- package/dist/core/modules/error-code/error-codes.js.map +1 -1
- package/dist/core.module.js +8 -0
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/ai/ai-tools.module.d.ts +5 -0
- package/dist/server/modules/ai/ai-tools.module.js +36 -0
- package/dist/server/modules/ai/ai-tools.module.js.map +1 -0
- package/dist/server/modules/ai/tools/delete-user.tool.d.ts +30 -0
- package/dist/server/modules/ai/tools/delete-user.tool.js +49 -0
- package/dist/server/modules/ai/tools/delete-user.tool.js.map +1 -0
- package/dist/server/modules/ai/tools/find-users.tool.d.ts +30 -0
- package/dist/server/modules/ai/tools/find-users.tool.js +52 -0
- package/dist/server/modules/ai/tools/find-users.tool.js.map +1 -0
- package/dist/server/modules/ai/tools/get-user.tool.d.ts +26 -0
- package/dist/server/modules/ai/tools/get-user.tool.js +48 -0
- package/dist/server/modules/ai/tools/get-user.tool.js.map +1 -0
- package/dist/server/modules/ai/tools/update-user-job-title.tool.d.ts +32 -0
- package/dist/server/modules/ai/tools/update-user-job-title.tool.js +54 -0
- package/dist/server/modules/ai/tools/update-user-job-title.tool.js.map +1 -0
- package/dist/server/modules/error-code/error-codes.d.ts +9 -0
- package/dist/server/server.module.js +2 -0
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/docs/REQUEST-LIFECYCLE.md +10 -0
- package/migration-guides/11.25.x-to-11.26.0.md +278 -0
- package/package.json +2 -1
- package/src/config.env.ts +48 -1
- package/src/core/common/helpers/config.helper.ts +5 -2
- package/src/core/common/interceptors/check-security.interceptor.ts +13 -3
- package/src/core/common/interfaces/server-options.interface.ts +312 -0
- package/src/core/modules/ai/INTEGRATION-CHECKLIST.md +220 -0
- package/src/core/modules/ai/README.md +526 -0
- package/src/core/modules/ai/core-ai-mcp.controller.ts +223 -0
- package/src/core/modules/ai/core-ai.controller.ts +547 -0
- package/src/core/modules/ai/core-ai.module.ts +269 -0
- package/src/core/modules/ai/core-ai.resolver.ts +526 -0
- package/src/core/modules/ai/helpers/ai-mcp-oauth.helper.ts +35 -0
- package/src/core/modules/ai/hooks/ai-hook.base.ts +23 -0
- package/src/core/modules/ai/hooks/ai-hook.registry.ts +119 -0
- package/src/core/modules/ai/index.ts +70 -0
- package/src/core/modules/ai/inputs/core-ai-budget-limit-create.input.ts +27 -0
- package/src/core/modules/ai/inputs/core-ai-budget-limit.input.ts +52 -0
- package/src/core/modules/ai/inputs/core-ai-connection-create.input.ts +32 -0
- package/src/core/modules/ai/inputs/core-ai-connection-preference.input.ts +42 -0
- package/src/core/modules/ai/inputs/core-ai-connection.input.ts +235 -0
- package/src/core/modules/ai/inputs/core-ai-conversation-create.input.ts +13 -0
- package/src/core/modules/ai/inputs/core-ai-conversation.input.ts +33 -0
- package/src/core/modules/ai/inputs/core-ai-prompt-create.input.ts +50 -0
- package/src/core/modules/ai/inputs/core-ai-prompt-hint-create.input.ts +26 -0
- package/src/core/modules/ai/inputs/core-ai-prompt-hint.input.ts +43 -0
- package/src/core/modules/ai/inputs/core-ai-prompt-update.input.ts +42 -0
- package/src/core/modules/ai/inputs/core-ai-prompt.input.ts +144 -0
- package/src/core/modules/ai/inputs/core-ai-slot-create.input.ts +26 -0
- package/src/core/modules/ai/inputs/core-ai-slot-update.input.ts +65 -0
- package/src/core/modules/ai/interfaces/ai-hook.interface.ts +74 -0
- package/src/core/modules/ai/interfaces/ai-placeholder.interface.ts +49 -0
- package/src/core/modules/ai/interfaces/ai-tool.interface.ts +112 -0
- package/src/core/modules/ai/interfaces/llm-provider.interface.ts +187 -0
- package/src/core/modules/ai/interfaces/resolved-ai-connection.interface.ts +55 -0
- package/src/core/modules/ai/models/core-ai-action.model.ts +37 -0
- package/src/core/modules/ai/models/core-ai-available-connection.model.ts +42 -0
- package/src/core/modules/ai/models/core-ai-budget-limit.model.ts +82 -0
- package/src/core/modules/ai/models/core-ai-connection-preference.model.ts +72 -0
- package/src/core/modules/ai/models/core-ai-connection.model.ts +330 -0
- package/src/core/modules/ai/models/core-ai-conversation.model.ts +87 -0
- package/src/core/modules/ai/models/core-ai-interaction.model.ts +145 -0
- package/src/core/modules/ai/models/core-ai-message.model.ts +29 -0
- package/src/core/modules/ai/models/core-ai-mode.model.ts +93 -0
- package/src/core/modules/ai/models/core-ai-prompt-hint.model.ts +98 -0
- package/src/core/modules/ai/models/core-ai-prompt.model.ts +120 -0
- package/src/core/modules/ai/models/core-ai-response.model.ts +119 -0
- package/src/core/modules/ai/models/core-ai-slot.model.ts +146 -0
- package/src/core/modules/ai/models/core-ai-tool-grant.model.ts +87 -0
- package/src/core/modules/ai/models/core-ai-tool-policy.model.ts +115 -0
- package/src/core/modules/ai/models/core-ai-usage-info.model.ts +107 -0
- package/src/core/modules/ai/models/core-ai-usage.model.ts +29 -0
- package/src/core/modules/ai/providers/claude-cli.provider.ts +240 -0
- package/src/core/modules/ai/providers/llm-provider.factory.ts +63 -0
- package/src/core/modules/ai/providers/openai-compatible.provider.ts +329 -0
- package/src/core/modules/ai/services/ai-crypto.service.ts +120 -0
- package/src/core/modules/ai/services/core-ai-budget.service.ts +297 -0
- package/src/core/modules/ai/services/core-ai-connection-preference.service.ts +74 -0
- package/src/core/modules/ai/services/core-ai-connection-resolver.service.ts +308 -0
- package/src/core/modules/ai/services/core-ai-connection.service.ts +387 -0
- package/src/core/modules/ai/services/core-ai-conversation.service.ts +105 -0
- package/src/core/modules/ai/services/core-ai-interaction.service.ts +56 -0
- package/src/core/modules/ai/services/core-ai-mcp-client.service.ts +169 -0
- package/src/core/modules/ai/services/core-ai-mcp-oauth.service.ts +445 -0
- package/src/core/modules/ai/services/core-ai-mcp.service.ts +94 -0
- package/src/core/modules/ai/services/core-ai-mode.service.ts +43 -0
- package/src/core/modules/ai/services/core-ai-placeholder.registry.ts +123 -0
- package/src/core/modules/ai/services/core-ai-prompt-builder.service.ts +228 -0
- package/src/core/modules/ai/services/core-ai-prompt-hint.service.ts +133 -0
- package/src/core/modules/ai/services/core-ai-prompt.service.ts +164 -0
- package/src/core/modules/ai/services/core-ai-slot.service.ts +526 -0
- package/src/core/modules/ai/services/core-ai-tool-grant.service.ts +107 -0
- package/src/core/modules/ai/services/core-ai-tool-policy.service.ts +124 -0
- package/src/core/modules/ai/services/core-ai.service.ts +1396 -0
- package/src/core/modules/ai/tools/ai-tool.base.ts +46 -0
- package/src/core/modules/ai/tools/ai-tool.registry.ts +124 -0
- package/src/core/modules/ai/tools/ask-user-question.tool.ts +76 -0
- package/src/core/modules/ai/tools/search-tools.tool.ts +70 -0
- package/src/core/modules/error-code/error-codes.ts +86 -0
- package/src/core.module.ts +12 -0
- package/src/index.ts +6 -0
- package/src/server/modules/ai/ai-tools.module.ts +33 -0
- package/src/server/modules/ai/tools/delete-user.tool.ts +44 -0
- package/src/server/modules/ai/tools/find-users.tool.ts +49 -0
- package/src/server/modules/ai/tools/get-user.tool.ts +43 -0
- package/src/server/modules/ai/tools/update-user-job-title.tool.ts +62 -0
- package/src/server/server.module.ts +5 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { ObjectType } from '@nestjs/graphql';
|
|
2
|
+
import { Prop, Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
3
|
+
import { Document } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator';
|
|
6
|
+
import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
|
|
7
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
8
|
+
import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
|
|
9
|
+
|
|
10
|
+
export type AiConnectionDocument = CoreAiConnection & Document;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Persisted configuration for an LLM connection (provider endpoint + model + key).
|
|
14
|
+
*
|
|
15
|
+
* Connections are the database-backed configuration the user emphasized: admins
|
|
16
|
+
* manage them at runtime (later via a frontend settings area) instead of editing
|
|
17
|
+
* `config.env.ts`. The API key is encrypted at rest ({@link AiCryptoService}) and
|
|
18
|
+
* NEVER returned through the API — only {@link hasApiKey} is exposed.
|
|
19
|
+
*
|
|
20
|
+
* The whole model is restricted to {@link RoleEnum.ADMIN}: only administrators may
|
|
21
|
+
* read or manage connections.
|
|
22
|
+
*/
|
|
23
|
+
@MongooseSchema({ collection: 'aiConnections', timestamps: true })
|
|
24
|
+
@ObjectType({ description: 'AI connection configuration (LLM provider endpoint, model and credentials)' })
|
|
25
|
+
@Restricted(RoleEnum.ADMIN)
|
|
26
|
+
export class CoreAiConnection extends CorePersistenceModel {
|
|
27
|
+
// ===================================================================================================================
|
|
28
|
+
// Properties
|
|
29
|
+
// ===================================================================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* AES-256-GCM-encrypted API key (`iv.tag.ciphertext`).
|
|
33
|
+
*
|
|
34
|
+
* Mongoose-only: NOT a GraphQL field, so it never appears in the GraphQL schema.
|
|
35
|
+
* It is read internally by the service (e.g. {@link CoreAiConnectionService.resolve})
|
|
36
|
+
* and stripped from every HTTP response by two layers: {@link securityCheck}
|
|
37
|
+
* (which also derives {@link hasApiKey}) and the global `secretFields` list
|
|
38
|
+
* (`apiKeyEncrypted` is a registered secret field). It deliberately carries no
|
|
39
|
+
* `@Restricted` so it survives the service `checkRestricted` step long enough for
|
|
40
|
+
* {@link securityCheck} to compute {@link hasApiKey}.
|
|
41
|
+
*/
|
|
42
|
+
@Prop()
|
|
43
|
+
apiKeyEncrypted?: string = undefined;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Name of an environment variable used as API-key fallback when no key is
|
|
47
|
+
* stored in the database (e.g. 'AI_API_KEY').
|
|
48
|
+
*/
|
|
49
|
+
@UnifiedField({
|
|
50
|
+
description: 'Name of the environment variable used as API-key fallback',
|
|
51
|
+
isOptional: true,
|
|
52
|
+
mongoose: true,
|
|
53
|
+
roles: RoleEnum.ADMIN,
|
|
54
|
+
})
|
|
55
|
+
apiKeyEnv?: string = undefined;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Base URL of the OpenAI-compatible endpoint.
|
|
59
|
+
*/
|
|
60
|
+
@UnifiedField({
|
|
61
|
+
description: 'Base URL of the OpenAI-compatible endpoint (e.g. https://llm.example.com/v1)',
|
|
62
|
+
mongoose: true,
|
|
63
|
+
roles: RoleEnum.ADMIN,
|
|
64
|
+
})
|
|
65
|
+
baseUrl: string = undefined;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Free-form capability tags (e.g. 'analysis', 'ocr', 'both') for routing/UI.
|
|
69
|
+
*/
|
|
70
|
+
@UnifiedField({
|
|
71
|
+
description: 'Capability tags of the model (free-form, e.g. analysis, ocr, vision)',
|
|
72
|
+
isArray: true,
|
|
73
|
+
isOptional: true,
|
|
74
|
+
mongoose: [String],
|
|
75
|
+
roles: RoleEnum.ADMIN,
|
|
76
|
+
type: () => String,
|
|
77
|
+
})
|
|
78
|
+
capabilities?: string[] = undefined;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Default maximum number of tokens for completions on this connection.
|
|
82
|
+
*/
|
|
83
|
+
@UnifiedField({
|
|
84
|
+
description: 'Default maximum number of tokens for completions',
|
|
85
|
+
isOptional: true,
|
|
86
|
+
mongoose: true,
|
|
87
|
+
roles: RoleEnum.ADMIN,
|
|
88
|
+
type: () => Number,
|
|
89
|
+
})
|
|
90
|
+
defaultMaxTokens?: number = undefined;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Total context window (input + output tokens) the model supports. Used to budget
|
|
94
|
+
* the assembled messages and trim/condense history when it would overflow. Falls
|
|
95
|
+
* back to `ai.contextWindow` config (default 8192) when unset.
|
|
96
|
+
*/
|
|
97
|
+
@UnifiedField({
|
|
98
|
+
description: 'Total context window (tokens) the model supports; enables context-overflow handling',
|
|
99
|
+
isOptional: true,
|
|
100
|
+
mongoose: true,
|
|
101
|
+
roles: RoleEnum.ADMIN,
|
|
102
|
+
type: () => Number,
|
|
103
|
+
})
|
|
104
|
+
contextWindow?: number = undefined;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Default sampling temperature for completions on this connection.
|
|
108
|
+
*/
|
|
109
|
+
@UnifiedField({
|
|
110
|
+
description: 'Default sampling temperature for completions',
|
|
111
|
+
isOptional: true,
|
|
112
|
+
mongoose: true,
|
|
113
|
+
roles: RoleEnum.ADMIN,
|
|
114
|
+
type: () => Number,
|
|
115
|
+
})
|
|
116
|
+
defaultTemperature?: number = undefined;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Provider-side default token quota per user over the configured
|
|
120
|
+
* {@link defaultUserMaxPeriod}. Used as a soft fallback in the budget
|
|
121
|
+
* summary when no per-user / per-tenant hard limit is configured — the
|
|
122
|
+
* admin pins this per connection based on the provider's known plan
|
|
123
|
+
* (e.g. mittwald 100k tokens/day). Surfaces in the UI's token bar with
|
|
124
|
+
* `scope: 'llm'` and a "kumulativ" label.
|
|
125
|
+
*
|
|
126
|
+
* Zero / undefined disables the fallback for this connection.
|
|
127
|
+
*/
|
|
128
|
+
@UnifiedField({
|
|
129
|
+
description: 'Provider-side soft user quota (tokens / period) used when no hard budget is set',
|
|
130
|
+
isOptional: true,
|
|
131
|
+
mongoose: true,
|
|
132
|
+
roles: RoleEnum.ADMIN,
|
|
133
|
+
type: () => Number,
|
|
134
|
+
})
|
|
135
|
+
defaultUserMaxTokens?: number = undefined;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Aggregation period for {@link defaultUserMaxTokens}. Accepts the same
|
|
139
|
+
* values as `ai.budget.period` (`'day'`, `'month'`, `'none'`). Defaults
|
|
140
|
+
* to the configured `ai.budget.period` (or `'day'`) when unset.
|
|
141
|
+
*/
|
|
142
|
+
@UnifiedField({
|
|
143
|
+
description: 'Period for the provider-side soft user quota (day | month | none)',
|
|
144
|
+
isOptional: true,
|
|
145
|
+
mongoose: true,
|
|
146
|
+
roles: RoleEnum.ADMIN,
|
|
147
|
+
})
|
|
148
|
+
defaultUserMaxPeriod?: string = undefined;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Human-readable description.
|
|
152
|
+
*/
|
|
153
|
+
@UnifiedField({
|
|
154
|
+
description: 'Human-readable description of the connection',
|
|
155
|
+
isOptional: true,
|
|
156
|
+
mongoose: true,
|
|
157
|
+
roles: RoleEnum.ADMIN,
|
|
158
|
+
})
|
|
159
|
+
description?: string = undefined;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Whether the connection is active and may be used.
|
|
163
|
+
*/
|
|
164
|
+
@UnifiedField({
|
|
165
|
+
description: 'Whether the connection is enabled',
|
|
166
|
+
isOptional: true,
|
|
167
|
+
mongoose: { default: true },
|
|
168
|
+
roles: RoleEnum.ADMIN,
|
|
169
|
+
type: () => Boolean,
|
|
170
|
+
})
|
|
171
|
+
enabled?: boolean = undefined;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Admin-enforced globally: when true, this connection is mandated for all tenants
|
|
175
|
+
* and overrides any user/client/tenant selection (resolution layer 6).
|
|
176
|
+
*/
|
|
177
|
+
@UnifiedField({
|
|
178
|
+
description: 'Admin-enforced for all tenants (overrides user/client/tenant selection)',
|
|
179
|
+
isOptional: true,
|
|
180
|
+
mongoose: { default: false },
|
|
181
|
+
roles: RoleEnum.ADMIN,
|
|
182
|
+
type: () => Boolean,
|
|
183
|
+
})
|
|
184
|
+
enforced?: boolean = undefined;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Admin-enforced for specific tenants: this connection is mandated for the listed
|
|
188
|
+
* tenants (resolution layer 7, the most specific admin mandate).
|
|
189
|
+
*/
|
|
190
|
+
@UnifiedField({
|
|
191
|
+
description: 'Tenant ids for which this connection is admin-enforced',
|
|
192
|
+
isArray: true,
|
|
193
|
+
isOptional: true,
|
|
194
|
+
mongoose: [String],
|
|
195
|
+
roles: RoleEnum.ADMIN,
|
|
196
|
+
type: () => String,
|
|
197
|
+
})
|
|
198
|
+
enforcedTenantIds?: string[] = undefined;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Whether an encrypted API key is currently stored. Computed, read-only;
|
|
202
|
+
* the plaintext key is never returned.
|
|
203
|
+
*/
|
|
204
|
+
@UnifiedField({
|
|
205
|
+
description: 'Whether an API key is currently stored (the key itself is never returned)',
|
|
206
|
+
isOptional: true,
|
|
207
|
+
roles: RoleEnum.ADMIN,
|
|
208
|
+
type: () => Boolean,
|
|
209
|
+
})
|
|
210
|
+
hasApiKey?: boolean = undefined;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Whether this is the default connection used when no connection is specified.
|
|
214
|
+
*/
|
|
215
|
+
@UnifiedField({
|
|
216
|
+
description: 'Whether this is the default connection',
|
|
217
|
+
isOptional: true,
|
|
218
|
+
mongoose: { default: false },
|
|
219
|
+
roles: RoleEnum.ADMIN,
|
|
220
|
+
type: () => Boolean,
|
|
221
|
+
})
|
|
222
|
+
isDefault?: boolean = undefined;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Model id sent to the backend (e.g. 'gpt-oss-120b').
|
|
226
|
+
*/
|
|
227
|
+
@UnifiedField({
|
|
228
|
+
description: 'Model id sent to the backend (e.g. gpt-oss-120b)',
|
|
229
|
+
mongoose: true,
|
|
230
|
+
roles: RoleEnum.ADMIN,
|
|
231
|
+
})
|
|
232
|
+
model: string = undefined;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Human-readable connection name.
|
|
236
|
+
*/
|
|
237
|
+
@UnifiedField({
|
|
238
|
+
description: 'Human-readable connection name',
|
|
239
|
+
mongoose: { trim: true },
|
|
240
|
+
roles: RoleEnum.ADMIN,
|
|
241
|
+
})
|
|
242
|
+
name: string = undefined;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Provider implementation key (decides which provider builder is used).
|
|
246
|
+
*/
|
|
247
|
+
@UnifiedField({
|
|
248
|
+
description: 'Provider type (e.g. openai-compatible)',
|
|
249
|
+
isOptional: true,
|
|
250
|
+
mongoose: { default: 'openai-compatible' },
|
|
251
|
+
roles: RoleEnum.ADMIN,
|
|
252
|
+
})
|
|
253
|
+
providerType?: string = undefined;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Whether the backend natively supports JSON / structured-output mode.
|
|
257
|
+
* When false, JSON is requested via the prompt and parsed defensively.
|
|
258
|
+
* Leave UNDEFINED to auto-detect on first use / on save (no mongoose default,
|
|
259
|
+
* so "not set" stays distinguishable from an explicit false).
|
|
260
|
+
*/
|
|
261
|
+
@UnifiedField({
|
|
262
|
+
description: 'Whether the backend supports native JSON/structured-output mode (undefined = auto-detect)',
|
|
263
|
+
isOptional: true,
|
|
264
|
+
mongoose: true,
|
|
265
|
+
roles: RoleEnum.ADMIN,
|
|
266
|
+
type: () => Boolean,
|
|
267
|
+
})
|
|
268
|
+
supportsJsonResponse?: boolean = undefined;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Whether the backend natively supports function/tool calling. When false, tool
|
|
272
|
+
* calling is emulated via the system prompt. Leave UNDEFINED to auto-detect
|
|
273
|
+
* (no mongoose default, so "not set" stays distinguishable from an explicit false).
|
|
274
|
+
*/
|
|
275
|
+
@UnifiedField({
|
|
276
|
+
description: 'Whether the backend supports native function/tool calling (undefined = auto-detect)',
|
|
277
|
+
isOptional: true,
|
|
278
|
+
mongoose: true,
|
|
279
|
+
roles: RoleEnum.ADMIN,
|
|
280
|
+
type: () => Boolean,
|
|
281
|
+
})
|
|
282
|
+
supportsNativeTools?: boolean = undefined;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Whether the model can process images.
|
|
286
|
+
*/
|
|
287
|
+
@UnifiedField({
|
|
288
|
+
description: 'Whether the model supports vision (image input)',
|
|
289
|
+
isOptional: true,
|
|
290
|
+
mongoose: { default: false },
|
|
291
|
+
roles: RoleEnum.ADMIN,
|
|
292
|
+
type: () => Boolean,
|
|
293
|
+
})
|
|
294
|
+
supportsVision?: boolean = undefined;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Tenants this connection is available to. Empty/undefined = available to ALL
|
|
298
|
+
* tenants (the global pool); otherwise restricted to the listed tenants. This is
|
|
299
|
+
* the per-tenant availability restriction of the overall selection.
|
|
300
|
+
*/
|
|
301
|
+
@UnifiedField({
|
|
302
|
+
description: 'Tenant ids this connection is available to (empty = all tenants)',
|
|
303
|
+
isArray: true,
|
|
304
|
+
isOptional: true,
|
|
305
|
+
mongoose: [String],
|
|
306
|
+
roles: RoleEnum.ADMIN,
|
|
307
|
+
type: () => String,
|
|
308
|
+
})
|
|
309
|
+
tenantIds?: string[] = undefined;
|
|
310
|
+
|
|
311
|
+
// ===================================================================================================================
|
|
312
|
+
// Methods
|
|
313
|
+
// ===================================================================================================================
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Compute the non-secret {@link hasApiKey} indicator and strip the encrypted
|
|
317
|
+
* key from every output. Runs via the CheckSecurityInterceptor on responses.
|
|
318
|
+
*/
|
|
319
|
+
override securityCheck(user?: any, force?: boolean) {
|
|
320
|
+
this.hasApiKey = !!this.apiKeyEncrypted;
|
|
321
|
+
this.apiKeyEncrypted = undefined;
|
|
322
|
+
// Access to the whole model is already gated by @Restricted(ADMIN); nothing
|
|
323
|
+
// else to filter here. `force` and `user` are kept for signature symmetry.
|
|
324
|
+
void force;
|
|
325
|
+
void user;
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export const AiConnectionSchema = SchemaFactory.createForClass(CoreAiConnection);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ObjectType } from '@nestjs/graphql';
|
|
2
|
+
import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
3
|
+
import { Document, Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator';
|
|
6
|
+
import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
|
|
7
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
8
|
+
import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
|
|
9
|
+
import { CoreAiMessage } from './core-ai-message.model';
|
|
10
|
+
|
|
11
|
+
export type AiConversationDocument = CoreAiConversation & Document;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A multi-turn AI conversation owned by a user.
|
|
15
|
+
*
|
|
16
|
+
* Messages are stored as a Mongoose Mixed subdocument array and only ever
|
|
17
|
+
* appended via `$push` (never round-tripped through `update()` — see the
|
|
18
|
+
* subdocument-array rule). Ownership is enforced by {@link securityCheck}:
|
|
19
|
+
* only the creator (or an admin) may read a conversation.
|
|
20
|
+
*/
|
|
21
|
+
@MongooseSchema({ collection: 'aiConversations', timestamps: true })
|
|
22
|
+
@ObjectType({ description: 'A multi-turn AI conversation' })
|
|
23
|
+
@Restricted(RoleEnum.S_USER)
|
|
24
|
+
export class CoreAiConversation extends CorePersistenceModel {
|
|
25
|
+
/**
|
|
26
|
+
* Id of the AI connection used for this conversation.
|
|
27
|
+
*/
|
|
28
|
+
@UnifiedField({
|
|
29
|
+
description: 'Id of the AI connection used for this conversation',
|
|
30
|
+
isOptional: true,
|
|
31
|
+
mongoose: true,
|
|
32
|
+
roles: RoleEnum.S_USER,
|
|
33
|
+
})
|
|
34
|
+
connectionId?: string = undefined;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Id of the user who created the conversation.
|
|
38
|
+
*/
|
|
39
|
+
@UnifiedField({
|
|
40
|
+
description: 'Id of the user who created the conversation',
|
|
41
|
+
isOptional: true,
|
|
42
|
+
mongoose: { index: true, ref: 'User', type: Schema.Types.ObjectId },
|
|
43
|
+
roles: RoleEnum.S_USER,
|
|
44
|
+
type: () => String,
|
|
45
|
+
})
|
|
46
|
+
createdBy?: string = undefined;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Conversation messages (appended via $push).
|
|
50
|
+
*/
|
|
51
|
+
@UnifiedField({
|
|
52
|
+
description: 'Conversation messages',
|
|
53
|
+
isArray: true,
|
|
54
|
+
isOptional: true,
|
|
55
|
+
mongoose: { default: [], type: [Schema.Types.Mixed] },
|
|
56
|
+
roles: RoleEnum.S_USER,
|
|
57
|
+
type: () => CoreAiMessage,
|
|
58
|
+
})
|
|
59
|
+
messages?: CoreAiMessage[] = undefined;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Human-readable title.
|
|
63
|
+
*/
|
|
64
|
+
@UnifiedField({
|
|
65
|
+
description: 'Human-readable title',
|
|
66
|
+
isOptional: true,
|
|
67
|
+
mongoose: { trim: true },
|
|
68
|
+
roles: RoleEnum.S_USER,
|
|
69
|
+
})
|
|
70
|
+
title?: string = undefined;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Ownership check: only the creator or an admin may read a conversation.
|
|
74
|
+
*/
|
|
75
|
+
override securityCheck(user?: any, force?: boolean) {
|
|
76
|
+
if (force) {
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
if (user && (user.hasRole?.(RoleEnum.ADMIN) || (this.createdBy && String(this.createdBy) === user.id))) {
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
// Hide conversations owned by other users (filtered out of list responses).
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const AiConversationSchema = SchemaFactory.createForClass(CoreAiConversation);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { ObjectType } from '@nestjs/graphql';
|
|
2
|
+
import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
3
|
+
import { Document, Schema } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator';
|
|
6
|
+
import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
|
|
7
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
8
|
+
import { JSON } from '../../../common/scalars/json.scalar';
|
|
9
|
+
import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
|
|
10
|
+
|
|
11
|
+
export type AiInteractionDocument = CoreAiInteraction & Document;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Audit record of a single AI prompt run.
|
|
15
|
+
*
|
|
16
|
+
* Persisted when `ai.audit` is enabled. Admin-only (compliance/debugging). The
|
|
17
|
+
* per-user history surfaced to end users is the conversation feature, not this log.
|
|
18
|
+
*/
|
|
19
|
+
@MongooseSchema({ collection: 'aiInteractions', timestamps: true })
|
|
20
|
+
@ObjectType({ description: 'Audit record of an AI prompt run' })
|
|
21
|
+
@Restricted(RoleEnum.ADMIN)
|
|
22
|
+
export class CoreAiInteraction extends CorePersistenceModel {
|
|
23
|
+
/**
|
|
24
|
+
* Tool actions executed during the run (name + success).
|
|
25
|
+
*/
|
|
26
|
+
@UnifiedField({
|
|
27
|
+
description: 'Tool actions executed during the run',
|
|
28
|
+
isOptional: true,
|
|
29
|
+
mongoose: { type: Schema.Types.Mixed },
|
|
30
|
+
roles: RoleEnum.ADMIN,
|
|
31
|
+
type: () => JSON,
|
|
32
|
+
})
|
|
33
|
+
actions?: { name: string; success: boolean }[] = undefined;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Number of completion (output) tokens.
|
|
37
|
+
*/
|
|
38
|
+
@UnifiedField({
|
|
39
|
+
description: 'Number of completion tokens',
|
|
40
|
+
isOptional: true,
|
|
41
|
+
mongoose: true,
|
|
42
|
+
roles: RoleEnum.ADMIN,
|
|
43
|
+
type: () => Number,
|
|
44
|
+
})
|
|
45
|
+
completionTokens?: number = undefined;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Id of the AI connection used.
|
|
49
|
+
*/
|
|
50
|
+
@UnifiedField({
|
|
51
|
+
description: 'Id of the AI connection used',
|
|
52
|
+
isOptional: true,
|
|
53
|
+
mongoose: true,
|
|
54
|
+
roles: RoleEnum.ADMIN,
|
|
55
|
+
})
|
|
56
|
+
connectionId?: string = undefined;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Number of agent-loop iterations.
|
|
60
|
+
*/
|
|
61
|
+
@UnifiedField({
|
|
62
|
+
description: 'Number of agent-loop iterations',
|
|
63
|
+
isOptional: true,
|
|
64
|
+
mongoose: true,
|
|
65
|
+
roles: RoleEnum.ADMIN,
|
|
66
|
+
type: () => Number,
|
|
67
|
+
})
|
|
68
|
+
iterations?: number = undefined;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The prompt text.
|
|
72
|
+
*/
|
|
73
|
+
@UnifiedField({
|
|
74
|
+
description: 'The prompt text',
|
|
75
|
+
isOptional: true,
|
|
76
|
+
mongoose: true,
|
|
77
|
+
roles: RoleEnum.ADMIN,
|
|
78
|
+
})
|
|
79
|
+
prompt?: string = undefined;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Number of prompt (input) tokens.
|
|
83
|
+
*/
|
|
84
|
+
@UnifiedField({
|
|
85
|
+
description: 'Number of prompt tokens',
|
|
86
|
+
isOptional: true,
|
|
87
|
+
mongoose: true,
|
|
88
|
+
roles: RoleEnum.ADMIN,
|
|
89
|
+
type: () => Number,
|
|
90
|
+
})
|
|
91
|
+
promptTokens?: number = undefined;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The natural-language answer returned to the user.
|
|
95
|
+
*/
|
|
96
|
+
@UnifiedField({
|
|
97
|
+
description: 'The natural-language answer returned to the user',
|
|
98
|
+
isOptional: true,
|
|
99
|
+
mongoose: true,
|
|
100
|
+
roles: RoleEnum.ADMIN,
|
|
101
|
+
})
|
|
102
|
+
responseText?: string = undefined;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Tenant the prompt ran in (auto-set by the tenant plugin; used for per-tenant
|
|
106
|
+
* budget accounting). No manual index — the tenant plugin indexes `tenantId`.
|
|
107
|
+
*/
|
|
108
|
+
@UnifiedField({
|
|
109
|
+
description: 'Tenant id the prompt ran in',
|
|
110
|
+
isOptional: true,
|
|
111
|
+
mongoose: true,
|
|
112
|
+
roles: RoleEnum.ADMIN,
|
|
113
|
+
})
|
|
114
|
+
tenantId?: string = undefined;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Total number of tokens.
|
|
118
|
+
*/
|
|
119
|
+
@UnifiedField({
|
|
120
|
+
description: 'Total number of tokens',
|
|
121
|
+
isOptional: true,
|
|
122
|
+
mongoose: true,
|
|
123
|
+
roles: RoleEnum.ADMIN,
|
|
124
|
+
type: () => Number,
|
|
125
|
+
})
|
|
126
|
+
totalTokens?: number = undefined;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Id of the user who ran the prompt.
|
|
130
|
+
*/
|
|
131
|
+
@UnifiedField({
|
|
132
|
+
// No single-field index: the compound { userId: 1, createdAt: 1 } below already
|
|
133
|
+
// serves userId-prefix lookups, so a standalone index would be redundant.
|
|
134
|
+
description: 'Id of the user who ran the prompt',
|
|
135
|
+
isOptional: true,
|
|
136
|
+
mongoose: true,
|
|
137
|
+
roles: RoleEnum.ADMIN,
|
|
138
|
+
})
|
|
139
|
+
userId?: string = undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const AiInteractionSchema = SchemaFactory.createForClass(CoreAiInteraction);
|
|
143
|
+
// Compound indexes for the budget period query (userId/tenantId + createdAt range).
|
|
144
|
+
AiInteractionSchema.index({ userId: 1, createdAt: 1 });
|
|
145
|
+
AiInteractionSchema.index({ tenantId: 1, createdAt: 1 });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Field, ObjectType } from '@nestjs/graphql';
|
|
2
|
+
|
|
3
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator';
|
|
4
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A single message in an AI conversation (stored as a Mongoose Mixed subdocument).
|
|
8
|
+
*/
|
|
9
|
+
@ObjectType({ description: 'A message in an AI conversation' })
|
|
10
|
+
@Restricted(RoleEnum.S_EVERYONE)
|
|
11
|
+
export class CoreAiMessage {
|
|
12
|
+
/**
|
|
13
|
+
* Message content.
|
|
14
|
+
*/
|
|
15
|
+
@Field(() => String, { description: 'Message content' })
|
|
16
|
+
content: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creation timestamp.
|
|
20
|
+
*/
|
|
21
|
+
@Field(() => Date, { description: 'Creation timestamp', nullable: true })
|
|
22
|
+
createdAt?: Date;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Author role ('user' or 'assistant').
|
|
26
|
+
*/
|
|
27
|
+
@Field(() => String, { description: "Author role ('user' or 'assistant')" })
|
|
28
|
+
role: string;
|
|
29
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ObjectType } from '@nestjs/graphql';
|
|
2
|
+
import { Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
3
|
+
import { Document } from 'mongoose';
|
|
4
|
+
|
|
5
|
+
import { Restricted } from '../../../common/decorators/restricted.decorator';
|
|
6
|
+
import { UnifiedField } from '../../../common/decorators/unified-field.decorator';
|
|
7
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
8
|
+
import { CorePersistenceModel } from '../../../common/models/core-persistence.model';
|
|
9
|
+
|
|
10
|
+
export type AiModeDocument = CoreAiMode & Document;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Admin-editable **named agent mode** — bundles a curated prompt scope, a
|
|
14
|
+
* restricted tool set, an optional model override, and optional role
|
|
15
|
+
* restrictions under a name like `support`, `audit`, `billing`. Activated by
|
|
16
|
+
* setting `CoreAiPromptInput.mode` to the mode's `name`.
|
|
17
|
+
*
|
|
18
|
+
* Modes are an opinionated, end-user-friendly way for admins to ship
|
|
19
|
+
* domain-specialized assistants without forking the orchestrator. Like every
|
|
20
|
+
* other ai layer, modes can only ADD restrictions; they cannot relax the
|
|
21
|
+
* permission model (`@Restricted` / `@Roles` / `authorize()` still apply).
|
|
22
|
+
*/
|
|
23
|
+
@MongooseSchema({ collection: 'aiModes', timestamps: true })
|
|
24
|
+
@ObjectType({ description: 'Named agent mode' })
|
|
25
|
+
@Restricted(RoleEnum.ADMIN)
|
|
26
|
+
export class CoreAiMode extends CorePersistenceModel {
|
|
27
|
+
/** Restrict the assistant to this whitelist of tool names. Empty = all role-permitted tools. */
|
|
28
|
+
@UnifiedField({
|
|
29
|
+
description: 'Whitelist of tool names available in this mode (empty = all role-permitted tools)',
|
|
30
|
+
isOptional: true,
|
|
31
|
+
mongoose: { default: [] },
|
|
32
|
+
roles: RoleEnum.ADMIN,
|
|
33
|
+
type: () => [String],
|
|
34
|
+
})
|
|
35
|
+
allowedTools?: string[] = undefined;
|
|
36
|
+
|
|
37
|
+
/** Force a specific LLM connection (overrides the resolution chain). */
|
|
38
|
+
@UnifiedField({
|
|
39
|
+
description: 'Force a specific LLM connection id when this mode is active',
|
|
40
|
+
isOptional: true,
|
|
41
|
+
mongoose: true,
|
|
42
|
+
roles: RoleEnum.ADMIN,
|
|
43
|
+
})
|
|
44
|
+
connectionId?: string = undefined;
|
|
45
|
+
|
|
46
|
+
/** Admin-facing description shown in any mode picker. */
|
|
47
|
+
@UnifiedField({
|
|
48
|
+
description: 'Admin-facing description',
|
|
49
|
+
isOptional: true,
|
|
50
|
+
mongoose: true,
|
|
51
|
+
roles: RoleEnum.ADMIN,
|
|
52
|
+
})
|
|
53
|
+
description?: string = undefined;
|
|
54
|
+
|
|
55
|
+
/** Whether the mode is active. */
|
|
56
|
+
@UnifiedField({
|
|
57
|
+
description: 'Whether the mode is enabled',
|
|
58
|
+
isOptional: true,
|
|
59
|
+
mongoose: { default: true },
|
|
60
|
+
roles: RoleEnum.ADMIN,
|
|
61
|
+
type: () => Boolean,
|
|
62
|
+
})
|
|
63
|
+
enabled?: boolean = undefined;
|
|
64
|
+
|
|
65
|
+
/** Unique mode name (used as `input.mode`). */
|
|
66
|
+
@UnifiedField({
|
|
67
|
+
description: 'Unique mode name',
|
|
68
|
+
mongoose: { unique: true },
|
|
69
|
+
roles: RoleEnum.ADMIN,
|
|
70
|
+
})
|
|
71
|
+
name: string = undefined;
|
|
72
|
+
|
|
73
|
+
/** Optional system-prompt override appended to the assembled base prompt. */
|
|
74
|
+
@UnifiedField({
|
|
75
|
+
description: 'Optional system-prompt addendum injected when the mode is active',
|
|
76
|
+
isOptional: true,
|
|
77
|
+
mongoose: true,
|
|
78
|
+
roles: RoleEnum.ADMIN,
|
|
79
|
+
})
|
|
80
|
+
promptAddendum?: string = undefined;
|
|
81
|
+
|
|
82
|
+
/** Restrict mode activation to users who have at least one of these roles. */
|
|
83
|
+
@UnifiedField({
|
|
84
|
+
description: 'Restrict the mode to users with at least one of these roles',
|
|
85
|
+
isOptional: true,
|
|
86
|
+
mongoose: { default: [] },
|
|
87
|
+
roles: RoleEnum.ADMIN,
|
|
88
|
+
type: () => [String],
|
|
89
|
+
})
|
|
90
|
+
roles?: string[] = undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const AiModeSchema = SchemaFactory.createForClass(CoreAiMode);
|