@futdevpro/nts-dynamo 1.15.86 → 1.15.88

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