@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,46 @@
|
|
|
1
|
+
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
4
|
+
import { AiToolContext, AiToolResult, IAiTool } from '../interfaces/ai-tool.interface';
|
|
5
|
+
import { AiToolRegistry } from './ai-tool.registry';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Convenience base class for AI tools.
|
|
9
|
+
*
|
|
10
|
+
* Extending {@link AiTool} gives a tool automatic self-registration in the
|
|
11
|
+
* {@link AiToolRegistry} on module init — so a project only needs to declare the
|
|
12
|
+
* class as a provider in its module. Implement {@link name}, {@link description},
|
|
13
|
+
* {@link parameters}, {@link roles} and {@link execute}.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* @Injectable()
|
|
18
|
+
* export class FindUsersAiTool extends AiTool {
|
|
19
|
+
* readonly name = 'find_users';
|
|
20
|
+
* readonly description = 'Search users by email or name.';
|
|
21
|
+
* readonly parameters = { properties: { query: { type: 'string' } }, type: 'object' };
|
|
22
|
+
* readonly roles = [RoleEnum.ADMIN];
|
|
23
|
+
* constructor(registry: AiToolRegistry, private readonly userService: UserService) { super(registry); }
|
|
24
|
+
* async execute(args, context) {
|
|
25
|
+
* return this.userService.find({ filterQuery: { ... } }, context.serviceOptions);
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
@Injectable()
|
|
31
|
+
export abstract class AiTool implements IAiTool, OnModuleInit {
|
|
32
|
+
protected readonly logger = new Logger(this.constructor.name);
|
|
33
|
+
|
|
34
|
+
abstract readonly description: string;
|
|
35
|
+
abstract readonly name: string;
|
|
36
|
+
abstract readonly parameters: Record<string, any>;
|
|
37
|
+
abstract readonly roles: (RoleEnum | string)[];
|
|
38
|
+
|
|
39
|
+
protected constructor(protected readonly registry: AiToolRegistry) {}
|
|
40
|
+
|
|
41
|
+
onModuleInit(): void {
|
|
42
|
+
this.registry.register(this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
abstract execute(args: Record<string, any>, context: AiToolContext): Promise<AiToolResult | unknown>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
4
|
+
import { IAiTool } from '../interfaces/ai-tool.interface';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Minimal shape of the current user needed for tool-visibility checks.
|
|
8
|
+
*/
|
|
9
|
+
export interface AiToolUser {
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
emailVerified?: boolean;
|
|
12
|
+
id?: string;
|
|
13
|
+
roles?: string[];
|
|
14
|
+
verified?: boolean;
|
|
15
|
+
verifiedAt?: Date | string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Central registry of all AI tools — the single source of truth that feeds both
|
|
20
|
+
* the internal agent loop ({@link CoreAiService}) and any external MCP server.
|
|
21
|
+
*
|
|
22
|
+
* The registry is a global singleton service: tools self-register (typically
|
|
23
|
+
* from `onModuleInit`), so projects can add or override tools from ANY module
|
|
24
|
+
* without running into NestJS DI-scope limitations. Registering a tool whose
|
|
25
|
+
* name already exists overrides the previous one (last write wins) — this is the
|
|
26
|
+
* supported override mechanism for projects customizing core tools.
|
|
27
|
+
*/
|
|
28
|
+
@Injectable()
|
|
29
|
+
export class AiToolRegistry {
|
|
30
|
+
private readonly logger = new Logger(AiToolRegistry.name);
|
|
31
|
+
private readonly tools = new Map<string, IAiTool>();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Register (or override) a tool by its name.
|
|
35
|
+
*/
|
|
36
|
+
register(tool: IAiTool): void {
|
|
37
|
+
if (this.tools.has(tool.name)) {
|
|
38
|
+
this.logger.warn(`AI tool "${tool.name}" is being overridden.`);
|
|
39
|
+
}
|
|
40
|
+
this.tools.set(tool.name, tool);
|
|
41
|
+
this.logger.debug(`Registered AI tool: ${tool.name}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Remove a tool from the registry.
|
|
46
|
+
*/
|
|
47
|
+
unregister(name: string): void {
|
|
48
|
+
this.tools.delete(name);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get a tool by name.
|
|
53
|
+
*/
|
|
54
|
+
get(name: string): IAiTool | undefined {
|
|
55
|
+
return this.tools.get(name);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* All registered tools (unfiltered).
|
|
60
|
+
*/
|
|
61
|
+
all(): IAiTool[] {
|
|
62
|
+
return [...this.tools.values()];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Tools the given user is allowed to see and use.
|
|
67
|
+
*
|
|
68
|
+
* This is a first-line visibility filter (defense in depth) — the authoritative
|
|
69
|
+
* authorization happens when a tool's `execute()` routes through a CrudService
|
|
70
|
+
* with the user's serviceOptions.
|
|
71
|
+
*/
|
|
72
|
+
forUser(user: AiToolUser | null | undefined): IAiTool[] {
|
|
73
|
+
return this.all().filter((tool) => this.userCanAccess(tool, user));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Whether a user satisfies a tool's role requirements.
|
|
78
|
+
*/
|
|
79
|
+
userCanAccess(tool: IAiTool, user: AiToolUser | null | undefined): boolean {
|
|
80
|
+
const roles = tool.roles ?? [];
|
|
81
|
+
|
|
82
|
+
// Locked tools are never accessible.
|
|
83
|
+
if (roles.includes(RoleEnum.S_NO_ONE)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Public tools are always accessible.
|
|
88
|
+
if (roles.includes(RoleEnum.S_EVERYONE)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Everything below requires an authenticated user.
|
|
93
|
+
if (!user?.id) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Admin bypass.
|
|
98
|
+
if (user.roles?.includes(RoleEnum.ADMIN)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Any authenticated user.
|
|
103
|
+
if (roles.includes(RoleEnum.S_USER)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Verified users.
|
|
108
|
+
if (roles.includes(RoleEnum.S_VERIFIED) && (user.verified || user.verifiedAt || user.emailVerified)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Real roles: user must hold at least one of the required roles.
|
|
113
|
+
const systemRoles: string[] = [
|
|
114
|
+
RoleEnum.S_CREATOR,
|
|
115
|
+
RoleEnum.S_EVERYONE,
|
|
116
|
+
RoleEnum.S_NO_ONE,
|
|
117
|
+
RoleEnum.S_SELF,
|
|
118
|
+
RoleEnum.S_USER,
|
|
119
|
+
RoleEnum.S_VERIFIED,
|
|
120
|
+
];
|
|
121
|
+
const requiredRealRoles = roles.filter((r) => !systemRoles.includes(r));
|
|
122
|
+
return requiredRealRoles.some((r) => user.roles?.includes(r));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
4
|
+
import { AiToolContext, AiToolResult } from '../interfaces/ai-tool.interface';
|
|
5
|
+
import { AiTool } from './ai-tool.base';
|
|
6
|
+
import { AiToolRegistry } from './ai-tool.registry';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Sentinel marker the orchestrator detects to short-circuit the loop with a
|
|
10
|
+
* `pendingQuestion`. Tools never set this directly — only this built-in does.
|
|
11
|
+
*/
|
|
12
|
+
export const ASK_USER_QUESTION_SENTINEL = Symbol.for('@lenne.tech/nest-server/ai/ask-user-question');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Built-in tool the model can call to pause the run and ask the end user for a
|
|
16
|
+
* clarification (e.g. "did you mean A, B or C?") instead of guessing — important
|
|
17
|
+
* because our target users are NOT prompt experts: a focused question often beats
|
|
18
|
+
* a wrong action. The tool does not perform an action; the orchestrator detects the
|
|
19
|
+
* sentinel return shape, breaks the loop, and surfaces the question on `CoreAiResponse.pendingQuestion`.
|
|
20
|
+
*
|
|
21
|
+
* After answering, the client sends the user's answer as the next prompt — no
|
|
22
|
+
* special "answer" field is needed; the conversation continues naturally.
|
|
23
|
+
*
|
|
24
|
+
* Roles: `S_USER` (anyone can be asked). Not `mutating`/`destructive` (it is a
|
|
25
|
+
* read-only interaction surface).
|
|
26
|
+
*/
|
|
27
|
+
@Injectable()
|
|
28
|
+
export class AskUserQuestionAiTool extends AiTool {
|
|
29
|
+
readonly description =
|
|
30
|
+
'Ask the end user a clarifying question before acting. Use ONLY when you genuinely cannot proceed without more information from the user; otherwise prefer using a tool to find the answer.';
|
|
31
|
+
readonly name = 'ask_user_question';
|
|
32
|
+
readonly parameters = {
|
|
33
|
+
properties: {
|
|
34
|
+
options: {
|
|
35
|
+
description: 'Optional list of suggested answers ({label, value}) for a multiple-choice question.',
|
|
36
|
+
items: {
|
|
37
|
+
properties: {
|
|
38
|
+
label: { type: 'string' },
|
|
39
|
+
value: { type: 'string' },
|
|
40
|
+
},
|
|
41
|
+
required: ['label', 'value'],
|
|
42
|
+
type: 'object',
|
|
43
|
+
},
|
|
44
|
+
type: 'array',
|
|
45
|
+
},
|
|
46
|
+
question: { description: 'The clarifying question to ask the user, in their language.', type: 'string' },
|
|
47
|
+
},
|
|
48
|
+
required: ['question'],
|
|
49
|
+
type: 'object',
|
|
50
|
+
};
|
|
51
|
+
readonly roles = [RoleEnum.S_USER];
|
|
52
|
+
|
|
53
|
+
// Re-declares the constructor publicly so NestJS DI can instantiate this provider
|
|
54
|
+
// (AiTool's constructor is `protected`).
|
|
55
|
+
// eslint-disable-next-line no-useless-constructor
|
|
56
|
+
constructor(registry: AiToolRegistry) {
|
|
57
|
+
super(registry);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
61
|
+
async execute(args: Record<string, any>, _context: AiToolContext): Promise<AiToolResult> {
|
|
62
|
+
const question = typeof args?.question === 'string' ? args.question.trim() : '';
|
|
63
|
+
if (!question) {
|
|
64
|
+
return { message: 'question is required.', success: false };
|
|
65
|
+
}
|
|
66
|
+
const options = Array.isArray(args?.options)
|
|
67
|
+
? args.options
|
|
68
|
+
.filter((o: any) => o && typeof o.value === 'string' && typeof o.label === 'string')
|
|
69
|
+
.map((o: any) => ({ label: o.label, value: o.value }))
|
|
70
|
+
: undefined;
|
|
71
|
+
return {
|
|
72
|
+
data: { [ASK_USER_QUESTION_SENTINEL as unknown as string]: true, options, question },
|
|
73
|
+
success: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { RoleEnum } from '../../../common/enums/role.enum';
|
|
4
|
+
import { AiToolContext, AiToolResult } from '../interfaces/ai-tool.interface';
|
|
5
|
+
import { AiTool } from './ai-tool.base';
|
|
6
|
+
import { AiToolRegistry } from './ai-tool.registry';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Built-in **meta-tool** for the "deferred tool-schemas" mode
|
|
10
|
+
* (`ai.deferToolSchemas: true`): the system prompt then contains only the tool
|
|
11
|
+
* NAMES + short descriptions, not the full JSON-Schemas — which can drastically
|
|
12
|
+
* cut the context cost when many tools are registered. The LLM uses this tool to
|
|
13
|
+
* fetch the parameter schema for a specific tool BEFORE calling it.
|
|
14
|
+
*
|
|
15
|
+
* The result respects the caller's role visibility — only tools the user can use
|
|
16
|
+
* are returned (defense in depth on top of the orchestrator's role filter).
|
|
17
|
+
*/
|
|
18
|
+
@Injectable()
|
|
19
|
+
export class SearchToolsAiTool extends AiTool {
|
|
20
|
+
readonly description =
|
|
21
|
+
'Search the available backend tools and fetch the parameter schema of a specific tool. Use this before calling a tool whose parameter schema you have not yet seen.';
|
|
22
|
+
readonly name = 'search_tools';
|
|
23
|
+
readonly parameters = {
|
|
24
|
+
properties: {
|
|
25
|
+
name: { description: 'The exact tool name to fetch the full schema for.', type: 'string' },
|
|
26
|
+
query: {
|
|
27
|
+
description: 'Optional substring matched against tool name and description (returns a short list).',
|
|
28
|
+
type: 'string',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
type: 'object',
|
|
32
|
+
};
|
|
33
|
+
readonly roles = [RoleEnum.S_USER];
|
|
34
|
+
|
|
35
|
+
// Re-declares the constructor publicly so NestJS DI can instantiate this provider
|
|
36
|
+
// (AiTool's constructor is `protected`).
|
|
37
|
+
// eslint-disable-next-line no-useless-constructor
|
|
38
|
+
constructor(registry: AiToolRegistry) {
|
|
39
|
+
super(registry);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async execute(args: Record<string, any>, context: AiToolContext): Promise<AiToolResult> {
|
|
43
|
+
const allowed = this.registry.forUser(context.currentUser);
|
|
44
|
+
const query = typeof args?.query === 'string' ? args.query.trim().toLowerCase() : '';
|
|
45
|
+
const name = typeof args?.name === 'string' ? args.name.trim() : '';
|
|
46
|
+
if (name) {
|
|
47
|
+
const tool = allowed.find((t) => t.name === name);
|
|
48
|
+
if (!tool) {
|
|
49
|
+
return { message: `Tool "${name}" is not available to you.`, success: false };
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
data: {
|
|
53
|
+
description: tool.description,
|
|
54
|
+
mutating: !!tool.mutating,
|
|
55
|
+
destructive: !!tool.destructive,
|
|
56
|
+
name: tool.name,
|
|
57
|
+
parameters: tool.parameters,
|
|
58
|
+
},
|
|
59
|
+
success: true,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const matches = query
|
|
63
|
+
? allowed.filter((t) => t.name.toLowerCase().includes(query) || t.description.toLowerCase().includes(query))
|
|
64
|
+
: allowed;
|
|
65
|
+
return {
|
|
66
|
+
data: matches.map((t) => ({ description: t.description, name: t.name })),
|
|
67
|
+
success: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* - LTNS_0300-LTNS_0399: Validation errors
|
|
22
22
|
* - LTNS_0400-LTNS_0499: Resource errors
|
|
23
23
|
* - LTNS_0500-LTNS_0599: File errors
|
|
24
|
+
* - LTNS_0600-LTNS_0699: AI errors
|
|
24
25
|
* - LTNS_0900-LTNS_0999: Internal errors
|
|
25
26
|
*
|
|
26
27
|
* @example
|
|
@@ -493,6 +494,91 @@ export const LtnsErrors = {
|
|
|
493
494
|
en: 'System setup requires BetterAuth.',
|
|
494
495
|
},
|
|
495
496
|
},
|
|
497
|
+
|
|
498
|
+
// =====================================================
|
|
499
|
+
// AI Errors (LTNS_0600-LTNS_0699)
|
|
500
|
+
// =====================================================
|
|
501
|
+
|
|
502
|
+
AI_NO_CONNECTION: {
|
|
503
|
+
code: 'LTNS_0600',
|
|
504
|
+
message: 'No usable AI connection configured',
|
|
505
|
+
translations: {
|
|
506
|
+
de: 'Es ist keine nutzbare KI-Verbindung konfiguriert.',
|
|
507
|
+
en: 'No usable AI connection is configured.',
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
|
|
511
|
+
AI_CONNECTION_DISABLED: {
|
|
512
|
+
code: 'LTNS_0601',
|
|
513
|
+
message: 'AI connection is disabled',
|
|
514
|
+
translations: {
|
|
515
|
+
de: 'Die KI-Verbindung ist deaktiviert.',
|
|
516
|
+
en: 'The AI connection is disabled.',
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
|
|
520
|
+
AI_CONNECTION_NOT_AVAILABLE: {
|
|
521
|
+
code: 'LTNS_0602',
|
|
522
|
+
message: 'The selected AI connection is not available',
|
|
523
|
+
translations: {
|
|
524
|
+
de: 'Die ausgewählte KI-Verbindung ist nicht verfügbar.',
|
|
525
|
+
en: 'The selected AI connection is not available.',
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
|
|
529
|
+
AI_CONNECTION_NOT_FOUND: {
|
|
530
|
+
code: 'LTNS_0603',
|
|
531
|
+
message: 'AI connection does not exist or is not usable',
|
|
532
|
+
translations: {
|
|
533
|
+
de: 'Die KI-Verbindung existiert nicht oder ist nicht nutzbar.',
|
|
534
|
+
en: 'The AI connection does not exist or is not usable.',
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
|
|
538
|
+
AI_PREFERENCES_UNAVAILABLE: {
|
|
539
|
+
code: 'LTNS_0604',
|
|
540
|
+
message: 'AI connection preferences are not available',
|
|
541
|
+
translations: {
|
|
542
|
+
de: 'KI-Verbindungseinstellungen sind nicht verfügbar.',
|
|
543
|
+
en: 'AI connection preferences are not available.',
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
AI_BUDGET_EXCEEDED: {
|
|
548
|
+
code: 'LTNS_0605',
|
|
549
|
+
message: 'AI token budget for this period is exhausted',
|
|
550
|
+
translations: {
|
|
551
|
+
de: 'Dein KI-Token-Kontingent für diesen Zeitraum ist aufgebraucht. Bitte versuche es nach dem nächsten Reset erneut.',
|
|
552
|
+
en: 'Your AI token budget for this period is exhausted. Please try again after the next reset.',
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
AI_RATE_LIMITED: {
|
|
557
|
+
code: 'LTNS_0606',
|
|
558
|
+
message: 'Too many AI requests',
|
|
559
|
+
translations: {
|
|
560
|
+
de: 'Zu viele KI-Anfragen. Bitte etwas langsamer.',
|
|
561
|
+
en: 'Too many AI requests, please slow down.',
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
|
|
565
|
+
AI_PROVIDER_ERROR: {
|
|
566
|
+
code: 'LTNS_0607',
|
|
567
|
+
message: 'The AI provider request failed',
|
|
568
|
+
translations: {
|
|
569
|
+
de: 'Die Anfrage an den KI-Anbieter ist fehlgeschlagen.',
|
|
570
|
+
en: 'The AI provider request failed.',
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
|
|
574
|
+
AI_CONNECTION_INVALID_URL: {
|
|
575
|
+
code: 'LTNS_0608',
|
|
576
|
+
message: 'AI connection has no valid base URL',
|
|
577
|
+
translations: {
|
|
578
|
+
de: 'Die KI-Verbindung hat keine gültige Basis-URL.',
|
|
579
|
+
en: 'The AI connection has no valid base URL.',
|
|
580
|
+
},
|
|
581
|
+
},
|
|
496
582
|
} as const satisfies IErrorRegistry;
|
|
497
583
|
|
|
498
584
|
// =====================================================
|
package/src/core.module.ts
CHANGED
|
@@ -37,6 +37,7 @@ import { EmailService } from './core/common/services/email.service';
|
|
|
37
37
|
import { MailjetService } from './core/common/services/mailjet.service';
|
|
38
38
|
import { ModelDocService } from './core/common/services/model-doc.service';
|
|
39
39
|
import { TemplateService } from './core/common/services/template.service';
|
|
40
|
+
import { CoreAiModule } from './core/modules/ai/core-ai.module';
|
|
40
41
|
import { CoreBetterAuthUserMapper } from './core/modules/better-auth/core-better-auth-user.mapper';
|
|
41
42
|
import { CoreBetterAuthModule } from './core/modules/better-auth/core-better-auth.module';
|
|
42
43
|
import { CoreBetterAuthService } from './core/modules/better-auth/core-better-auth.service';
|
|
@@ -443,6 +444,17 @@ export class CoreModule implements NestModule {
|
|
|
443
444
|
imports.push(CoreSystemSetupModule);
|
|
444
445
|
}
|
|
445
446
|
|
|
447
|
+
// Add CoreAiModule when an `ai` config block is present (presence implies enabled)
|
|
448
|
+
const aiConfig = config.ai;
|
|
449
|
+
const isAiEnabled =
|
|
450
|
+
aiConfig === true || (typeof aiConfig === 'object' && aiConfig !== null && aiConfig.enabled !== false);
|
|
451
|
+
if (isAiEnabled) {
|
|
452
|
+
const aiObj = typeof aiConfig === 'object' && aiConfig !== null ? aiConfig : undefined;
|
|
453
|
+
const mcpEnabled =
|
|
454
|
+
aiObj?.mcp === true || (typeof aiObj?.mcp === 'object' && aiObj.mcp !== null && aiObj.mcp.enabled !== false);
|
|
455
|
+
imports.push(CoreAiModule.forRoot({ ...overrides?.ai, mcpEnabled }));
|
|
456
|
+
}
|
|
457
|
+
|
|
446
458
|
// Add CoreTenantModule when multiTenancy is configured (presence implies enabled)
|
|
447
459
|
if (config.multiTenancy && config.multiTenancy.enabled !== false) {
|
|
448
460
|
// Auto-add TenantMember to excludeSchemas (membership is tenant-spanning)
|
package/src/index.ts
CHANGED
|
@@ -140,6 +140,12 @@ export * from './core/modules/auth/strategies/jwt-refresh.strategy';
|
|
|
140
140
|
export * from './core/modules/auth/strategies/jwt.strategy';
|
|
141
141
|
export * from './core/modules/auth/tokens.decorator';
|
|
142
142
|
|
|
143
|
+
// =====================================================================================================================
|
|
144
|
+
// Core - Modules - AI
|
|
145
|
+
// =====================================================================================================================
|
|
146
|
+
|
|
147
|
+
export * from './core/modules/ai';
|
|
148
|
+
|
|
143
149
|
// =====================================================================================================================
|
|
144
150
|
// Core - Modules - BetterAuth
|
|
145
151
|
// =====================================================================================================================
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { ClaudeCliProvider } from '../../../core/modules/ai/providers/claude-cli.provider';
|
|
4
|
+
import { LlmProviderFactory } from '../../../core/modules/ai/providers/llm-provider.factory';
|
|
5
|
+
import { UserModule } from '../user/user.module';
|
|
6
|
+
import { DeleteUserAiTool } from './tools/delete-user.tool';
|
|
7
|
+
import { FindUsersAiTool } from './tools/find-users.tool';
|
|
8
|
+
import { GetUserAiTool } from './tools/get-user.tool';
|
|
9
|
+
import { UpdateUserJobTitleAiTool } from './tools/update-user-job-title.tool';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Registers the example AI tools.
|
|
13
|
+
*
|
|
14
|
+
* Each tool extends `AiTool` and self-registers in the global `AiToolRegistry`
|
|
15
|
+
* on module init. The registry is provided globally by `CoreAiModule` (auto-
|
|
16
|
+
* registered by `CoreModule` when an `ai` config block is present), so no extra
|
|
17
|
+
* import is needed for it here — only `UserModule` for `UserService`.
|
|
18
|
+
*
|
|
19
|
+
* This is the reference implementation showing how a project adds (or overrides)
|
|
20
|
+
* AI tools from its own module. It also demonstrates the opt-in registration of
|
|
21
|
+
* the Claude Code CLI provider on the global {@link LlmProviderFactory}, so a
|
|
22
|
+
* connection with `providerType: 'claude-cli'` can be used.
|
|
23
|
+
*/
|
|
24
|
+
@Module({
|
|
25
|
+
imports: [UserModule],
|
|
26
|
+
providers: [DeleteUserAiTool, FindUsersAiTool, GetUserAiTool, UpdateUserJobTitleAiTool],
|
|
27
|
+
})
|
|
28
|
+
export class AiToolsModule {
|
|
29
|
+
constructor(protected readonly providerFactory: LlmProviderFactory) {
|
|
30
|
+
// Opt-in: enable connections with providerType 'claude-cli' (Claude Code CLI backend).
|
|
31
|
+
this.providerFactory.registerBuilder('claude-cli', (connection) => new ClaudeCliProvider(connection));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { AiToolContext } from '../../../../core/modules/ai/interfaces/ai-tool.interface';
|
|
4
|
+
import { AiTool } from '../../../../core/modules/ai/tools/ai-tool.base';
|
|
5
|
+
import { AiToolRegistry } from '../../../../core/modules/ai/tools/ai-tool.registry';
|
|
6
|
+
import { RoleEnum } from '../../../../core/common/enums/role.enum';
|
|
7
|
+
import { UserService } from '../../user/user.service';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Example destructive AI tool: delete a user (admin only).
|
|
11
|
+
*
|
|
12
|
+
* Marked `destructive: true`, so the orchestrator returns a `requiresConfirmation`
|
|
13
|
+
* response listing this action instead of executing it — the prompt must be
|
|
14
|
+
* re-sent with `confirm: true` to actually delete.
|
|
15
|
+
*/
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class DeleteUserAiTool extends AiTool {
|
|
18
|
+
readonly description = 'Delete a user identified by id. Destructive — requires confirmation. Admin only.';
|
|
19
|
+
readonly destructive = true;
|
|
20
|
+
readonly name = 'delete_user';
|
|
21
|
+
readonly parameters = {
|
|
22
|
+
properties: {
|
|
23
|
+
id: { description: 'The user id', type: 'string' },
|
|
24
|
+
},
|
|
25
|
+
required: ['id'],
|
|
26
|
+
type: 'object',
|
|
27
|
+
};
|
|
28
|
+
readonly roles = [RoleEnum.ADMIN];
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
registry: AiToolRegistry,
|
|
32
|
+
private readonly userService: UserService,
|
|
33
|
+
) {
|
|
34
|
+
super(registry);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async execute(args: Record<string, any>, context: AiToolContext) {
|
|
38
|
+
const deleted = await this.userService.delete(String(args.id), {
|
|
39
|
+
...context.serviceOptions,
|
|
40
|
+
roles: [RoleEnum.ADMIN],
|
|
41
|
+
});
|
|
42
|
+
return { data: { id: deleted?.id }, message: 'User deleted', success: true };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { AiToolContext } from '../../../../core/modules/ai/interfaces/ai-tool.interface';
|
|
4
|
+
import { AiTool } from '../../../../core/modules/ai/tools/ai-tool.base';
|
|
5
|
+
import { AiToolRegistry } from '../../../../core/modules/ai/tools/ai-tool.registry';
|
|
6
|
+
import { RoleEnum } from '../../../../core/common/enums/role.enum';
|
|
7
|
+
import { UserService } from '../../user/user.service';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Example AI tool: search users (admin only).
|
|
11
|
+
*
|
|
12
|
+
* Demonstrates the secure pattern: the tool routes through `UserService.find`
|
|
13
|
+
* with the caller's `serviceOptions`, so `@Restricted` field filtering and
|
|
14
|
+
* `securityCheck()` still apply — the LLM never receives data the user may not see.
|
|
15
|
+
*/
|
|
16
|
+
@Injectable()
|
|
17
|
+
export class FindUsersAiTool extends AiTool {
|
|
18
|
+
readonly description =
|
|
19
|
+
'Search users by email or username and return the matches. Use for questions like ' +
|
|
20
|
+
'"how many users are there", "find the user with email X" or "list recent users". Admin only.';
|
|
21
|
+
readonly name = 'find_users';
|
|
22
|
+
readonly parameters = {
|
|
23
|
+
properties: {
|
|
24
|
+
limit: { description: 'Maximum number of results (default 20, max 100)', type: 'number' },
|
|
25
|
+
search: { description: 'Search term matched against email and username', type: 'string' },
|
|
26
|
+
},
|
|
27
|
+
type: 'object',
|
|
28
|
+
};
|
|
29
|
+
readonly roles = [RoleEnum.ADMIN];
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
registry: AiToolRegistry,
|
|
33
|
+
private readonly userService: UserService,
|
|
34
|
+
) {
|
|
35
|
+
super(registry);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async execute(args: Record<string, any>, context: AiToolContext) {
|
|
39
|
+
const search = typeof args.search === 'string' ? args.search.trim() : '';
|
|
40
|
+
const limit = Math.min(Math.max(Number(args.limit) || 20, 1), 100);
|
|
41
|
+
const escaped = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
42
|
+
const filterQuery = search
|
|
43
|
+
? { $or: [{ email: { $options: 'i', $regex: escaped } }, { username: { $options: 'i', $regex: escaped } }] }
|
|
44
|
+
: {};
|
|
45
|
+
|
|
46
|
+
const users = await this.userService.find({ filterQuery, queryOptions: { limit } }, context.serviceOptions);
|
|
47
|
+
return { data: users, message: `Found ${users.length} user(s)`, success: true };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
import { AiToolContext } from '../../../../core/modules/ai/interfaces/ai-tool.interface';
|
|
4
|
+
import { AiTool } from '../../../../core/modules/ai/tools/ai-tool.base';
|
|
5
|
+
import { AiToolRegistry } from '../../../../core/modules/ai/tools/ai-tool.registry';
|
|
6
|
+
import { RoleEnum } from '../../../../core/common/enums/role.enum';
|
|
7
|
+
import { UserService } from '../../user/user.service';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Example AI tool: get a single user by id (any authenticated user).
|
|
11
|
+
*
|
|
12
|
+
* Authorization is enforced by passing `roles: [ADMIN, S_CREATOR, S_SELF]` to the
|
|
13
|
+
* service — regular users only get their own record, admins get any.
|
|
14
|
+
*/
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class GetUserAiTool extends AiTool {
|
|
17
|
+
readonly description =
|
|
18
|
+
'Get a single user by id. Regular users can only access their own data; admins can access any user.';
|
|
19
|
+
readonly name = 'get_user';
|
|
20
|
+
readonly parameters = {
|
|
21
|
+
properties: {
|
|
22
|
+
id: { description: 'The user id', type: 'string' },
|
|
23
|
+
},
|
|
24
|
+
required: ['id'],
|
|
25
|
+
type: 'object',
|
|
26
|
+
};
|
|
27
|
+
readonly roles = [RoleEnum.S_USER];
|
|
28
|
+
|
|
29
|
+
constructor(
|
|
30
|
+
registry: AiToolRegistry,
|
|
31
|
+
private readonly userService: UserService,
|
|
32
|
+
) {
|
|
33
|
+
super(registry);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async execute(args: Record<string, any>, context: AiToolContext) {
|
|
37
|
+
const user = await this.userService.get(String(args.id), {
|
|
38
|
+
...context.serviceOptions,
|
|
39
|
+
roles: [RoleEnum.ADMIN, RoleEnum.S_CREATOR, RoleEnum.S_SELF],
|
|
40
|
+
});
|
|
41
|
+
return { data: user, success: true };
|
|
42
|
+
}
|
|
43
|
+
}
|