@futdevpro/nts-dynamo 1.15.36 → 1.15.38

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.
Files changed (340) hide show
  1. package/.c8rc.json +26 -26
  2. package/.copilot/patterns.json +7 -7
  3. package/.cursor/rules/__assistant_guide.mdc +30 -30
  4. package/.cursor/rules/_ag_backend-structure.mdc +85 -85
  5. package/.cursor/rules/_ag_backend.mdc +16 -16
  6. package/.cursor/rules/_ag_frontend-structure.mdc +86 -86
  7. package/.cursor/rules/_ag_frontend.mdc +39 -39
  8. package/.cursor/rules/_ag_import-rules.mdc +44 -44
  9. package/.cursor/rules/_ag_naming.mdc +115 -115
  10. package/.cursor/rules/_ag_should-be.mdc +6 -6
  11. package/.cursor/rules/ai_development_guide.md +60 -60
  12. package/.cursor/rules/cursor-rules.md +160 -160
  13. package/.cursor/rules/default-command.mdc +464 -464
  14. package/.cursor/rules/error_code_pattern.md +39 -39
  15. package/.cursor/rules/saved rule mcp server use.md +15 -15
  16. package/.github/workflows/main.yml +432 -432
  17. package/.vscode/settings.json +10 -10
  18. package/HOWTO.md +15 -15
  19. package/LICENSE +21 -21
  20. package/__documentations/2026-06-01-fr041-cors-middleware.md +96 -0
  21. package/__documentations/nts-integration-tests-2026-03-17.md +26 -26
  22. package/_specifications/BACKLOG.md +92 -92
  23. package/_specifications/TODO.md +15 -15
  24. package/_specifications/agent.md +138 -138
  25. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts +24 -2
  26. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts.map +1 -1
  27. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js +124 -0
  28. package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js.map +1 -1
  29. package/build/_modules/ai/_services/ai-llm.service-base.d.ts +56 -1
  30. package/build/_modules/ai/_services/ai-llm.service-base.d.ts.map +1 -1
  31. package/build/_modules/ai/_services/ai-llm.service-base.js +122 -0
  32. package/build/_modules/ai/_services/ai-llm.service-base.js.map +1 -1
  33. package/build/_modules/server/errors/errors.control-service.d.ts +2 -1
  34. package/build/_modules/server/errors/errors.control-service.d.ts.map +1 -1
  35. package/build/_modules/server/errors/errors.control-service.js.map +1 -1
  36. package/build/_modules/server/errors/errors.controller.d.ts.map +1 -1
  37. package/build/_modules/server/errors/errors.controller.js +26 -0
  38. package/build/_modules/server/errors/errors.controller.js.map +1 -1
  39. package/build/_modules/server/errors/errors.data-service.d.ts +20 -1
  40. package/build/_modules/server/errors/errors.data-service.d.ts.map +1 -1
  41. package/build/_modules/server/errors/errors.data-service.js +93 -0
  42. package/build/_modules/server/errors/errors.data-service.js.map +1 -1
  43. package/eslint.config.js +3 -3
  44. package/nodemon.json +24 -24
  45. package/package.json +2 -2
  46. package/pnpm-workspace.yaml +7 -2
  47. package/scripts/run-coverage-tests.js +28 -28
  48. package/spec/support/helpers/spec-reporter-loader.js +359 -359
  49. package/spec/support/helpers/ts-node-helper.js +93 -93
  50. package/spec/support/jasmine.coverage.json +24 -24
  51. package/spec/support/jasmine.json +24 -24
  52. package/src/_collections/archive.util.spec.ts +57 -57
  53. package/src/_collections/archive.util.ts +18 -18
  54. package/src/_collections/atlas-default-db-options.const.ts +9 -9
  55. package/src/_collections/default-fallback-cache-max-age.const.spec.ts +11 -11
  56. package/src/_collections/default-fallback-cache-max-age.const.ts +2 -2
  57. package/src/_collections/default-not-found-page.const.spec.ts +19 -19
  58. package/src/_collections/default-not-found-page.const.ts +22 -22
  59. package/src/_collections/default-socket-path.const.spec.ts +12 -12
  60. package/src/_collections/default-socket-path.const.ts +2 -2
  61. package/src/_collections/get-environment-settings.util.spec.ts +210 -210
  62. package/src/_collections/get-environment-settings.util.ts +48 -48
  63. package/src/_collections/sample.env +21 -21
  64. package/src/_collections/star.controller.spec.ts +224 -224
  65. package/src/_collections/star.controller.ts +129 -129
  66. package/src/_enums/data-model-type.enum.ts +14 -14
  67. package/src/_enums/data-service-function.enum.ts +24 -24
  68. package/src/_enums/predefined-data-types.enum.ts +16 -16
  69. package/src/_enums/route-security.enum.ts +12 -12
  70. package/src/_models/control-models/api-call-params.control-model.spec.ts +152 -152
  71. package/src/_models/control-models/api-call-params.control-model.ts +142 -142
  72. package/src/_models/control-models/app-ext-system-controls.control-model.spec.ts +52 -52
  73. package/src/_models/control-models/app-ext-system-controls.control-model.ts +9 -9
  74. package/src/_models/control-models/app-params.control-model.spec.ts +225 -225
  75. package/src/_models/control-models/app-params.control-model.ts +136 -136
  76. package/src/_models/control-models/app-system-controls.control-model.spec.ts +31 -31
  77. package/src/_models/control-models/app-system-controls.control-model.ts +9 -9
  78. package/src/_models/control-models/endpoint-params.control-model.spec.ts +578 -578
  79. package/src/_models/control-models/endpoint-params.control-model.ts +526 -526
  80. package/src/_models/control-models/http-settings.control-model.spec.ts +77 -77
  81. package/src/_models/control-models/http-settings.control-model.ts +37 -37
  82. package/src/_models/control-models/system-control.control-model.spec.ts +27 -27
  83. package/src/_models/control-models/system-control.control-model.ts +12 -12
  84. package/src/_models/interfaces/certification-settings.interface.ts +7 -7
  85. package/src/_models/interfaces/environment-settings.interface.ts +59 -59
  86. package/src/_models/interfaces/global-log-settings.interface.ts +144 -144
  87. package/src/_models/interfaces/global-service-settings.interface.ts +47 -47
  88. package/src/_models/interfaces/routing-module-settings.interface.ts +21 -21
  89. package/src/_models/interfaces/static-client-settings.interface.spec.ts +29 -29
  90. package/src/_models/interfaces/static-client-settings.interface.ts +28 -28
  91. package/src/_models/types/db-update.type.ts +100 -100
  92. package/src/_modules/ai/_models/ai-input-interfaces.ts +117 -117
  93. package/src/_modules/ai/_models/ai-test-generation-result.interface.ts +16 -16
  94. package/src/_modules/ai/_modules/anthropic/_services/aai-user-key.control-service.ts +138 -138
  95. package/src/_modules/ai/_modules/anthropic/index.ts +5 -5
  96. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.spec.ts +242 -242
  97. package/src/_modules/ai/_modules/document-ai/_collections/dai-chunking.util.ts +639 -639
  98. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.spec.ts +209 -209
  99. package/src/_modules/ai/_modules/document-ai/_collections/dai-document.util.ts +85 -85
  100. package/src/_modules/ai/_modules/document-ai/_enums/dai-compare-result-type.enum.ts +7 -7
  101. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-chunk.data-model.ts +146 -146
  102. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-doc-page.data-model.ts +162 -162
  103. package/src/_modules/ai/_modules/document-ai/_models/data-models/dai-document.data-model.ts +99 -99
  104. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-chunk-compare-result.interface.ts +18 -18
  105. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-doc-page-compare-result.interface.ts +19 -19
  106. package/src/_modules/ai/_modules/document-ai/_models/interfaces/dai-document-compare-result.interface.ts +25 -25
  107. package/src/_modules/ai/_modules/document-ai/index.ts +28 -28
  108. package/src/_modules/ai/_modules/fdp-ai/_services/fdpai-user-key.control-service.ts +189 -189
  109. package/src/_modules/ai/_modules/fdp-ai/index.ts +5 -5
  110. package/src/_modules/ai/_modules/open-ai/_collections/oai-global-settings.const.ts +9 -9
  111. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests-hu.conts.ts +82 -82
  112. package/src/_modules/ai/_modules/open-ai/_collections/oai-llm-predefined-requests.conts.ts +75 -75
  113. package/src/_modules/ai/_modules/open-ai/_enums/oai-gpt-message-role.enum.ts +45 -45
  114. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-global-settings.interface.ts +7 -7
  115. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-gpt-message.interface.ts +7 -7
  116. package/src/_modules/ai/_modules/open-ai/_models/interfaces/oai-llm-predefined-requests.interface.ts +57 -57
  117. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-doc-chunk-data.service.ts +292 -292
  118. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-document.data-service.spec.ts +342 -342
  119. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.spec.ts +550 -550
  120. package/src/_modules/ai/_modules/open-ai/_services/data-services/oai-vector-data.service.ts +630 -630
  121. package/src/_modules/ai/_modules/open-ai/_services/oai-embedding.control-service.spec.ts +332 -332
  122. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.spec.ts +462 -462
  123. package/src/_modules/ai/_modules/open-ai/_services/oai-llm-chat.service-base.ts +634 -634
  124. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.spec.ts +489 -489
  125. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.tools.spec.ts +106 -0
  126. package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +1011 -862
  127. package/src/_modules/ai/_modules/open-ai/_services/oai-user-key.control-service.ts +157 -157
  128. package/src/_modules/ai/_services/ai-embedding.service-base.spec.ts +98 -98
  129. package/src/_modules/ai/_services/ai-embedding.service-base.ts +48 -48
  130. package/src/_modules/ai/_services/ai-llm-chat.service-base.spec.ts +229 -229
  131. package/src/_modules/ai/_services/ai-llm-chat.service-base.ts +68 -68
  132. package/src/_modules/ai/_services/ai-llm.service-base.spec.ts +250 -250
  133. package/src/_modules/ai/_services/ai-llm.service-base.ts +510 -332
  134. package/src/_modules/ai/_services/ai-provider.service-base.spec.ts +158 -158
  135. package/src/_modules/ai/_services/ai-user-key.service-base.ts +59 -59
  136. package/src/_modules/ai/index.ts +13 -13
  137. package/src/_modules/assistant/_collections/ass-global-settings.const.ts +13 -13
  138. package/src/_modules/assistant/_collections/ass.util.spec.ts +176 -176
  139. package/src/_modules/assistant/_collections/ass.util.ts +50 -50
  140. package/src/_modules/assistant/_models/ass-global-settings.interface.ts +15 -15
  141. package/src/_modules/assistant/_services/ass-io.control-service.spec.ts +140 -140
  142. package/src/_modules/assistant/_services/ass-main.control-service.spec.ts +192 -192
  143. package/src/_modules/assistant/_services/ass-main.control-service.ts +107 -107
  144. package/src/_modules/bot/_collections/bot-default-commands.const.ts +12 -12
  145. package/src/_modules/bot/_collections/bot-global-settings.const.ts +39 -39
  146. package/src/_modules/bot/_models/bot-channel-wrapper.interface.ts +62 -62
  147. package/src/_modules/bot/_models/bot-command.interface.ts +8 -8
  148. package/src/_modules/bot/_models/bot-global-settings.interface.ts +96 -96
  149. package/src/_modules/bot/_models/bot-last-mention-date.interface.ts +6 -6
  150. package/src/_modules/bot/_models/bot-last-message-date.interface.ts +5 -5
  151. package/src/_modules/bot/_models/bot-user-wrapper.interface.ts +41 -41
  152. package/src/_modules/bot/_modules/discord-bot/_models/dib-platform.types.ts +9 -9
  153. package/src/_modules/bot/_modules/discord-bot/_services/dib-messaging-provider.control-service.spec.ts +431 -431
  154. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.spec.ts +160 -160
  155. package/src/_modules/bot/_modules/dynamo-bot/_collections/dyb-operations.util.ts +55 -55
  156. package/src/_modules/bot/_modules/dynamo-bot/_models/dyb-platform.types.ts +15 -15
  157. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.spec.ts +374 -374
  158. package/src/_modules/bot/_modules/dynamo-bot/_services/dyb-messaging-provider.control-service.ts +447 -447
  159. package/src/_modules/bot/_modules/dynamo-bot/index.ts +15 -15
  160. package/src/_modules/bot/_modules/slack-bot/_models/slb-platform.types.ts +9 -9
  161. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.spec.ts +344 -344
  162. package/src/_modules/bot/_modules/slack-bot/_services/slb-messaging-provider.control-service.ts +197 -197
  163. package/src/_modules/bot/_modules/teams-bot/_models/teb-platform.types.ts +9 -9
  164. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.spec.ts +345 -345
  165. package/src/_modules/bot/_modules/teams-bot/_services/teb-messaging-provider.control-service.ts +197 -197
  166. package/src/_modules/bot/_services/bot-commands.control-service.spec.ts +116 -116
  167. package/src/_modules/bot/_services/bot-io.control-service.spec.ts +285 -285
  168. package/src/_modules/bot/_services/bot-main.control-service.spec.ts +208 -208
  169. package/src/_modules/bot/_services/bot-messaging-provider.service-base.spec.ts +349 -349
  170. package/src/_modules/bot/_services/bot-routines.control-service.spec.ts +111 -111
  171. package/src/_modules/custom-data/custom-data.controller.spec.ts +49 -49
  172. package/src/_modules/custom-data/custom-data.controller.ts +67 -67
  173. package/src/_modules/custom-data/custom-data.data-service.spec.ts +54 -54
  174. package/src/_modules/custom-data/custom-data.data-service.ts +21 -21
  175. package/src/_modules/custom-data/get-custom-data-routing-module.util.spec.ts +28 -28
  176. package/src/_modules/custom-data/get-custom-data-routing-module.util.ts +24 -24
  177. package/src/_modules/custom-data/index.ts +9 -9
  178. package/src/_modules/defaults/_collections/default-endpoints.util.ts +487 -487
  179. package/src/_modules/defaults/_models/default-user.data-model.ts +72 -72
  180. package/src/_modules/defaults/_services/default-auth.service.spec.ts +269 -269
  181. package/src/_modules/defaults/_services/default-auth.service.ts +177 -177
  182. package/src/_modules/defaults/_services/default-socket-events.service.spec.ts +42 -42
  183. package/src/_modules/defaults/_services/default-socket-events.service.ts +61 -61
  184. package/src/_modules/defaults/_services/default-user.data-service.spec.ts +187 -187
  185. package/src/_modules/defaults/_services/default-user.data-service.ts +98 -98
  186. package/src/_modules/defaults/index.ts +17 -17
  187. package/src/_modules/discord-assistant/_collections/dias-global-settings.const.ts +19 -19
  188. package/src/_modules/discord-assistant/_collections/dias.util.spec.ts +366 -366
  189. package/src/_modules/discord-assistant/_collections/dias.util.ts +132 -132
  190. package/src/_modules/discord-assistant/_models/dias-global-settings.interface.ts +19 -19
  191. package/src/_modules/discord-assistant/_models/dias-knowledge.data-model.ts +52 -52
  192. package/src/_modules/discord-assistant/_services/dias-chunk.data-service.ts +177 -177
  193. package/src/_modules/discord-assistant/_services/dias-io.control-service.spec.ts +108 -108
  194. package/src/_modules/discord-assistant/_services/dias-io.control-service.ts +69 -69
  195. package/src/_modules/discord-assistant/_services/dias-main.control-service.spec.ts +22 -22
  196. package/src/_modules/discord-assistant/_services/dias-main.control-service.ts +27 -27
  197. package/src/_modules/discord-assistant/_services/dias.service-base.spec.ts +195 -195
  198. package/src/_modules/discord-assistant/_services/dias.service-base.ts +76 -76
  199. package/src/_modules/discord-assistant/index.ts +38 -38
  200. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.spec.ts +34 -34
  201. package/src/_modules/discord-assistant-voiced/_services/dias-discord-bot.control-service.ts +11 -11
  202. package/src/_modules/discord-assistant-voiced/index.ts +36 -36
  203. package/src/_modules/discord-bot/_collections/dibo-default-commands.const.ts +16 -16
  204. package/src/_modules/discord-bot/_collections/dibo-global-settings.conts.ts +55 -55
  205. package/src/_modules/discord-bot/_collections/dibo-operations.util.spec.ts +214 -214
  206. package/src/_modules/discord-bot/_collections/dibo-operations.util.ts +387 -387
  207. package/src/_modules/discord-bot/_models/dibo-command.interface.ts +12 -12
  208. package/src/_modules/discord-bot/_models/dibo-global-settings.interface.ts +98 -98
  209. package/src/_modules/discord-bot/_models/dibo-last-mention-date.inteface.ts +7 -7
  210. package/src/_modules/discord-bot/_models/dibo-last-message-date.interface.ts +6 -6
  211. package/src/_modules/discord-bot/_services/dibo-commands.control-service.spec.ts +154 -154
  212. package/src/_modules/discord-bot/_services/dibo-commands.control-service.ts +153 -153
  213. package/src/_modules/discord-bot/_services/dibo-io.control-service.spec.ts +264 -264
  214. package/src/_modules/discord-bot/_services/dibo-io.control-service.ts +306 -306
  215. package/src/_modules/discord-bot/_services/dibo-main.control-service.spec.ts +408 -408
  216. package/src/_modules/discord-bot/_services/dibo-main.control-service.ts +487 -487
  217. package/src/_modules/discord-bot/_services/dibo-routines.control-service.spec.ts +105 -105
  218. package/src/_modules/discord-bot/index.ts +36 -36
  219. package/src/_modules/local-vector-search/_enums/lvs-search-mode.enum.ts +35 -35
  220. package/src/_modules/local-vector-search/_models/lvs-search-result.interface.ts +17 -17
  221. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.spec.ts +418 -418
  222. package/src/_modules/local-vector-search/_services/lvs-doc-chunk-data.service.ts +276 -276
  223. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.spec.ts +480 -480
  224. package/src/_modules/local-vector-search/_services/lvs-local-vector-search.data-service.ts +416 -416
  225. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +393 -393
  226. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +220 -220
  227. package/src/_modules/local-vector-search/index.ts +11 -11
  228. package/src/_modules/messaging/README.md +354 -354
  229. package/src/_modules/messaging/_collections/get-messaging-routing-module.util.ts +26 -26
  230. package/src/_modules/messaging/_collections/msg-global-settings.const.ts +22 -22
  231. package/src/_modules/messaging/_collections/msg.util.spec.ts +226 -226
  232. package/src/_modules/messaging/_models/msg-global-settings.interface.ts +37 -37
  233. package/src/_modules/messaging/_services/msg-conversation.data-service.ts +146 -146
  234. package/src/_modules/messaging/_services/msg-events.service.spec.ts +219 -219
  235. package/src/_modules/messaging/_services/msg-events.service.ts +267 -267
  236. package/src/_modules/messaging/_services/msg-integration.control-service.ts +179 -179
  237. package/src/_modules/messaging/_services/msg-main.control-service.spec.ts +147 -147
  238. package/src/_modules/messaging/_services/msg-main.control-service.ts +571 -571
  239. package/src/_modules/messaging/_services/msg-message.data-service.ts +129 -129
  240. package/src/_modules/messaging/_services/msg.controller.spec.ts +201 -201
  241. package/src/_modules/messaging/index.ts +30 -30
  242. package/src/_modules/mock/app-extended-server.mock.ts +201 -201
  243. package/src/_modules/mock/app-integration-test.mock.ts +51 -51
  244. package/src/_modules/mock/app-params.mock.spec.ts +21 -21
  245. package/src/_modules/mock/app-params.mock.ts +9 -9
  246. package/src/_modules/mock/app-server.mock.ts +188 -188
  247. package/src/_modules/mock/auth-service.mock.spec.ts +47 -47
  248. package/src/_modules/mock/auth-service.mock.ts +28 -28
  249. package/src/_modules/mock/controller.mock.spec.ts +26 -26
  250. package/src/_modules/mock/controller.mock.ts +16 -16
  251. package/src/_modules/mock/data-model.mock.spec.ts +111 -111
  252. package/src/_modules/mock/data-model.mock.ts +82 -82
  253. package/src/_modules/mock/email-service-collection.mock.spec.ts +24 -24
  254. package/src/_modules/mock/email-service-collection.mock.ts +15 -15
  255. package/src/_modules/mock/email-service.mock.spec.ts +17 -17
  256. package/src/_modules/mock/email-service.mock.ts +20 -20
  257. package/src/_modules/mock/email-template.mock.html +14 -14
  258. package/src/_modules/mock/endpoint.mock.ts +91 -91
  259. package/src/_modules/mock/socket-client.mock.spec.ts +40 -40
  260. package/src/_modules/mock/socket-client.mock.ts +45 -45
  261. package/src/_modules/mock/socket-server.mock.spec.ts +44 -44
  262. package/src/_modules/mock/socket-server.mock.ts +46 -46
  263. package/src/_modules/oauth2/_routes/oauth2.controller.spec.ts +107 -107
  264. package/src/_modules/oauth2/_routes/oauth2.controller.ts +98 -98
  265. package/src/_modules/oauth2/_services/oauth2.auth-service.spec.ts +254 -254
  266. package/src/_modules/oauth2/_services/oauth2.auth-service.ts +232 -232
  267. package/src/_modules/oauth2/_services/oauth2.control-service.spec.ts +585 -585
  268. package/src/_modules/oauth2/_services/oauth2.control-service.ts +653 -653
  269. package/src/_modules/oauth2/index.ts +17 -17
  270. package/src/_modules/server/errors/errors.control-service.spec.ts +234 -230
  271. package/src/_modules/server/errors/errors.control-service.ts +77 -69
  272. package/src/_modules/server/errors/errors.controller.spec.ts +238 -235
  273. package/src/_modules/server/errors/errors.controller.ts +402 -372
  274. package/src/_modules/server/errors/errors.data-service.spec.ts +355 -355
  275. package/src/_modules/server/errors/errors.data-service.ts +109 -1
  276. package/src/_modules/server/index.ts +30 -30
  277. package/src/_modules/server/server-status/server-status-snapshot.control-service.spec.ts +70 -70
  278. package/src/_modules/server/server-status/server-status-snapshot.control-service.ts +17 -17
  279. package/src/_modules/server/server-status/server-status-snapshot.data-service.spec.ts +77 -77
  280. package/src/_modules/server/server-status/server-status-snapshot.data-service.ts +37 -37
  281. package/src/_modules/server/server-status/server-status.control-service.spec.ts +520 -516
  282. package/src/_modules/server/server-status/server-status.control-service.ts +336 -336
  283. package/src/_modules/server/server-status/server-status.controller.spec.ts +159 -156
  284. package/src/_modules/server/server-status/server-status.controller.ts +131 -131
  285. package/src/_modules/socket/_enums/socket-security.enum.ts +11 -11
  286. package/src/_modules/socket/_models/socket-client-service-params.control-model.spec.ts +32 -32
  287. package/src/_modules/socket/_models/socket-client-service-params.control-model.ts +22 -22
  288. package/src/_modules/socket/_models/socket-presence.control-model.spec.ts +164 -164
  289. package/src/_modules/socket/_models/socket-presence.control-model.ts +210 -210
  290. package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +46 -46
  291. package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +22 -22
  292. package/src/_modules/socket/_services/socket-client.service.spec.ts +15 -15
  293. package/src/_modules/socket/_services/socket-client.service.ts +260 -260
  294. package/src/_modules/socket/_services/socket-server.service.spec.ts +11 -11
  295. package/src/_modules/socket/app-extended.integration.spec.ts +85 -85
  296. package/src/_modules/socket/app-extended.server.ts +630 -630
  297. package/src/_modules/socket/index.ts +42 -42
  298. package/src/_modules/test/get-test-routing-module.util.spec.ts +28 -28
  299. package/src/_modules/test/get-test-routing-module.util.ts +23 -23
  300. package/src/_modules/test/index.ts +11 -11
  301. package/src/_modules/test/test.controller.spec.ts +72 -72
  302. package/src/_modules/test/test.controller.ts +115 -115
  303. package/src/_modules/usage/get-usage-routing-module.util.ts +22 -22
  304. package/src/_modules/usage/index.ts +15 -15
  305. package/src/_modules/usage/usage.controller.spec.ts +81 -81
  306. package/src/_modules/usage/usage.controller.ts +126 -126
  307. package/src/_modules/usage/usage.data-service.spec.ts +332 -332
  308. package/src/_modules/usage/usage.data-service.ts +185 -185
  309. package/src/_services/base/api.service-base.spec.ts +125 -125
  310. package/src/_services/base/api.service-base.ts +74 -74
  311. package/src/_services/base/archive-data.service.spec.ts +196 -196
  312. package/src/_services/base/archive-data.service.ts +216 -216
  313. package/src/_services/base/data.service.spec.ts +674 -674
  314. package/src/_services/base/data.service.ts +2719 -2719
  315. package/src/_services/base/db.service.spec.ts +73 -73
  316. package/src/_services/base/db.service.ts +1575 -1575
  317. package/src/_services/base/singleton.service-base.spec.ts +28 -28
  318. package/src/_services/base/singleton.service-base.ts +24 -24
  319. package/src/_services/base/singleton.service.spec.ts +114 -114
  320. package/src/_services/base/singleton.service.ts +38 -38
  321. package/src/_services/core/api.service.spec.ts +140 -140
  322. package/src/_services/core/auth.service.spec.ts +159 -159
  323. package/src/_services/core/auth.service.ts +174 -174
  324. package/src/_services/core/email.service.spec.ts +85 -85
  325. package/src/_services/core/email.service.ts +742 -742
  326. package/src/_services/core/global.service.spec.ts +275 -275
  327. package/src/_services/core/global.service.ts +461 -461
  328. package/src/_services/core/service-collection.service.spec.ts +46 -46
  329. package/src/_services/core/service-collection.service.ts +6 -6
  330. package/src/_services/route/controller.service.spec.ts +53 -53
  331. package/src/_services/route/controller.service.ts +148 -148
  332. package/src/_services/route/routing-module.service.spec.ts +98 -98
  333. package/src/_services/route/routing-module.service.ts +330 -330
  334. package/src/_services/shared.static-service.spec.ts +99 -99
  335. package/src/_services/shared.static-service.ts +78 -78
  336. package/src/index.ts +95 -95
  337. package/tsconfig.app.json +12 -12
  338. package/tsconfig.json +42 -42
  339. package/.dynamo/logs/cicd-pipeline/output.log +0 -2593
  340. package/.dynamo/logs/cicd-pipeline/status.json +0 -321
