@multiplayer-app/ai-agent-node 0.1.0-beta.8 → 0.1.0-beta.81

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 (338) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/config.cjs +88 -37
  3. package/dist/cjs/config.cjs.map +1 -1
  4. package/dist/cjs/config.d.ts +62 -23
  5. package/dist/cjs/config.d.ts.map +1 -1
  6. package/dist/cjs/helpers/AIHelper.cjs +134 -68
  7. package/dist/cjs/helpers/AIHelper.cjs.map +1 -1
  8. package/dist/cjs/helpers/AIHelper.d.ts +24 -16
  9. package/dist/cjs/helpers/AIHelper.d.ts.map +1 -1
  10. package/dist/cjs/helpers/AIHelper.test.cjs +22 -15
  11. package/dist/cjs/helpers/AIHelper.test.cjs.map +1 -1
  12. package/dist/cjs/helpers/ConfigHelper.cjs +15 -6
  13. package/dist/cjs/helpers/ConfigHelper.cjs.map +1 -1
  14. package/dist/cjs/helpers/ConfigHelper.d.ts.map +1 -1
  15. package/dist/cjs/helpers/FileHelper.cjs +131 -151
  16. package/dist/cjs/helpers/FileHelper.cjs.map +1 -1
  17. package/dist/cjs/helpers/FileHelper.d.ts +19 -25
  18. package/dist/cjs/helpers/FileHelper.d.ts.map +1 -1
  19. package/dist/cjs/helpers/index.cjs +0 -1
  20. package/dist/cjs/helpers/index.cjs.map +1 -1
  21. package/dist/cjs/helpers/index.d.ts +0 -1
  22. package/dist/cjs/helpers/index.d.ts.map +1 -1
  23. package/dist/cjs/index.cjs +125 -28
  24. package/dist/cjs/index.cjs.map +1 -1
  25. package/dist/cjs/index.d.ts +47 -11
  26. package/dist/cjs/index.d.ts.map +1 -1
  27. package/dist/cjs/libs/index.cjs +0 -1
  28. package/dist/cjs/libs/index.cjs.map +1 -1
  29. package/dist/cjs/libs/index.d.ts +0 -1
  30. package/dist/cjs/libs/index.d.ts.map +1 -1
  31. package/dist/cjs/libs/s3/index.cjs +3 -39
  32. package/dist/cjs/libs/s3/index.cjs.map +1 -1
  33. package/dist/cjs/libs/s3/index.d.ts +1 -2
  34. package/dist/cjs/libs/s3/index.d.ts.map +1 -1
  35. package/dist/cjs/libs/s3/s3.lib.cjs +173 -186
  36. package/dist/cjs/libs/s3/s3.lib.cjs.map +1 -1
  37. package/dist/cjs/libs/s3/s3.lib.d.ts +29 -22
  38. package/dist/cjs/libs/s3/s3.lib.d.ts.map +1 -1
  39. package/dist/cjs/processors/ActivityProcessor.cjs +53 -0
  40. package/dist/cjs/processors/ActivityProcessor.cjs.map +1 -0
  41. package/dist/cjs/processors/ActivityProcessor.d.ts +34 -0
  42. package/dist/cjs/processors/ActivityProcessor.d.ts.map +1 -0
  43. package/dist/cjs/processors/ActivityProcessor.test.cjs +139 -0
  44. package/dist/cjs/processors/ActivityProcessor.test.cjs.map +1 -0
  45. package/dist/cjs/processors/ActivityProcessor.test.d.ts +2 -0
  46. package/dist/cjs/processors/ActivityProcessor.test.d.ts.map +1 -0
  47. package/dist/cjs/processors/AgentProcessor.cjs +47 -0
  48. package/dist/cjs/processors/AgentProcessor.cjs.map +1 -0
  49. package/dist/cjs/processors/AgentProcessor.d.ts +25 -0
  50. package/dist/cjs/processors/AgentProcessor.d.ts.map +1 -0
  51. package/dist/cjs/processors/AgentProcessor.test.cjs +103 -0
  52. package/dist/cjs/processors/AgentProcessor.test.cjs.map +1 -0
  53. package/dist/cjs/processors/AgentProcessor.test.d.ts +2 -0
  54. package/dist/cjs/processors/AgentProcessor.test.d.ts.map +1 -0
  55. package/dist/cjs/processors/ChatProcessor.cjs +1029 -148
  56. package/dist/cjs/processors/ChatProcessor.cjs.map +1 -1
  57. package/dist/cjs/processors/ChatProcessor.d.ts +108 -12
  58. package/dist/cjs/processors/ChatProcessor.d.ts.map +1 -1
  59. package/dist/cjs/processors/ChatProcessor.test.cjs +803 -0
  60. package/dist/cjs/processors/ChatProcessor.test.cjs.map +1 -0
  61. package/dist/cjs/processors/ChatProcessor.test.d.ts +2 -0
  62. package/dist/cjs/processors/ChatProcessor.test.d.ts.map +1 -0
  63. package/dist/cjs/processors/index.cjs +2 -0
  64. package/dist/cjs/processors/index.cjs.map +1 -1
  65. package/dist/cjs/processors/index.d.ts +2 -0
  66. package/dist/cjs/processors/index.d.ts.map +1 -1
  67. package/dist/cjs/services/AIService.cjs +114 -68
  68. package/dist/cjs/services/AIService.cjs.map +1 -1
  69. package/dist/cjs/services/AIService.d.ts +34 -13
  70. package/dist/cjs/services/AIService.d.ts.map +1 -1
  71. package/dist/cjs/services/CredentialProvider.cjs +62 -0
  72. package/dist/cjs/services/CredentialProvider.cjs.map +1 -0
  73. package/dist/cjs/services/CredentialProvider.d.ts +20 -0
  74. package/dist/cjs/services/CredentialProvider.d.ts.map +1 -0
  75. package/dist/cjs/services/CredentialProvider.test.cjs +71 -0
  76. package/dist/cjs/services/CredentialProvider.test.cjs.map +1 -0
  77. package/dist/cjs/services/CredentialProvider.test.d.ts +2 -0
  78. package/dist/cjs/services/CredentialProvider.test.d.ts.map +1 -0
  79. package/dist/cjs/services/ExecutionContext.cjs +3 -0
  80. package/dist/cjs/services/ExecutionContext.cjs.map +1 -0
  81. package/dist/cjs/services/ExecutionContext.d.ts +4 -0
  82. package/dist/cjs/services/ExecutionContext.d.ts.map +1 -0
  83. package/dist/cjs/services/InternalEventsHandler.cjs +3 -3
  84. package/dist/cjs/services/InternalEventsHandler.cjs.map +1 -1
  85. package/dist/cjs/services/InternalEventsHandler.d.ts +3 -1
  86. package/dist/cjs/services/InternalEventsHandler.d.ts.map +1 -1
  87. package/dist/cjs/services/ModelAccessPolicy.cjs +24 -0
  88. package/dist/cjs/services/ModelAccessPolicy.cjs.map +1 -0
  89. package/dist/cjs/services/ModelAccessPolicy.d.ts +7 -0
  90. package/dist/cjs/services/ModelAccessPolicy.d.ts.map +1 -0
  91. package/dist/cjs/services/ModelFetcher.cjs +2 -8
  92. package/dist/cjs/services/ModelFetcher.cjs.map +1 -1
  93. package/dist/cjs/services/ModelFetcher.d.ts +2 -7
  94. package/dist/cjs/services/ModelFetcher.d.ts.map +1 -1
  95. package/dist/cjs/services/ProviderClientFactory.cjs +29 -0
  96. package/dist/cjs/services/ProviderClientFactory.cjs.map +1 -0
  97. package/dist/cjs/services/ProviderClientFactory.d.ts +9 -0
  98. package/dist/cjs/services/ProviderClientFactory.d.ts.map +1 -0
  99. package/dist/cjs/services/RedisService.cjs +20 -16
  100. package/dist/cjs/services/RedisService.cjs.map +1 -1
  101. package/dist/cjs/services/RedisService.d.ts +5 -2
  102. package/dist/cjs/services/RedisService.d.ts.map +1 -1
  103. package/dist/cjs/services/SocketService.cjs +8 -8
  104. package/dist/cjs/services/SocketService.cjs.map +1 -1
  105. package/dist/cjs/services/SocketService.d.ts +9 -6
  106. package/dist/cjs/services/SocketService.d.ts.map +1 -1
  107. package/dist/cjs/services/TenantCredentialResolver.cjs +136 -0
  108. package/dist/cjs/services/TenantCredentialResolver.cjs.map +1 -0
  109. package/dist/cjs/services/TenantCredentialResolver.d.ts +32 -0
  110. package/dist/cjs/services/TenantCredentialResolver.d.ts.map +1 -0
  111. package/dist/cjs/services/TenantCredentialResolver.test.cjs +113 -0
  112. package/dist/cjs/services/TenantCredentialResolver.test.cjs.map +1 -0
  113. package/dist/cjs/services/TenantCredentialResolver.test.d.ts +2 -0
  114. package/dist/cjs/services/TenantCredentialResolver.test.d.ts.map +1 -0
  115. package/dist/cjs/services/index.cjs +5 -1
  116. package/dist/cjs/services/index.cjs.map +1 -1
  117. package/dist/cjs/services/index.d.ts +5 -1
  118. package/dist/cjs/services/index.d.ts.map +1 -1
  119. package/dist/cjs/store/AgentStore.cjs +14 -4
  120. package/dist/cjs/store/AgentStore.cjs.map +1 -1
  121. package/dist/cjs/store/AgentStore.d.ts +3 -1
  122. package/dist/cjs/store/AgentStore.d.ts.map +1 -1
  123. package/dist/cjs/store/ConfigStore.cjs +14 -3
  124. package/dist/cjs/store/ConfigStore.cjs.map +1 -1
  125. package/dist/cjs/store/ConfigStore.d.ts +2 -0
  126. package/dist/cjs/store/ConfigStore.d.ts.map +1 -1
  127. package/dist/cjs/tools/generateChartTool.d.ts +2 -2
  128. package/dist/cjs/tools/proposeFormValuesTool.d.ts +2 -2
  129. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  130. package/dist/cjs/utils/utils.cjs +31 -0
  131. package/dist/cjs/utils/utils.cjs.map +1 -0
  132. package/dist/cjs/utils/utils.d.ts +5 -0
  133. package/dist/cjs/utils/utils.d.ts.map +1 -0
  134. package/dist/esm/config.d.ts +62 -23
  135. package/dist/esm/config.d.ts.map +1 -1
  136. package/dist/esm/config.js +88 -35
  137. package/dist/esm/config.js.map +1 -1
  138. package/dist/esm/helpers/AIHelper.d.ts +24 -16
  139. package/dist/esm/helpers/AIHelper.d.ts.map +1 -1
  140. package/dist/esm/helpers/AIHelper.js +141 -73
  141. package/dist/esm/helpers/AIHelper.js.map +1 -1
  142. package/dist/esm/helpers/AIHelper.test.js +22 -15
  143. package/dist/esm/helpers/AIHelper.test.js.map +1 -1
  144. package/dist/esm/helpers/ConfigHelper.d.ts.map +1 -1
  145. package/dist/esm/helpers/ConfigHelper.js +15 -6
  146. package/dist/esm/helpers/ConfigHelper.js.map +1 -1
  147. package/dist/esm/helpers/FileHelper.d.ts +19 -25
  148. package/dist/esm/helpers/FileHelper.d.ts.map +1 -1
  149. package/dist/esm/helpers/FileHelper.js +131 -146
  150. package/dist/esm/helpers/FileHelper.js.map +1 -1
  151. package/dist/esm/helpers/index.d.ts +0 -1
  152. package/dist/esm/helpers/index.d.ts.map +1 -1
  153. package/dist/esm/helpers/index.js +0 -1
  154. package/dist/esm/helpers/index.js.map +1 -1
  155. package/dist/esm/index.d.ts +47 -11
  156. package/dist/esm/index.d.ts.map +1 -1
  157. package/dist/esm/index.js +98 -11
  158. package/dist/esm/index.js.map +1 -1
  159. package/dist/esm/libs/index.d.ts +0 -1
  160. package/dist/esm/libs/index.d.ts.map +1 -1
  161. package/dist/esm/libs/index.js +0 -1
  162. package/dist/esm/libs/index.js.map +1 -1
  163. package/dist/esm/libs/s3/index.d.ts +1 -2
  164. package/dist/esm/libs/s3/index.d.ts.map +1 -1
  165. package/dist/esm/libs/s3/index.js +1 -2
  166. package/dist/esm/libs/s3/index.js.map +1 -1
  167. package/dist/esm/libs/s3/s3.lib.d.ts +29 -22
  168. package/dist/esm/libs/s3/s3.lib.d.ts.map +1 -1
  169. package/dist/esm/libs/s3/s3.lib.js +177 -172
  170. package/dist/esm/libs/s3/s3.lib.js.map +1 -1
  171. package/dist/esm/processors/ActivityProcessor.d.ts +34 -0
  172. package/dist/esm/processors/ActivityProcessor.d.ts.map +1 -0
  173. package/dist/esm/processors/ActivityProcessor.js +50 -0
  174. package/dist/esm/processors/ActivityProcessor.js.map +1 -0
  175. package/dist/esm/processors/ActivityProcessor.test.d.ts +2 -0
  176. package/dist/esm/processors/ActivityProcessor.test.d.ts.map +1 -0
  177. package/dist/esm/processors/ActivityProcessor.test.js +137 -0
  178. package/dist/esm/processors/ActivityProcessor.test.js.map +1 -0
  179. package/dist/esm/processors/AgentProcessor.d.ts +25 -0
  180. package/dist/esm/processors/AgentProcessor.d.ts.map +1 -0
  181. package/dist/esm/processors/AgentProcessor.js +44 -0
  182. package/dist/esm/processors/AgentProcessor.js.map +1 -0
  183. package/dist/esm/processors/AgentProcessor.test.d.ts +2 -0
  184. package/dist/esm/processors/AgentProcessor.test.d.ts.map +1 -0
  185. package/dist/esm/processors/AgentProcessor.test.js +101 -0
  186. package/dist/esm/processors/AgentProcessor.test.js.map +1 -0
  187. package/dist/esm/processors/ChatProcessor.d.ts +108 -12
  188. package/dist/esm/processors/ChatProcessor.d.ts.map +1 -1
  189. package/dist/esm/processors/ChatProcessor.js +1038 -150
  190. package/dist/esm/processors/ChatProcessor.js.map +1 -1
  191. package/dist/esm/processors/ChatProcessor.test.d.ts +2 -0
  192. package/dist/esm/processors/ChatProcessor.test.d.ts.map +1 -0
  193. package/dist/esm/processors/ChatProcessor.test.js +801 -0
  194. package/dist/esm/processors/ChatProcessor.test.js.map +1 -0
  195. package/dist/esm/processors/index.d.ts +2 -0
  196. package/dist/esm/processors/index.d.ts.map +1 -1
  197. package/dist/esm/processors/index.js +2 -0
  198. package/dist/esm/processors/index.js.map +1 -1
  199. package/dist/esm/services/AIService.d.ts +34 -13
  200. package/dist/esm/services/AIService.d.ts.map +1 -1
  201. package/dist/esm/services/AIService.js +118 -68
  202. package/dist/esm/services/AIService.js.map +1 -1
  203. package/dist/esm/services/CredentialProvider.d.ts +20 -0
  204. package/dist/esm/services/CredentialProvider.d.ts.map +1 -0
  205. package/dist/esm/services/CredentialProvider.js +60 -0
  206. package/dist/esm/services/CredentialProvider.js.map +1 -0
  207. package/dist/esm/services/CredentialProvider.test.d.ts +2 -0
  208. package/dist/esm/services/CredentialProvider.test.d.ts.map +1 -0
  209. package/dist/esm/services/CredentialProvider.test.js +69 -0
  210. package/dist/esm/services/CredentialProvider.test.js.map +1 -0
  211. package/dist/esm/services/ExecutionContext.d.ts +4 -0
  212. package/dist/esm/services/ExecutionContext.d.ts.map +1 -0
  213. package/dist/esm/services/ExecutionContext.js +2 -0
  214. package/dist/esm/services/ExecutionContext.js.map +1 -0
  215. package/dist/esm/services/InternalEventsHandler.d.ts +3 -1
  216. package/dist/esm/services/InternalEventsHandler.d.ts.map +1 -1
  217. package/dist/esm/services/InternalEventsHandler.js +4 -3
  218. package/dist/esm/services/InternalEventsHandler.js.map +1 -1
  219. package/dist/esm/services/ModelAccessPolicy.d.ts +7 -0
  220. package/dist/esm/services/ModelAccessPolicy.d.ts.map +1 -0
  221. package/dist/esm/services/ModelAccessPolicy.js +20 -0
  222. package/dist/esm/services/ModelAccessPolicy.js.map +1 -0
  223. package/dist/esm/services/ModelFetcher.d.ts +2 -7
  224. package/dist/esm/services/ModelFetcher.d.ts.map +1 -1
  225. package/dist/esm/services/ModelFetcher.js +2 -8
  226. package/dist/esm/services/ModelFetcher.js.map +1 -1
  227. package/dist/esm/services/ProviderClientFactory.d.ts +9 -0
  228. package/dist/esm/services/ProviderClientFactory.d.ts.map +1 -0
  229. package/dist/esm/services/ProviderClientFactory.js +25 -0
  230. package/dist/esm/services/ProviderClientFactory.js.map +1 -0
  231. package/dist/esm/services/RedisService.d.ts +5 -2
  232. package/dist/esm/services/RedisService.d.ts.map +1 -1
  233. package/dist/esm/services/RedisService.js +21 -14
  234. package/dist/esm/services/RedisService.js.map +1 -1
  235. package/dist/esm/services/SocketService.d.ts +9 -6
  236. package/dist/esm/services/SocketService.d.ts.map +1 -1
  237. package/dist/esm/services/SocketService.js +10 -6
  238. package/dist/esm/services/SocketService.js.map +1 -1
  239. package/dist/esm/services/TenantCredentialResolver.d.ts +32 -0
  240. package/dist/esm/services/TenantCredentialResolver.d.ts.map +1 -0
  241. package/dist/esm/services/TenantCredentialResolver.js +133 -0
  242. package/dist/esm/services/TenantCredentialResolver.js.map +1 -0
  243. package/dist/esm/services/TenantCredentialResolver.test.d.ts +2 -0
  244. package/dist/esm/services/TenantCredentialResolver.test.d.ts.map +1 -0
  245. package/dist/esm/services/TenantCredentialResolver.test.js +111 -0
  246. package/dist/esm/services/TenantCredentialResolver.test.js.map +1 -0
  247. package/dist/esm/services/index.d.ts +5 -1
  248. package/dist/esm/services/index.d.ts.map +1 -1
  249. package/dist/esm/services/index.js +5 -1
  250. package/dist/esm/services/index.js.map +1 -1
  251. package/dist/esm/store/AgentStore.d.ts +3 -1
  252. package/dist/esm/store/AgentStore.d.ts.map +1 -1
  253. package/dist/esm/store/AgentStore.js +15 -2
  254. package/dist/esm/store/AgentStore.js.map +1 -1
  255. package/dist/esm/store/ConfigStore.d.ts +2 -0
  256. package/dist/esm/store/ConfigStore.d.ts.map +1 -1
  257. package/dist/esm/store/ConfigStore.js +14 -3
  258. package/dist/esm/store/ConfigStore.js.map +1 -1
  259. package/dist/esm/tools/generateChartTool.d.ts +2 -2
  260. package/dist/esm/tools/proposeFormValuesTool.d.ts +2 -2
  261. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  262. package/dist/esm/utils/utils.d.ts +5 -0
  263. package/dist/esm/utils/utils.d.ts.map +1 -0
  264. package/dist/esm/utils/utils.js +26 -0
  265. package/dist/esm/utils/utils.js.map +1 -0
  266. package/package.json +7 -8
  267. package/dist/cjs/helpers/SetupHelper.cjs +0 -37
  268. package/dist/cjs/helpers/SetupHelper.cjs.map +0 -1
  269. package/dist/cjs/helpers/SetupHelper.d.ts +0 -5
  270. package/dist/cjs/helpers/SetupHelper.d.ts.map +0 -1
  271. package/dist/cjs/libs/kafka/config.cjs +0 -8
  272. package/dist/cjs/libs/kafka/config.cjs.map +0 -1
  273. package/dist/cjs/libs/kafka/config.d.ts +0 -5
  274. package/dist/cjs/libs/kafka/config.d.ts.map +0 -1
  275. package/dist/cjs/libs/kafka/consumer.cjs +0 -131
  276. package/dist/cjs/libs/kafka/consumer.cjs.map +0 -1
  277. package/dist/cjs/libs/kafka/consumer.d.ts +0 -16
  278. package/dist/cjs/libs/kafka/consumer.d.ts.map +0 -1
  279. package/dist/cjs/libs/kafka/index.cjs +0 -19
  280. package/dist/cjs/libs/kafka/index.cjs.map +0 -1
  281. package/dist/cjs/libs/kafka/index.d.ts +0 -3
  282. package/dist/cjs/libs/kafka/index.d.ts.map +0 -1
  283. package/dist/cjs/libs/kafka/kafka.cjs +0 -27
  284. package/dist/cjs/libs/kafka/kafka.cjs.map +0 -1
  285. package/dist/cjs/libs/kafka/kafka.d.ts +0 -3
  286. package/dist/cjs/libs/kafka/kafka.d.ts.map +0 -1
  287. package/dist/cjs/libs/kafka/producer.cjs +0 -48
  288. package/dist/cjs/libs/kafka/producer.cjs.map +0 -1
  289. package/dist/cjs/libs/kafka/producer.d.ts +0 -11
  290. package/dist/cjs/libs/kafka/producer.d.ts.map +0 -1
  291. package/dist/cjs/libs/logger/config.cjs +0 -8
  292. package/dist/cjs/libs/logger/config.cjs.map +0 -1
  293. package/dist/cjs/libs/logger/config.d.ts +0 -5
  294. package/dist/cjs/libs/logger/config.d.ts.map +0 -1
  295. package/dist/cjs/libs/s3/config.cjs +0 -10
  296. package/dist/cjs/libs/s3/config.cjs.map +0 -1
  297. package/dist/cjs/libs/s3/config.d.ts +0 -7
  298. package/dist/cjs/libs/s3/config.d.ts.map +0 -1
  299. package/dist/cjs/services/KafkaService.cjs +0 -122
  300. package/dist/cjs/services/KafkaService.cjs.map +0 -1
  301. package/dist/cjs/services/KafkaService.d.ts +0 -35
  302. package/dist/cjs/services/KafkaService.d.ts.map +0 -1
  303. package/dist/esm/helpers/SetupHelper.d.ts +0 -5
  304. package/dist/esm/helpers/SetupHelper.d.ts.map +0 -1
  305. package/dist/esm/helpers/SetupHelper.js +0 -32
  306. package/dist/esm/helpers/SetupHelper.js.map +0 -1
  307. package/dist/esm/libs/kafka/config.d.ts +0 -5
  308. package/dist/esm/libs/kafka/config.d.ts.map +0 -1
  309. package/dist/esm/libs/kafka/config.js +0 -5
  310. package/dist/esm/libs/kafka/config.js.map +0 -1
  311. package/dist/esm/libs/kafka/consumer.d.ts +0 -16
  312. package/dist/esm/libs/kafka/consumer.d.ts.map +0 -1
  313. package/dist/esm/libs/kafka/consumer.js +0 -125
  314. package/dist/esm/libs/kafka/consumer.js.map +0 -1
  315. package/dist/esm/libs/kafka/index.d.ts +0 -3
  316. package/dist/esm/libs/kafka/index.d.ts.map +0 -1
  317. package/dist/esm/libs/kafka/index.js +0 -3
  318. package/dist/esm/libs/kafka/index.js.map +0 -1
  319. package/dist/esm/libs/kafka/kafka.d.ts +0 -3
  320. package/dist/esm/libs/kafka/kafka.d.ts.map +0 -1
  321. package/dist/esm/libs/kafka/kafka.js +0 -24
  322. package/dist/esm/libs/kafka/kafka.js.map +0 -1
  323. package/dist/esm/libs/kafka/producer.d.ts +0 -11
  324. package/dist/esm/libs/kafka/producer.d.ts.map +0 -1
  325. package/dist/esm/libs/kafka/producer.js +0 -45
  326. package/dist/esm/libs/kafka/producer.js.map +0 -1
  327. package/dist/esm/libs/logger/config.d.ts +0 -5
  328. package/dist/esm/libs/logger/config.d.ts.map +0 -1
  329. package/dist/esm/libs/logger/config.js +0 -5
  330. package/dist/esm/libs/logger/config.js.map +0 -1
  331. package/dist/esm/libs/s3/config.d.ts +0 -7
  332. package/dist/esm/libs/s3/config.d.ts.map +0 -1
  333. package/dist/esm/libs/s3/config.js +0 -7
  334. package/dist/esm/libs/s3/config.js.map +0 -1
  335. package/dist/esm/services/KafkaService.d.ts +0 -35
  336. package/dist/esm/services/KafkaService.d.ts.map +0 -1
  337. package/dist/esm/services/KafkaService.js +0 -123
  338. package/dist/esm/services/KafkaService.js.map +0 -1
