@futdevpro/nts-dynamo 1.15.104 → 1.15.107

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