@@ -1,332 +1,510 @@
1
- import { DyNTS_AI_Provider_ServiceBase } from './ai-provider.service-base';
2
- import { DyFM_AI_CallSettings, DyFM_AI_Message, DyFM_AI_LLM_Response, DyFM_AI_MessageRole } from '@futdevpro/fsm-dynamo/ai';
3
- import { DyFM_Error, DyFM_Error_Settings, DyFM_getLocalStackLocation, DyFM_Log, DyFM_Object } from '@futdevpro/fsm-dynamo';
4
- import {
5
- DyFM_AI_GenericSelect_Input,
6
- DyFM_AI_GenericMultiSelect_Input,
7
- DyFM_AI_JSONKeysDescription_Input,
8
- DyFM_AI_JSONExactKeys_Input,
9
- DyFM_AI_Message_Input,
10
- } from '../_models/ai-input-interfaces';
11
- import { Items } from 'openai/resources/conversations/items';
12
-
13
- /**
14
- * Abstract base class for LLM services
15
- * Defines all methods that must be implemented by AI providers
16
- */
17
- export abstract class DyNTS_AI_LLM_ServiceBase<
18
- T_AISettings extends DyFM_AI_CallSettings = DyFM_AI_CallSettings
19
- > extends DyNTS_AI_Provider_ServiceBase {
20
- /** Default settings for LLM calls */
21
- abstract readonly defaultSettings: T_AISettings;
22
-
23
- /** Default model to use for LLM calls */
24
- /* abstract readonly defaultModel: string; */
25
-
26
- /** Provider-specific predefined requests */
27
- abstract readonly predefinedRequests: any;
28
-
29
- _debugLog: boolean = false;
30
- get debugLog(): boolean {
31
- return this.defaultSettings?.debugLog ?? this._debugLog;
32
- }
33
-
34
- get defaultSystemPrompt(): string {
35
- return this.defaultSettings.systemPrompt;
36
- }
37
-
38
- get defaultModel(): string {
39
- return this.defaultSettings.useModel;
40
- }
41
-
42
- defaultLogReplacer: string = '...long-context...';
43
-
44
- // Core abstract methods
45
- /**
46
- * Call LLM with system and user messages
47
- */
48
- /* abstract callLLM(
49
- systemMessage: string,
50
- userMessage: string,
51
- settings?: DyFM_AI_CallSettings,
52
- issuer?: string
53
- ): Promise<string>; */
54
-
55
- /**
56
- * Call LLM with message history
57
- */
58
- /* abstract callLLMWithHistory(
59
- messages: DyFM_AI_Message[],
60
- settings?: DyFM_AI_CallSettings,
61
- issuer?: string
62
- ): Promise<string>; */
63
-
64
- /**
65
- * Call LLM and return raw response
66
- */
67
- /* abstract callLLMRaw(
68
- messages: DyFM_AI_Message[],
69
- settings?: DyFM_AI_CallSettings,
70
- issuer?: string
71
- ): Promise<DyFM_AI_LLM_Response>; */
72
-
73
- // Question methods (from OAI_LLM_ServiceBase)
74
- abstract requestSimpleMessage(set: DyFM_AI_Message_Input<T_AISettings>): Promise<string>;
75
- abstract requestYesNo(set: DyFM_AI_Message_Input<T_AISettings>): Promise<boolean>;
76
- abstract requestPercentage(set: DyFM_AI_Message_Input<T_AISettings>): Promise<number>;
77
-
78
- /* abstract askSelectQuestion(set: DyFM_AI_ListSelect_Input): Promise<string>; */
79
- abstract requestSelect<T>(
80
- set: DyFM_AI_GenericSelect_Input<T, T_AISettings>
81
- ): Promise<T | { unparsableResult: string }>;
82
- /* abstract askMultipleSelectQuestionWithOptions(set: DyFM_AI_MultiSelect_Input): Promise<string[]>; */
83
- abstract requestMultiselect<T>(
84
- set: DyFM_AI_GenericMultiSelect_Input<T, T_AISettings>
85
- ): Promise<T[] | { unparsableResult: string }>;
86
-
87
- abstract requestJSON<T>(set: DyFM_AI_Message_Input<T_AISettings>): Promise<T | { unparsableResult: string }>;
88
- abstract requestJSONQuestionWithKeysDescription<T>(
89
- set: DyFM_AI_JSONKeysDescription_Input<T_AISettings>
90
- ): Promise<T | { unparsableResult: string }>;
91
- /* abstract askJSONQuestionWithExactKeys(set: DyFM_AI_JSONExactKeys_Input): Promise<object>; */
92
- abstract requestJSONWithExactKeys<T>(
93
- set: DyFM_AI_JSONExactKeys_Input<T_AISettings>
94
- ): Promise<T | { unparsableResult: string }>;
95
- /* abstract sendMessage(set: DyFM_AI_SimpleMessage_Input): Promise<string>; */
96
-
97
- /* abstract requestStringList(set: DyFM_AI_Base_Input<T_AISettings>): Promise<string[] | { unparsableResult: string }>; */
98
- abstract requestList<T>(set: DyFM_AI_Message_Input<T_AISettings>): Promise<T[] | { unparsableResult: string }>;
99
-
100
- // Helper methods
101
- /* protected abstract getDefaultErrorSettings(
102
- method: string,
103
- error: any,
104
- issuer?: string
105
- ): DyFM_Error_Settings; */
106
-
107
- /* protected abstract getTextListAsText(list: string[]): string; */
108
-
109
- /* protected abstract logQuestion(set: DyFM_AI_Base_Input<T_AISettings>): void; */
110
-
111
- protected convertAnswerToBoolean(answer: string): boolean {
112
- return answer.toUpperCase().includes(this.predefinedRequests.yesNo.upperCaseYes);
113
- }
114
-
115
- protected convertAnswerToNumber(answer: string, message: string): number {
116
- if (this.isAnswerValid(answer, message)) {
117
- return null;
118
- }
119
-
120
- if (isNaN(+answer)) {
121
- DyFM_Log.T_error(
122
- 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToNumber got an invalid answer',
123
- {
124
- question: message,
125
- answer: answer,
126
- }
127
- );
128
-
129
- return null;
130
- }
131
-
132
- return +answer;
133
- }
134
-
135
- protected convertAnswerToSelectOption<T>(answer: string, message: string, options: T[]): T {
136
- if (this.isAnswerValid(answer, message)) {
137
- return null;
138
- }
139
-
140
- answer = answer.toLocaleUpperCase();
141
-
142
- const stringifiedOptions: string[] = this.stringifySelectOptions(options);
143
- for (const stringifiedItem of stringifiedOptions) {
144
- if (answer.includes(stringifiedItem.toLocaleUpperCase())) {
145
- const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(stringifiedItem);
146
-
147
- if ((parsedItem as { unparsableResult: string }).unparsableResult) {
148
- DyFM_Log.T_error(
149
- 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToSelectOption got an invalid answer',
150
- {
151
- question: message,
152
- answer: answer,
153
- }
154
- );
155
-
156
- return stringifiedItem as T;
157
- } else {
158
- return parsedItem as T;
159
- }
160
- }
161
- }
162
-
163
- return null;
164
- }
165
-
166
- protected convertAnswerToSelectOptions<T>(answer: string, message: string, options: T[]): T[] {
167
- if (this.isAnswerValid(answer, message)) {
168
- return null;
169
- }
170
-
171
- const enrichedOptions: { stringifiedOption: string, parsedOption: T }[] = options.map(
172
- (option: T) => ({
173
- stringifiedOption: this.stringifySelectOption(option),
174
- parsedOption: option
175
- })
176
- );
177
- const result: T[] = [];
178
-
179
- for (const item of enrichedOptions) {
180
- if (answer.includes(item.stringifiedOption)) {
181
- result.push(item.parsedOption);
182
- }
183
- }
184
-
185
- return result;
186
- }
187
-
188
- protected convertAnswerToJSON<T>(answer: string, message: string): T | { unparsableResult: string } {
189
- if (this.isAnswerValid(answer, message)) {
190
- return { unparsableResult: answer };
191
- }
192
-
193
- const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(answer);
194
- if ((parsedItem as { unparsableResult: string }).unparsableResult) {
195
- DyFM_Log.T_error(
196
- 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToJSON got an invalid answer',
197
- {
198
- question: message,
199
- answer: answer,
200
- }
201
- );
202
-
203
- return { unparsableResult: answer };
204
- }
205
-
206
- return parsedItem as T;
207
- }
208
-
209
- protected convertAnswerToList<T>(answer: string, message: string): T[] | { unparsableResult: string } {
210
- if (this.isAnswerValid(answer, message)) {
211
- return { unparsableResult: answer };
212
- }
213
-
214
- // Check if safeParseJSON returns unparsableResult before calling safeParseList
215
- // because safeParseList doesn't properly handle unparsableResult
216
- const parsedCheck: T[] | { unparsableResult: string } = DyFM_Object.safeParseJSON<T[]>(answer, true);
217
- if ((parsedCheck as { unparsableResult: string }).unparsableResult) {
218
- DyFM_Log.T_error(
219
- 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToList got an invalid answer',
220
- {
221
- question: message,
222
- answer: answer,
223
- }
224
- );
225
-
226
- return { unparsableResult: answer };
227
- }
228
-
229
- return DyFM_Object.safeParseList<T[]>(answer);
230
- }
231
-
232
- protected stringifySelectOptions<T>(options: T[]): string[] {
233
- return options.map(item => this.stringifySelectOption(item));
234
- }
235
-
236
- protected stringifySelectOption<T>(option: T): string {
237
- return JSON.stringify(option);
238
- }
239
-
240
- protected isAnswerValid(answer: string, message: string): boolean {
241
- if (!answer?.trim?.()?.length) {
242
- DyFM_Log.T_error(
243
- 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToSelectOption got an invalid answer',
244
- {
245
- question: message,
246
- answer: answer,
247
- }
248
- );
249
-
250
- return true;
251
- }
252
-
253
- return false;
254
- }
255
-
256
- /**
257
- * olvasható mondatszerű-listaszerű formába teszi a listaelemeket
258
- * pl.: ['a', 'b', 'c'] -> '"a", "b" or "c"'
259
- */
260
- protected getTextListAsText(list: string[]): string {
261
- list = list.filter(item => item?.trim()).map(item => `"${item}"`);
262
-
263
- /* list = list.map(item => item.toLocaleLowerCase()); */
264
-
265
- list.push(list.pop() + ' or ' + list.pop());
266
-
267
- return list.join(', ');
268
- }
269
-
270
- protected logQuestion(
271
- set: DyFM_AI_Message_Input<T_AISettings>
272
- ): void {
273
- if (set.settings?.debugLog ?? this._debugLog) {
274
- console.log('\n - ', set.message);
275
- }
276
- }
277
-
278
- protected getDefaultSystemMessage(settings: T_AISettings): DyFM_AI_Message {
279
- return {
280
- role: DyFM_AI_MessageRole.system,
281
- content: settings?.systemPrompt || this.defaultSystemPrompt,
282
- };
283
- }
284
-
285
- protected validateConversation(conversation: DyFM_AI_Message[]): void {
286
- conversation.forEach((message: DyFM_AI_Message, index: number) => {
287
- if (!message.role) {
288
- throw new DyFM_Error({
289
- message: `Message has no role at index ${index}`,
290
- additionalContent: {
291
- invalidMessage: message,
292
- conversation: conversation,
293
- }
294
- });
295
- }
296
- });
297
-
298
- conversation = conversation.filter(message => message.content);
299
- }
300
-
301
- protected logAnswer(answer: string): void {
302
- if (this._debugLog) {
303
- console.log(' - answer: ', answer);
304
- }
305
- }
306
-
307
-
308
-
309
- //////////////////////////////////////////////////////////////////////////////////////////
310
- // LLM CHAT METHODS //
311
- //////////////////////////////////////////////////////////////////////////////////////////
312
-
313
-
314
- protected logConversation(
315
- set: {
316
- conversation: DyFM_AI_Message[],
317
- debugLog?: boolean,
318
- /** this is used to readably replace too long contents to eg '...' in logs */
319
- replaceThisInLog?: string,
320
- }
321
- ) {
322
- if (set.debugLog || this._debugLog) {
323
- DyFM_Log.info('Conversation log at', DyFM_getLocalStackLocation());
324
-
325
- set.conversation.forEach(message => {
326
- console.log(
327
- ` - ${message.role}: ${message.content.replace(set.replaceThisInLog, this.defaultLogReplacer)}`
328
- );
329
- });
330
- }
331
- }
332
- }
1
+ import { DyNTS_AI_Provider_ServiceBase } from './ai-provider.service-base';
2
+ import {
3
+ DyFM_AI_CallSettings,
4
+ DyFM_AI_Message,
5
+ DyFM_AI_LLM_Response,
6
+ DyFM_AI_MessageRole,
7
+ DyFM_AI_Tool,
8
+ DyFM_AI_ToolCall,
9
+ DyFM_AI_ToolResult,
10
+ DyFM_AI_ToolHandlers,
11
+ DyFM_AI_ModelInfo,
12
+ DyFM_AI_ModelRegistry_Util,
13
+ } from '@futdevpro/fsm-dynamo/ai';
14
+ import { DyFM_Error, DyFM_Error_Settings, DyFM_getLocalStackLocation, DyFM_Log, DyFM_Object } from '@futdevpro/fsm-dynamo';
15
+ import {
16
+ DyFM_AI_GenericSelect_Input,
17
+ DyFM_AI_GenericMultiSelect_Input,
18
+ DyFM_AI_JSONKeysDescription_Input,
19
+ DyFM_AI_JSONExactKeys_Input,
20
+ DyFM_AI_Message_Input,
21
+ } from '../_models/ai-input-interfaces';
22
+ import { Items } from 'openai/resources/conversations/items';
23
+
24
+ /**
25
+ * Abstract base class for LLM services
26
+ * Defines all methods that must be implemented by AI providers
27
+ */
28
+ export abstract class DyNTS_AI_LLM_ServiceBase<
29
+ T_AISettings extends DyFM_AI_CallSettings = DyFM_AI_CallSettings
30
+ > extends DyNTS_AI_Provider_ServiceBase {
31
+ /** Default settings for LLM calls */
32
+ abstract readonly defaultSettings: T_AISettings;
33
+
34
+ /** Default model to use for LLM calls */
35
+ /* abstract readonly defaultModel: string; */
36
+
37
+ /** Provider-specific predefined requests */
38
+ abstract readonly predefinedRequests: any;
39
+
40
+ _debugLog: boolean = false;
41
+ get debugLog(): boolean {
42
+ return this.defaultSettings?.debugLog ?? this._debugLog;
43
+ }
44
+
45
+ get defaultSystemPrompt(): string {
46
+ return this.defaultSettings.systemPrompt;
47
+ }
48
+
49
+ get defaultModel(): string {
50
+ return this.defaultSettings.useModel;
51
+ }
52
+
53
+ defaultLogReplacer: string = '...long-context...';
54
+
55
+ //////////////////////////////////////////////////////////////////////////////////////////
56
+ // FUNCTION CALLING (TOOL USE) — FR-047 //
57
+ //////////////////////////////////////////////////////////////////////////////////////////
58
+ // Provider-agnostic agent-loop. The loop logic lives here ONCE (ported from the legacy
59
+ // FDPNTS_GPT_ControlService.getAnswerWithTools); each provider only overrides
60
+ // `callModelWithTools` (one provider turn) and `getModelRegistry` (capability honesty).
61
+ // Tools are a REQUEST parameter (not on settings), per the FR-047 design.
62
+
63
+ /**
64
+ * A provider tool-kepes modell-registry-je (override providerenkent — pl. DyFM_OAI_Models).
65
+ * Ures default a modell tool-kepessege ismeretlen → a precheck elutasitja (honesty).
66
+ */
67
+ protected getModelRegistry(): DyFM_AI_ModelInfo[] {
68
+ return [];
69
+ }
70
+
71
+ /**
72
+ * Ellenorzi, hogy a feloldott modell tamogatja-e a function calling-ot; ha nem, beszedes
73
+ * hibaval elhasal MIELOTT barmilyen API-hivas tortenne (kritikus pl. a Local providernel).
74
+ */
75
+ protected assertToolsSupported(modelId: string): void {
76
+ if (!DyFM_AI_ModelRegistry_Util.modelSupportsTools(this.getModelRegistry(), modelId)) {
77
+ throw new DyFM_Error({
78
+ message: `Model '${modelId}' does not support function calling (provider: ${this.aiProvider})`,
79
+ userMessage: `The selected AI model does not support tools.`,
80
+ errorCode: 'DyNTS-AILSB-TLC0',
81
+ });
82
+ }
83
+ }
84
+
85
+ /**
86
+ * GPT valasz Function Calling Agent Tool-okkal — provider-agnosztikus agent-loop.
87
+ * @description A `tools` definiciok + `toolHandlers` alapjan tool-loop-ot futtat: hivja a
88
+ * modellt (callModelWithTools) → ha a valaszban tool-call van, lefuttatja a regisztralt
89
+ * handler-t (runToolCall, never-throw) es az eredmenyt visszafuzi → ismetli, amig a model
90
+ * vegso (tool-call nelkuli) valaszt ad, vagy a maxIterations limitet eleri. A tool-ok a
91
+ * REQUEST-parameterben jonnek, nem a settings-ben.
92
+ */
93
+ async requestWithTools(
94
+ set: {
95
+ conversation: DyFM_AI_Message[];
96
+ tools: DyFM_AI_Tool[];
97
+ toolHandlers: DyFM_AI_ToolHandlers;
98
+ settings?: T_AISettings;
99
+ issuer: string;
100
+ maxIterations?: number;
101
+ }
102
+ ): Promise<DyFM_AI_LLM_Response> {
103
+ const modelId: string = (set.settings?.useModel ?? this.defaultModel) as string;
104
+ this.assertToolsSupported(modelId);
105
+
106
+ return this.runToolLoop(set);
107
+ }
108
+
109
+ /**
110
+ * Egy provider-kor a tool-loop-ban: elkuldi a beszelgetest + tool-okat, normalizalt valaszt ad.
111
+ * @description Override-olando providerenkent (OpenAI / Anthropic / Google / …). A default
112
+ * elhasal — egy provider, ami nem implementalja, tool-use-t nem tud kiszolgalni.
113
+ */
114
+ protected async callModelWithTools(
115
+ _set: {
116
+ conversation: DyFM_AI_Message[];
117
+ tools: DyFM_AI_Tool[];
118
+ settings?: T_AISettings;
119
+ issuer: string;
120
+ }
121
+ ): Promise<DyFM_AI_LLM_Response> {
122
+ throw new DyFM_Error({
123
+ message: `callModelWithTools is not implemented for provider '${this.aiProvider}'`,
124
+ userMessage: `Function calling is not available for this AI provider yet.`,
125
+ errorCode: 'DyNTS-AILSB-TLN0',
126
+ });
127
+ }
128
+
129
+ /**
130
+ * A provider-agnosztikus agent-loop torzse. A bemeno `conversation` ele a provider teszi a
131
+ * system-message-et (callModelWithTools); a loop a tool-call/tool-result uzeneteket fuzi hozza.
132
+ */
133
+ protected async runToolLoop(
134
+ set: {
135
+ conversation: DyFM_AI_Message[];
136
+ tools: DyFM_AI_Tool[];
137
+ toolHandlers: DyFM_AI_ToolHandlers;
138
+ settings?: T_AISettings;
139
+ issuer: string;
140
+ maxIterations?: number;
141
+ }
142
+ ): Promise<DyFM_AI_LLM_Response> {
143
+ const maxIterations: number = set.maxIterations ?? 8;
144
+ const conversation: DyFM_AI_Message[] = [...set.conversation];
145
+
146
+ for (let iteration: number = 0; iteration < maxIterations; iteration++) {
147
+ const response: DyFM_AI_LLM_Response = await this.callModelWithTools({
148
+ conversation: conversation,
149
+ tools: set.tools,
150
+ settings: set.settings,
151
+ issuer: set.issuer,
152
+ });
153
+
154
+ // nincs tool-hivas → ez a vegso valasz
155
+ if (!response.toolCalls?.length) {
156
+ return response;
157
+ }
158
+
159
+ // a model tool-hivo (assistant) uzenetet visszatesszuk a kontextusba
160
+ conversation.push({
161
+ role: DyFM_AI_MessageRole.assistant,
162
+ content: response.content ?? '',
163
+ toolCalls: response.toolCalls,
164
+ });
165
+
166
+ // minden tool-hivast lefuttatunk (never-throw), es az eredmenyt visszaadjuk a modellnek
167
+ const results: DyFM_AI_ToolResult[] = await Promise.all(
168
+ response.toolCalls.map((call: DyFM_AI_ToolCall) => this.runToolCall(call, set.toolHandlers))
169
+ );
170
+
171
+ results.forEach((result: DyFM_AI_ToolResult) => {
172
+ conversation.push({
173
+ role: DyFM_AI_MessageRole.tool,
174
+ content: result.content,
175
+ toolCallId: result.toolCallId,
176
+ });
177
+ });
178
+ }
179
+
180
+ // a tool-loop nem konvergalt a limiten belul
181
+ throw new DyFM_Error({
182
+ message: `Tool loop did not converge within ${maxIterations} iterations`,
183
+ userMessage: `We encountered an error while running AI tools, please contact the responsible development team.`,
184
+ errorCode: 'DyNTS-AILSB-TL0',
185
+ });
186
+ }
187
+
188
+ /**
189
+ * Egy tool-hivas lefuttatasa a regisztralt handler-rel. SOHA nem dob — a tool-hiba string-kent
190
+ * megy vissza a modellnek (hogy korrigalhasson), hianyzo handler eseten is informativ uzenet
191
+ * (soha nem [object Object]).
192
+ */
193
+ protected async runToolCall(
194
+ call: DyFM_AI_ToolCall,
195
+ toolHandlers: DyFM_AI_ToolHandlers
196
+ ): Promise<DyFM_AI_ToolResult> {
197
+ const handler = toolHandlers[call.name];
198
+
199
+ if (!handler) {
200
+ return {
201
+ toolCallId: call.id,
202
+ content: `ERROR: no handler registered for tool '${call.name}'`,
203
+ isError: true,
204
+ };
205
+ }
206
+
207
+ try {
208
+ return {
209
+ toolCallId: call.id,
210
+ content: await handler(call.arguments),
211
+ };
212
+ } catch (error) {
213
+ return {
214
+ toolCallId: call.id,
215
+ content: `ERROR executing tool '${call.name}': ` +
216
+ `${error instanceof Error ? error.message : String(error)}`,
217
+ isError: true,
218
+ };
219
+ }
220
+ }
221
+
222
+ // Core abstract methods
223
+ /**
224
+ * Call LLM with system and user messages
225
+ */
226
+ /* abstract callLLM(
227
+ systemMessage: string,
228
+ userMessage: string,
229
+ settings?: DyFM_AI_CallSettings,
230
+ issuer?: string
231
+ ): Promise<string>; */
232
+
233
+ /**
234
+ * Call LLM with message history
235
+ */
236
+ /* abstract callLLMWithHistory(
237
+ messages: DyFM_AI_Message[],
238
+ settings?: DyFM_AI_CallSettings,
239
+ issuer?: string
240
+ ): Promise<string>; */
241
+
242
+ /**
243
+ * Call LLM and return raw response
244
+ */
245
+ /* abstract callLLMRaw(
246
+ messages: DyFM_AI_Message[],
247
+ settings?: DyFM_AI_CallSettings,
248
+ issuer?: string
249
+ ): Promise<DyFM_AI_LLM_Response>; */
250
+
251
+ // Question methods (from OAI_LLM_ServiceBase)
252
+ abstract requestSimpleMessage(set: DyFM_AI_Message_Input<T_AISettings>): Promise<string>;
253
+ abstract requestYesNo(set: DyFM_AI_Message_Input<T_AISettings>): Promise<boolean>;
254
+ abstract requestPercentage(set: DyFM_AI_Message_Input<T_AISettings>): Promise<number>;
255
+
256
+ /* abstract askSelectQuestion(set: DyFM_AI_ListSelect_Input): Promise<string>; */
257
+ abstract requestSelect<T>(
258
+ set: DyFM_AI_GenericSelect_Input<T, T_AISettings>
259
+ ): Promise<T | { unparsableResult: string }>;
260
+ /* abstract askMultipleSelectQuestionWithOptions(set: DyFM_AI_MultiSelect_Input): Promise<string[]>; */
261
+ abstract requestMultiselect<T>(
262
+ set: DyFM_AI_GenericMultiSelect_Input<T, T_AISettings>
263
+ ): Promise<T[] | { unparsableResult: string }>;
264
+
265
+ abstract requestJSON<T>(set: DyFM_AI_Message_Input<T_AISettings>): Promise<T | { unparsableResult: string }>;
266
+ abstract requestJSONQuestionWithKeysDescription<T>(
267
+ set: DyFM_AI_JSONKeysDescription_Input<T_AISettings>
268
+ ): Promise<T | { unparsableResult: string }>;
269
+ /* abstract askJSONQuestionWithExactKeys(set: DyFM_AI_JSONExactKeys_Input): Promise<object>; */
270
+ abstract requestJSONWithExactKeys<T>(
271
+ set: DyFM_AI_JSONExactKeys_Input<T_AISettings>
272
+ ): Promise<T | { unparsableResult: string }>;
273
+ /* abstract sendMessage(set: DyFM_AI_SimpleMessage_Input): Promise<string>; */
274
+
275
+ /* abstract requestStringList(set: DyFM_AI_Base_Input<T_AISettings>): Promise<string[] | { unparsableResult: string }>; */
276
+ abstract requestList<T>(set: DyFM_AI_Message_Input<T_AISettings>): Promise<T[] | { unparsableResult: string }>;
277
+
278
+ // Helper methods
279
+ /* protected abstract getDefaultErrorSettings(
280
+ method: string,
281
+ error: any,
282
+ issuer?: string
283
+ ): DyFM_Error_Settings; */
284
+
285
+ /* protected abstract getTextListAsText(list: string[]): string; */
286
+
287
+ /* protected abstract logQuestion(set: DyFM_AI_Base_Input<T_AISettings>): void; */
288
+
289
+ protected convertAnswerToBoolean(answer: string): boolean {
290
+ return answer.toUpperCase().includes(this.predefinedRequests.yesNo.upperCaseYes);
291
+ }
292
+
293
+ protected convertAnswerToNumber(answer: string, message: string): number {
294
+ if (this.isAnswerValid(answer, message)) {
295
+ return null;
296
+ }
297
+
298
+ if (isNaN(+answer)) {
299
+ DyFM_Log.T_error(
300
+ 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToNumber got an invalid answer',
301
+ {
302
+ question: message,
303
+ answer: answer,
304
+ }
305
+ );
306
+
307
+ return null;
308
+ }
309
+
310
+ return +answer;
311
+ }
312
+
313
+ protected convertAnswerToSelectOption<T>(answer: string, message: string, options: T[]): T {
314
+ if (this.isAnswerValid(answer, message)) {
315
+ return null;
316
+ }
317
+
318
+ answer = answer.toLocaleUpperCase();
319
+
320
+ const stringifiedOptions: string[] = this.stringifySelectOptions(options);
321
+ for (const stringifiedItem of stringifiedOptions) {
322
+ if (answer.includes(stringifiedItem.toLocaleUpperCase())) {
323
+ const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(stringifiedItem);
324
+
325
+ if ((parsedItem as { unparsableResult: string }).unparsableResult) {
326
+ DyFM_Log.T_error(
327
+ 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToSelectOption got an invalid answer',
328
+ {
329
+ question: message,
330
+ answer: answer,
331
+ }
332
+ );
333
+
334
+ return stringifiedItem as T;
335
+ } else {
336
+ return parsedItem as T;
337
+ }
338
+ }
339
+ }
340
+
341
+ return null;
342
+ }
343
+
344
+ protected convertAnswerToSelectOptions<T>(answer: string, message: string, options: T[]): T[] {
345
+ if (this.isAnswerValid(answer, message)) {
346
+ return null;
347
+ }
348
+
349
+ const enrichedOptions: { stringifiedOption: string, parsedOption: T }[] = options.map(
350
+ (option: T) => ({
351
+ stringifiedOption: this.stringifySelectOption(option),
352
+ parsedOption: option
353
+ })
354
+ );
355
+ const result: T[] = [];
356
+
357
+ for (const item of enrichedOptions) {
358
+ if (answer.includes(item.stringifiedOption)) {
359
+ result.push(item.parsedOption);
360
+ }
361
+ }
362
+
363
+ return result;
364
+ }
365
+
366
+ protected convertAnswerToJSON<T>(answer: string, message: string): T | { unparsableResult: string } {
367
+ if (this.isAnswerValid(answer, message)) {
368
+ return { unparsableResult: answer };
369
+ }
370
+
371
+ const parsedItem: T | { unparsableResult: string } = DyFM_Object.safeParseJSON<T>(answer);
372
+ if ((parsedItem as { unparsableResult: string }).unparsableResult) {
373
+ DyFM_Log.T_error(
374
+ 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToJSON got an invalid answer',
375
+ {
376
+ question: message,
377
+ answer: answer,
378
+ }
379
+ );
380
+
381
+ return { unparsableResult: answer };
382
+ }
383
+
384
+ return parsedItem as T;
385
+ }
386
+
387
+ protected convertAnswerToList<T>(answer: string, message: string): T[] | { unparsableResult: string } {
388
+ if (this.isAnswerValid(answer, message)) {
389
+ return { unparsableResult: answer };
390
+ }
391
+
392
+ // Check if safeParseJSON returns unparsableResult before calling safeParseList
393
+ // because safeParseList doesn't properly handle unparsableResult
394
+ const parsedCheck: T[] | { unparsableResult: string } = DyFM_Object.safeParseJSON<T[]>(answer, true);
395
+ if ((parsedCheck as { unparsableResult: string }).unparsableResult) {
396
+ DyFM_Log.T_error(
397
+ 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToList got an invalid answer',
398
+ {
399
+ question: message,
400
+ answer: answer,
401
+ }
402
+ );
403
+
404
+ return { unparsableResult: answer };
405
+ }
406
+
407
+ return DyFM_Object.safeParseList<T[]>(answer);
408
+ }
409
+
410
+ protected stringifySelectOptions<T>(options: T[]): string[] {
411
+ return options.map(item => this.stringifySelectOption(item));
412
+ }
413
+
414
+ protected stringifySelectOption<T>(option: T): string {
415
+ return JSON.stringify(option);
416
+ }
417
+
418
+ protected isAnswerValid(answer: string, message: string): boolean {
419
+ if (!answer?.trim?.()?.length) {
420
+ DyFM_Log.T_error(
421
+ 'DyNTS_AI_LLMChat_ServiceBase.convertAnswerToSelectOption got an invalid answer',
422
+ {
423
+ question: message,
424
+ answer: answer,
425
+ }
426
+ );
427
+
428
+ return true;
429
+ }
430
+
431
+ return false;
432
+ }
433
+
434
+ /**
435
+ * olvasható mondatszerű-listaszerű formába teszi a listaelemeket
436
+ * pl.: ['a', 'b', 'c'] -> '"a", "b" or "c"'
437
+ */
438
+ protected getTextListAsText(list: string[]): string {
439
+ list = list.filter(item => item?.trim()).map(item => `"${item}"`);
440
+
441
+ /* list = list.map(item => item.toLocaleLowerCase()); */
442
+
443
+ list.push(list.pop() + ' or ' + list.pop());
444
+
445
+ return list.join(', ');
446
+ }
447
+
448
+ protected logQuestion(
449
+ set: DyFM_AI_Message_Input<T_AISettings>
450
+ ): void {
451
+ if (set.settings?.debugLog ?? this._debugLog) {
452
+ console.log('\n - ', set.message);
453
+ }
454
+ }
455
+
456
+ protected getDefaultSystemMessage(settings: T_AISettings): DyFM_AI_Message {
457
+ return {
458
+ role: DyFM_AI_MessageRole.system,
459
+ content: settings?.systemPrompt || this.defaultSystemPrompt,
460
+ };
461
+ }
462
+
463
+ protected validateConversation(conversation: DyFM_AI_Message[]): void {
464
+ conversation.forEach((message: DyFM_AI_Message, index: number) => {
465
+ if (!message.role) {
466
+ throw new DyFM_Error({
467
+ message: `Message has no role at index ${index}`,
468
+ additionalContent: {
469
+ invalidMessage: message,
470
+ conversation: conversation,
471
+ }
472
+ });
473
+ }
474
+ });
475
+
476
+ conversation = conversation.filter(message => message.content);
477
+ }
478
+
479
+ protected logAnswer(answer: string): void {
480
+ if (this._debugLog) {
481
+ console.log(' - answer: ', answer);
482
+ }
483
+ }
484
+
485
+
486
+
487
+ //////////////////////////////////////////////////////////////////////////////////////////
488
+ // LLM CHAT METHODS //
489
+ //////////////////////////////////////////////////////////////////////////////////////////
490
+
491
+
492
+ protected logConversation(
493
+ set: {
494
+ conversation: DyFM_AI_Message[],
495
+ debugLog?: boolean,
496
+ /** this is used to readably replace too long contents to eg '...' in logs */
497
+ replaceThisInLog?: string,
498
+ }
499
+ ) {
500
+ if (set.debugLog || this._debugLog) {
501
+ DyFM_Log.info('Conversation log at', DyFM_getLocalStackLocation());
502
+
503
+ set.conversation.forEach(message => {
504
+ console.log(
505
+ ` - ${message.role}: ${message.content.replace(set.replaceThisInLog, this.defaultLogReplacer)}`
506
+ );
507
+ });
508
+ }
509
+ }
510
+ }