@@ -2,75 +2,361 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ChatProcessor = void 0;
4
4
  const ai_agent_types_1 = require("@multiplayer-app/ai-agent-types");
5
- const services_1 = require("../services/index.cjs");
6
- const services_2 = require("../services/index.cjs");
7
- const helpers_1 = require("../helpers/index.cjs");
5
+ const zod_1 = require("zod");
8
6
  const store_1 = require("../store/index.cjs");
9
- const helpers_2 = require("../helpers/index.cjs");
10
- const config_1 = require("../config.cjs");
7
+ const helpers_1 = require("../helpers/index.cjs");
11
8
  const stream_1 = require("stream");
12
- const util_1 = require("util");
13
9
  const logger_1 = require("../libs/logger/index.cjs");
14
- const pipelineAsync = (0, util_1.promisify)(stream_1.pipeline);
10
+ const ai_agent_types_2 = require("@multiplayer-app/ai-agent-types");
11
+ const utils_1 = require("../utils/utils.cjs");
15
12
  class ChatProcessor {
16
- constructor(chatRepository, messageRepository, artifactStore) {
17
- this.chatRepository = chatRepository;
18
- this.messageRepository = messageRepository;
19
- this.artifactStore = artifactStore;
13
+ getChatUserId(chat) {
14
+ return chat.tenants?.userId;
15
+ }
16
+ constructor(params) {
17
+ this.chatRepository = params.chatRepository;
18
+ this.messageRepository = params.messageRepository;
19
+ this.artifactStore = params.artifactStore;
20
+ this.config = params.config;
21
+ this.socketService = params.socketService;
22
+ this.agentStore = params.agentStore;
23
+ this.activityRepository = params.activityRepository;
24
+ this.agentConfigRepository = params.agentConfigRepository;
25
+ const fileHelper = new helpers_1.FileHelper(params.s3Lib, this.config);
26
+ this.aiHelper = new helpers_1.AIHelper(fileHelper, this.config, params.tenantCredentialResolver);
27
+ this.debug = this.config.debug;
20
28
  }
21
29
  getTemporaryTitle(contextKey) {
22
30
  return `${contextKey} session ${new Date().toISOString()}`;
23
31
  }
32
+ isTemporaryTitle(title) {
33
+ // Matches pattern: "{contextKey} session {ISO_DATE_STRING}"
34
+ // Example: "default session 2026-01-23T10:30:45.123Z"
35
+ // toISOString() always includes milliseconds, so we require them
36
+ const pattern = /^.+ session \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
37
+ return pattern.test(title);
38
+ }
39
+ isPlainObject(value) {
40
+ return !!value && typeof value === 'object' && !Array.isArray(value);
41
+ }
42
+ getExecutionTenants(payload) {
43
+ const contextTenants = payload.executionContext?.tenants;
44
+ if (contextTenants && Object.keys(contextTenants).length > 0) {
45
+ return contextTenants;
46
+ }
47
+ return payload.tenants ?? {};
48
+ }
49
+ getParticipantIds(chat) {
50
+ const primary = chat.userId ?? this.getChatUserId(chat);
51
+ return Array.from(new Set([primary, ...(chat.participantIds ?? [])].filter(Boolean)));
52
+ }
53
+ hasChatAccess(chat, userId) {
54
+ if (!userId)
55
+ return true;
56
+ return this.getParticipantIds(chat).includes(userId);
57
+ }
58
+ emitChatToParticipants(chat, chatToEmit, excludeSocketId) {
59
+ for (const userId of this.getParticipantIds(chatToEmit.participantIds ? chatToEmit : chat)) {
60
+ this.socketService.emitChatUpdate(userId, chatToEmit, excludeSocketId);
61
+ }
62
+ }
63
+ emitMessageToParticipants(chat, message, excludeSocketId) {
64
+ for (const userId of this.getParticipantIds(chat)) {
65
+ this.socketService.emitMessageUpdate(userId, message, excludeSocketId);
66
+ }
67
+ }
68
+ async updateChatAndEmit(chat, update, excludeSocketId) {
69
+ await this.chatRepository.update(chat.id, update);
70
+ const updatedChat = await this.chatRepository.findById(chat.id);
71
+ const chatToEmit = updatedChat ?? { ...chat, ...update };
72
+ this.emitChatToParticipants(chat, chatToEmit, excludeSocketId);
73
+ return chatToEmit;
74
+ }
75
+ async startSubagentProcess(params) {
76
+ const parentUserId = params.parentChat.userId ?? this.getChatUserId(params.parentChat) ?? 'guest';
77
+ const childChat = await this.chatRepository.create({
78
+ title: `${params.subAgentConfig.name} subagent`,
79
+ type: ai_agent_types_1.ChatType.Agent,
80
+ status: ai_agent_types_1.AgentStatus.Streaming,
81
+ sessionKind: ai_agent_types_2.AgentSessionKind.SUBAGENT,
82
+ parentChatId: params.parentChat.id,
83
+ parentMessageId: params.parentMessage.id,
84
+ parentToolCallId: params.parentToolCallId,
85
+ contextKey: params.parentChat.contextKey,
86
+ userId: parentUserId,
87
+ tenants: { ...params.parentChat.tenants },
88
+ model: params.subAgentConfig.defaultModel || params.parentChat.model,
89
+ });
90
+ try {
91
+ const parentToolCall = params.parentMessage.toolCalls?.find((toolCall) => toolCall.id === params.parentToolCallId);
92
+ if (parentToolCall) {
93
+ parentToolCall.input = {
94
+ ...(parentToolCall.input ?? {}),
95
+ subagentChatId: childChat.id,
96
+ };
97
+ parentToolCall.subagentChatId = childChat.id;
98
+ const updatedParentMessage = await this.messageRepository.update(params.parentMessage.id, {
99
+ toolCalls: params.parentMessage.toolCalls,
100
+ });
101
+ if (updatedParentMessage) {
102
+ this.emitMessageToParticipants(params.parentChat, updatedParentMessage);
103
+ }
104
+ }
105
+ this.emitChatToParticipants(params.parentChat, childChat);
106
+ const executionTenants = this.getExecutionTenants(params);
107
+ const abortController = this.agentStore.registerSubAgentProcess(childChat.id, params.parentChat.id);
108
+ const userMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.User, {
109
+ content: JSON.stringify(params.input),
110
+ agentName: undefined
111
+ });
112
+ await this.agentStore.shareAgentProcessEvent(childChat.id, {
113
+ type: store_1.AgentProcessEventType.Update,
114
+ data: userMessage
115
+ });
116
+ let assistantMessage = await this.createMessage(childChat, ai_agent_types_1.MessageRole.Assistant, {
117
+ content: '',
118
+ agentName: params.subAgentConfig.name
119
+ });
120
+ const parentActivity = await this.activityRepository.create({
121
+ ownerId: parentUserId,
122
+ groupId: params.parentChat.id,
123
+ name: ai_agent_types_1.ActivityOperationName.SUBAGENT,
124
+ tenants: executionTenants,
125
+ sourceId: assistantMessage.id,
126
+ sourceType: 'AgentMessage',
127
+ metadata: {
128
+ modelId: this.aiHelper.getLanguageModelId(childChat.model),
129
+ agentOptions: {
130
+ name: params.subAgentConfig.name,
131
+ modelId: this.aiHelper.getLanguageModelId(params.subAgentConfig.defaultModel),
132
+ temperature: params.subAgentConfig.temperature,
133
+ maxOutputTokens: params.subAgentConfig.maxOutputTokens,
134
+ topP: params.subAgentConfig.topP,
135
+ topK: params.subAgentConfig.topK,
136
+ presencePenalty: params.subAgentConfig.presencePenalty,
137
+ frequencyPenalty: params.subAgentConfig.frequencyPenalty,
138
+ stopSequences: params.subAgentConfig.stopSequences,
139
+ seed: params.subAgentConfig.seed,
140
+ },
141
+ },
142
+ });
143
+ const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
144
+ activity: parentActivity.id
145
+ });
146
+ const agentOptions = this.aiHelper.getAgentOptionsFromConfig(params.subAgentConfig, params.context);
147
+ agentOptions.onStepFinish = (stepResult) => {
148
+ return this.storeStepActivity({
149
+ chat: params.parentChat,
150
+ parentId: assistantMessage.activity,
151
+ stepResult,
152
+ name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
153
+ sourceId: assistantMessage.id,
154
+ sourceType: 'AgentMessage',
155
+ tenants: executionTenants,
156
+ });
157
+ };
158
+ const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(parentUserId, agentOptions.name);
159
+ agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
160
+ await this.streamMessageStep({
161
+ chat: childChat,
162
+ existingMessages: [userMessage, updatedAssistantMessage],
163
+ assistantMessage: updatedAssistantMessage,
164
+ agentOptions,
165
+ signal: abortController.signal,
166
+ tenants: executionTenants,
167
+ executionContext: params.executionContext,
168
+ context: params.context,
169
+ });
170
+ }
171
+ catch (error) {
172
+ await this.storeSubagentResponse({
173
+ subagentChat: childChat,
174
+ content: undefined,
175
+ error: error,
176
+ context: params.context,
177
+ executionContext: params.executionContext,
178
+ });
179
+ }
180
+ }
181
+ mergeMissingUsageFields(target, source) {
182
+ for (const [key, sourceValue] of Object.entries(source)) {
183
+ const targetValue = target[key];
184
+ if (targetValue === undefined) {
185
+ target[key] = sourceValue;
186
+ continue;
187
+ }
188
+ if (this.isPlainObject(targetValue) && this.isPlainObject(sourceValue)) {
189
+ this.mergeMissingUsageFields(targetValue, sourceValue);
190
+ }
191
+ }
192
+ }
193
+ extractCostUsageFields(source) {
194
+ const extracted = {};
195
+ for (const [key, value] of Object.entries(source)) {
196
+ const normalizedKey = key.toLowerCase();
197
+ if (normalizedKey.includes('cost')) {
198
+ extracted[key] = value;
199
+ continue;
200
+ }
201
+ if (this.isPlainObject(value)) {
202
+ const nestedCostFields = this.extractCostUsageFields(value);
203
+ if (Object.keys(nestedCostFields).length > 0) {
204
+ extracted[key] = nestedCostFields;
205
+ }
206
+ }
207
+ }
208
+ return extracted;
209
+ }
210
+ mergeUsageWithProviderMetadata(stepUsage, providerMetadata) {
211
+ const mergedUsage = this.isPlainObject(stepUsage) ? { ...stepUsage } : {};
212
+ let hasProviderUsage = false;
213
+ if (this.isPlainObject(providerMetadata)) {
214
+ for (const providerEntry of Object.values(providerMetadata)) {
215
+ if (!this.isPlainObject(providerEntry) || !this.isPlainObject(providerEntry.usage)) {
216
+ continue;
217
+ }
218
+ const providerCostUsage = this.extractCostUsageFields(providerEntry.usage);
219
+ if (Object.keys(providerCostUsage).length === 0) {
220
+ continue;
221
+ }
222
+ hasProviderUsage = true;
223
+ this.mergeMissingUsageFields(mergedUsage, providerCostUsage);
224
+ }
225
+ }
226
+ if (this.isPlainObject(stepUsage)) {
227
+ return mergedUsage;
228
+ }
229
+ if (hasProviderUsage) {
230
+ return mergedUsage;
231
+ }
232
+ return stepUsage;
233
+ }
234
+ async validateToolCallInput(params) {
235
+ const agentOptions = await this.aiHelper.getAgentOptions({
236
+ agentName: params.agentName,
237
+ });
238
+ const tool = agentOptions.tools?.[params.toolName] ?? undefined;
239
+ const schema = tool?.inputSchema;
240
+ if (!schema) {
241
+ throw new Error(`Tool "${params.toolName}" schema not found`);
242
+ }
243
+ if (!(schema instanceof zod_1.z.ZodType)) {
244
+ throw new Error(`Tool "${params.toolName}" inputSchema must be a Zod schema`);
245
+ }
246
+ const result = schema.safeParse(params.input);
247
+ if (!result.success) {
248
+ throw new Error(`Invalid tool input for "${params.toolName}": ${result.error.message}`);
249
+ }
250
+ }
24
251
  async listChats(params) {
25
- // Build filter object from params
26
- const filter = {};
252
+ // Build filter object from params. Always exclude subagent chats:
253
+ // the repository translates ROOT into `sessionKind !== SUBAGENT`, which
254
+ // also includes legacy chats where the field is unset.
255
+ const filter = {
256
+ sessionKind: ai_agent_types_2.AgentSessionKind.ROOT
257
+ };
27
258
  if (params?.userId) {
259
+ // Chats visible to this user: owner, tenant owner, or participant (multi-user).
28
260
  filter.userId = params.userId;
29
261
  }
30
262
  if (params?.contextKey) {
31
263
  filter.contextKey = params.contextKey;
32
264
  }
33
- // Build query options for sort and limit with defaults
265
+ if (params?.multiUser !== undefined) {
266
+ filter.multiUser = params.multiUser;
267
+ }
268
+ // Build query options for sort and limit with defaults.
34
269
  const options = {
35
270
  sort: {
36
271
  field: params?.sortField ?? 'updatedAt',
37
272
  order: params?.sortOrder ?? ai_agent_types_1.SortOrder.Desc
38
273
  },
274
+ skip: params?.skip,
39
275
  limit: params?.limit
40
276
  };
41
- // Use aggregation to fetch chats with related messages
42
- return this.chatRepository.findWithMessages(filter, options);
277
+ const [total, data] = await Promise.all([
278
+ this.chatRepository.count(filter),
279
+ this.chatRepository.find(filter, options)
280
+ ]);
281
+ return {
282
+ cursor: {
283
+ ...(params?.skip != null ? { skip: params.skip } : {}),
284
+ ...(params?.limit != null ? { limit: params.limit } : {}),
285
+ total
286
+ },
287
+ data
288
+ };
43
289
  }
