@futdevpro/nts-dynamo 1.15.15 → 1.15.16
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/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,616 +1,616 @@
|
|
|
1
|
-
import { OpenAI } from 'openai';
|
|
2
|
-
|
|
3
|
-
import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
|
|
4
|
-
import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_getLocalStackLocation, DyFM_Log, DyFM_notNull, DyFM_Object, DyFM_Array } from '@futdevpro/fsm-dynamo';
|
|
5
|
-
import { DyFM_AI_Message } from '@futdevpro/fsm-dynamo/ai';
|
|
6
|
-
|
|
7
|
-
import { DyNTS_global_settings } from '../../../../../_collections/global-settings.const';
|
|
8
|
-
import { ChatCompletion } from 'openai/resources';
|
|
9
|
-
import { ChatCompletionCreateParamsBase, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
10
|
-
import { DyFM_AI_MessageRole } from '@futdevpro/fsm-dynamo/ai';
|
|
11
|
-
import { DyNTS_OAI_LLM_Predefined_Requests } from '../_models/interfaces/oai-llm-predefined-requests.interface';
|
|
12
|
-
import { DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
|
|
13
|
-
import { DyNTS_OAI_global_settings } from '../_collections/oai-global-settings.const';
|
|
14
|
-
import { DyNTS_AI_LLMChat_ServiceBase } from '../../../_services/ai-llm-chat.service-base';
|
|
15
|
-
import {
|
|
16
|
-
DyFM_AI_ConversationBase_Input,
|
|
17
|
-
DyFM_AI_ConversationSelect_Input,
|
|
18
|
-
DyFM_AI_ConversationGenericSelect_Input,
|
|
19
|
-
DyFM_AI_ConversationMultiSelect_Input,
|
|
20
|
-
DyFM_AI_ConversationGenericMultiSelect_Input,
|
|
21
|
-
DyFM_AI_ConversationJSONKeysDescription_Input,
|
|
22
|
-
DyFM_AI_ConversationJSONExactKeys_Input,
|
|
23
|
-
} from '../../../_models/ai-input-interfaces';
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* {
|
|
28
|
-
* organization: 'org-XY',
|
|
29
|
-
* apiKey: 'sk-XY',
|
|
30
|
-
* project: 'proj_XY',
|
|
31
|
-
* }
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
// Di Dictionary DiModel DiEz DiAz
|
|
35
|
-
|
|
36
|
-
export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase implements DyNTS_AI_LLMChat_ServiceBase {
|
|
37
|
-
|
|
38
|
-
// History management
|
|
39
|
-
/* private conversationHistories: Map<string, DyFM_AI_Message[]> = new Map(); */
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Hozzáad egy üzenetet a conversation history-hoz
|
|
43
|
-
*
|
|
44
|
-
* Adds a message to conversation history
|
|
45
|
-
*/
|
|
46
|
-
/* addMessageToHistory(message: DyFM_AI_Message, issuer: string): void {
|
|
47
|
-
if (!this.conversationHistories.has(issuer)) {
|
|
48
|
-
this.conversationHistories.set(issuer, []);
|
|
49
|
-
}
|
|
50
|
-
this.conversationHistories.get(issuer).push(message);
|
|
51
|
-
} */
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Törli a conversation history-t
|
|
55
|
-
*
|
|
56
|
-
* Clears conversation history
|
|
57
|
-
*/
|
|
58
|
-
/* clearHistory(issuer: string): void {
|
|
59
|
-
this.conversationHistories.delete(issuer);
|
|
60
|
-
} */
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Visszaadja a conversation history-t
|
|
64
|
-
*
|
|
65
|
-
* Gets conversation history
|
|
66
|
-
*/
|
|
67
|
-
/* getHistory(issuer: string): DyFM_AI_Message[] {
|
|
68
|
-
return this.conversationHistories.get(issuer) || [];
|
|
69
|
-
} */
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Converts generic AI messages to OpenAI-specific format
|
|
73
|
-
*
|
|
74
|
-
* Az generic AI üzeneteket OpenAI-specifikus formátumra alakítja át
|
|
75
|
-
*/
|
|
76
|
-
/* private convertToOAIMessages(messages: DyFM_AI_Message[]): DyFM_AI_Message[] {
|
|
77
|
-
return messages;
|
|
78
|
-
} */
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Asks the AI to answer a yes/no question
|
|
82
|
-
*
|
|
83
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.request} to ask the question,
|
|
84
|
-
* and the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.upperCaseYes} to check the answer
|
|
85
|
-
*/
|
|
86
|
-
async requestYesNoInConversation(set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>): Promise<boolean> {
|
|
87
|
-
set.message += this.predefinedRequests.yesNo.request;
|
|
88
|
-
|
|
89
|
-
//this.logQuestion(set);
|
|
90
|
-
|
|
91
|
-
const answer: string = await this.requestSimpleMessageInConversation(set);
|
|
92
|
-
|
|
93
|
-
return this.convertAnswerToBoolean(answer);
|
|
94
|
-
}
|
|
95
|
-
//askYesNoQuestionInConversation: typeof this.yesNoQuestionInConversation = this.yesNoQuestionInConversation;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Asks the AI to answer a simple question
|
|
99
|
-
*
|
|
100
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.simpleQuestion} to ask the question
|
|
101
|
-
*/
|
|
102
|
-
/* async requestSimpleQuestionInConversation(
|
|
103
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
104
|
-
): Promise<string> {
|
|
105
|
-
this.logQuestion(set);
|
|
106
|
-
|
|
107
|
-
return await this.getQuestionAnswerInConversation(set);
|
|
108
|
-
} */
|
|
109
|
-
//askSimpleQuestionInConversation: typeof this.simpleQuestionInConversation = this.simpleQuestionInConversation;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Asks the AI to answer a percentage question
|
|
113
|
-
*
|
|
114
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.percentageOnly} to ask the question
|
|
115
|
-
*/
|
|
116
|
-
async requestPercentageInConversation(
|
|
117
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
118
|
-
): Promise<number> {
|
|
119
|
-
set.message += this.predefinedRequests.percentageOnly;
|
|
120
|
-
|
|
121
|
-
//this.logQuestion(set);
|
|
122
|
-
|
|
123
|
-
const answer: string = await this.requestSimpleMessageInConversation(set);
|
|
124
|
-
|
|
125
|
-
return this.convertAnswerToNumber(answer, set.message);
|
|
126
|
-
}
|
|
127
|
-
//askPercentageQuestionInConversation: typeof this.percentageQuestionInConversation = this.percentageQuestionInConversation;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Asks the AI to select one of the options from the list
|
|
132
|
-
*
|
|
133
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
|
|
134
|
-
*/
|
|
135
|
-
async requestSelectInConversation<T>(
|
|
136
|
-
set: DyFM_AI_ConversationGenericSelect_Input<T, DyFM_OAI_CallSettings>
|
|
137
|
-
): Promise<T | { unparsableResult: string }> {
|
|
138
|
-
// replace the {{DyNTS_selectOptions}} with the list of options
|
|
139
|
-
const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
|
|
140
|
-
'{{DyNTS_selectOptions}}',
|
|
141
|
-
this.getTextListAsText(this.stringifySelectOptions(set.selectFrom))
|
|
142
|
-
);
|
|
143
|
-
set.message += selectQuestionAddition;
|
|
144
|
-
|
|
145
|
-
//this.logQuestion(set);
|
|
146
|
-
|
|
147
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
148
|
-
|
|
149
|
-
return this.convertAnswerToSelectOption<T>(answer, set.message, set.selectFrom);
|
|
150
|
-
}
|
|
151
|
-
//askSelectQuestionInConversation: typeof this.selectQuestionInConversation = this.selectQuestionInConversation;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Asks the AI to select one of the options from the list
|
|
155
|
-
* Similar to {@link askSelectQuestion},
|
|
156
|
-
* but with a more generic approach that can be used for objects
|
|
157
|
-
*
|
|
158
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
|
|
159
|
-
*/
|
|
160
|
-
/* async requestSelectInConversation<T>(
|
|
161
|
-
set: DyFM_AI_ConversationGenericSelect_Input<T, DyFM_OAI_CallSettings>
|
|
162
|
-
): Promise<T | { unparsableResult: string }> {
|
|
163
|
-
const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
|
|
164
|
-
'{{DyNTS_selectOptions}}',
|
|
165
|
-
this.getTextListAsText(set.selectFrom.map(item => `"${JSON.stringify(item)}"`))
|
|
166
|
-
);
|
|
167
|
-
set.message += selectQuestionAddition;
|
|
168
|
-
|
|
169
|
-
this.logQuestion(set);
|
|
170
|
-
|
|
171
|
-
const answer = await this.getQuestionAnswerInConversation(set);
|
|
172
|
-
|
|
173
|
-
return DyFM_Object.safeParseJSON<T>(answer);
|
|
174
|
-
} */
|
|
175
|
-
//askRequestSelectInConversation: typeof this.requestSelectInConversation = this.requestSelectInConversation;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Asks the AI to select one or more of the options from the list
|
|
179
|
-
*
|
|
180
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
|
|
181
|
-
*/
|
|
182
|
-
/* async requestMultiselectInConversation(set: DyFM_AI_ConversationMultiSelect_Input): Promise<string[]> {
|
|
183
|
-
const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
|
|
184
|
-
'{{DyNTS_selectOptions}}',
|
|
185
|
-
this.getTextListAsText(set.options)
|
|
186
|
-
);
|
|
187
|
-
set.message += selectQuestionAddition;
|
|
188
|
-
|
|
189
|
-
let answer = await this.getQuestionAnswerInConversation(set);
|
|
190
|
-
|
|
191
|
-
answer = answer.toLocaleUpperCase();
|
|
192
|
-
|
|
193
|
-
const result: string[] = [];
|
|
194
|
-
|
|
195
|
-
for (const item of set.options) {
|
|
196
|
-
if (answer.includes(item.toLocaleUpperCase())) {
|
|
197
|
-
result.push(item);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return result;
|
|
202
|
-
} */
|
|
203
|
-
//askMultipleSelectQuestionWithOptionsInConversation: typeof this.multipleSelectQuestionWithOptionsInConversation = this.multipleSelectQuestionWithOptionsInConversation;
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Asks the AI to select one or more of the options from the list
|
|
207
|
-
* Similar to {@link askMultipleSelectQuestionWithOptions},
|
|
208
|
-
* but with a more generic approach that can be used for objects
|
|
209
|
-
*
|
|
210
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
|
|
211
|
-
*/
|
|
212
|
-
async requestMultiselectInConversation<T>(
|
|
213
|
-
set: DyFM_AI_ConversationGenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
|
|
214
|
-
): Promise<T[] | { unparsableResult: string }> {
|
|
215
|
-
const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
|
|
216
|
-
'{{DyNTS_selectOptions}}',
|
|
217
|
-
this.getTextListAsText(this.stringifySelectOptions(set.options))
|
|
218
|
-
);
|
|
219
|
-
set.message += selectQuestionAddition;
|
|
220
|
-
|
|
221
|
-
//this.logQuestion(set);
|
|
222
|
-
|
|
223
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
224
|
-
|
|
225
|
-
return this.convertAnswerToList<T>(answer, set.message);
|
|
226
|
-
}
|
|
227
|
-
//askRequestMultipleSelectInConversation: typeof this.requestMultipleSelectInConversation = this.requestMultipleSelectInConversation;
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Asks the AI to answer a question that must result a JSON object
|
|
231
|
-
*
|
|
232
|
-
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
233
|
-
*
|
|
234
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequest} to ask the question
|
|
235
|
-
*
|
|
236
|
-
* (uses {@link DyFM_safeParseJSON})
|
|
237
|
-
*/
|
|
238
|
-
async requestJSONInConversation<T = any>(
|
|
239
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
240
|
-
): Promise<T | { unparsableResult: string }> {
|
|
241
|
-
set.message += this.predefinedRequests.jsonRequest;
|
|
242
|
-
|
|
243
|
-
//this.logQuestion(set);
|
|
244
|
-
|
|
245
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
246
|
-
|
|
247
|
-
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
248
|
-
}
|
|
249
|
-
//askJsonQuestionInConversation: typeof this.jsonQuestionInConversation = this.jsonQuestionInConversation;
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Asks the AI to answer a question that must result a JSON object with specific key descriptions
|
|
253
|
-
*
|
|
254
|
-
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
255
|
-
*
|
|
256
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
|
|
257
|
-
*
|
|
258
|
-
* (uses {@link DyFM_safeParseJSON})
|
|
259
|
-
*/
|
|
260
|
-
/* async requestJSONInConversationWithKeysDescription<T = any>(
|
|
261
|
-
set: DyFM_AI_ConversationJSONKeysDescription_Input<DyFM_OAI_CallSettings>
|
|
262
|
-
): Promise<T | { unparsableResult: string }> {
|
|
263
|
-
return this.jsonQuestionWithKeysDescriptionInConversation<any>(set);
|
|
264
|
-
} */
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Asks the AI to answer a question that must result a JSON object with specific key descriptions
|
|
268
|
-
*
|
|
269
|
-
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
270
|
-
*
|
|
271
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
|
|
272
|
-
*
|
|
273
|
-
* (uses {@link DyFM_safeParseJSON})
|
|
274
|
-
*/
|
|
275
|
-
async requestJSONInConversationWithKeysDescription<T = any>(
|
|
276
|
-
set: DyFM_AI_ConversationJSONKeysDescription_Input
|
|
277
|
-
): Promise<T | { unparsableResult: string }> {
|
|
278
|
-
const jsonRequestWithKeysDescription = this.predefinedRequests.jsonRequestWithKeysDescription.replace(
|
|
279
|
-
'{{DyNTS_jsonKeysDescription}}',
|
|
280
|
-
set.keysDescription
|
|
281
|
-
);
|
|
282
|
-
set.message += jsonRequestWithKeysDescription;
|
|
283
|
-
|
|
284
|
-
//this.logQuestion(set);
|
|
285
|
-
|
|
286
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
287
|
-
|
|
288
|
-
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
289
|
-
}
|
|
290
|
-
//askJsonQuestionWithKeysDescriptionInConversation: typeof this.jsonQuestionWithKeysDescriptionInConversation = this.jsonQuestionWithKeysDescriptionInConversation;
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Asks the AI to answer a question that must result a JSON object with specific keys
|
|
294
|
-
*
|
|
295
|
-
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
296
|
-
*
|
|
297
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
|
|
298
|
-
*
|
|
299
|
-
* (uses {@link DyFM_safeParseJSON})
|
|
300
|
-
*/
|
|
301
|
-
/* async requestJSONInConversationWithExactKeys(set: DyFM_AI_ConversationJSONExactKeys_Input): Promise<object> {
|
|
302
|
-
const result = await this.jsonQuestionWithExactKeysInConversation<any>(set);
|
|
303
|
-
return typeof result === 'object' ? result : {};
|
|
304
|
-
} */
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Asks the AI to answer a question that must result a JSON object with specific keys
|
|
308
|
-
*
|
|
309
|
-
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
310
|
-
*
|
|
311
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
|
|
312
|
-
*
|
|
313
|
-
* (uses {@link DyFM_safeParseJSON})
|
|
314
|
-
*/
|
|
315
|
-
async requestJSONInConversationWithExactKeys<T = any>(
|
|
316
|
-
set: DyFM_AI_ConversationJSONExactKeys_Input
|
|
317
|
-
): Promise<T | { unparsableResult: string }> {
|
|
318
|
-
const jsonRequestWithExactKeys = this.predefinedRequests.jsonRequestWithExactKeys.replace(
|
|
319
|
-
'{{DyNTS_jsonKeys}}',
|
|
320
|
-
this.getTextListAsText(set.keys)
|
|
321
|
-
);
|
|
322
|
-
set.message += jsonRequestWithExactKeys;
|
|
323
|
-
|
|
324
|
-
//this.logQuestion(set);
|
|
325
|
-
|
|
326
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
327
|
-
|
|
328
|
-
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
329
|
-
}
|
|
330
|
-
//askJsonQuestionWithExactKeysInConversation: typeof this.jsonQuestionWithExactKeysInConversation = this.jsonQuestionWithExactKeysInConversation;
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Asks the AI to answer a question that must result a list of strings
|
|
334
|
-
*
|
|
335
|
-
* If the answer is not a valid JSON list, it will return the answer as a single item in an array
|
|
336
|
-
*
|
|
337
|
-
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.listRequest} to ask the question
|
|
338
|
-
*
|
|
339
|
-
* (uses {@link DyFM_Object.safeParseList})
|
|
340
|
-
*/
|
|
341
|
-
async requestListInConversation<T = any>(
|
|
342
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
343
|
-
): Promise<T[] | { unparsableResult: string }> {
|
|
344
|
-
set.message += this.predefinedRequests.listRequest;
|
|
345
|
-
|
|
346
|
-
//this.logQuestion(set);
|
|
347
|
-
|
|
348
|
-
const answer = await this.requestSimpleMessageInConversation(set);
|
|
349
|
-
|
|
350
|
-
return this.convertAnswerToList<T>(answer, set.message);
|
|
351
|
-
}
|
|
352
|
-
//askListQuestionInConversation: typeof this.listQuestionInConversation = this.listQuestionInConversation;
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Asks the AI to answer a question
|
|
356
|
-
*
|
|
357
|
-
* Uses the {@link resolveSimpleUserMessage}
|
|
358
|
-
*/
|
|
359
|
-
/* async getQuestionAnswerInConversation(
|
|
360
|
-
conversation: DyFM_AI_Message[],
|
|
361
|
-
question: string,
|
|
362
|
-
issuer: string,
|
|
363
|
-
debugLog?: boolean,
|
|
364
|
-
messageSettings: DyFM_OAI_CallSettings = this.defaultSettings
|
|
365
|
-
): Promise<string> {
|
|
366
|
-
const answer = await this.resolveSimpleUserMessageInConversation(
|
|
367
|
-
conversation,
|
|
368
|
-
question,
|
|
369
|
-
issuer,
|
|
370
|
-
messageSettings,
|
|
371
|
-
) as Promise<string>;
|
|
372
|
-
|
|
373
|
-
if (debugLog) {
|
|
374
|
-
console.log(' - ', answer);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return answer;
|
|
378
|
-
} */
|
|
379
|
-
|
|
380
|
-
/* async requestSimpleQuestionInConversation(set: DyFM_AI_ConversationMessage_Input): Promise<string> {
|
|
381
|
-
return await this.getAnswerInConversation({
|
|
382
|
-
...set,
|
|
383
|
-
newMessage: set.message,
|
|
384
|
-
});
|
|
385
|
-
} */
|
|
386
|
-
/* getQuestionAnswerInConversation = this.getAnswerInConversation; */
|
|
387
|
-
//getQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
|
|
388
|
-
//askQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
|
|
389
|
-
//getConversationAnswer: typeof this.getAnswerInConversation = this.getAnswerInConversation;
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Asks the AI to answer a question using the whole conversation
|
|
393
|
-
* (If you want to use only the conversation, without adding a new message,
|
|
394
|
-
* use directly the {@link resolveConversation})
|
|
395
|
-
*
|
|
396
|
-
* Uses the {@link resolveConversation}
|
|
397
|
-
*/
|
|
398
|
-
async requestSimpleMessageInConversation(set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>): Promise<string> {
|
|
399
|
-
// Convert generic AI messages to OpenAI-specific format
|
|
400
|
-
//const oaiConversation: DyFM_AI_Message[] = /* this.convertToOAIMessages(set.conversation) */ set.conversation;
|
|
401
|
-
|
|
402
|
-
if (set.message) {
|
|
403
|
-
set.conversation.push({
|
|
404
|
-
role: DyFM_AI_MessageRole.user,
|
|
405
|
-
content: set.message,
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const answer: string = await this.resolveConversation({
|
|
410
|
-
...set,
|
|
411
|
-
getFullResponse: false,
|
|
412
|
-
}) as string;
|
|
413
|
-
|
|
414
|
-
this.logAnswer(answer);
|
|
415
|
-
|
|
416
|
-
return answer;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/* async resolveConversationMessage(
|
|
420
|
-
set: {
|
|
421
|
-
conversation: DyFM_AI_Message[],
|
|
422
|
-
issuer: string,
|
|
423
|
-
settings?: DyFM_OAI_CallSettings,
|
|
424
|
-
getFullResponse?: boolean,
|
|
425
|
-
debugLog?: boolean,
|
|
426
|
-
* this is used to readably replace too long contents to eg '...' in logs
|
|
427
|
-
replaceThisInLog?: string,
|
|
428
|
-
}
|
|
429
|
-
): Promise<string> {
|
|
430
|
-
return await this.resolveConversation(set) as string;
|
|
431
|
-
} */
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Resolves a conversation
|
|
435
|
-
*
|
|
436
|
-
* Uses the {@link getMessageCreateInput}
|
|
437
|
-
*/
|
|
438
|
-
async resolveConversation(
|
|
439
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
440
|
-
): Promise<string | ChatCompletion> {
|
|
441
|
-
try {
|
|
442
|
-
if (!set.conversation.some(message => message.role === DyFM_AI_MessageRole.system)) {
|
|
443
|
-
/* throw new DyFM_Error({
|
|
444
|
-
...this.getDefaultErrorSettings(
|
|
445
|
-
'resolveConversation',
|
|
446
|
-
new Error('System message found in conversation'),
|
|
447
|
-
set.issuer
|
|
448
|
-
),
|
|
449
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-RC1`,
|
|
450
|
-
}); */
|
|
451
|
-
/* DyFM_Log.error('System message found in conversation', {
|
|
452
|
-
conversation: set.conversation,
|
|
453
|
-
});
|
|
454
|
-
} else { */
|
|
455
|
-
set.conversation.unshift(this.getDefaultSystemMessage(set.settings));
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// conversation shortening
|
|
459
|
-
const shortenedConversation = this.shortenConversation(set);
|
|
460
|
-
|
|
461
|
-
this.validateConversation(shortenedConversation);
|
|
462
|
-
|
|
463
|
-
//this.logQuestion(set);
|
|
464
|
-
|
|
465
|
-
this.logConversation({
|
|
466
|
-
...set,
|
|
467
|
-
conversation: shortenedConversation,
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
const result: ChatCompletion = await this.openai.chat.completions.create(
|
|
471
|
-
this.getMessageCreateInput({
|
|
472
|
-
...set,
|
|
473
|
-
conversation: shortenedConversation,
|
|
474
|
-
})
|
|
475
|
-
) as ChatCompletion;
|
|
476
|
-
|
|
477
|
-
if (set.getFullResponse) {
|
|
478
|
-
return result;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return result.choices[0].message.content;
|
|
482
|
-
} catch (error) {
|
|
483
|
-
throw new DyFM_Error({
|
|
484
|
-
...this.getDefaultErrorSettings('resolveConversation', error, set.issuer),
|
|
485
|
-
|
|
486
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-RC0`,
|
|
487
|
-
});
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
//resolveSimpleUserMessageInConversation: typeof this.resolveConversation = this.resolveConversation;
|
|
491
|
-
|
|
492
|
-
protected shortenConversation(
|
|
493
|
-
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
494
|
-
): DyFM_AI_Message[] {
|
|
495
|
-
try {
|
|
496
|
-
// Step 1: Clone the conversation to avoid mutating the original
|
|
497
|
-
const clonedConversation: DyFM_AI_Message[] = DyFM_Object.clone(set.conversation);
|
|
498
|
-
|
|
499
|
-
// Step 2: Separate system messages from user/assistant messages
|
|
500
|
-
// System messages are kept and not shortened
|
|
501
|
-
const systemMessages: DyFM_AI_Message[] = clonedConversation.filter(
|
|
502
|
-
(message: DyFM_AI_Message): boolean => message.role === DyFM_AI_MessageRole.system
|
|
503
|
-
);
|
|
504
|
-
|
|
505
|
-
// Step 3: Calculate system messages length as JSON string
|
|
506
|
-
// ⚠️ ISSUE: This measures JSON string length, not actual token count
|
|
507
|
-
// ⚠️ ISSUE: Doesn't account for message structure overhead (role, content keys, formatting)
|
|
508
|
-
const systemMessagesStringLength: number = JSON.stringify(systemMessages).length;
|
|
509
|
-
|
|
510
|
-
// Step 4: Extract only content strings from non-system messages
|
|
511
|
-
// ⚠️ ISSUE: Only measuring content strings, not full message structure
|
|
512
|
-
// ⚠️ ISSUE: OpenAI counts tokens for full message format: {"role": "...", "content": "..."}
|
|
513
|
-
const msgs: string[] = clonedConversation.filter(
|
|
514
|
-
(message: DyFM_AI_Message): boolean => message.role !== DyFM_AI_MessageRole.system
|
|
515
|
-
).map((message: DyFM_AI_Message): string => message.content);
|
|
516
|
-
|
|
517
|
-
// Step 5: Stringify the content array to measure total length
|
|
518
|
-
// ⚠️ ISSUE: This is character count, not token count - ratio varies (1 token ≈ 1-4 chars)
|
|
519
|
-
let stringifiedMessages: string = JSON.stringify(msgs);
|
|
520
|
-
|
|
521
|
-
// Step 6: Log initial state if debug is enabled
|
|
522
|
-
if (this._debugLog || set.debugLog) {
|
|
523
|
-
DyFM_Log.info(
|
|
524
|
-
' DyNTS_OAI_LLMChat_ServiceBase: before shortening conversation', {
|
|
525
|
-
stringifiedMessagesLength: stringifiedMessages.length,
|
|
526
|
-
conversationLength: clonedConversation.length,
|
|
527
|
-
lastMessage: DyFM_Array.last(clonedConversation)?.content,
|
|
528
|
-
}
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Step 7: Initialize tracking variables
|
|
533
|
-
let removedMessagesCount: number = 0;
|
|
534
|
-
let lastStringifiedMessagesLength: number = stringifiedMessages.length;
|
|
535
|
-
|
|
536
|
-
// Step 8: Loop to remove messages until under character limit
|
|
537
|
-
// ⚠️ ISSUE: Comparing character count to token limit - different units!
|
|
538
|
-
// ⚠️ ISSUE: maxMessagesStringLength (120k chars) may not safely map to 128k tokens
|
|
539
|
-
// ⚠️ ISSUE: Condition allows single very long message to remain (length > 1)
|
|
540
|
-
while (
|
|
541
|
-
(stringifiedMessages.length + systemMessagesStringLength) > DyNTS_OAI_global_settings.maxMessagesStringLength &&
|
|
542
|
-
clonedConversation.length > 1
|
|
543
|
-
) {
|
|
544
|
-
// Step 8a: Remove oldest message from full conversation
|
|
545
|
-
clonedConversation.splice(0, 1);
|
|
546
|
-
|
|
547
|
-
// Step 8b: Remove corresponding content from msgs array
|
|
548
|
-
// ⚠️ CRITICAL BUG: Always removes from msgs, even if removed message was a system message!
|
|
549
|
-
// ⚠️ This causes array desynchronization - msgs and clonedConversation get out of sync
|
|
550
|
-
msgs.splice(0, 1);
|
|
551
|
-
|
|
552
|
-
removedMessagesCount++;
|
|
553
|
-
|
|
554
|
-
// Step 8c: Recalculate stringified length after removal
|
|
555
|
-
stringifiedMessages = JSON.stringify(msgs);
|
|
556
|
-
lastStringifiedMessagesLength = stringifiedMessages.length;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// Step 9: Log final state if debug is enabled
|
|
560
|
-
if (this._debugLog || set.debugLog) {
|
|
561
|
-
DyFM_Log.info(
|
|
562
|
-
' DyNTS_OAI_LLMChat_ServiceBase: after shortening conversation', {
|
|
563
|
-
removedMessagesCount: removedMessagesCount,
|
|
564
|
-
lastStringifiedMessagesLength: lastStringifiedMessagesLength,
|
|
565
|
-
lastMessage: DyFM_Array.last(clonedConversation)?.content,
|
|
566
|
-
localStackLocation: DyFM_getLocalStackLocation(),
|
|
567
|
-
}
|
|
568
|
-
);
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// Step 10: Safety check - ensure we didn't remove everything
|
|
572
|
-
if (!clonedConversation.length) {
|
|
573
|
-
DyFM_Log.error('No conversation messages (left)', {
|
|
574
|
-
/* conversation: DyFM_Object.clone(conversation), */
|
|
575
|
-
conversationLength: set.conversation.length,
|
|
576
|
-
clonedConversation: DyFM_Object.clone(clonedConversation),
|
|
577
|
-
});
|
|
578
|
-
throw new Error('No conversation messages (left)');
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Step 11: Reconstruct conversation: system messages first, then shortened non-system messages
|
|
582
|
-
// ⚠️ ISSUE: clonedConversation may still contain system messages mixed in
|
|
583
|
-
// ⚠️ This could result in duplicate system messages in the final array
|
|
584
|
-
return [ ...systemMessages, ...clonedConversation ];
|
|
585
|
-
} catch (error) {
|
|
586
|
-
DyFM_Error.logSimple('❌❌ Error shortening conversation:', error);
|
|
587
|
-
|
|
588
|
-
throw new DyFM_Error({
|
|
589
|
-
...this.getDefaultErrorSettings('shortenConversation', error, set.issuer),
|
|
590
|
-
|
|
591
|
-
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-SC0`,
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Kérdez egy kérdést és JSON választ vár exact keys-szel
|
|
598
|
-
*
|
|
599
|
-
* Asks a question and expects JSON response with exact keys
|
|
600
|
-
*/
|
|
601
|
-
/* async requestJSONInConversationWithExactKeys<T>(
|
|
602
|
-
set: DyFM_AI_ConversationJSONExactKeys_Input
|
|
603
|
-
): Promise<T> {
|
|
604
|
-
const answer = await this.jsonQuestionWithExactKeysInConversation<any>(set);
|
|
605
|
-
|
|
606
|
-
if ('unparsableResult' in answer) {
|
|
607
|
-
throw new DyFM_Error({
|
|
608
|
-
message: 'Invalid JSON response from AI',
|
|
609
|
-
additionalContent: { answer },
|
|
610
|
-
userMessage: 'Failed to parse AI response'
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
return answer as T;
|
|
615
|
-
} */
|
|
1
|
+
import { OpenAI } from 'openai';
|
|
2
|
+
|
|
3
|
+
import { DyFM_OAI_Settings, DyFM_OAI_Model, DyFM_OAI_CallSettings } from '@futdevpro/fsm-dynamo/ai/open-ai';
|
|
4
|
+
import { DyFM_AnyError, DyFM_Error, DyFM_Error_Settings, DyFM_getLocalStackLocation, DyFM_Log, DyFM_notNull, DyFM_Object, DyFM_Array } from '@futdevpro/fsm-dynamo';
|
|
5
|
+
import { DyFM_AI_Message } from '@futdevpro/fsm-dynamo/ai';
|
|
6
|
+
|
|
7
|
+
import { DyNTS_global_settings } from '../../../../../_collections/global-settings.const';
|
|
8
|
+
import { ChatCompletion } from 'openai/resources';
|
|
9
|
+
import { ChatCompletionCreateParamsBase, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
10
|
+
import { DyFM_AI_MessageRole } from '@futdevpro/fsm-dynamo/ai';
|
|
11
|
+
import { DyNTS_OAI_LLM_Predefined_Requests } from '../_models/interfaces/oai-llm-predefined-requests.interface';
|
|
12
|
+
import { DyNTS_OAI_LLM_ServiceBase } from './oai-llm.service-base';
|
|
13
|
+
import { DyNTS_OAI_global_settings } from '../_collections/oai-global-settings.const';
|
|
14
|
+
import { DyNTS_AI_LLMChat_ServiceBase } from '../../../_services/ai-llm-chat.service-base';
|
|
15
|
+
import {
|
|
16
|
+
DyFM_AI_ConversationBase_Input,
|
|
17
|
+
DyFM_AI_ConversationSelect_Input,
|
|
18
|
+
DyFM_AI_ConversationGenericSelect_Input,
|
|
19
|
+
DyFM_AI_ConversationMultiSelect_Input,
|
|
20
|
+
DyFM_AI_ConversationGenericMultiSelect_Input,
|
|
21
|
+
DyFM_AI_ConversationJSONKeysDescription_Input,
|
|
22
|
+
DyFM_AI_ConversationJSONExactKeys_Input,
|
|
23
|
+
} from '../../../_models/ai-input-interfaces';
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* {
|
|
28
|
+
* organization: 'org-XY',
|
|
29
|
+
* apiKey: 'sk-XY',
|
|
30
|
+
* project: 'proj_XY',
|
|
31
|
+
* }
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// Di Dictionary DiModel DiEz DiAz
|
|
35
|
+
|
|
36
|
+
export class DyNTS_OAI_LLMChat_ServiceBase extends DyNTS_OAI_LLM_ServiceBase implements DyNTS_AI_LLMChat_ServiceBase {
|
|
37
|
+
|
|
38
|
+
// History management
|
|
39
|
+
/* private conversationHistories: Map<string, DyFM_AI_Message[]> = new Map(); */
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Hozzáad egy üzenetet a conversation history-hoz
|
|
43
|
+
*
|
|
44
|
+
* Adds a message to conversation history
|
|
45
|
+
*/
|
|
46
|
+
/* addMessageToHistory(message: DyFM_AI_Message, issuer: string): void {
|
|
47
|
+
if (!this.conversationHistories.has(issuer)) {
|
|
48
|
+
this.conversationHistories.set(issuer, []);
|
|
49
|
+
}
|
|
50
|
+
this.conversationHistories.get(issuer).push(message);
|
|
51
|
+
} */
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Törli a conversation history-t
|
|
55
|
+
*
|
|
56
|
+
* Clears conversation history
|
|
57
|
+
*/
|
|
58
|
+
/* clearHistory(issuer: string): void {
|
|
59
|
+
this.conversationHistories.delete(issuer);
|
|
60
|
+
} */
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Visszaadja a conversation history-t
|
|
64
|
+
*
|
|
65
|
+
* Gets conversation history
|
|
66
|
+
*/
|
|
67
|
+
/* getHistory(issuer: string): DyFM_AI_Message[] {
|
|
68
|
+
return this.conversationHistories.get(issuer) || [];
|
|
69
|
+
} */
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Converts generic AI messages to OpenAI-specific format
|
|
73
|
+
*
|
|
74
|
+
* Az generic AI üzeneteket OpenAI-specifikus formátumra alakítja át
|
|
75
|
+
*/
|
|
76
|
+
/* private convertToOAIMessages(messages: DyFM_AI_Message[]): DyFM_AI_Message[] {
|
|
77
|
+
return messages;
|
|
78
|
+
} */
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Asks the AI to answer a yes/no question
|
|
82
|
+
*
|
|
83
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.request} to ask the question,
|
|
84
|
+
* and the {@link DyNTS_OAI_LLM_Predefined_Requests.yesNo.upperCaseYes} to check the answer
|
|
85
|
+
*/
|
|
86
|
+
async requestYesNoInConversation(set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>): Promise<boolean> {
|
|
87
|
+
set.message += this.predefinedRequests.yesNo.request;
|
|
88
|
+
|
|
89
|
+
//this.logQuestion(set);
|
|
90
|
+
|
|
91
|
+
const answer: string = await this.requestSimpleMessageInConversation(set);
|
|
92
|
+
|
|
93
|
+
return this.convertAnswerToBoolean(answer);
|
|
94
|
+
}
|
|
95
|
+
//askYesNoQuestionInConversation: typeof this.yesNoQuestionInConversation = this.yesNoQuestionInConversation;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Asks the AI to answer a simple question
|
|
99
|
+
*
|
|
100
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.simpleQuestion} to ask the question
|
|
101
|
+
*/
|
|
102
|
+
/* async requestSimpleQuestionInConversation(
|
|
103
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
104
|
+
): Promise<string> {
|
|
105
|
+
this.logQuestion(set);
|
|
106
|
+
|
|
107
|
+
return await this.getQuestionAnswerInConversation(set);
|
|
108
|
+
} */
|
|
109
|
+
//askSimpleQuestionInConversation: typeof this.simpleQuestionInConversation = this.simpleQuestionInConversation;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Asks the AI to answer a percentage question
|
|
113
|
+
*
|
|
114
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.percentageOnly} to ask the question
|
|
115
|
+
*/
|
|
116
|
+
async requestPercentageInConversation(
|
|
117
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
118
|
+
): Promise<number> {
|
|
119
|
+
set.message += this.predefinedRequests.percentageOnly;
|
|
120
|
+
|
|
121
|
+
//this.logQuestion(set);
|
|
122
|
+
|
|
123
|
+
const answer: string = await this.requestSimpleMessageInConversation(set);
|
|
124
|
+
|
|
125
|
+
return this.convertAnswerToNumber(answer, set.message);
|
|
126
|
+
}
|
|
127
|
+
//askPercentageQuestionInConversation: typeof this.percentageQuestionInConversation = this.percentageQuestionInConversation;
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Asks the AI to select one of the options from the list
|
|
132
|
+
*
|
|
133
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
|
|
134
|
+
*/
|
|
135
|
+
async requestSelectInConversation<T>(
|
|
136
|
+
set: DyFM_AI_ConversationGenericSelect_Input<T, DyFM_OAI_CallSettings>
|
|
137
|
+
): Promise<T | { unparsableResult: string }> {
|
|
138
|
+
// replace the {{DyNTS_selectOptions}} with the list of options
|
|
139
|
+
const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
|
|
140
|
+
'{{DyNTS_selectOptions}}',
|
|
141
|
+
this.getTextListAsText(this.stringifySelectOptions(set.selectFrom))
|
|
142
|
+
);
|
|
143
|
+
set.message += selectQuestionAddition;
|
|
144
|
+
|
|
145
|
+
//this.logQuestion(set);
|
|
146
|
+
|
|
147
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
148
|
+
|
|
149
|
+
return this.convertAnswerToSelectOption<T>(answer, set.message, set.selectFrom);
|
|
150
|
+
}
|
|
151
|
+
//askSelectQuestionInConversation: typeof this.selectQuestionInConversation = this.selectQuestionInConversation;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Asks the AI to select one of the options from the list
|
|
155
|
+
* Similar to {@link askSelectQuestion},
|
|
156
|
+
* but with a more generic approach that can be used for objects
|
|
157
|
+
*
|
|
158
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.selectRequest} to ask the question
|
|
159
|
+
*/
|
|
160
|
+
/* async requestSelectInConversation<T>(
|
|
161
|
+
set: DyFM_AI_ConversationGenericSelect_Input<T, DyFM_OAI_CallSettings>
|
|
162
|
+
): Promise<T | { unparsableResult: string }> {
|
|
163
|
+
const selectQuestionAddition = this.predefinedRequests.selectRequest.replace(
|
|
164
|
+
'{{DyNTS_selectOptions}}',
|
|
165
|
+
this.getTextListAsText(set.selectFrom.map(item => `"${JSON.stringify(item)}"`))
|
|
166
|
+
);
|
|
167
|
+
set.message += selectQuestionAddition;
|
|
168
|
+
|
|
169
|
+
this.logQuestion(set);
|
|
170
|
+
|
|
171
|
+
const answer = await this.getQuestionAnswerInConversation(set);
|
|
172
|
+
|
|
173
|
+
return DyFM_Object.safeParseJSON<T>(answer);
|
|
174
|
+
} */
|
|
175
|
+
//askRequestSelectInConversation: typeof this.requestSelectInConversation = this.requestSelectInConversation;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Asks the AI to select one or more of the options from the list
|
|
179
|
+
*
|
|
180
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
|
|
181
|
+
*/
|
|
182
|
+
/* async requestMultiselectInConversation(set: DyFM_AI_ConversationMultiSelect_Input): Promise<string[]> {
|
|
183
|
+
const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
|
|
184
|
+
'{{DyNTS_selectOptions}}',
|
|
185
|
+
this.getTextListAsText(set.options)
|
|
186
|
+
);
|
|
187
|
+
set.message += selectQuestionAddition;
|
|
188
|
+
|
|
189
|
+
let answer = await this.getQuestionAnswerInConversation(set);
|
|
190
|
+
|
|
191
|
+
answer = answer.toLocaleUpperCase();
|
|
192
|
+
|
|
193
|
+
const result: string[] = [];
|
|
194
|
+
|
|
195
|
+
for (const item of set.options) {
|
|
196
|
+
if (answer.includes(item.toLocaleUpperCase())) {
|
|
197
|
+
result.push(item);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return result;
|
|
202
|
+
} */
|
|
203
|
+
//askMultipleSelectQuestionWithOptionsInConversation: typeof this.multipleSelectQuestionWithOptionsInConversation = this.multipleSelectQuestionWithOptionsInConversation;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Asks the AI to select one or more of the options from the list
|
|
207
|
+
* Similar to {@link askMultipleSelectQuestionWithOptions},
|
|
208
|
+
* but with a more generic approach that can be used for objects
|
|
209
|
+
*
|
|
210
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.multiselect} to ask the question
|
|
211
|
+
*/
|
|
212
|
+
async requestMultiselectInConversation<T>(
|
|
213
|
+
set: DyFM_AI_ConversationGenericMultiSelect_Input<T, DyFM_OAI_CallSettings>
|
|
214
|
+
): Promise<T[] | { unparsableResult: string }> {
|
|
215
|
+
const selectQuestionAddition = this.predefinedRequests.multiselect.replace(
|
|
216
|
+
'{{DyNTS_selectOptions}}',
|
|
217
|
+
this.getTextListAsText(this.stringifySelectOptions(set.options))
|
|
218
|
+
);
|
|
219
|
+
set.message += selectQuestionAddition;
|
|
220
|
+
|
|
221
|
+
//this.logQuestion(set);
|
|
222
|
+
|
|
223
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
224
|
+
|
|
225
|
+
return this.convertAnswerToList<T>(answer, set.message);
|
|
226
|
+
}
|
|
227
|
+
//askRequestMultipleSelectInConversation: typeof this.requestMultipleSelectInConversation = this.requestMultipleSelectInConversation;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Asks the AI to answer a question that must result a JSON object
|
|
231
|
+
*
|
|
232
|
+
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
233
|
+
*
|
|
234
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequest} to ask the question
|
|
235
|
+
*
|
|
236
|
+
* (uses {@link DyFM_safeParseJSON})
|
|
237
|
+
*/
|
|
238
|
+
async requestJSONInConversation<T = any>(
|
|
239
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
240
|
+
): Promise<T | { unparsableResult: string }> {
|
|
241
|
+
set.message += this.predefinedRequests.jsonRequest;
|
|
242
|
+
|
|
243
|
+
//this.logQuestion(set);
|
|
244
|
+
|
|
245
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
246
|
+
|
|
247
|
+
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
248
|
+
}
|
|
249
|
+
//askJsonQuestionInConversation: typeof this.jsonQuestionInConversation = this.jsonQuestionInConversation;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Asks the AI to answer a question that must result a JSON object with specific key descriptions
|
|
253
|
+
*
|
|
254
|
+
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
255
|
+
*
|
|
256
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
|
|
257
|
+
*
|
|
258
|
+
* (uses {@link DyFM_safeParseJSON})
|
|
259
|
+
*/
|
|
260
|
+
/* async requestJSONInConversationWithKeysDescription<T = any>(
|
|
261
|
+
set: DyFM_AI_ConversationJSONKeysDescription_Input<DyFM_OAI_CallSettings>
|
|
262
|
+
): Promise<T | { unparsableResult: string }> {
|
|
263
|
+
return this.jsonQuestionWithKeysDescriptionInConversation<any>(set);
|
|
264
|
+
} */
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Asks the AI to answer a question that must result a JSON object with specific key descriptions
|
|
268
|
+
*
|
|
269
|
+
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
270
|
+
*
|
|
271
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithKeysDescription} to ask the question
|
|
272
|
+
*
|
|
273
|
+
* (uses {@link DyFM_safeParseJSON})
|
|
274
|
+
*/
|
|
275
|
+
async requestJSONInConversationWithKeysDescription<T = any>(
|
|
276
|
+
set: DyFM_AI_ConversationJSONKeysDescription_Input
|
|
277
|
+
): Promise<T | { unparsableResult: string }> {
|
|
278
|
+
const jsonRequestWithKeysDescription = this.predefinedRequests.jsonRequestWithKeysDescription.replace(
|
|
279
|
+
'{{DyNTS_jsonKeysDescription}}',
|
|
280
|
+
set.keysDescription
|
|
281
|
+
);
|
|
282
|
+
set.message += jsonRequestWithKeysDescription;
|
|
283
|
+
|
|
284
|
+
//this.logQuestion(set);
|
|
285
|
+
|
|
286
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
287
|
+
|
|
288
|
+
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
289
|
+
}
|
|
290
|
+
//askJsonQuestionWithKeysDescriptionInConversation: typeof this.jsonQuestionWithKeysDescriptionInConversation = this.jsonQuestionWithKeysDescriptionInConversation;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Asks the AI to answer a question that must result a JSON object with specific keys
|
|
294
|
+
*
|
|
295
|
+
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
296
|
+
*
|
|
297
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
|
|
298
|
+
*
|
|
299
|
+
* (uses {@link DyFM_safeParseJSON})
|
|
300
|
+
*/
|
|
301
|
+
/* async requestJSONInConversationWithExactKeys(set: DyFM_AI_ConversationJSONExactKeys_Input): Promise<object> {
|
|
302
|
+
const result = await this.jsonQuestionWithExactKeysInConversation<any>(set);
|
|
303
|
+
return typeof result === 'object' ? result : {};
|
|
304
|
+
} */
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Asks the AI to answer a question that must result a JSON object with specific keys
|
|
308
|
+
*
|
|
309
|
+
* If the answer is not a valid JSON object, it will return { unparsableResult: answer }
|
|
310
|
+
*
|
|
311
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.jsonRequestWithExactKeys} to ask the question
|
|
312
|
+
*
|
|
313
|
+
* (uses {@link DyFM_safeParseJSON})
|
|
314
|
+
*/
|
|
315
|
+
async requestJSONInConversationWithExactKeys<T = any>(
|
|
316
|
+
set: DyFM_AI_ConversationJSONExactKeys_Input
|
|
317
|
+
): Promise<T | { unparsableResult: string }> {
|
|
318
|
+
const jsonRequestWithExactKeys = this.predefinedRequests.jsonRequestWithExactKeys.replace(
|
|
319
|
+
'{{DyNTS_jsonKeys}}',
|
|
320
|
+
this.getTextListAsText(set.keys)
|
|
321
|
+
);
|
|
322
|
+
set.message += jsonRequestWithExactKeys;
|
|
323
|
+
|
|
324
|
+
//this.logQuestion(set);
|
|
325
|
+
|
|
326
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
327
|
+
|
|
328
|
+
return this.convertAnswerToJSON<T>(answer, set.message);
|
|
329
|
+
}
|
|
330
|
+
//askJsonQuestionWithExactKeysInConversation: typeof this.jsonQuestionWithExactKeysInConversation = this.jsonQuestionWithExactKeysInConversation;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Asks the AI to answer a question that must result a list of strings
|
|
334
|
+
*
|
|
335
|
+
* If the answer is not a valid JSON list, it will return the answer as a single item in an array
|
|
336
|
+
*
|
|
337
|
+
* Uses the {@link DyNTS_OAI_LLM_Predefined_Requests.listRequest} to ask the question
|
|
338
|
+
*
|
|
339
|
+
* (uses {@link DyFM_Object.safeParseList})
|
|
340
|
+
*/
|
|
341
|
+
async requestListInConversation<T = any>(
|
|
342
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
343
|
+
): Promise<T[] | { unparsableResult: string }> {
|
|
344
|
+
set.message += this.predefinedRequests.listRequest;
|
|
345
|
+
|
|
346
|
+
//this.logQuestion(set);
|
|
347
|
+
|
|
348
|
+
const answer = await this.requestSimpleMessageInConversation(set);
|
|
349
|
+
|
|
350
|
+
return this.convertAnswerToList<T>(answer, set.message);
|
|
351
|
+
}
|
|
352
|
+
//askListQuestionInConversation: typeof this.listQuestionInConversation = this.listQuestionInConversation;
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Asks the AI to answer a question
|
|
356
|
+
*
|
|
357
|
+
* Uses the {@link resolveSimpleUserMessage}
|
|
358
|
+
*/
|
|
359
|
+
/* async getQuestionAnswerInConversation(
|
|
360
|
+
conversation: DyFM_AI_Message[],
|
|
361
|
+
question: string,
|
|
362
|
+
issuer: string,
|
|
363
|
+
debugLog?: boolean,
|
|
364
|
+
messageSettings: DyFM_OAI_CallSettings = this.defaultSettings
|
|
365
|
+
): Promise<string> {
|
|
366
|
+
const answer = await this.resolveSimpleUserMessageInConversation(
|
|
367
|
+
conversation,
|
|
368
|
+
question,
|
|
369
|
+
issuer,
|
|
370
|
+
messageSettings,
|
|
371
|
+
) as Promise<string>;
|
|
372
|
+
|
|
373
|
+
if (debugLog) {
|
|
374
|
+
console.log(' - ', answer);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return answer;
|
|
378
|
+
} */
|
|
379
|
+
|
|
380
|
+
/* async requestSimpleQuestionInConversation(set: DyFM_AI_ConversationMessage_Input): Promise<string> {
|
|
381
|
+
return await this.getAnswerInConversation({
|
|
382
|
+
...set,
|
|
383
|
+
newMessage: set.message,
|
|
384
|
+
});
|
|
385
|
+
} */
|
|
386
|
+
/* getQuestionAnswerInConversation = this.getAnswerInConversation; */
|
|
387
|
+
//getQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
|
|
388
|
+
//askQuestionInConversation: typeof this.getQuestionAnswerInConversation = this.getQuestionAnswerInConversation;
|
|
389
|
+
//getConversationAnswer: typeof this.getAnswerInConversation = this.getAnswerInConversation;
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Asks the AI to answer a question using the whole conversation
|
|
393
|
+
* (If you want to use only the conversation, without adding a new message,
|
|
394
|
+
* use directly the {@link resolveConversation})
|
|
395
|
+
*
|
|
396
|
+
* Uses the {@link resolveConversation}
|
|
397
|
+
*/
|
|
398
|
+
async requestSimpleMessageInConversation(set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>): Promise<string> {
|
|
399
|
+
// Convert generic AI messages to OpenAI-specific format
|
|
400
|
+
//const oaiConversation: DyFM_AI_Message[] = /* this.convertToOAIMessages(set.conversation) */ set.conversation;
|
|
401
|
+
|
|
402
|
+
if (set.message) {
|
|
403
|
+
set.conversation.push({
|
|
404
|
+
role: DyFM_AI_MessageRole.user,
|
|
405
|
+
content: set.message,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const answer: string = await this.resolveConversation({
|
|
410
|
+
...set,
|
|
411
|
+
getFullResponse: false,
|
|
412
|
+
}) as string;
|
|
413
|
+
|
|
414
|
+
this.logAnswer(answer);
|
|
415
|
+
|
|
416
|
+
return answer;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* async resolveConversationMessage(
|
|
420
|
+
set: {
|
|
421
|
+
conversation: DyFM_AI_Message[],
|
|
422
|
+
issuer: string,
|
|
423
|
+
settings?: DyFM_OAI_CallSettings,
|
|
424
|
+
getFullResponse?: boolean,
|
|
425
|
+
debugLog?: boolean,
|
|
426
|
+
* this is used to readably replace too long contents to eg '...' in logs
|
|
427
|
+
replaceThisInLog?: string,
|
|
428
|
+
}
|
|
429
|
+
): Promise<string> {
|
|
430
|
+
return await this.resolveConversation(set) as string;
|
|
431
|
+
} */
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Resolves a conversation
|
|
435
|
+
*
|
|
436
|
+
* Uses the {@link getMessageCreateInput}
|
|
437
|
+
*/
|
|
438
|
+
async resolveConversation(
|
|
439
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
440
|
+
): Promise<string | ChatCompletion> {
|
|
441
|
+
try {
|
|
442
|
+
if (!set.conversation.some(message => message.role === DyFM_AI_MessageRole.system)) {
|
|
443
|
+
/* throw new DyFM_Error({
|
|
444
|
+
...this.getDefaultErrorSettings(
|
|
445
|
+
'resolveConversation',
|
|
446
|
+
new Error('System message found in conversation'),
|
|
447
|
+
set.issuer
|
|
448
|
+
),
|
|
449
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-RC1`,
|
|
450
|
+
}); */
|
|
451
|
+
/* DyFM_Log.error('System message found in conversation', {
|
|
452
|
+
conversation: set.conversation,
|
|
453
|
+
});
|
|
454
|
+
} else { */
|
|
455
|
+
set.conversation.unshift(this.getDefaultSystemMessage(set.settings));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// conversation shortening
|
|
459
|
+
const shortenedConversation = this.shortenConversation(set);
|
|
460
|
+
|
|
461
|
+
this.validateConversation(shortenedConversation);
|
|
462
|
+
|
|
463
|
+
//this.logQuestion(set);
|
|
464
|
+
|
|
465
|
+
this.logConversation({
|
|
466
|
+
...set,
|
|
467
|
+
conversation: shortenedConversation,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const result: ChatCompletion = await this.openai.chat.completions.create(
|
|
471
|
+
this.getMessageCreateInput({
|
|
472
|
+
...set,
|
|
473
|
+
conversation: shortenedConversation,
|
|
474
|
+
})
|
|
475
|
+
) as ChatCompletion;
|
|
476
|
+
|
|
477
|
+
if (set.getFullResponse) {
|
|
478
|
+
return result;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return result.choices[0].message.content;
|
|
482
|
+
} catch (error) {
|
|
483
|
+
throw new DyFM_Error({
|
|
484
|
+
...this.getDefaultErrorSettings('resolveConversation', error, set.issuer),
|
|
485
|
+
|
|
486
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-RC0`,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
//resolveSimpleUserMessageInConversation: typeof this.resolveConversation = this.resolveConversation;
|
|
491
|
+
|
|
492
|
+
protected shortenConversation(
|
|
493
|
+
set: DyFM_AI_ConversationBase_Input<DyFM_OAI_CallSettings>
|
|
494
|
+
): DyFM_AI_Message[] {
|
|
495
|
+
try {
|
|
496
|
+
// Step 1: Clone the conversation to avoid mutating the original
|
|
497
|
+
const clonedConversation: DyFM_AI_Message[] = DyFM_Object.clone(set.conversation);
|
|
498
|
+
|
|
499
|
+
// Step 2: Separate system messages from user/assistant messages
|
|
500
|
+
// System messages are kept and not shortened
|
|
501
|
+
const systemMessages: DyFM_AI_Message[] = clonedConversation.filter(
|
|
502
|
+
(message: DyFM_AI_Message): boolean => message.role === DyFM_AI_MessageRole.system
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
// Step 3: Calculate system messages length as JSON string
|
|
506
|
+
// ⚠️ ISSUE: This measures JSON string length, not actual token count
|
|
507
|
+
// ⚠️ ISSUE: Doesn't account for message structure overhead (role, content keys, formatting)
|
|
508
|
+
const systemMessagesStringLength: number = JSON.stringify(systemMessages).length;
|
|
509
|
+
|
|
510
|
+
// Step 4: Extract only content strings from non-system messages
|
|
511
|
+
// ⚠️ ISSUE: Only measuring content strings, not full message structure
|
|
512
|
+
// ⚠️ ISSUE: OpenAI counts tokens for full message format: {"role": "...", "content": "..."}
|
|
513
|
+
const msgs: string[] = clonedConversation.filter(
|
|
514
|
+
(message: DyFM_AI_Message): boolean => message.role !== DyFM_AI_MessageRole.system
|
|
515
|
+
).map((message: DyFM_AI_Message): string => message.content);
|
|
516
|
+
|
|
517
|
+
// Step 5: Stringify the content array to measure total length
|
|
518
|
+
// ⚠️ ISSUE: This is character count, not token count - ratio varies (1 token ≈ 1-4 chars)
|
|
519
|
+
let stringifiedMessages: string = JSON.stringify(msgs);
|
|
520
|
+
|
|
521
|
+
// Step 6: Log initial state if debug is enabled
|
|
522
|
+
if (this._debugLog || set.debugLog) {
|
|
523
|
+
DyFM_Log.info(
|
|
524
|
+
' DyNTS_OAI_LLMChat_ServiceBase: before shortening conversation', {
|
|
525
|
+
stringifiedMessagesLength: stringifiedMessages.length,
|
|
526
|
+
conversationLength: clonedConversation.length,
|
|
527
|
+
lastMessage: DyFM_Array.last(clonedConversation)?.content,
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Step 7: Initialize tracking variables
|
|
533
|
+
let removedMessagesCount: number = 0;
|
|
534
|
+
let lastStringifiedMessagesLength: number = stringifiedMessages.length;
|
|
535
|
+
|
|
536
|
+
// Step 8: Loop to remove messages until under character limit
|
|
537
|
+
// ⚠️ ISSUE: Comparing character count to token limit - different units!
|
|
538
|
+
// ⚠️ ISSUE: maxMessagesStringLength (120k chars) may not safely map to 128k tokens
|
|
539
|
+
// ⚠️ ISSUE: Condition allows single very long message to remain (length > 1)
|
|
540
|
+
while (
|
|
541
|
+
(stringifiedMessages.length + systemMessagesStringLength) > DyNTS_OAI_global_settings.maxMessagesStringLength &&
|
|
542
|
+
clonedConversation.length > 1
|
|
543
|
+
) {
|
|
544
|
+
// Step 8a: Remove oldest message from full conversation
|
|
545
|
+
clonedConversation.splice(0, 1);
|
|
546
|
+
|
|
547
|
+
// Step 8b: Remove corresponding content from msgs array
|
|
548
|
+
// ⚠️ CRITICAL BUG: Always removes from msgs, even if removed message was a system message!
|
|
549
|
+
// ⚠️ This causes array desynchronization - msgs and clonedConversation get out of sync
|
|
550
|
+
msgs.splice(0, 1);
|
|
551
|
+
|
|
552
|
+
removedMessagesCount++;
|
|
553
|
+
|
|
554
|
+
// Step 8c: Recalculate stringified length after removal
|
|
555
|
+
stringifiedMessages = JSON.stringify(msgs);
|
|
556
|
+
lastStringifiedMessagesLength = stringifiedMessages.length;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Step 9: Log final state if debug is enabled
|
|
560
|
+
if (this._debugLog || set.debugLog) {
|
|
561
|
+
DyFM_Log.info(
|
|
562
|
+
' DyNTS_OAI_LLMChat_ServiceBase: after shortening conversation', {
|
|
563
|
+
removedMessagesCount: removedMessagesCount,
|
|
564
|
+
lastStringifiedMessagesLength: lastStringifiedMessagesLength,
|
|
565
|
+
lastMessage: DyFM_Array.last(clonedConversation)?.content,
|
|
566
|
+
localStackLocation: DyFM_getLocalStackLocation(),
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Step 10: Safety check - ensure we didn't remove everything
|
|
572
|
+
if (!clonedConversation.length) {
|
|
573
|
+
DyFM_Log.error('No conversation messages (left)', {
|
|
574
|
+
/* conversation: DyFM_Object.clone(conversation), */
|
|
575
|
+
conversationLength: set.conversation.length,
|
|
576
|
+
clonedConversation: DyFM_Object.clone(clonedConversation),
|
|
577
|
+
});
|
|
578
|
+
throw new Error('No conversation messages (left)');
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Step 11: Reconstruct conversation: system messages first, then shortened non-system messages
|
|
582
|
+
// ⚠️ ISSUE: clonedConversation may still contain system messages mixed in
|
|
583
|
+
// ⚠️ This could result in duplicate system messages in the final array
|
|
584
|
+
return [ ...systemMessages, ...clonedConversation ];
|
|
585
|
+
} catch (error) {
|
|
586
|
+
DyFM_Error.logSimple('❌❌ Error shortening conversation:', error);
|
|
587
|
+
|
|
588
|
+
throw new DyFM_Error({
|
|
589
|
+
...this.getDefaultErrorSettings('shortenConversation', error, set.issuer),
|
|
590
|
+
|
|
591
|
+
errorCode: `${DyNTS_global_settings.systemShortCodeName}|DyNTS-OAB-SC0`,
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Kérdez egy kérdést és JSON választ vár exact keys-szel
|
|
598
|
+
*
|
|
599
|
+
* Asks a question and expects JSON response with exact keys
|
|
600
|
+
*/
|
|
601
|
+
/* async requestJSONInConversationWithExactKeys<T>(
|
|
602
|
+
set: DyFM_AI_ConversationJSONExactKeys_Input
|
|
603
|
+
): Promise<T> {
|
|
604
|
+
const answer = await this.jsonQuestionWithExactKeysInConversation<any>(set);
|
|
605
|
+
|
|
606
|
+
if ('unparsableResult' in answer) {
|
|
607
|
+
throw new DyFM_Error({
|
|
608
|
+
message: 'Invalid JSON response from AI',
|
|
609
|
+
additionalContent: { answer },
|
|
610
|
+
userMessage: 'Failed to parse AI response'
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
return answer as T;
|
|
615
|
+
} */
|
|
616
616
|
}
|