@futdevpro/nts-dynamo 1.15.15 → 1.15.17
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/.c8rc.json +26 -26
- package/.copilot/patterns.json +7 -7
- package/.cursor/rules/__assistant_guide.mdc +30 -30
- package/.cursor/rules/_ag_backend-structure.mdc +85 -85
- package/.cursor/rules/_ag_backend.mdc +16 -16
- package/.cursor/rules/_ag_frontend-structure.mdc +86 -86
- package/.cursor/rules/_ag_frontend.mdc +39 -39
- package/.cursor/rules/_ag_import-rules.mdc +44 -44
- package/.cursor/rules/_ag_naming.mdc +115 -115
- package/.cursor/rules/_ag_should-be.mdc +6 -6
- package/.cursor/rules/ai_development_guide.md +60 -60
- package/.cursor/rules/cursor-rules.md +160 -160
- package/.cursor/rules/default-command.mdc +464 -464
- package/.cursor/rules/error_code_pattern.md +39 -39
- package/.cursor/rules/saved rule mcp server use.md +15 -15
- package/.dynamo/version-bump.config.json +5 -0
- package/.github/workflows/main.yml +426 -393
- package/.husky/pre-commit +1 -0
- package/.vscode/settings.json +10 -10
- package/HOWTO.md +15 -15
- package/LICENSE +21 -21
- package/__documentations/2026-04-28-logs-module.md +49 -0
- package/__documentations/nts-integration-tests-2026-03-17.md +26 -26
- package/_specifications/BACKLOG.md +50 -50
- package/_specifications/TODO.md +15 -15
- package/_specifications/agent.md +138 -138
- package/eslint.config.js +3 -3
- package/nodemon.json +24 -24
- package/package.json +343 -362
- package/pipeline.cicd.config.json +152 -0
- package/pnpm-workspace.yaml +2 -0
- package/scripts/run-coverage-tests.js +28 -28
- package/spec/support/helpers/spec-reporter-loader.js +359 -359
- package/spec/support/helpers/ts-node-helper.js +93 -93
- package/spec/support/jasmine.coverage.json +24 -24
- package/spec/support/jasmine.json +24 -24
- package/src/_collections/archive.util.spec.ts +57 -57
- package/src/_collections/archive.util.ts +18 -18
- package/src/_collections/atlas-default-db-options.const.ts +9 -9
- package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -11
- package/src/_collections/default-fallback-cache-max-age.const.ts +2 -2
- package/src/_collections/default-not-found-page.const.spec.ts +19 -19
- package/src/_collections/default-not-found-page.const.ts +22 -22
- package/src/_collections/default-socket-path.const.spec.ts +12 -12
- package/src/_collections/default-socket-path.const.ts +2 -2
- package/src/_collections/get-environment-settings.util.spec.ts +210 -210
- package/src/_collections/get-environment-settings.util.ts +48 -48
- package/src/_collections/sample.env +21 -21
- package/src/_collections/star.controller.spec.ts +224 -224
- package/src/_collections/star.controller.ts +129 -129
- package/src/_enums/data-model-type.enum.ts +14 -14
- package/src/_enums/data-service-function.enum.ts +24 -24
- package/src/_enums/predefined-data-types.enum.ts +16 -16
- package/src/_enums/route-security.enum.ts +12 -12
- package/src/_models/control-models/api-call-params.control-model.spec.ts +152 -152
- package/src/_models/control-models/api-call-params.control-model.ts +142 -142
- package/src/_models/control-models/app-ext-system-controls.control-model.spec.ts +52 -52
- package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
- package/src/_models/control-models/app-params.control-model.spec.ts +225 -225
- package/src/_models/control-models/app-params.control-model.ts +136 -136
- package/src/_models/control-models/app-system-controls.control-model.spec.ts +31 -31
- package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
- package/src/_models/control-models/endpoint-params.control-model.spec.ts +578 -578
- package/src/_models/control-models/endpoint-params.control-model.ts +526 -526
- package/src/_models/control-models/http-settings.control-model.spec.ts +77 -77
- package/src/_models/control-models/http-settings.control-model.ts +37 -37
- package/src/_models/control-models/system-control.control-model.spec.ts +27 -27
- package/src/_models/control-models/system-control.control-model.ts +12 -12
- package/src/_models/interfaces/certification-settings.interface.ts +7 -7
- package/src/_models/interfaces/environment-settings.interface.ts +59 -59
- package/src/_models/interfaces/global-log-settings.interface.ts +108 -108
- package/src/_models/interfaces/global-service-settings.interface.ts +47 -47
- package/src/_models/interfaces/routing-module-settings.interface.ts +21 -21
- package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -29
- package/src/_models/interfaces/static-client-settings.interface.ts +28 -28
- package/src/_models/types/db-update.type.ts +100 -100
- package/src/_modules/ai/_models/ai-input-interfaces.ts +117 -117
- package/src/_modules/ai/_models/ai-test-generation-result.interface.ts +16 -16
- package/src/_modules/ai/_modules/anthropic/_services/aai-user-key.control-service.ts +138 -138
- package/src/_modules/ai/_modules/anthropic/index.ts +5 -5
- package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.spec.ts +242 -242
- package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.ts +639 -639
- package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.spec.ts +209 -209
- package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.ts +85 -85
- package/src/_modules/ai/_modules/document-ai/_enums/dai-compare-result-type.enum.ts +7 -7
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-chunk.data-model.ts +146 -146
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-page.data-model.ts +162 -162
- package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-document.data-model.ts +99 -99
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-chunk-compare-result.interface.ts +18 -18
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-page-compare-result.interface.ts +19 -19
- package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-document-compare-result.interface.ts +25 -25
- package/src/_modules/ai/_modules/document-ai/index.ts +28 -28
- package/src/_modules/ai/_modules/fdp-ai/_services/fdpai-user-key.control-service.ts +189 -189
- package/src/_modules/ai/_modules/fdp-ai/index.ts +5 -5
- package/src/_modules/ai/_modules/open-ai/_collections/oai-global-settings.const.ts +9 -9
- package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests-hu.conts.ts +82 -82
- package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests.conts.ts +75 -75
- package/src/_modules/ai/_modules/open-ai/_enums/oai-gpt-message-role.enum.ts +45 -45
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-global-settings.interface.ts +7 -7
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-gpt-message.interface.ts +7 -7
- package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-llm-predefined-requests.interface.ts +57 -57
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-doc-chunk-data.service.ts +292 -292
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-document.data-service.spec.ts +342 -342
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.spec.ts +550 -550
- package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.ts +630 -630
- package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +240 -240
- package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.ts +98 -98
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.spec.ts +462 -462
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +615 -615
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +437 -437
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +833 -833
- package/src/_modules/ai/_modules/open-ai/_services/oai-user-key.control-service.ts +157 -157
- package/src/_modules/ai/_services/ai-embedding.service-base.spec.ts +98 -98
- package/src/_modules/ai/_services/ai-embedding.service-base.ts +48 -48
- package/src/_modules/ai/_services/ai-llm-chat.service-base.spec.ts +229 -229
- package/src/_modules/ai/_services/ai-llm-chat.service-base.ts +68 -68
- package/src/_modules/ai/_services/ai-llm.service-base.spec.ts +250 -250
- package/src/_modules/ai/_services/ai-llm.service-base.ts +332 -332
- package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +79 -79
- package/src/_modules/ai/_services/ai-provider.service-base.ts +29 -29
- package/src/_modules/ai/_services/ai-user-key.service-base.ts +59 -59
- package/src/_modules/ai/index.ts +13 -13
- package/src/_modules/assistant/_collections/ass-global-settings.const.ts +13 -13
- package/src/_modules/assistant/_collections/ass.util.spec.ts +176 -176
- package/src/_modules/assistant/_collections/ass.util.ts +50 -50
- package/src/_modules/assistant/_models/ass-global-settings.interface.ts +15 -15
- package/src/_modules/assistant/_services/ass-io.control-service.spec.ts +140 -140
- package/src/_modules/assistant/_services/ass-main.control-service.spec.ts +192 -192
- package/src/_modules/assistant/_services/ass-main.control-service.ts +107 -107
- package/src/_modules/bot/_collections/bot-default-commands.const.ts +12 -12
- package/src/_modules/bot/_collections/bot-global-settings.const.ts +39 -39
- package/src/_modules/bot/_models/bot-channel-wrapper.interface.ts +62 -62
- package/src/_modules/bot/_models/bot-command.interface.ts +8 -8
- package/src/_modules/bot/_models/bot-global-settings.interface.ts +96 -96
- package/src/_modules/bot/_models/bot-last-mention-date.interface.ts +6 -6
- package/src/_modules/bot/_models/bot-last-message-date.interface.ts +5 -5
- package/src/_modules/bot/_models/bot-user-wrapper.interface.ts +41 -41
- package/src/_modules/bot/_modules/discord-bot/_models/dib-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/discord-bot/_services/dib-messaging-provider.control-service.spec.ts +431 -431
- package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.spec.ts +160 -160
- package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.ts +55 -55
- package/src/_modules/bot/_modules/dynamo-bot/_models/dyb-platform.types.ts +15 -15
- package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.spec.ts +374 -374
- package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.ts +447 -447
- package/src/_modules/bot/_modules/dynamo-bot/index.ts +15 -15
- package/src/_modules/bot/_modules/slack-bot/_models/slb-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.spec.ts +344 -344
- package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.ts +197 -197
- package/src/_modules/bot/_modules/teams-bot/_models/teb-platform.types.ts +9 -9
- package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.spec.ts +345 -345
- package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.ts +197 -197
- package/src/_modules/bot/_services/bot-commands.control-service.spec.ts +116 -116
- package/src/_modules/bot/_services/bot-io.control-service.spec.ts +285 -285
- package/src/_modules/bot/_services/bot-main.control-service.spec.ts +208 -208
- package/src/_modules/bot/_services/bot-messaging-provider.service-base.spec.ts +349 -349
- package/src/_modules/bot/_services/bot-routines.control-service.spec.ts +111 -111
- package/src/_modules/custom-data/custom-data.controller.spec.ts +49 -49
- package/src/_modules/custom-data/custom-data.controller.ts +67 -67
- package/src/_modules/custom-data/custom-data.data-service.spec.ts +54 -54
- package/src/_modules/custom-data/custom-data.data-service.ts +21 -21
- package/src/_modules/custom-data/get-custom-data-routing-module.util.spec.ts +28 -28
- package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +24 -24
- package/src/_modules/custom-data/index.ts +9 -9
- package/src/_modules/defaults/_collections/default-endpoints.util.ts +487 -487
- package/src/_modules/defaults/_models/default-user.data-model.ts +72 -72
- package/src/_modules/defaults/_services/default-auth.service.spec.ts +269 -269
- package/src/_modules/defaults/_services/default-auth.service.ts +177 -177
- package/src/_modules/defaults/_services/default-socket-events.service.spec.ts +42 -42
- package/src/_modules/defaults/_services/default-socket-events.service.ts +61 -61
- package/src/_modules/defaults/_services/default-user.data-service.spec.ts +187 -187
- package/src/_modules/defaults/_services/default-user.data-service.ts +98 -98
- package/src/_modules/defaults/index.ts +17 -17
- package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +19 -19
- package/src/_modules/discord-assistant/_collections/dias.util.spec.ts +366 -366
- package/src/_modules/discord-assistant/_collections/dias.util.ts +132 -132
- package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +19 -19
- package/src/_modules/discord-assistant/_models/dias-knowledge.data-model.ts +52 -52
- package/src/_modules/discord-assistant/_services/dias-chunk.data-service.ts +177 -177
- package/src/_modules/discord-assistant/_services/dias-io.control-service.spec.ts +108 -108
- package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +69 -69
- package/src/_modules/discord-assistant/_services/dias-main.control-service.spec.ts +22 -22
- package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +27 -27
- package/src/_modules/discord-assistant/_services/dias.service-base.spec.ts +195 -195
- package/src/_modules/discord-assistant/_services/dias.service-base.ts +76 -76
- package/src/_modules/discord-assistant/index.ts +38 -38
- package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.spec.ts +34 -34
- package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.ts +11 -11
- package/src/_modules/discord-assistant-voiced/index.ts +36 -36
- package/src/_modules/discord-bot/_collections/dibo-default-commands.const.ts +16 -16
- package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +55 -55
- package/src/_modules/discord-bot/_collections/dibo-operations.util.spec.ts +214 -214
- package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +387 -387
- package/src/_modules/discord-bot/_models/dibo-command.interface.ts +12 -12
- package/src/_modules/discord-bot/_models/dibo-global-settings.interface.ts +98 -98
- package/src/_modules/discord-bot/_models/dibo-last-mention-date.inteface.ts +7 -7
- package/src/_modules/discord-bot/_models/dibo-last-message-date.interface.ts +6 -6
- package/src/_modules/discord-bot/_services/dibo-commands.control-service.spec.ts +154 -154
- package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +153 -153
- package/src/_modules/discord-bot/_services/dibo-io.control-service.spec.ts +264 -264
- package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +306 -306
- package/src/_modules/discord-bot/_services/dibo-main.control-service.spec.ts +408 -408
- package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +487 -487
- package/src/_modules/discord-bot/_services/dibo-routines.control-service.spec.ts +105 -105
- package/src/_modules/discord-bot/index.ts +36 -36
- package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +19 -19
- package/src/_modules/local-vector-search/_models/lvs-search-result.interface.ts +17 -17
- package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.spec.ts +418 -418
- package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.ts +276 -276
- package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +345 -345
- package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +330 -330
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +393 -393
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +220 -220
- package/src/_modules/local-vector-search/index.ts +11 -11
- package/src/_modules/messaging/README.md +354 -354
- package/src/_modules/messaging/_collections/get-messaging-routing-module.util.ts +26 -26
- package/src/_modules/messaging/_collections/msg-global-settings.const.ts +22 -22
- package/src/_modules/messaging/_collections/msg.util.spec.ts +226 -226
- package/src/_modules/messaging/_models/msg-global-settings.interface.ts +37 -37
- package/src/_modules/messaging/_services/msg-conversation.data-service.ts +146 -146
- package/src/_modules/messaging/_services/msg-events.service.spec.ts +219 -219
- package/src/_modules/messaging/_services/msg-events.service.ts +267 -267
- package/src/_modules/messaging/_services/msg-integration.control-service.ts +179 -179
- package/src/_modules/messaging/_services/msg-main.control-service.spec.ts +147 -147
- package/src/_modules/messaging/_services/msg-main.control-service.ts +571 -571
- package/src/_modules/messaging/_services/msg-message.data-service.ts +129 -129
- package/src/_modules/messaging/_services/msg.controller.spec.ts +201 -201
- package/src/_modules/messaging/index.ts +30 -30
- package/src/_modules/mock/app-extended-server.mock.ts +201 -201
- package/src/_modules/mock/app-integration-test.mock.ts +51 -51
- package/src/_modules/mock/app-params.mock.spec.ts +21 -21
- package/src/_modules/mock/app-params.mock.ts +9 -9
- package/src/_modules/mock/app-server.mock.ts +188 -188
- package/src/_modules/mock/auth-service.mock.spec.ts +47 -47
- package/src/_modules/mock/auth-service.mock.ts +28 -28
- package/src/_modules/mock/controller.mock.spec.ts +26 -26
- package/src/_modules/mock/controller.mock.ts +16 -16
- package/src/_modules/mock/data-model.mock.spec.ts +111 -111
- package/src/_modules/mock/data-model.mock.ts +82 -82
- package/src/_modules/mock/email-service-collection.mock.spec.ts +24 -24
- package/src/_modules/mock/email-service-collection.mock.ts +15 -15
- package/src/_modules/mock/email-service.mock.spec.ts +17 -17
- package/src/_modules/mock/email-service.mock.ts +20 -20
- package/src/_modules/mock/email-template.mock.html +14 -14
- package/src/_modules/mock/endpoint.mock.ts +91 -91
- package/src/_modules/mock/socket-client.mock.spec.ts +40 -40
- package/src/_modules/mock/socket-client.mock.ts +45 -45
- package/src/_modules/mock/socket-server.mock.spec.ts +44 -44
- package/src/_modules/mock/socket-server.mock.ts +46 -46
- package/src/_modules/oauth2/_routes/oauth2.controller.spec.ts +107 -107
- package/src/_modules/oauth2/_routes/oauth2.controller.ts +98 -98
- package/src/_modules/oauth2/_services/oauth2.auth-service.spec.ts +254 -254
- package/src/_modules/oauth2/_services/oauth2.auth-service.ts +232 -232
- package/src/_modules/oauth2/_services/oauth2.control-service.spec.ts +585 -585
- package/src/_modules/oauth2/_services/oauth2.control-service.ts +653 -653
- package/src/_modules/oauth2/index.ts +17 -17
- package/src/_modules/server/errors/errors.control-service.spec.ts +230 -230
- package/src/_modules/server/errors/errors.control-service.ts +69 -69
- package/src/_modules/server/errors/errors.controller.spec.ts +165 -165
- package/src/_modules/server/errors/errors.controller.ts +270 -270
- package/src/_modules/server/errors/errors.data-service.spec.ts +355 -355
- package/src/_modules/server/index.ts +30 -30
- package/src/_modules/server/server-status/server-status-snapshot.control-service.spec.ts +70 -70
- package/src/_modules/server/server-status/server-status-snapshot.control-service.ts +17 -17
- package/src/_modules/server/server-status/server-status-snapshot.data-service.spec.ts +77 -77
- package/src/_modules/server/server-status/server-status-snapshot.data-service.ts +37 -37
- package/src/_modules/server/server-status/server-status.control-service.spec.ts +516 -516
- package/src/_modules/server/server-status/server-status.control-service.ts +336 -336
- package/src/_modules/server/server-status/server-status.controller.spec.ts +156 -156
- package/src/_modules/server/server-status/server-status.controller.ts +131 -131
- package/src/_modules/socket/_enums/socket-security.enum.ts +11 -11
- package/src/_modules/socket/_models/socket-client-service-params.control-model.spec.ts +32 -32
- package/src/_modules/socket/_models/socket-client-service-params.control-model.ts +22 -22
- package/src/_modules/socket/_models/socket-presence.control-model.spec.ts +164 -164
- package/src/_modules/socket/_models/socket-presence.control-model.ts +210 -210
- package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +46 -46
- package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +22 -22
- package/src/_modules/socket/_services/socket-client.service.spec.ts +15 -15
- package/src/_modules/socket/_services/socket-client.service.ts +260 -260
- package/src/_modules/socket/_services/socket-server.service.spec.ts +11 -11
- package/src/_modules/socket/app-extended.integration.spec.ts +85 -85
- package/src/_modules/socket/app-extended.server.ts +630 -630
- package/src/_modules/socket/index.ts +42 -42
- package/src/_modules/test/get-test-routing-module.util.spec.ts +28 -28
- package/src/_modules/test/get-test-routing-module.util.ts +23 -23
- package/src/_modules/test/index.ts +11 -11
- package/src/_modules/test/test.controller.spec.ts +72 -72
- package/src/_modules/test/test.controller.ts +115 -115
- package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
- package/src/_modules/usage/index.ts +15 -15
- package/src/_modules/usage/usage.controller.spec.ts +81 -81
- package/src/_modules/usage/usage.controller.ts +126 -126
- package/src/_modules/usage/usage.data-service.spec.ts +332 -332
- package/src/_modules/usage/usage.data-service.ts +185 -185
- package/src/_services/base/api.service-base.spec.ts +125 -125
- package/src/_services/base/api.service-base.ts +74 -74
- package/src/_services/base/archive-data.service.spec.ts +196 -196
- package/src/_services/base/archive-data.service.ts +216 -216
- package/src/_services/base/data.service.spec.ts +493 -493
- package/src/_services/base/data.service.ts +2525 -2525
- package/src/_services/base/db.service.spec.ts +73 -73
- package/src/_services/base/db.service.ts +1575 -1575
- package/src/_services/base/singleton.service-base.spec.ts +28 -28
- package/src/_services/base/singleton.service-base.ts +24 -24
- package/src/_services/base/singleton.service.spec.ts +114 -114
- package/src/_services/base/singleton.service.ts +38 -38
- package/src/_services/core/api.service.spec.ts +140 -140
- package/src/_services/core/auth.service.spec.ts +159 -159
- package/src/_services/core/auth.service.ts +174 -174
- package/src/_services/core/email.service.spec.ts +85 -85
- package/src/_services/core/email.service.ts +742 -742
- package/src/_services/core/global.service.spec.ts +275 -275
- package/src/_services/core/global.service.ts +461 -461
- package/src/_services/core/service-collection.service.spec.ts +46 -46
- package/src/_services/core/service-collection.service.ts +6 -6
- package/src/_services/route/controller.service.spec.ts +53 -53
- package/src/_services/route/controller.service.ts +148 -148
- package/src/_services/route/routing-module.service.spec.ts +98 -98
- package/src/_services/route/routing-module.service.ts +330 -330
- package/src/_services/shared.static-service.spec.ts +99 -99
- package/src/_services/shared.static-service.ts +78 -78
- package/src/index.ts +94 -94
- package/tsconfig.app.json +12 -12
- package/tsconfig.json +42 -42
- package/build/_modules/logs/get-logs-routing-module.util.d.ts +0 -19
- package/build/_modules/logs/get-logs-routing-module.util.d.ts.map +0 -1
- package/build/_modules/logs/get-logs-routing-module.util.js +0 -32
- package/build/_modules/logs/get-logs-routing-module.util.js.map +0 -1
- package/build/_modules/logs/index.d.ts +0 -4
- package/build/_modules/logs/index.d.ts.map +0 -1
- package/build/_modules/logs/index.js +0 -10
- package/build/_modules/logs/index.js.map +0 -1
- package/build/_modules/logs/log-buffer.service.d.ts +0 -38
- package/build/_modules/logs/log-buffer.service.d.ts.map +0 -1
- package/build/_modules/logs/log-buffer.service.js +0 -97
- package/build/_modules/logs/log-buffer.service.js.map +0 -1
- package/build/_modules/logs/logs.controller.d.ts +0 -27
- package/build/_modules/logs/logs.controller.d.ts.map +0 -1
- package/build/_modules/logs/logs.controller.js +0 -90
- package/build/_modules/logs/logs.controller.js.map +0 -1
- package/build/_modules/logs/logs.service.d.ts +0 -40
- package/build/_modules/logs/logs.service.d.ts.map +0 -1
- package/build/_modules/logs/logs.service.js +0 -97
- package/build/_modules/logs/logs.service.js.map +0 -1
- package/src/_modules/logs/get-logs-routing-module.util.ts +0 -36
- package/src/_modules/logs/index.ts +0 -3
- package/src/_modules/logs/log-buffer.service.ts +0 -101
- package/src/_modules/logs/logs.controller.ts +0 -109
- package/src/_modules/logs/logs.service.ts +0 -100
|
@@ -1,437 +1,437 @@
|
|
|
1
|
-
|
|
2
|
-
import { DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
|
|
3
|
-
import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
|
|
4
|
-
import { DyFM_AI_MessageRole, DyFM_AI_Message } from '@futdevpro/fsm-dynamo/ai';
|
|
5
|
-
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
6
|
-
import { ChatCompletion } from 'openai/resources';
|
|
7
|
-
|
|
8
|
-
describe('| DyNTS_OAI_LLM_ServiceBase', () => {
|
|
9
|
-
let service: DyNTS_OAI_LLM_ServiceBase;
|
|
10
|
-
let mockOpenAI: any;
|
|
11
|
-
let mockChatCompletionsCreate: jasmine.Spy;
|
|
12
|
-
let mockModelsList: jasmine.Spy;
|
|
13
|
-
|
|
14
|
-
const mockSettings: DyFM_OAI_Settings = {
|
|
15
|
-
config: {
|
|
16
|
-
apiKey: 'test-api-key',
|
|
17
|
-
organization: 'test-org',
|
|
18
|
-
},
|
|
19
|
-
defaultSettings: {
|
|
20
|
-
useModel: DyFM_OAI_Model.gpt4o_mini,
|
|
21
|
-
systemPrompt: 'Test system prompt',
|
|
22
|
-
temperature: 0.7,
|
|
23
|
-
maxTokens: 1000,
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
mockChatCompletionsCreate = jasmine.createSpy('chat.completions.create').and.returnValue({
|
|
29
|
-
id: 'chatcmpl-123',
|
|
30
|
-
object: 'chat.completion',
|
|
31
|
-
created: 1234567890,
|
|
32
|
-
model: 'gpt-4o-mini',
|
|
33
|
-
choices: [
|
|
34
|
-
{
|
|
35
|
-
index: 0,
|
|
36
|
-
message: {
|
|
37
|
-
role: 'assistant',
|
|
38
|
-
content: 'Test response',
|
|
39
|
-
},
|
|
40
|
-
finish_reason: 'stop',
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
usage: {
|
|
44
|
-
prompt_tokens: 10,
|
|
45
|
-
completion_tokens: 5,
|
|
46
|
-
total_tokens: 15,
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
mockModelsList = jasmine.createSpy('models.list').and.returnValue({
|
|
51
|
-
data: [],
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
mockOpenAI = {
|
|
55
|
-
chat: {
|
|
56
|
-
completions: {
|
|
57
|
-
create: mockChatCompletionsCreate,
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
models: {
|
|
61
|
-
list: mockModelsList,
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
service = new DyNTS_OAI_LLM_ServiceBase(mockSettings);
|
|
66
|
-
(service as any).openai = mockOpenAI;
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe('| constructor', () => {
|
|
70
|
-
it('| should initialize with provided settings', () => {
|
|
71
|
-
expect(service.defaultSettings).toEqual(mockSettings.defaultSettings);
|
|
72
|
-
expect(service.aiProvider).toBeDefined();
|
|
73
|
-
expect(service.capabilities).toBeDefined();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('| should initialize with default settings when not provided', () => {
|
|
77
|
-
// Creating service without settings requires OPENAI_API_KEY env var or throws
|
|
78
|
-
// Test that service creation with settings works and uses defaults for missing values
|
|
79
|
-
const serviceWithPartialSettings = new DyNTS_OAI_LLM_ServiceBase({
|
|
80
|
-
config: { apiKey: 'test-key' },
|
|
81
|
-
});
|
|
82
|
-
expect(serviceWithPartialSettings.defaultSettings).toBeDefined();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('| should set defaultModel from defaultSettings', () => {
|
|
86
|
-
expect(service.defaultModel).toBe(DyFM_OAI_Model.gpt4o_mini);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe('| setup', () => {
|
|
91
|
-
it('| should reinitialize OpenAI client with new config', () => {
|
|
92
|
-
const newConfig = {
|
|
93
|
-
apiKey: 'new-api-key',
|
|
94
|
-
organization: 'new-org',
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
service.setup(newConfig);
|
|
98
|
-
|
|
99
|
-
expect((service as any).openai).toBeDefined();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('| requestYesNo', () => {
|
|
104
|
-
it('| should return true when answer contains YES', async () => {
|
|
105
|
-
mockChatCompletionsCreate.and.returnValue({
|
|
106
|
-
choices: [
|
|
107
|
-
{
|
|
108
|
-
message: {
|
|
109
|
-
content: 'YES',
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
spyOn(service as any, 'convertAnswerToBoolean').and.returnValue(true);
|
|
116
|
-
|
|
117
|
-
const result = await service.requestYesNo({
|
|
118
|
-
message: 'Is this a test?',
|
|
119
|
-
issuer: 'test-issuer',
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(result).toBe(true);
|
|
123
|
-
expect((service as any).convertAnswerToBoolean).toHaveBeenCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('| should append predefined request to message', async () => {
|
|
127
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('YES'));
|
|
128
|
-
|
|
129
|
-
await service.requestYesNo({
|
|
130
|
-
message: 'Is this a test?',
|
|
131
|
-
issuer: 'test-issuer',
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(service.requestSimpleMessage).toHaveBeenCalled();
|
|
135
|
-
const callArgs = (service.requestSimpleMessage as jasmine.Spy).calls.mostRecent().args[0];
|
|
136
|
-
expect(callArgs.message).toContain('Is this a test?');
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
describe('| requestPercentage', () => {
|
|
141
|
-
it('| should return number from answer', async () => {
|
|
142
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('75'));
|
|
143
|
-
spyOn(service as any, 'convertAnswerToNumber').and.returnValue(75);
|
|
144
|
-
|
|
145
|
-
const result = await service.requestPercentage({
|
|
146
|
-
message: 'What percentage?',
|
|
147
|
-
issuer: 'test-issuer',
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
expect(result).toBe(75);
|
|
151
|
-
expect((service as any).convertAnswerToNumber).toHaveBeenCalled();
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe('| requestSelect', () => {
|
|
156
|
-
it('| should return selected option', async () => {
|
|
157
|
-
const options = ['option1', 'option2', 'option3'];
|
|
158
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('option1'));
|
|
159
|
-
spyOn(service as any, 'stringifySelectOptions').and.returnValue(['option1', 'option2', 'option3']);
|
|
160
|
-
spyOn(service as any, 'getTextListAsText').and.returnValue('option1, option2, option3');
|
|
161
|
-
spyOn(service as any, 'convertAnswerToSelectOption').and.returnValue('option1');
|
|
162
|
-
|
|
163
|
-
const result = await service.requestSelect({
|
|
164
|
-
message: 'Select an option',
|
|
165
|
-
selectFrom: options,
|
|
166
|
-
issuer: 'test-issuer',
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(result).toBe('option1');
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
describe('| requestMultiselect', () => {
|
|
174
|
-
it('| should return multiple selected options', async () => {
|
|
175
|
-
const options = ['option1', 'option2', 'option3'];
|
|
176
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('option1 and option2'));
|
|
177
|
-
spyOn(service as any, 'stringifySelectOptions').and.returnValue(['option1', 'option2', 'option3']);
|
|
178
|
-
spyOn(service as any, 'getTextListAsText').and.returnValue('option1, option2, option3');
|
|
179
|
-
spyOn(service as any, 'convertAnswerToSelectOptions').and.returnValue(['option1', 'option2']);
|
|
180
|
-
|
|
181
|
-
const result = await service.requestMultiselect({
|
|
182
|
-
message: 'Select options',
|
|
183
|
-
options: options,
|
|
184
|
-
issuer: 'test-issuer',
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
expect(result).toEqual(['option1', 'option2']);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
describe('| requestJSON', () => {
|
|
192
|
-
it('| should return parsed JSON', async () => {
|
|
193
|
-
const jsonString = '{"key": "value"}';
|
|
194
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve(jsonString));
|
|
195
|
-
spyOn(service as any, 'convertAnswerToJSON').and.returnValue({ key: 'value' });
|
|
196
|
-
|
|
197
|
-
const result = await service.requestJSON<{ key: string }>({
|
|
198
|
-
message: 'Return JSON',
|
|
199
|
-
issuer: 'test-issuer',
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(result).toEqual({ key: 'value' });
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe('| requestList', () => {
|
|
207
|
-
it('| should return list of items', async () => {
|
|
208
|
-
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('item1, item2, item3'));
|
|
209
|
-
spyOn(service as any, 'convertAnswerToList').and.returnValue(['item1', 'item2', 'item3']);
|
|
210
|
-
|
|
211
|
-
const result = await service.requestList<string>({
|
|
212
|
-
message: 'Return a list',
|
|
213
|
-
issuer: 'test-issuer',
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
expect(result).toEqual(['item1', 'item2', 'item3']);
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
describe('| requestSimpleMessage', () => {
|
|
221
|
-
it('| should resolve message and return answer', async () => {
|
|
222
|
-
spyOn(service as any, 'logQuestion');
|
|
223
|
-
spyOn(service as any, 'logAnswer');
|
|
224
|
-
spyOn(service, 'resolveMessage').and.returnValue(Promise.resolve('Test response'));
|
|
225
|
-
|
|
226
|
-
const result = await service.requestSimpleMessage({
|
|
227
|
-
message: 'Test question',
|
|
228
|
-
issuer: 'test-issuer',
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
expect(result).toBe('Test response');
|
|
232
|
-
expect((service as any).logQuestion).toHaveBeenCalled();
|
|
233
|
-
expect((service as any).logAnswer).toHaveBeenCalled();
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('| should add user message to conversation', async () => {
|
|
237
|
-
const conversation: DyFM_AI_Message[] = [];
|
|
238
|
-
spyOn(service, 'resolveMessage').and.returnValue(Promise.resolve('Test response'));
|
|
239
|
-
|
|
240
|
-
await service.requestSimpleMessage({
|
|
241
|
-
message: 'Test question',
|
|
242
|
-
conversation: conversation,
|
|
243
|
-
issuer: 'test-issuer',
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
expect(conversation.length).toBe(1);
|
|
247
|
-
expect(conversation[0].role).toBe(DyFM_AI_MessageRole.user);
|
|
248
|
-
expect(conversation[0].content).toBe('Test question');
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
describe('| resolveMessage', () => {
|
|
253
|
-
it('| should return string answer when getFullResponse is false', async () => {
|
|
254
|
-
const conversation: DyFM_AI_Message[] = [
|
|
255
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
256
|
-
];
|
|
257
|
-
|
|
258
|
-
const result = await service.resolveMessage({
|
|
259
|
-
conversation: conversation,
|
|
260
|
-
issuer: 'test-issuer',
|
|
261
|
-
getFullResponse: false,
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
expect(result).toBe('Test response');
|
|
265
|
-
expect(mockChatCompletionsCreate).toHaveBeenCalled();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('| should return full ChatCompletion when getFullResponse is true', async () => {
|
|
269
|
-
const conversation: DyFM_AI_Message[] = [
|
|
270
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
271
|
-
];
|
|
272
|
-
|
|
273
|
-
const fullResponse: ChatCompletion = {
|
|
274
|
-
id: 'chatcmpl-123',
|
|
275
|
-
object: 'chat.completion',
|
|
276
|
-
created: 1234567890,
|
|
277
|
-
model: 'gpt-4o-mini',
|
|
278
|
-
choices: [
|
|
279
|
-
{
|
|
280
|
-
index: 0,
|
|
281
|
-
message: {
|
|
282
|
-
role: 'assistant',
|
|
283
|
-
content: 'Test response',
|
|
284
|
-
refusal: null,
|
|
285
|
-
},
|
|
286
|
-
logprobs: null,
|
|
287
|
-
finish_reason: 'stop',
|
|
288
|
-
},
|
|
289
|
-
],
|
|
290
|
-
usage: {
|
|
291
|
-
prompt_tokens: 10,
|
|
292
|
-
completion_tokens: 5,
|
|
293
|
-
total_tokens: 15,
|
|
294
|
-
},
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
mockChatCompletionsCreate.and.returnValue(fullResponse);
|
|
298
|
-
|
|
299
|
-
const result = await service.resolveMessage({
|
|
300
|
-
conversation: conversation,
|
|
301
|
-
issuer: 'test-issuer',
|
|
302
|
-
getFullResponse: true,
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
expect(result).toEqual(fullResponse);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('| should add system message to conversation', async () => {
|
|
309
|
-
const conversation: DyFM_AI_Message[] = [
|
|
310
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
311
|
-
];
|
|
312
|
-
|
|
313
|
-
spyOn(service as any, 'getDefaultSystemMessage').and.returnValue({
|
|
314
|
-
role: DyFM_AI_MessageRole.system,
|
|
315
|
-
content: 'System prompt',
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
await service.resolveMessage({
|
|
319
|
-
conversation: conversation,
|
|
320
|
-
issuer: 'test-issuer',
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
expect(conversation[0].role).toBe(DyFM_AI_MessageRole.system);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('| should handle API errors', async () => {
|
|
327
|
-
const conversation: DyFM_AI_Message[] = [
|
|
328
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
329
|
-
];
|
|
330
|
-
|
|
331
|
-
mockChatCompletionsCreate.and.throwError(new Error('API Error'));
|
|
332
|
-
|
|
333
|
-
try {
|
|
334
|
-
await service.resolveMessage({
|
|
335
|
-
conversation: conversation,
|
|
336
|
-
issuer: 'test-issuer',
|
|
337
|
-
});
|
|
338
|
-
fail('Should have thrown an error');
|
|
339
|
-
} catch (error) {
|
|
340
|
-
expect(error).toBeInstanceOf(DyFM_Error);
|
|
341
|
-
expect((error as DyFM_Error)._errorCode).toContain('DyNTS-OLSB-RM0');
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
describe('| getMessageCreateInput', () => {
|
|
347
|
-
it('| should create input with default settings', () => {
|
|
348
|
-
const conversation: DyFM_AI_Message[] = [
|
|
349
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
350
|
-
];
|
|
351
|
-
|
|
352
|
-
const result = (service as any).getMessageCreateInput({
|
|
353
|
-
conversation: conversation,
|
|
354
|
-
issuer: 'test-issuer',
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
expect(result.model).toBe(DyFM_OAI_Model.gpt4o_mini);
|
|
358
|
-
expect(result.messages).toBeDefined();
|
|
359
|
-
expect(result.temperature).toBe(0.7);
|
|
360
|
-
expect(result.max_completion_tokens).toBe(1000);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it('| should use provided settings when available', () => {
|
|
364
|
-
const conversation: DyFM_AI_Message[] = [
|
|
365
|
-
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
366
|
-
];
|
|
367
|
-
|
|
368
|
-
const customSettings: DyFM_OAI_CallSettings = {
|
|
369
|
-
useModel: DyFM_OAI_Model.gpt4o,
|
|
370
|
-
temperature: 0.9,
|
|
371
|
-
maxTokens: 2000,
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
const result = (service as any).getMessageCreateInput({
|
|
375
|
-
conversation: conversation,
|
|
376
|
-
issuer: 'test-issuer',
|
|
377
|
-
settings: customSettings,
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
expect(result.model).toBe(DyFM_OAI_Model.gpt4o);
|
|
381
|
-
expect(result.temperature).toBe(0.9);
|
|
382
|
-
expect(result.max_completion_tokens).toBe(2000);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
it('| should handle errors', () => {
|
|
386
|
-
// Test that the method handles edge cases gracefully
|
|
387
|
-
// Passing null conversation may or may not throw depending on implementation
|
|
388
|
-
try {
|
|
389
|
-
const result = (service as any).getMessageCreateInput({
|
|
390
|
-
conversation: null as any,
|
|
391
|
-
issuer: 'test-issuer',
|
|
392
|
-
});
|
|
393
|
-
// If it doesn't throw, verify it returns something
|
|
394
|
-
expect(result).toBeDefined();
|
|
395
|
-
} catch (error) {
|
|
396
|
-
// If it throws, it should be a DyFM_Error
|
|
397
|
-
expect(error).toBeInstanceOf(DyFM_Error);
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
describe('| testConnection', () => {
|
|
403
|
-
it('| should return true when connection is successful', async () => {
|
|
404
|
-
const result = await service.testConnection('test-issuer');
|
|
405
|
-
|
|
406
|
-
expect(result).toBe(true);
|
|
407
|
-
expect(mockModelsList).toHaveBeenCalled();
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it('| should return false when connection fails', async () => {
|
|
411
|
-
const logSpy = spyOn(DyFM_Log, 'error');
|
|
412
|
-
mockModelsList.and.throwError(new Error('Connection failed'));
|
|
413
|
-
|
|
414
|
-
const result = await service.testConnection('test-issuer');
|
|
415
|
-
|
|
416
|
-
expect(result).toBe(false);
|
|
417
|
-
expect(logSpy).toHaveBeenCalled();
|
|
418
|
-
});
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
describe('| properties', () => {
|
|
422
|
-
it('| should have aiProvider property', () => {
|
|
423
|
-
expect(service.aiProvider).toBeDefined();
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('| should have capabilities property', () => {
|
|
427
|
-
expect(service.capabilities).toBeDefined();
|
|
428
|
-
expect(service.capabilities.chat).toBe(true);
|
|
429
|
-
expect(service.capabilities.embeddings).toBe(true);
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it('| should have predefinedRequests property', () => {
|
|
433
|
-
expect(service.predefinedRequests).toBeDefined();
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
|
|
1
|
+
|
|
2
|
+
import { DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
|
|
3
|
+
import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
|
|
4
|
+
import { DyFM_AI_MessageRole, DyFM_AI_Message } from '@futdevpro/fsm-dynamo/ai';
|
|
5
|
+
import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
|
|
6
|
+
import { ChatCompletion } from 'openai/resources';
|
|
7
|
+
|
|
8
|
+
describe('| DyNTS_OAI_LLM_ServiceBase', () => {
|
|
9
|
+
let service: DyNTS_OAI_LLM_ServiceBase;
|
|
10
|
+
let mockOpenAI: any;
|
|
11
|
+
let mockChatCompletionsCreate: jasmine.Spy;
|
|
12
|
+
let mockModelsList: jasmine.Spy;
|
|
13
|
+
|
|
14
|
+
const mockSettings: DyFM_OAI_Settings = {
|
|
15
|
+
config: {
|
|
16
|
+
apiKey: 'test-api-key',
|
|
17
|
+
organization: 'test-org',
|
|
18
|
+
},
|
|
19
|
+
defaultSettings: {
|
|
20
|
+
useModel: DyFM_OAI_Model.gpt4o_mini,
|
|
21
|
+
systemPrompt: 'Test system prompt',
|
|
22
|
+
temperature: 0.7,
|
|
23
|
+
maxTokens: 1000,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
mockChatCompletionsCreate = jasmine.createSpy('chat.completions.create').and.returnValue({
|
|
29
|
+
id: 'chatcmpl-123',
|
|
30
|
+
object: 'chat.completion',
|
|
31
|
+
created: 1234567890,
|
|
32
|
+
model: 'gpt-4o-mini',
|
|
33
|
+
choices: [
|
|
34
|
+
{
|
|
35
|
+
index: 0,
|
|
36
|
+
message: {
|
|
37
|
+
role: 'assistant',
|
|
38
|
+
content: 'Test response',
|
|
39
|
+
},
|
|
40
|
+
finish_reason: 'stop',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
usage: {
|
|
44
|
+
prompt_tokens: 10,
|
|
45
|
+
completion_tokens: 5,
|
|
46
|
+
total_tokens: 15,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
mockModelsList = jasmine.createSpy('models.list').and.returnValue({
|
|
51
|
+
data: [],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
mockOpenAI = {
|
|
55
|
+
chat: {
|
|
56
|
+
completions: {
|
|
57
|
+
create: mockChatCompletionsCreate,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
models: {
|
|
61
|
+
list: mockModelsList,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
service = new DyNTS_OAI_LLM_ServiceBase(mockSettings);
|
|
66
|
+
(service as any).openai = mockOpenAI;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('| constructor', () => {
|
|
70
|
+
it('| should initialize with provided settings', () => {
|
|
71
|
+
expect(service.defaultSettings).toEqual(mockSettings.defaultSettings);
|
|
72
|
+
expect(service.aiProvider).toBeDefined();
|
|
73
|
+
expect(service.capabilities).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('| should initialize with default settings when not provided', () => {
|
|
77
|
+
// Creating service without settings requires OPENAI_API_KEY env var or throws
|
|
78
|
+
// Test that service creation with settings works and uses defaults for missing values
|
|
79
|
+
const serviceWithPartialSettings = new DyNTS_OAI_LLM_ServiceBase({
|
|
80
|
+
config: { apiKey: 'test-key' },
|
|
81
|
+
});
|
|
82
|
+
expect(serviceWithPartialSettings.defaultSettings).toBeDefined();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('| should set defaultModel from defaultSettings', () => {
|
|
86
|
+
expect(service.defaultModel).toBe(DyFM_OAI_Model.gpt4o_mini);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('| setup', () => {
|
|
91
|
+
it('| should reinitialize OpenAI client with new config', () => {
|
|
92
|
+
const newConfig = {
|
|
93
|
+
apiKey: 'new-api-key',
|
|
94
|
+
organization: 'new-org',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
service.setup(newConfig);
|
|
98
|
+
|
|
99
|
+
expect((service as any).openai).toBeDefined();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('| requestYesNo', () => {
|
|
104
|
+
it('| should return true when answer contains YES', async () => {
|
|
105
|
+
mockChatCompletionsCreate.and.returnValue({
|
|
106
|
+
choices: [
|
|
107
|
+
{
|
|
108
|
+
message: {
|
|
109
|
+
content: 'YES',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
spyOn(service as any, 'convertAnswerToBoolean').and.returnValue(true);
|
|
116
|
+
|
|
117
|
+
const result = await service.requestYesNo({
|
|
118
|
+
message: 'Is this a test?',
|
|
119
|
+
issuer: 'test-issuer',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(result).toBe(true);
|
|
123
|
+
expect((service as any).convertAnswerToBoolean).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('| should append predefined request to message', async () => {
|
|
127
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('YES'));
|
|
128
|
+
|
|
129
|
+
await service.requestYesNo({
|
|
130
|
+
message: 'Is this a test?',
|
|
131
|
+
issuer: 'test-issuer',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(service.requestSimpleMessage).toHaveBeenCalled();
|
|
135
|
+
const callArgs = (service.requestSimpleMessage as jasmine.Spy).calls.mostRecent().args[0];
|
|
136
|
+
expect(callArgs.message).toContain('Is this a test?');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('| requestPercentage', () => {
|
|
141
|
+
it('| should return number from answer', async () => {
|
|
142
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('75'));
|
|
143
|
+
spyOn(service as any, 'convertAnswerToNumber').and.returnValue(75);
|
|
144
|
+
|
|
145
|
+
const result = await service.requestPercentage({
|
|
146
|
+
message: 'What percentage?',
|
|
147
|
+
issuer: 'test-issuer',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(result).toBe(75);
|
|
151
|
+
expect((service as any).convertAnswerToNumber).toHaveBeenCalled();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('| requestSelect', () => {
|
|
156
|
+
it('| should return selected option', async () => {
|
|
157
|
+
const options = ['option1', 'option2', 'option3'];
|
|
158
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('option1'));
|
|
159
|
+
spyOn(service as any, 'stringifySelectOptions').and.returnValue(['option1', 'option2', 'option3']);
|
|
160
|
+
spyOn(service as any, 'getTextListAsText').and.returnValue('option1, option2, option3');
|
|
161
|
+
spyOn(service as any, 'convertAnswerToSelectOption').and.returnValue('option1');
|
|
162
|
+
|
|
163
|
+
const result = await service.requestSelect({
|
|
164
|
+
message: 'Select an option',
|
|
165
|
+
selectFrom: options,
|
|
166
|
+
issuer: 'test-issuer',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(result).toBe('option1');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('| requestMultiselect', () => {
|
|
174
|
+
it('| should return multiple selected options', async () => {
|
|
175
|
+
const options = ['option1', 'option2', 'option3'];
|
|
176
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('option1 and option2'));
|
|
177
|
+
spyOn(service as any, 'stringifySelectOptions').and.returnValue(['option1', 'option2', 'option3']);
|
|
178
|
+
spyOn(service as any, 'getTextListAsText').and.returnValue('option1, option2, option3');
|
|
179
|
+
spyOn(service as any, 'convertAnswerToSelectOptions').and.returnValue(['option1', 'option2']);
|
|
180
|
+
|
|
181
|
+
const result = await service.requestMultiselect({
|
|
182
|
+
message: 'Select options',
|
|
183
|
+
options: options,
|
|
184
|
+
issuer: 'test-issuer',
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(result).toEqual(['option1', 'option2']);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('| requestJSON', () => {
|
|
192
|
+
it('| should return parsed JSON', async () => {
|
|
193
|
+
const jsonString = '{"key": "value"}';
|
|
194
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve(jsonString));
|
|
195
|
+
spyOn(service as any, 'convertAnswerToJSON').and.returnValue({ key: 'value' });
|
|
196
|
+
|
|
197
|
+
const result = await service.requestJSON<{ key: string }>({
|
|
198
|
+
message: 'Return JSON',
|
|
199
|
+
issuer: 'test-issuer',
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
expect(result).toEqual({ key: 'value' });
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('| requestList', () => {
|
|
207
|
+
it('| should return list of items', async () => {
|
|
208
|
+
spyOn(service, 'requestSimpleMessage').and.returnValue(Promise.resolve('item1, item2, item3'));
|
|
209
|
+
spyOn(service as any, 'convertAnswerToList').and.returnValue(['item1', 'item2', 'item3']);
|
|
210
|
+
|
|
211
|
+
const result = await service.requestList<string>({
|
|
212
|
+
message: 'Return a list',
|
|
213
|
+
issuer: 'test-issuer',
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(result).toEqual(['item1', 'item2', 'item3']);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe('| requestSimpleMessage', () => {
|
|
221
|
+
it('| should resolve message and return answer', async () => {
|
|
222
|
+
spyOn(service as any, 'logQuestion');
|
|
223
|
+
spyOn(service as any, 'logAnswer');
|
|
224
|
+
spyOn(service, 'resolveMessage').and.returnValue(Promise.resolve('Test response'));
|
|
225
|
+
|
|
226
|
+
const result = await service.requestSimpleMessage({
|
|
227
|
+
message: 'Test question',
|
|
228
|
+
issuer: 'test-issuer',
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(result).toBe('Test response');
|
|
232
|
+
expect((service as any).logQuestion).toHaveBeenCalled();
|
|
233
|
+
expect((service as any).logAnswer).toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('| should add user message to conversation', async () => {
|
|
237
|
+
const conversation: DyFM_AI_Message[] = [];
|
|
238
|
+
spyOn(service, 'resolveMessage').and.returnValue(Promise.resolve('Test response'));
|
|
239
|
+
|
|
240
|
+
await service.requestSimpleMessage({
|
|
241
|
+
message: 'Test question',
|
|
242
|
+
conversation: conversation,
|
|
243
|
+
issuer: 'test-issuer',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expect(conversation.length).toBe(1);
|
|
247
|
+
expect(conversation[0].role).toBe(DyFM_AI_MessageRole.user);
|
|
248
|
+
expect(conversation[0].content).toBe('Test question');
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('| resolveMessage', () => {
|
|
253
|
+
it('| should return string answer when getFullResponse is false', async () => {
|
|
254
|
+
const conversation: DyFM_AI_Message[] = [
|
|
255
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
256
|
+
];
|
|
257
|
+
|
|
258
|
+
const result = await service.resolveMessage({
|
|
259
|
+
conversation: conversation,
|
|
260
|
+
issuer: 'test-issuer',
|
|
261
|
+
getFullResponse: false,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
expect(result).toBe('Test response');
|
|
265
|
+
expect(mockChatCompletionsCreate).toHaveBeenCalled();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('| should return full ChatCompletion when getFullResponse is true', async () => {
|
|
269
|
+
const conversation: DyFM_AI_Message[] = [
|
|
270
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
const fullResponse: ChatCompletion = {
|
|
274
|
+
id: 'chatcmpl-123',
|
|
275
|
+
object: 'chat.completion',
|
|
276
|
+
created: 1234567890,
|
|
277
|
+
model: 'gpt-4o-mini',
|
|
278
|
+
choices: [
|
|
279
|
+
{
|
|
280
|
+
index: 0,
|
|
281
|
+
message: {
|
|
282
|
+
role: 'assistant',
|
|
283
|
+
content: 'Test response',
|
|
284
|
+
refusal: null,
|
|
285
|
+
},
|
|
286
|
+
logprobs: null,
|
|
287
|
+
finish_reason: 'stop',
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
usage: {
|
|
291
|
+
prompt_tokens: 10,
|
|
292
|
+
completion_tokens: 5,
|
|
293
|
+
total_tokens: 15,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
mockChatCompletionsCreate.and.returnValue(fullResponse);
|
|
298
|
+
|
|
299
|
+
const result = await service.resolveMessage({
|
|
300
|
+
conversation: conversation,
|
|
301
|
+
issuer: 'test-issuer',
|
|
302
|
+
getFullResponse: true,
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(result).toEqual(fullResponse);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('| should add system message to conversation', async () => {
|
|
309
|
+
const conversation: DyFM_AI_Message[] = [
|
|
310
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
spyOn(service as any, 'getDefaultSystemMessage').and.returnValue({
|
|
314
|
+
role: DyFM_AI_MessageRole.system,
|
|
315
|
+
content: 'System prompt',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
await service.resolveMessage({
|
|
319
|
+
conversation: conversation,
|
|
320
|
+
issuer: 'test-issuer',
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
expect(conversation[0].role).toBe(DyFM_AI_MessageRole.system);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('| should handle API errors', async () => {
|
|
327
|
+
const conversation: DyFM_AI_Message[] = [
|
|
328
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
329
|
+
];
|
|
330
|
+
|
|
331
|
+
mockChatCompletionsCreate.and.throwError(new Error('API Error'));
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await service.resolveMessage({
|
|
335
|
+
conversation: conversation,
|
|
336
|
+
issuer: 'test-issuer',
|
|
337
|
+
});
|
|
338
|
+
fail('Should have thrown an error');
|
|
339
|
+
} catch (error) {
|
|
340
|
+
expect(error).toBeInstanceOf(DyFM_Error);
|
|
341
|
+
expect((error as DyFM_Error)._errorCode).toContain('DyNTS-OLSB-RM0');
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe('| getMessageCreateInput', () => {
|
|
347
|
+
it('| should create input with default settings', () => {
|
|
348
|
+
const conversation: DyFM_AI_Message[] = [
|
|
349
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
350
|
+
];
|
|
351
|
+
|
|
352
|
+
const result = (service as any).getMessageCreateInput({
|
|
353
|
+
conversation: conversation,
|
|
354
|
+
issuer: 'test-issuer',
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
expect(result.model).toBe(DyFM_OAI_Model.gpt4o_mini);
|
|
358
|
+
expect(result.messages).toBeDefined();
|
|
359
|
+
expect(result.temperature).toBe(0.7);
|
|
360
|
+
expect(result.max_completion_tokens).toBe(1000);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('| should use provided settings when available', () => {
|
|
364
|
+
const conversation: DyFM_AI_Message[] = [
|
|
365
|
+
{ role: DyFM_AI_MessageRole.user, content: 'Test question' },
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
const customSettings: DyFM_OAI_CallSettings = {
|
|
369
|
+
useModel: DyFM_OAI_Model.gpt4o,
|
|
370
|
+
temperature: 0.9,
|
|
371
|
+
maxTokens: 2000,
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const result = (service as any).getMessageCreateInput({
|
|
375
|
+
conversation: conversation,
|
|
376
|
+
issuer: 'test-issuer',
|
|
377
|
+
settings: customSettings,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
expect(result.model).toBe(DyFM_OAI_Model.gpt4o);
|
|
381
|
+
expect(result.temperature).toBe(0.9);
|
|
382
|
+
expect(result.max_completion_tokens).toBe(2000);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('| should handle errors', () => {
|
|
386
|
+
// Test that the method handles edge cases gracefully
|
|
387
|
+
// Passing null conversation may or may not throw depending on implementation
|
|
388
|
+
try {
|
|
389
|
+
const result = (service as any).getMessageCreateInput({
|
|
390
|
+
conversation: null as any,
|
|
391
|
+
issuer: 'test-issuer',
|
|
392
|
+
});
|
|
393
|
+
// If it doesn't throw, verify it returns something
|
|
394
|
+
expect(result).toBeDefined();
|
|
395
|
+
} catch (error) {
|
|
396
|
+
// If it throws, it should be a DyFM_Error
|
|
397
|
+
expect(error).toBeInstanceOf(DyFM_Error);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
describe('| testConnection', () => {
|
|
403
|
+
it('| should return true when connection is successful', async () => {
|
|
404
|
+
const result = await service.testConnection('test-issuer');
|
|
405
|
+
|
|
406
|
+
expect(result).toBe(true);
|
|
407
|
+
expect(mockModelsList).toHaveBeenCalled();
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('| should return false when connection fails', async () => {
|
|
411
|
+
const logSpy = spyOn(DyFM_Log, 'error');
|
|
412
|
+
mockModelsList.and.throwError(new Error('Connection failed'));
|
|
413
|
+
|
|
414
|
+
const result = await service.testConnection('test-issuer');
|
|
415
|
+
|
|
416
|
+
expect(result).toBe(false);
|
|
417
|
+
expect(logSpy).toHaveBeenCalled();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe('| properties', () => {
|
|
422
|
+
it('| should have aiProvider property', () => {
|
|
423
|
+
expect(service.aiProvider).toBeDefined();
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('| should have capabilities property', () => {
|
|
427
|
+
expect(service.capabilities).toBeDefined();
|
|
428
|
+
expect(service.capabilities.chat).toBe(true);
|
|
429
|
+
expect(service.capabilities.embeddings).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it('| should have predefinedRequests property', () => {
|
|
433
|
+
expect(service.predefinedRequests).toBeDefined();
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|