44
290
  async getChat(chatId) {
45
291
  const chat = await this.chatRepository.findById(chatId);
46
292
  if (!chat) {
47
293
  throw new Error('Chat not found');
48
294
  }
49
- const messages = await this.messageRepository.findByChatId(chatId);
50
- return {
51
- ...chat,
52
- messages
53
- };
295
+ return chat;
296
+ }
297
+ /**
298
+ * Get messages for a chat with optional cursor pagination.
299
+ * When limit is omitted, returns all messages (backward compatible).
300
+ * Messages are returned in chronological order (oldest → newest).
301
+ */
302
+ async getMessages(chatId, options) {
303
+ const chat = await this.chatRepository.findById(chatId);
304
+ if (!chat) {
305
+ throw new Error('Chat not found');
306
+ }
307
+ return this.messageRepository.findByChatIdPaginated(chatId, options);
54
308
  }
55
309
  async deleteChat(chatId) {
310
+ // Collect all subagent descendants BEFORE removing the parent, otherwise the
311
+ // `parentChatId` link is severed and we'd orphan the subtree. Subagents can
312
+ // themselves spawn subagents, so traversal must be recursive.
313
+ const descendantIds = await this.collectDescendantChatIds(chatId);
56
314
  const deleted = await this.chatRepository.delete(chatId);
57
315
  if (!deleted) {
58
316
  throw new Error('Chat not found');
59
317
  }
60
- this.artifactStore.deleteArtifacts(chatId);
318
+ // Delete descendant chat rows in parallel. Use `Promise.allSettled` so a
319
+ // missing/already-deleted descendant doesn't abort cleanup of the rest.
320
+ if (descendantIds.length > 0) {
321
+ await Promise.allSettled(descendantIds.map(id => this.chatRepository.delete(id)));
322
+ }
323
+ const allIds = [chatId, ...descendantIds];
324
+ await Promise.all([
325
+ ...allIds.map(id => this.messageRepository.deleteByChatId(id)),
326
+ ...allIds.map(id => this.activityRepository.deleteByGroupId(id)),
327
+ ]);
328
+ for (const id of allIds) {
329
+ this.artifactStore.deleteArtifacts(id);
330
+ }
331
+ }
332
+ /**
333
+ * Walk the subagent tree rooted at `rootChatId` and return every descendant
334
+ * chat id (excluding the root itself). BFS, with parallel fan-out per level
335
+ * so deeply nested trees don't serialize one DB roundtrip per depth.
336
+ */
337
+ async collectDescendantChatIds(rootChatId) {
338
+ const descendants = [];
339
+ let frontier = [rootChatId];
340
+ while (frontier.length > 0) {
341
+ const childLists = await Promise.all(frontier.map(id => this.chatRepository.find({ parentChatId: id })));
342
+ const nextFrontier = [];
343
+ for (const list of childLists) {
344
+ for (const child of list) {
345
+ descendants.push(child.id);
346
+ nextFrontier.push(child.id);
347
+ }
348
+ }
349
+ frontier = nextFrontier;
350
+ }
351
+ return descendants;
61
352
  }
62
353
  async upsertAndGetChat(payload, excludeSocketId) {
63
- const targetUserId = payload.userId ?? 'guest';
64
354
  let chat = null;
65
355
  if (payload.chatId) {
66
356
  chat = await this.chatRepository.findById(payload.chatId);
67
357
  if (!chat) {
68
358
  throw new Error('Chat not found');
69
359
  }
70
- // Ensure chat is associated with the caller's userId
71
- if (chat.userId && chat.userId !== targetUserId) {
72
- throw new Error('Chat does not belong to this user');
73
- }
74
360
  }
75
361
  if (!chat) {
76
362
  chat = await this.createChat(payload, excludeSocketId);
@@ -92,7 +378,7 @@ class ChatProcessor {
92
378
  if (!content) {
93
379
  return this.getTemporaryTitle(payload.contextKey);
94
380
  }
95
- return helpers_1.AIHelper.generateTitleForMessage(payload.contextKey, [{
381
+ return this.aiHelper.generateTitleForMessage(payload.contextKey, [{
96
382
  role: ai_agent_types_1.MessageRole.User,
97
383
  content: content
98
384
  }]);
@@ -103,34 +389,38 @@ class ChatProcessor {
103
389
  role,
104
390
  content: messageData.content,
105
391
  agentName: messageData.agentName,
392
+ sender: messageData.sender,
393
+ mentions: messageData.mentions ?? [],
394
+ annotations: messageData.annotations,
106
395
  attachments: attachments ?? [],
107
396
  reasoning: "",
108
397
  toolCalls: []
109
398
  });
110
- if (chat.userId) {
111
- services_1.socketService.emitMessageUpdate(chat.userId, message, excludeSocketId);
112
- }
399
+ this.emitMessageToParticipants(chat, message, excludeSocketId);
113
400
  return message;
114
401
  }
115
402
  async createChat(payload, excludeSocketId) {
116
- const targetUserId = payload.userId ?? 'guest';
403
+ const targetUserId = payload.userId ?? payload.tenants?.userId ?? 'guest';
117
404
  const contextKey = 'contextKey' in payload ? payload.contextKey : 'default';
118
405
  const metadata = 'metadata' in payload ? payload.metadata : {};
406
+ const requestedParticipantIds = 'participantIds' in payload && Array.isArray(payload.participantIds) ? payload.participantIds : [];
407
+ const participantIds = Array.from(new Set([targetUserId, ...requestedParticipantIds].filter(Boolean)));
119
408
  const chat = await this.chatRepository.create({
120
409
  title: this.getTemporaryTitle(contextKey),
121
410
  type: ai_agent_types_1.ChatType.Chat,
122
411
  status: ai_agent_types_1.AgentStatus.Streaming,
412
+ sessionKind: ai_agent_types_2.AgentSessionKind.ROOT,
123
413
  contextKey,
124
414
  userId: targetUserId,
415
+ tenants: {
416
+ ...(payload.tenants ?? {}),
417
+ userId: targetUserId,
418
+ },
419
+ participantIds,
125
420
  metadata,
126
421
  ...(payload.model ? { model: payload.model } : {})
127
422
  });
128
- await services_2.kafkaService.sendChatTitleGenerationEvent(chat.id);
129
- const initialChatResponse = {
130
- ...chat,
131
- messages: []
132
- };
133
- services_1.socketService.emitChatUpdate(targetUserId, initialChatResponse, excludeSocketId);
423
+ this.emitChatToParticipants(chat, chat, excludeSocketId);
134
424
  return chat;
135
425
  }
136
426
  /**
@@ -185,33 +475,163 @@ class ChatProcessor {
185
475
  await this.messageRepository.update(message.id, { toolCalls });
186
476
  // Bump chat updatedAt so listChats ordering reflects the action.
187
477
  await this.chatRepository.update(chat.id, { updatedAt: now });
188
- services_1.socketService.emitMessageUpdate(chat.userId, updatedMessage, params.excludeSocketId);
478
+ this.emitMessageToParticipants(chat, updatedMessage, params.excludeSocketId);
189
479
  if (params.systemMessage) {
190
480
  //todo discuss support for system messages
191
481
  //await this.createMessage(chat, MessageRole.System, params.systemMessage, undefined, params.excludeSocketId);
192
482
  }
193
483
  return { ok: true };
194
484
  }
485
+ /**
486
+ * Update selected fields (input/output/status) on a specific tool call.
487
+ */
488
+ async updateToolCall(params) {
489
+ if (params.input === undefined &&
490
+ params.output === undefined &&
491
+ params.status === undefined &&
492
+ params.subagentChatId === undefined) {
493
+ throw new Error('At least one tool call update field must be provided');
494
+ }
495
+ const chat = await this.chatRepository.findById(params.chatId);
496
+ if (!chat) {
497
+ throw new Error('Chat not found');
498
+ }
499
+ if (params.userId && !this.hasChatAccess(chat, params.userId)) {
500
+ throw new Error('Chat does not belong to this user');
501
+ }
502
+ const message = await this.messageRepository.findById(params.messageId);
503
+ if (!message || message.chat !== params.chatId) {
504
+ throw new Error('Message not found or does not belong to this chat');
505
+ }
506
+ const targetToolCall = (message.toolCalls ?? []).find((tc) => tc.id === params.toolCallId);
507
+ if (!targetToolCall) {
508
+ throw new Error('Tool call not found in message');
509
+ }
510
+ if (params.input !== undefined) {
511
+ await this.validateToolCallInput({
512
+ agentName: message.agentName,
513
+ toolName: targetToolCall.name,
514
+ input: params.input,
515
+ });
516
+ }
517
+ const updatedMessage = await this.messageRepository.updateToolCall(params.messageId, params.toolCallId, {
518
+ ...(params.input !== undefined ? { input: params.input } : {}),
519
+ ...(params.output !== undefined ? { output: params.output } : {}),
520
+ ...(params.status !== undefined ? { status: params.status } : {}),
521
+ ...(params.subagentChatId !== undefined ? { subagentChatId: params.subagentChatId } : {}),
522
+ });
523
+ if (!updatedMessage) {
524
+ throw new Error('Tool call not found in message');
525
+ }
526
+ const now = new Date().toISOString();
527
+ await this.chatRepository.update(chat.id, { updatedAt: now });
528
+ this.emitMessageToParticipants(chat, updatedMessage, params.excludeSocketId);
529
+ return updatedMessage;
530
+ }
531
+ async storeSubagentResponse(params) {
532
+ const { subagentChat, content, error, context, executionContext } = params;
533
+ if (!subagentChat.parentChatId || !subagentChat.parentMessageId) {
534
+ throw new Error(`Parent chat or message not found for subagent ${subagentChat.id}`);
535
+ }
536
+ const chat = await this.chatRepository.findById(subagentChat.parentChatId);
537
+ if (!chat) {
538
+ throw new Error(`Parent chat not found for subagent ${subagentChat.id}`);
539
+ }
540
+ const assistantMessage = await this.messageRepository.findById(subagentChat.parentMessageId);
541
+ if (!assistantMessage || assistantMessage.chat !== subagentChat.parentChatId) {
542
+ throw new Error(`Assistant message with id ${subagentChat.parentMessageId} not found`);
543
+ }
544
+ const toolCall = assistantMessage.toolCalls?.find(tc => tc.id === subagentChat.parentToolCallId);
545
+ if (!toolCall) {
546
+ throw new Error(`Tool call with id ${subagentChat.parentToolCallId} not found`);
547
+ }
548
+ if (error) {
549
+ toolCall.output = {
550
+ type: 'error',
551
+ message: error,
552
+ };
553
+ toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
554
+ }
555
+ else {
556
+ toolCall.output = content;
557
+ toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
558
+ }
559
+ await this.messageRepository.update(assistantMessage.id, assistantMessage);
560
+ const agentOptions = await this.aiHelper.getAgentOptions({
561
+ agentName: assistantMessage.agentName,
562
+ context: context,
563
+ executionContext: executionContext,
564
+ });
565
+ const executionTenants = this.getExecutionTenants(params);
566
+ const abortController = this.agentStore.registerAgentProcess(chat.id);
567
+ const existingMessages = await this.messageRepository.findByChatId(chat.id);
568
+ // Limit context to prevent exceeding token limits
569
+ const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
570
+ maxMessages: this.config.ai.maxContextMessages,
571
+ keepFirstUserMessage: true,
572
+ keepSystemMessages: true,
573
+ });
574
+ agentOptions.onStepFinish = (stepResult) => {
575
+ return this.storeStepActivity({
576
+ chat,
577
+ parentId: assistantMessage.activity,
578
+ stepResult,
579
+ name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
580
+ sourceId: assistantMessage.id,
581
+ sourceType: 'AgentMessage',
582
+ tenants: executionTenants,
583
+ });
584
+ };
585
+ const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(this.getChatUserId(chat) ?? chat.userId ?? 'guest', agentOptions.name);
586
+ agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
587
+ await this.streamMessageStep({
588
+ chat,
589
+ existingMessages: limitedMessages,
590
+ assistantMessage,
591
+ agentOptions,
592
+ signal: abortController.signal,
593
+ tenants: executionTenants,
594
+ executionContext,
595
+ context,
596
+ });
597
+ }
195
598
  async streamMessageStep(params) {
196
599
  const { chat, assistantMessage, existingMessages, signal, excludeSocketId, agentOptions } = params;
600
+ const persistAndBroadcastToolCalls = async () => {
601
+ await this.messageRepository.update(assistantMessage.id, { toolCalls: assistantMessage.toolCalls ?? [] });
602
+ this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
603
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
604
+ };
197
605
  if (signal.aborted) {
198
606
  return;
199
607
  }
200
- const result = await helpers_1.AIHelper.streamAssistantResponse(existingMessages, signal, agentOptions);
608
+ const result = await this.aiHelper.streamAssistantResponse(existingMessages, signal, {
609
+ ...agentOptions,
610
+ executionContext: params.executionContext,
611
+ });
201
612
  try {
202
613
  for await (const chunk of result.fullStream) {
203
614
  if (chunk.type === 'error') {
204
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: chunk.error });
615
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: chunk.error });
205
616
  assistantMessage.content = chunk.error.message || 'Sorry, I cannot process you request due to the error';
206
617
  await this.messageRepository.update(assistantMessage.id, assistantMessage);
207
- await this.chatRepository.update(chat.id, { status: ai_agent_types_1.AgentStatus.Error });
618
+ await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Error }, excludeSocketId);
619
+ if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
620
+ await this.storeSubagentResponse({
621
+ subagentChat: chat,
622
+ content: undefined,
623
+ error: chunk.error,
624
+ context: params.context,
625
+ executionContext: params.executionContext,
626
+ });
627
+ }
208
628
  continue;
209
629
  }
210
630
  if (chunk.type === 'abort') {
211
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Aborted, data: undefined });
212
- await this.chatRepository.update(chat.id, { status: ai_agent_types_1.AgentStatus.Aborted });
631
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Aborted, data: undefined });
632
+ await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Aborted }, excludeSocketId);
213
633
  await this.messageRepository.update(assistantMessage.id, assistantMessage);
214
- services_1.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
634
+ this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
215
635
  continue;
216
636
  }
217
637
  if (chunk.type === 'finish') {
@@ -228,38 +648,76 @@ class ChatProcessor {
228
648
  ((totalUsage.promptTokens ?? 0) + (totalUsage.completionTokens ?? 0));
229
649
  }
230
650
  await this.messageRepository.update(assistantMessage.id, { ...assistantMessage });
651
+ this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
231
652
  if (chunk.finishReason === 'stop') {
232
- if (assistantMessage.toolCalls?.some(toolCall => toolCall.requiresConfirmation && toolCall.approvalId && !toolCall.output)) {
233
- await this.chatRepository.update(chat.id, { status: ai_agent_types_1.AgentStatus.WaitingForUserAction });
234
- }
235
- else if (!assistantMessage.content && assistantMessage.toolCalls?.length && assistantMessage.toolCalls[assistantMessage.toolCalls?.length - 1].output) {
236
- // handle tool-calls stop, openrouter provider does not return valid type
237
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
238
- await this.streamMessageStep(params);
239
- continue;
653
+ let nextChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Finished }, excludeSocketId);
654
+ if (chat.title && this.isTemporaryTitle(chat.title)) {
655
+ const title = await this.aiHelper.generateTitleForMessage(chat.contextKey, existingMessages.filter(m => m.role === ai_agent_types_1.MessageRole.User), (stepResult) => {
656
+ return this.storeStepActivity({
657
+ chat,
658
+ stepResult,
659
+ name: ai_agent_types_1.ActivityOperationName.TITLE_GENERATION,
660
+ sourceId: chat.id,
661
+ sourceType: 'Chat',
662
+ tenants: params.tenants || {},
663
+ });
664
+ }, params.executionContext);
665
+ nextChat = await this.updateChatAndEmit(nextChat, { title }, excludeSocketId);
240
666
  }
241
- else {
242
- await this.chatRepository.update(chat.id, { status: ai_agent_types_1.AgentStatus.Finished });
667
+ if (chat.sessionKind === ai_agent_types_2.AgentSessionKind.SUBAGENT) {
668
+ await this.storeSubagentResponse({
669
+ subagentChat: chat,
670
+ content: assistantMessage.content,
671
+ error: undefined,
672
+ context: params.context,
673
+ executionContext: params.executionContext,
674
+ });
243
675
  }
244
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
245
- continue;
246
676
  }
247
677
  if (chunk.finishReason === 'tool-calls') {
248
- if (assistantMessage.toolCalls?.some(toolCall => toolCall.requiresConfirmation && toolCall.approvalId && !toolCall.output)) {
249
- await this.chatRepository.update(chat.id, { status: ai_agent_types_1.AgentStatus.WaitingForUserAction });
250
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
678
+ const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.output === undefined && toolCall.status === ai_agent_types_1.AgentToolCallStatus.Running);
679
+ if (!toolCall) {
680
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
681
+ await this.storeSubagentResponse({
682
+ subagentChat: chat,
683
+ content: JSON.stringify(assistantMessage.toolCalls),
684
+ error: undefined,
685
+ context: params.context,
686
+ executionContext: params.executionContext,
687
+ });
688
+ continue;
689
+ }
690
+ const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
691
+ if (toolCall.requiresConfirmation && toolCall.approvalId) {
692
+ await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.WaitingForUserAction }, excludeSocketId);
693
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
251
694
  }
252
- else {
253
- await store_1.agentStore.shareAgentProcessEvent(chat.id, {
254
- type: store_1.AgentProcessEventType.Update,
255
- data: assistantMessage
695
+ else if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
696
+ void this.startSubagentProcess({
697
+ parentChat: chat,
698
+ parentMessage: assistantMessage,
699
+ parentToolCallId: toolCall.id,
700
+ toolName: toolCall.name,
701
+ input: toolCall.input,
702
+ subAgentConfig: toolConfig.data.subAgent,
703
+ context: params.context,
704
+ executionContext: params.executionContext,
705
+ }).catch(error => {
706
+ logger_1.logger.error(error);
707
+ //todo: store error in response
256
708
  });
257
- await this.streamMessageStep(params);
258
709
  }
259
- continue;
260
710
  }
261
711
  //todo: Handle other finish reasons // length, content, error, other, undefined
262
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
712
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Finished, data: assistantMessage });
713
+ if (assistantMessage.activity) {
714
+ const groupedMeta = await this.activityRepository.getGroupedMetadataByParentId(assistantMessage.activity);
715
+ await this.activityRepository.updateMetadata(assistantMessage.activity, {
716
+ usage: groupedMeta,
717
+ finishReason: chunk.finishReason,
718
+ responseTimestamp: new Date().toISOString(),
719
+ });
720
+ }
263
721
  continue;
264
722
  }
265
723
  if (chunk.type === 'text-delta') {
@@ -268,55 +726,85 @@ class ChatProcessor {
268
726
  ...assistantMessage,
269
727
  content: assistantMessage.content
270
728
  };
271
- services_1.socketService.emitMessageUpdate(chat.userId, updatedMessage, excludeSocketId);
272
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: updatedMessage });
729
+ this.emitMessageToParticipants(chat, updatedMessage, excludeSocketId);
730
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: updatedMessage });
273
731
  await this.messageRepository.update(assistantMessage.id, { content: assistantMessage.content });
274
732
  continue;
275
733
  }
276
734
  if (chunk.type === 'tool-input-start') {
277
735
  if (!assistantMessage.toolCalls)
278
736
  assistantMessage.toolCalls = [];
279
- assistantMessage.toolCalls.push({
280
- id: chunk.id,
281
- name: chunk.toolName,
282
- status: ai_agent_types_1.AgentToolCallStatus.Pending,
283
- input: {},
284
- });
737
+ const existingToolCall = assistantMessage.toolCalls.find((toolCall) => toolCall.id === chunk.id);
738
+ if (existingToolCall) {
739
+ existingToolCall.name = chunk.toolName;
740
+ if (!existingToolCall.status) {
741
+ existingToolCall.status = ai_agent_types_1.AgentToolCallStatus.Pending;
742
+ }
743
+ existingToolCall.input = existingToolCall.input ?? {};
744
+ }
745
+ else {
746
+ assistantMessage.toolCalls.push({
747
+ id: chunk.id,
748
+ name: chunk.toolName,
749
+ status: ai_agent_types_1.AgentToolCallStatus.Pending,
750
+ input: {},
751
+ });
752
+ }
753
+ await persistAndBroadcastToolCalls();
285
754
  continue;
286
755
  }
287
- if (chunk.type === 'tool-call') { //Todo possible place to handle user-approval
288
- const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
289
- if (toolCall) {
756
+ if (chunk.type === 'tool-call') {
757
+ if (!assistantMessage.toolCalls)
758
+ assistantMessage.toolCalls = [];
759
+ let toolCall = assistantMessage.toolCalls.find(toolCall => toolCall.id === chunk.toolCallId);
760
+ if (!toolCall) {
761
+ toolCall = {
762
+ id: chunk.toolCallId,
763
+ name: chunk.toolName,
764
+ status: ai_agent_types_1.AgentToolCallStatus.Running,
765
+ input: chunk.input,
766
+ };
767
+ assistantMessage.toolCalls.push(toolCall);
768
+ }
769
+ else {
290
770
  toolCall.status = ai_agent_types_1.AgentToolCallStatus.Running;
291
771
  toolCall.input = chunk.input;
292
772
  }
773
+ await persistAndBroadcastToolCalls();
293
774
  continue;
294
775
  }
295
776
  if (chunk.type === 'tool-error') {
296
777
  const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
297
778
  if (toolCall) {
298
779
  toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
299
- toolCall.error = JSON.stringify(chunk.error);
780
+ toolCall.error = chunk.error.message || JSON.stringify(chunk.error);
781
+ await persistAndBroadcastToolCalls();
300
782
  }
301
783
  continue;
302
784
  }
303
785
  if (chunk.type === 'tool-approval-request') {
304
786
  const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCall.toolCallId);
305
787
  if (toolCall) {
788
+ const toolConfig = store_1.ConfigStore.getInstance().getToolConfig(assistantMessage.agentName || '', toolCall.name);
789
+ if (toolConfig && toolConfig.type === ai_agent_types_1.AgentToolType.SUBAGENT) {
790
+ // TODO: allow needsApproval flow for the subagents too
791
+ continue;
792
+ }
306
793
  toolCall.requiresConfirmation = true;
307
794
  toolCall.approvalId = chunk.approvalId;
795
+ if (toolCall.name === ai_agent_types_1.AgentToolType.REQUEST_CLARIFICATION) {
796
+ toolCall.requiresUserAction = true;
797
+ }
798
+ await persistAndBroadcastToolCalls();
308
799
  }
309
800
  continue;
310
801
  }
311
802
  if (chunk.type === 'tool-result') {
312
803
  const toolCall = assistantMessage.toolCalls?.find(toolCall => toolCall.id === chunk.toolCallId);
313
804
  if (toolCall) {
314
- if (chunk.output.requiresApproval) {
315
- toolCall.requiresConfirmation = true;
316
- continue;
317
- }
318
805
  toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
319
806
  toolCall.output = chunk.output;
807
+ await persistAndBroadcastToolCalls();
320
808
  }
321
809
  continue;
322
810
  }
@@ -324,9 +812,9 @@ class ChatProcessor {
324
812
  if (!assistantMessage.reasoning)
325
813
  assistantMessage.reasoning = '';
326
814
  assistantMessage.reasoning += chunk.text;
327
- services_1.socketService.emitMessageUpdate(chat.userId, assistantMessage, excludeSocketId);
815
+ this.emitMessageToParticipants(chat, assistantMessage, excludeSocketId);
328
816
  await this.messageRepository.update(assistantMessage.id, { reasoning: assistantMessage.reasoning });
329
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
817
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: assistantMessage });
330
818
  continue;
331
819
  }
332
820
  }
@@ -335,7 +823,7 @@ class ChatProcessor {
335
823
  if (streamError instanceof Error && streamError.name === 'AbortError') {
336
824
  return;
337
825
  }
338
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: streamError });
826
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Error, data: streamError });
339
827
  throw streamError;
340
828
  }
341
829
  }
@@ -347,9 +835,10 @@ class ChatProcessor {
347
835
  if (!assistantMessage || assistantMessage.chat !== chat.id) {
348
836
  throw new Error(`Assistant message with id ${payload.messageId} not found`);
349
837
  }
350
- const agentOptions = await helpers_1.AIHelper.getAgentOptions({
838
+ const agentOptions = await this.aiHelper.getAgentOptions({
351
839
  agentName: assistantMessage.agentName,
352
- context: payload.context
840
+ context: payload.context,
841
+ executionContext: payload.executionContext,
353
842
  });
354
843
  const toolCall = assistantMessage.toolCalls?.find(tc => tc.approvalId === payload.approvalId);
355
844
  if (!toolCall) {
@@ -360,14 +849,20 @@ class ChatProcessor {
360
849
  };
361
850
  }
362
851
  toolCall.approved = payload.approved;
363
- toolCall.reason = payload.reason;
852
+ toolCall.userResponse = payload.userResponse;
364
853
  if (!toolCall.approved) {
365
854
  toolCall.output = {
366
855
  type: 'execution-denied',
367
- reason: toolCall.reason
856
+ reason: toolCall.userResponse
368
857
  };
369
858
  toolCall.status = ai_agent_types_1.AgentToolCallStatus.Failed;
370
859
  }
860
+ else if (toolCall.requiresUserAction) {
861
+ toolCall.output = {
862
+ userResponse: toolCall.userResponse
863
+ };
864
+ toolCall.status = ai_agent_types_1.AgentToolCallStatus.Succeeded;
865
+ }
371
866
  else {
372
867
  const executeFunction = agentOptions.tools?.[toolCall.name]?.execute;
373
868
  if (executeFunction) {
@@ -399,33 +894,333 @@ class ChatProcessor {
399
894
  };
400
895
  }
401
896
  async processNewUserMessage(chat, payload, prevMessages, excludeSocketId) {
897
+ const executionTenants = this.getExecutionTenants(payload);
898
+ const chatUserId = this.getChatUserId(chat) ?? 'guest';
402
899
  const userMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.User, { content: payload.content, agentName: undefined }, payload.attachments);
403
- await store_1.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: userMessage });
404
- const agentOptions = await helpers_1.AIHelper.getAgentOptions({
900
+ await this.agentStore.shareAgentProcessEvent(chat.id, { type: store_1.AgentProcessEventType.Update, data: userMessage });
901
+ let assistantMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.Assistant, { content: '', agentName: undefined }, undefined, excludeSocketId);
902
+ const parentActivity = await this.activityRepository.create({
903
+ ownerId: chatUserId,
904
+ groupId: chat.id,
905
+ name: ai_agent_types_1.ActivityOperationName.MESSAGE_PROCESSING,
906
+ tenants: executionTenants,
907
+ sourceId: userMessage.id,
908
+ sourceType: 'AgentMessage',
909
+ metadata: {
910
+ contextKey: chat.contextKey,
911
+ modelId: this.aiHelper.getLanguageModelId(chat.model),
912
+ },
913
+ });
914
+ const agentOptions = await this.aiHelper.getAgentOptions({
405
915
  contextKey: chat.contextKey,
406
- messages: await helpers_1.AIHelper.convertMessages([...prevMessages, userMessage], true),
916
+ messages: [...prevMessages, userMessage],
407
917
  context: payload.context,
408
918
  agentName: undefined,
409
919
  modelId: chat.model,
920
+ executionContext: payload.executionContext,
921
+ }, {
922
+ onStepFinish: async (stepResult) => {
923
+ await this.storeStepActivity({
924
+ chat,
925
+ parentId: parentActivity.id,
926
+ stepResult,
927
+ name: ai_agent_types_1.ActivityOperationName.AGENT_SELECTION,
928
+ sourceId: userMessage.id,
929
+ sourceType: 'AgentMessage',
930
+ tenants: executionTenants,
931
+ });
932
+ }
933
+ });
934
+ const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
935
+ agentName: agentOptions.name,
936
+ activity: parentActivity.id
937
+ });
938
+ await this.activityRepository.update(parentActivity.id, {
939
+ metadata: {
940
+ ...parentActivity.metadata,
941
+ agentOptions: {
942
+ name: agentOptions.name,
943
+ modelId: this.aiHelper.getLanguageModelId(agentOptions.model),
944
+ temperature: agentOptions.temperature,
945
+ maxOutputTokens: agentOptions.maxOutputTokens,
946
+ topP: agentOptions.topP,
947
+ topK: agentOptions.topK,
948
+ presencePenalty: agentOptions.presencePenalty,
949
+ frequencyPenalty: agentOptions.frequencyPenalty,
950
+ stopSequences: agentOptions.stopSequences,
951
+ seed: agentOptions.seed,
952
+ },
953
+ },
410
954
  });
411
- const assistantMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.Assistant, { content: ' ', agentName: agentOptions.name }, undefined, excludeSocketId);
412
- assistantMessage.content = '';
955
+ if (!updatedAssistantMessage) {
956
+ throw new Error(`Assistant message with id ${assistantMessage.id} not found after update`);
957
+ }
958
+ assistantMessage = updatedAssistantMessage;
413
959
  return {
414
960
  userMessage,
415
961
  assistantMessage,
416
962
  agentOptions,
417
963
  };
418
964
  }
965
+ getAgentNamesForContext(contextKey) {
966
+ try {
967
+ return store_1.ConfigStore.getInstance().getAgentsForContext(contextKey).map((config) => config.name);
968
+ }
969
+ catch {
970
+ return [];
971
+ }
972
+ }
973
+ normalizeMentionName(value) {
974
+ return value.trim().replace(/^@/, '').toLowerCase();
975
+ }
976
+ extractMentionNames(content) {
977
+ const mentions = content.matchAll(/(^|[\s([{])@([a-zA-Z0-9_.-]+)/g);
978
+ return Array.from(mentions, (match) => match[2]).filter(Boolean);
979
+ }
980
+ getExplicitAgentMention(params) {
981
+ const agentNames = this.getAgentNamesForContext(params.contextKey);
982
+ const normalizedAgentNames = new Map(agentNames.map((name) => [this.normalizeMentionName(name), name]));
983
+ for (const mention of params.mentions ?? []) {
984
+ if (mention.type !== 'agent')
985
+ continue;
986
+ const normalized = this.normalizeMentionName(mention.name);
987
+ return { mentioned: true, agentName: normalizedAgentNames.get(normalized) };
988
+ }
989
+ for (const name of this.extractMentionNames(params.content)) {
990
+ const normalized = this.normalizeMentionName(name);
991
+ if (normalized === 'agent') {
992
+ return { mentioned: true };
993
+ }
994
+ const agentName = normalizedAgentNames.get(normalized);
995
+ if (agentName) {
996
+ return { mentioned: true, agentName };
997
+ }
998
+ }
999
+ return { mentioned: false };
1000
+ }
1001
+ hasNonAgentMention(params) {
1002
+ const agentNames = this.getAgentNamesForContext(params.contextKey);
1003
+ const normalizedAgentNames = new Set(['agent', ...agentNames.map((name) => this.normalizeMentionName(name))]);
1004
+ if ((params.mentions ?? []).some((mention) => mention.type === 'user')) {
1005
+ return true;
1006
+ }
1007
+ return this.extractMentionNames(params.content).some((name) => {
1008
+ const normalized = this.normalizeMentionName(name);
1009
+ return !normalizedAgentNames.has(normalized);
1010
+ });
1011
+ }
1012
+ renderMessageForDecision(message) {
1013
+ const sender = message.sender?.displayName || message.sender?.id || message.agentName || message.role;
1014
+ return `${sender}: ${message.content}`;
1015
+ }
1016
+ async analyzeAgentShouldRespond(params) {
1017
+ try {
1018
+ const recentMessages = [...params.previousMessages.slice(-8), params.userMessage]
1019
+ .map((message) => this.renderMessageForDecision(message))
1020
+ .join('\n');
1021
+ const response = await this.aiHelper.getAssistantResponse([
1022
+ {
1023
+ role: ai_agent_types_1.MessageRole.User,
1024
+ content: `Conversation:\n${recentMessages}\n\nShould the AI agent respond to the latest message?`
1025
+ }
1026
+ ], {
1027
+ system: [
1028
+ 'You decide whether an AI agent should reply in a multi-user chat.',
1029
+ 'Reply with exactly YES or NO.',
1030
+ 'YES only when the latest message asks for help, requests agent action, or is clearly addressed to the AI.',
1031
+ 'NO when the latest message is human-to-human chatter, status, acknowledgement, or otherwise does not need the AI.'
1032
+ ].join('\n'),
1033
+ temperature: 0,
1034
+ maxOutputTokens: 5,
1035
+ model: params.chat.model,
1036
+ executionContext: params.executionContext
1037
+ });
1038
+ return /^yes\b/i.test(response.trim());
1039
+ }
1040
+ catch (error) {
1041
+ logger_1.logger.warn({ error, chatId: params.chat.id }, 'Agent response decision failed');
1042
+ return false;
1043
+ }
1044
+ }
1045
+ async shouldRunAgentForMultiUserMessage(params) {
1046
+ const firstUserMessage = !params.previousMessages.some((message) => message.role === ai_agent_types_1.MessageRole.User);
1047
+ if (firstUserMessage) {
1048
+ return { shouldRun: true };
1049
+ }
1050
+ const explicitAgent = this.getExplicitAgentMention({
1051
+ content: params.payload.content,
1052
+ mentions: params.payload.mentions,
1053
+ contextKey: params.chat.contextKey,
1054
+ });
1055
+ if (explicitAgent.mentioned) {
1056
+ return { shouldRun: true, agentName: explicitAgent.agentName };
1057
+ }
1058
+ if (this.hasNonAgentMention({
1059
+ content: params.payload.content,
1060
+ mentions: params.payload.mentions,
1061
+ contextKey: params.chat.contextKey,
1062
+ })) {
1063
+ return { shouldRun: false };
1064
+ }
1065
+ const shouldRun = await this.analyzeAgentShouldRespond({
1066
+ chat: params.chat,
1067
+ previousMessages: params.previousMessages,
1068
+ userMessage: params.userMessage,
1069
+ executionContext: params.payload.executionContext,
1070
+ });
1071
+ return { shouldRun };
1072
+ }
1073
+ async prepareAgentResponseForUserMessage(chat, payload, prevMessages, userMessage, excludeSocketId, agentName) {
1074
+ const executionTenants = this.getExecutionTenants(payload);
1075
+ let assistantMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.Assistant, {
1076
+ content: '',
1077
+ agentName: agentName,
1078
+ sender: {
1079
+ id: agentName ?? 'agent',
1080
+ type: 'agent',
1081
+ displayName: agentName ?? 'Agent',
1082
+ }
1083
+ }, undefined, excludeSocketId);
1084
+ const ownerId = payload.userId ?? chat.userId ?? this.getChatUserId(chat) ?? 'guest';
1085
+ const parentActivity = await this.activityRepository.create({
1086
+ ownerId,
1087
+ groupId: chat.id,
1088
+ name: ai_agent_types_1.ActivityOperationName.MESSAGE_PROCESSING,
1089
+ tenants: executionTenants,
1090
+ sourceId: userMessage.id,
1091
+ sourceType: 'AgentMessage',
1092
+ metadata: {
1093
+ contextKey: chat.contextKey,
1094
+ modelId: this.aiHelper.getLanguageModelId(chat.model),
1095
+ },
1096
+ });
1097
+ const agentOptions = await this.aiHelper.getAgentOptions(agentName
1098
+ ? {
1099
+ agentName,
1100
+ modelId: chat.model,
1101
+ context: payload.context,
1102
+ executionContext: payload.executionContext,
1103
+ }
1104
+ : {
1105
+ contextKey: chat.contextKey,
1106
+ messages: [...prevMessages, userMessage],
1107
+ context: payload.context,
1108
+ agentName: undefined,
1109
+ modelId: chat.model,
1110
+ executionContext: payload.executionContext,
1111
+ }, {
1112
+ onStepFinish: async (stepResult) => {
1113
+ await this.storeStepActivity({
1114
+ chat,
1115
+ parentId: parentActivity.id,
1116
+ stepResult,
1117
+ name: ai_agent_types_1.ActivityOperationName.AGENT_SELECTION,
1118
+ sourceId: userMessage.id,
1119
+ sourceType: 'AgentMessage',
1120
+ tenants: executionTenants,
1121
+ });
1122
+ }
1123
+ });
1124
+ const updatedAssistantMessage = await this.messageRepository.update(assistantMessage.id, {
1125
+ agentName: agentOptions.name,
1126
+ activity: parentActivity.id,
1127
+ sender: {
1128
+ id: agentOptions.name,
1129
+ type: 'agent',
1130
+ displayName: agentOptions.name,
1131
+ }
1132
+ });
1133
+ await this.activityRepository.update(parentActivity.id, {
1134
+ metadata: {
1135
+ ...parentActivity.metadata,
1136
+ agentOptions: {
1137
+ name: agentOptions.name,
1138
+ modelId: this.aiHelper.getLanguageModelId(agentOptions.model),
1139
+ temperature: agentOptions.temperature,
1140
+ maxOutputTokens: agentOptions.maxOutputTokens,
1141
+ topP: agentOptions.topP,
1142
+ topK: agentOptions.topK,
1143
+ presencePenalty: agentOptions.presencePenalty,
1144
+ frequencyPenalty: agentOptions.frequencyPenalty,
1145
+ stopSequences: agentOptions.stopSequences,
1146
+ seed: agentOptions.seed,
1147
+ },
1148
+ },
1149
+ });
1150
+ if (!updatedAssistantMessage) {
1151
+ throw new Error(`Assistant message with id ${assistantMessage.id} not found after update`);
1152
+ }
1153
+ assistantMessage = updatedAssistantMessage;
1154
+ return {
1155
+ assistantMessage,
1156
+ agentOptions,
1157
+ executionTenants,
1158
+ };
1159
+ }
1160
+ async streamAgentResponseForUserMessage(params) {
1161
+ const { assistantMessage, agentOptions, executionTenants } = await this.prepareAgentResponseForUserMessage(params.chat, params.payload, params.previousMessages, params.userMessage, params.excludeSocketId, params.agentName);
1162
+ const messagesForAgent = [...params.previousMessages, params.userMessage];
1163
+ agentOptions.onStepFinish = (stepResult) => {
1164
+ return this.storeStepActivity({
1165
+ chat: params.chat,
1166
+ parentId: assistantMessage.activity,
1167
+ stepResult,
1168
+ name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
1169
+ sourceId: assistantMessage.id,
1170
+ sourceType: 'AgentMessage',
1171
+ tenants: executionTenants,
1172
+ });
1173
+ };
1174
+ const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(params.payload.userId ?? params.chat.userId ?? this.getChatUserId(params.chat) ?? 'guest', agentOptions.name);
1175
+ agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
1176
+ await this.streamMessageStep({
1177
+ chat: params.chat,
1178
+ existingMessages: messagesForAgent,
1179
+ assistantMessage,
1180
+ agentOptions,
1181
+ excludeSocketId: params.excludeSocketId,
1182
+ signal: params.signal,
1183
+ tenants: executionTenants,
1184
+ executionContext: params.payload.executionContext,
1185
+ context: params.payload.context,
1186
+ });
1187
+ }
1188
+ async storeStepActivity(params) {
1189
+ try {
1190
+ const stepResult = params.stepResult;
1191
+ const mergedUsage = this.mergeUsageWithProviderMetadata(stepResult.usage, stepResult.providerMetadata);
1192
+ const activity = await this.activityRepository.create({
1193
+ ownerId: this.getChatUserId(params.chat) ?? 'guest',
1194
+ groupId: params.chat.id,
1195
+ name: params.name,
1196
+ tenants: params.tenants || {},
1197
+ sourceId: params.sourceId,
1198
+ sourceType: params.sourceType,
1199
+ metadata: {
1200
+ finishReason: stepResult.finishReason,
1201
+ usage: mergedUsage,
1202
+ responseTimestamp: stepResult.response.timestamp,
1203
+ modelId: stepResult.response.modelId,
1204
+ messages: this.debug ? stepResult.request?.body?.messages : undefined,
1205
+ },
1206
+ parentId: params.parentId,
1207
+ });
1208
+ }
1209
+ catch (error) {
1210
+ logger_1.logger.error({ error, chatId: params.chat.id, parentId: params.parentId }, 'Failed to store step activity');
1211
+ }
1212
+ }
419
1213
  async streamMessage(chat, payload, excludeSocketId, onAgentStart) {
420
1214
  try {
421
- const abortController = store_1.agentStore.registerAgentProcess(chat.id);
1215
+ const executionTenants = this.getExecutionTenants(payload);
1216
+ const abortController = this.agentStore.registerAgentProcess(chat.id);
422
1217
  onAgentStart?.();
423
1218
  let assistantMessage;
424
1219
  let agentOptions;
425
1220
  const existingMessages = await this.messageRepository.findByChatId(chat.id);
426
1221
  // Limit context to prevent exceeding token limits
427
- const limitedMessages = helpers_2.ContextLimiter.limitContext(existingMessages, {
428
- maxMessages: config_1.config.ai.maxContextMessages,
1222
+ const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
1223
+ maxMessages: this.config.ai.maxContextMessages,
429
1224
  keepFirstUserMessage: true,
430
1225
  keepSystemMessages: true,
431
1226
  });
@@ -447,6 +1242,19 @@ class ChatProcessor {
447
1242
  agentOptions = result.agentOptions;
448
1243
  limitedMessages.push(result.userMessage);
449
1244
  }
1245
+ agentOptions.onStepFinish = (stepResult) => {
1246
+ return this.storeStepActivity({
1247
+ chat,
1248
+ parentId: assistantMessage.activity,
1249
+ stepResult,
1250
+ name: ai_agent_types_1.ActivityOperationName.STEP_FINISHED,
1251
+ sourceId: assistantMessage.id,
1252
+ sourceType: 'AgentMessage',
1253
+ tenants: executionTenants,
1254
+ });
1255
+ };
1256
+ const userPreferences = await this.agentConfigRepository.findByUserIdAndAgentName(this.getChatUserId(chat) ?? 'guest', agentOptions.name);
1257
+ agentOptions.activeTools = this.getAvailableTools(agentOptions, userPreferences);
450
1258
  await this.streamMessageStep({
451
1259
  chat,
452
1260
  existingMessages: limitedMessages,
@@ -454,12 +1262,30 @@ class ChatProcessor {
454
1262
  agentOptions,
455
1263
  excludeSocketId: excludeSocketId,
456
1264
  signal: abortController.signal,
1265
+ tenants: executionTenants,
1266
+ executionContext: payload.executionContext,
1267
+ context: payload.context,
457
1268
  });
458
1269
  }
459
1270
  catch (error) {
460
1271
  throw error;
461
1272
  }
462
1273
  }
1274
+ getAvailableTools(agentOptions, userPreferences) {
1275
+ const toolNames = Object.keys(agentOptions.tools || {});
1276
+ const availableToolsMap = Object.fromEntries(toolNames.map(key => [key, true]));
1277
+ const agentsConfiguration = store_1.ConfigStore.getInstance().getAgentConfigByName(agentOptions.name);
1278
+ agentsConfiguration.tools.forEach((tool) => {
1279
+ const toolTitle = (0, utils_1.getAgentToolName)(tool);
1280
+ if (tool.disabledByDefault) {
1281
+ availableToolsMap[toolTitle] = false;
1282
+ }
1283
+ if (tool.userConfigurable && userPreferences?.tools?.[toolTitle] !== undefined) {
1284
+ availableToolsMap[toolTitle] = userPreferences.tools[toolTitle];
1285
+ }
1286
+ });
1287
+ return Object.keys(availableToolsMap).filter(key => availableToolsMap[key]);
1288
+ }
463
1289
  listArtifacts(chatId) {
464
1290
  return this.artifactStore.listArtifacts(chatId);
465
1291
  }
@@ -490,7 +1316,7 @@ class ChatProcessor {
490
1316
  return null;
491
1317
  }
492
1318
  }
493
- getMessageStream(chatId) {
1319
+ getMessageStream(chatId, signal) {
494
1320
  const stream = new stream_1.PassThrough();
495
1321
  let ended = false;
496
1322
  const endStream = (error) => {
@@ -511,13 +1337,15 @@ class ChatProcessor {
511
1337
  }
512
1338
  };
513
1339
  const pushChunk = (chunk) => {
514
- if (ended || stream.destroyed || stream.writableEnded)
1340
+ if (ended || stream.destroyed || stream.writableEnded || signal?.aborted)
515
1341
  return;
516
1342
  stream.write(`data: ${JSON.stringify(chunk)}\n\n`);
517
1343
  };
518
1344
  const listener = (event) => {
519
- if (ended)
1345
+ if (signal?.aborted) {
1346
+ endStream();
520
1347
  return;
1348
+ }
521
1349
  try {
522
1350
  const chunk = this.eventToChunk(event);
523
1351
  if (chunk) {
@@ -527,7 +1355,6 @@ class ChatProcessor {
527
1355
  event.type === store_1.AgentProcessEventType.Error ||
528
1356
  event.type === store_1.AgentProcessEventType.Aborted) {
529
1357
  endStream();
530
- store_1.agentStore.removeListener(chatId, listener);
531
1358
  }
532
1359
  }
533
1360
  catch (err) {
@@ -536,21 +1363,18 @@ class ChatProcessor {
536
1363
  error: err instanceof Error ? err.message : 'Unknown error occurred',
537
1364
  });
538
1365
  endStream(err);
539
- store_1.agentStore.removeListener(chatId, listener);
540
1366
  }
541
1367
  };
542
- // Cleanup on consumer side closing
543
1368
  const closeHandler = () => {
544
- store_1.agentStore.removeListener(chatId, listener);
1369
+ this.agentStore.removeListener(chatId, listener);
545
1370
  };
546
1371
  const errorHandler = (err) => {
547
- logger_1.logger.error({ err }, 'Readable stream error');
548
- store_1.agentStore.removeListener(chatId, listener);
1372
+ signal?.removeEventListener('abort', endStream);
549
1373
  endStream(err);
550
1374
  };
551
1375
  stream.on('close', closeHandler);
552
1376
  stream.on('error', errorHandler);
553
- const listenerAttached = store_1.agentStore.addListener(chatId, listener);
1377
+ const listenerAttached = this.agentStore.addListener(chatId, listener);
554
1378
  if (!listenerAttached) {
555
1379
  // Remove stream listeners if listener attachment failed to prevent memory leak
556
1380
  stream.removeListener('close', closeHandler);
@@ -559,51 +1383,108 @@ class ChatProcessor {
559
1383
  }
560
1384
  return stream;
561
1385
  }
562
- async createMessageStream(payload, excludeSocketId) {
563
- const stream = new stream_1.PassThrough();
564
- (async () => {
565
- try {
566
- const chat = await this.upsertAndGetChat(payload, excludeSocketId);
567
- // Send chat metadata first
568
- if (!('chatId' in payload) && !('messageId' in payload) && chat) {
569
- stream.write(`data: ${JSON.stringify({
570
- type: ai_agent_types_1.StreamChunkType.Chat,
571
- chatId: chat.id,
572
- chat,
573
- })}\n\n`);
574
- }
575
- await this.streamMessage(chat, payload, excludeSocketId, async () => {
576
- if (stream.destroyed || stream.writableEnded) {
577
- return;
578
- }
579
- const messageStream = this.getMessageStream(chat.id);
580
- // If client disconnects, destroy inner stream
581
- stream.on('close', () => {
582
- if (!messageStream.destroyed) {
583
- messageStream.destroy();
584
- }
585
- });
586
- await pipelineAsync(messageStream, stream);
587
- });
1386
+ async upsertAndGetMultiUserChat(payload, excludeSocketId) {
1387
+ const targetUserId = payload.userId ?? 'guest';
1388
+ let chat = null;
1389
+ let isNewChat = false;
1390
+ if (payload.chatId) {
1391
+ chat = await this.chatRepository.findById(payload.chatId);
1392
+ if (!chat) {
1393
+ throw new Error('Chat not found');
588
1394
  }
589
- catch (error) {
590
- logger_1.logger.error({ error }, 'createMessageStream failed');
591
- if (!stream.destroyed && !stream.writableEnded) {
592
- stream.write(`data: ${JSON.stringify({
593
- type: ai_agent_types_1.StreamChunkType.Error,
594
- error: error instanceof Error ? error.message : 'Unknown error occurred',
595
- })}\n\n`);
596
- stream.write('data: [DONE]\n\n');
597
- stream.end();
598
- }
1395
+ if (!this.hasChatAccess(chat, targetUserId)) {
1396
+ throw new Error('Chat does not belong to this user');
1397
+ }
1398
+ const participantIds = Array.from(new Set([
1399
+ ...this.getParticipantIds(chat),
1400
+ ...(payload.participantIds ?? []),
1401
+ targetUserId,
1402
+ ].filter(Boolean)));
1403
+ const updates = {};
1404
+ if (participantIds.length !== this.getParticipantIds(chat).length) {
1405
+ updates.participantIds = participantIds;
1406
+ }
1407
+ if ('model' in payload) {
1408
+ updates.model = payload.model || undefined;
599
1409
  }
600
- })().catch((err) => {
601
- logger_1.logger.error({ err }, 'Unhandled stream task error');
602
- if (!stream.destroyed)
603
- stream.destroy(err);
1410
+ if (Object.keys(updates).length > 0) {
1411
+ chat = await this.updateChatAndEmit(chat, updates, excludeSocketId);
1412
+ }
1413
+ }
1414
+ if (!chat) {
1415
+ chat = await this.createChat(payload, excludeSocketId);
1416
+ isNewChat = true;
1417
+ }
1418
+ return { chat, isNewChat };
1419
+ }
1420
+ async postMultiUserMessage(payload, excludeSocketId) {
1421
+ const { chat } = await this.upsertAndGetMultiUserChat(payload, excludeSocketId);
1422
+ const existingMessages = await this.messageRepository.findByChatId(chat.id);
1423
+ const sender = {
1424
+ id: payload.userId ?? 'guest',
1425
+ type: 'user',
1426
+ ...(payload.senderDisplayName ? { displayName: payload.senderDisplayName } : {}),
1427
+ ...(payload.senderAvatarUrl ? { avatarUrl: payload.senderAvatarUrl } : {}),
1428
+ };
1429
+ const userMessage = await this.createMessage(chat, ai_agent_types_1.MessageRole.User, {
1430
+ content: payload.content,
1431
+ agentName: undefined,
1432
+ sender,
1433
+ mentions: payload.mentions ?? [],
1434
+ }, payload.attachments, excludeSocketId);
1435
+ const decision = await this.shouldRunAgentForMultiUserMessage({
1436
+ chat,
1437
+ previousMessages: existingMessages,
1438
+ userMessage,
1439
+ payload,
1440
+ });
1441
+ if (!decision.shouldRun) {
1442
+ const updatedChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Finished }, excludeSocketId);
1443
+ return { chat: updatedChat, message: userMessage, agentTriggered: false };
1444
+ }
1445
+ const updatedChat = await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Streaming }, undefined);
1446
+ const abortController = this.agentStore.registerAgentProcess(chat.id);
1447
+ const limitedMessages = helpers_1.ContextLimiter.limitContext(existingMessages, {
1448
+ maxMessages: this.config.ai.maxContextMessages,
1449
+ keepFirstUserMessage: true,
1450
+ keepSystemMessages: true,
1451
+ });
1452
+ void this.streamAgentResponseForUserMessage({
1453
+ chat,
1454
+ payload,
1455
+ previousMessages: limitedMessages,
1456
+ userMessage,
1457
+ excludeSocketId: undefined,
1458
+ signal: abortController.signal,
1459
+ agentName: decision.agentName,
1460
+ }).catch(async (error) => {
1461
+ logger_1.logger.error({ error, chatId: chat.id }, 'Multi-user background agent flow failed');
1462
+ await this.updateChatAndEmit(chat, { status: ai_agent_types_1.AgentStatus.Error }, undefined);
1463
+ });
1464
+ return { chat: updatedChat, message: userMessage, agentTriggered: true };
1465
+ }
1466
+ async createMessageStream(payload, excludeSocketId, signal) {
1467
+ const stream = new stream_1.PassThrough();
1468
+ this.runMessageStream(stream, payload, excludeSocketId, signal)
1469
+ .catch(err => {
1470
+ logger_1.logger.error({ err }, 'Stream task failed');
604
1471
  });
605
1472
  return stream;
606
1473
  }
1474
+ async runMessageStream(stream, payload, excludeSocketId, signal) {
1475
+ const chat = await this.upsertAndGetChat(payload, excludeSocketId);
1476
+ if (!('chatId' in payload) && !('messageId' in payload) && chat) {
1477
+ stream.write(`data: ${JSON.stringify({
1478
+ type: ai_agent_types_1.StreamChunkType.Chat,
1479
+ chatId: chat.id,
1480
+ chat,
1481
+ })}\n\n`);
1482
+ }
1483
+ await this.streamMessage(chat, payload, excludeSocketId, () => {
1484
+ const messageStream = this.getMessageStream(chat.id, signal);
1485
+ messageStream.pipe(stream);
1486
+ });
1487
+ }
607
1488
  }
608
1489
  exports.ChatProcessor = ChatProcessor;
609
1490
  //# sourceMappingURL=ChatProcessor.js.map