@memberjunction/server 6.2.0-edge.4 → 6.2.0-edge.6

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 (560) hide show
  1. package/README.md +47 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/agentSessions/SessionJanitor.d.ts +91 -30
  4. package/dist/agentSessions/SessionJanitor.d.ts.map +1 -1
  5. package/dist/agentSessions/SessionJanitor.js +311 -81
  6. package/dist/agentSessions/SessionJanitor.js.map +1 -1
  7. package/dist/agentSessions/SessionManager.d.ts +17 -3
  8. package/dist/agentSessions/SessionManager.d.ts.map +1 -1
  9. package/dist/agentSessions/SessionManager.js +44 -10
  10. package/dist/agentSessions/SessionManager.js.map +1 -1
  11. package/dist/apiRoot.d.ts +32 -0
  12. package/dist/apiRoot.d.ts.map +1 -0
  13. package/dist/apiRoot.js +67 -0
  14. package/dist/apiRoot.js.map +1 -0
  15. package/dist/auth/AuthProviderCatalogRouter.d.ts.map +1 -1
  16. package/dist/auth/AuthProviderCatalogRouter.js +27 -0
  17. package/dist/auth/AuthProviderCatalogRouter.js.map +1 -1
  18. package/dist/auth/LoginScreenEngine.d.ts +22 -0
  19. package/dist/auth/LoginScreenEngine.d.ts.map +1 -0
  20. package/dist/auth/LoginScreenEngine.js +57 -0
  21. package/dist/auth/LoginScreenEngine.js.map +1 -0
  22. package/dist/auth/index.d.ts +1 -0
  23. package/dist/auth/index.d.ts.map +1 -1
  24. package/dist/auth/index.js +52 -10
  25. package/dist/auth/index.js.map +1 -1
  26. package/dist/auth/initializeProviders.d.ts +10 -0
  27. package/dist/auth/initializeProviders.d.ts.map +1 -1
  28. package/dist/auth/initializeProviders.js +37 -1
  29. package/dist/auth/initializeProviders.js.map +1 -1
  30. package/dist/auth/localDevAuth.d.ts +79 -0
  31. package/dist/auth/localDevAuth.d.ts.map +1 -0
  32. package/dist/auth/localDevAuth.js +439 -0
  33. package/dist/auth/localDevAuth.js.map +1 -0
  34. package/dist/auth/magicLink/MagicLinkKeys.d.ts +2 -2
  35. package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -1
  36. package/dist/auth/magicLink/MagicLinkKeys.js +1 -1
  37. package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -1
  38. package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -1
  39. package/dist/auth/magicLink/MagicLinkRouter.js +3 -2
  40. package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -1
  41. package/dist/auth/magicLink/types.d.ts +12 -0
  42. package/dist/auth/magicLink/types.d.ts.map +1 -1
  43. package/dist/auth/sessionUserClone.d.ts +1 -1
  44. package/dist/auth/sessionUserClone.d.ts.map +1 -1
  45. package/dist/auth/sessionUserClone.js +3 -2
  46. package/dist/auth/sessionUserClone.js.map +1 -1
  47. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts +292 -0
  48. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.d.ts.map +1 -0
  49. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js +442 -0
  50. package/dist/broadcast/BaseCacheInvalidationBroadcastProvider.js.map +1 -0
  51. package/dist/broadcast/index.d.ts +6 -0
  52. package/dist/broadcast/index.d.ts.map +1 -0
  53. package/dist/broadcast/index.js +6 -0
  54. package/dist/broadcast/index.js.map +1 -0
  55. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts +43 -0
  56. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.d.ts.map +1 -0
  57. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js +144 -0
  58. package/dist/broadcast/providers/AWSIoTCoreBroadcastProvider.js.map +1 -0
  59. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts +46 -0
  60. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.d.ts.map +1 -0
  61. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js +149 -0
  62. package/dist/broadcast/providers/AzureWebPubSubBroadcastProvider.js.map +1 -0
  63. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts +49 -0
  64. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.d.ts.map +1 -0
  65. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js +131 -0
  66. package/dist/broadcast/providers/GCPPubSubBroadcastProvider.js.map +1 -0
  67. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts +24 -0
  68. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.d.ts.map +1 -0
  69. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js +51 -0
  70. package/dist/broadcast/providers/SequencedRoleBucketBroadcastProvider.js.map +1 -0
  71. package/dist/cache.d.ts +3 -2
  72. package/dist/cache.d.ts.map +1 -1
  73. package/dist/cache.js.map +1 -1
  74. package/dist/config.d.ts +632 -22
  75. package/dist/config.d.ts.map +1 -1
  76. package/dist/config.js +104 -4
  77. package/dist/config.js.map +1 -1
  78. package/dist/context.d.ts +3 -1
  79. package/dist/context.d.ts.map +1 -1
  80. package/dist/context.js +29 -8
  81. package/dist/context.js.map +1 -1
  82. package/dist/coreRoutes.d.ts +29 -0
  83. package/dist/coreRoutes.d.ts.map +1 -0
  84. package/dist/coreRoutes.js +156 -0
  85. package/dist/coreRoutes.js.map +1 -0
  86. package/dist/generated/graphql-schemas/__mj.d.ts +1016 -29
  87. package/dist/generated/graphql-schemas/__mj.d.ts.map +1 -1
  88. package/dist/generated/graphql-schemas/__mj.js +5125 -434
  89. package/dist/generated/graphql-schemas/__mj.js.map +1 -1
  90. package/dist/generic/CacheInvalidationResolver.d.ts +85 -30
  91. package/dist/generic/CacheInvalidationResolver.d.ts.map +1 -1
  92. package/dist/generic/CacheInvalidationResolver.js +175 -60
  93. package/dist/generic/CacheInvalidationResolver.js.map +1 -1
  94. package/dist/generic/OrphanedConversationDetailReconciler.d.ts.map +1 -1
  95. package/dist/generic/OrphanedConversationDetailReconciler.js +2 -0
  96. package/dist/generic/OrphanedConversationDetailReconciler.js.map +1 -1
  97. package/dist/generic/PubSubManager.d.ts +10 -0
  98. package/dist/generic/PubSubManager.d.ts.map +1 -1
  99. package/dist/generic/PubSubManager.js +44 -1
  100. package/dist/generic/PubSubManager.js.map +1 -1
  101. package/dist/generic/PushStatusResolver.d.ts +39 -6
  102. package/dist/generic/PushStatusResolver.d.ts.map +1 -1
  103. package/dist/generic/PushStatusResolver.js +94 -12
  104. package/dist/generic/PushStatusResolver.js.map +1 -1
  105. package/dist/generic/ResolverBase.d.ts +168 -69
  106. package/dist/generic/ResolverBase.d.ts.map +1 -1
  107. package/dist/generic/ResolverBase.js +464 -405
  108. package/dist/generic/ResolverBase.js.map +1 -1
  109. package/dist/generic/RunViewResolver.d.ts +11 -3
  110. package/dist/generic/RunViewResolver.d.ts.map +1 -1
  111. package/dist/generic/RunViewResolver.js +91 -13
  112. package/dist/generic/RunViewResolver.js.map +1 -1
  113. package/dist/generic/actionOutputFieldSecurity.d.ts +26 -0
  114. package/dist/generic/actionOutputFieldSecurity.d.ts.map +1 -0
  115. package/dist/generic/actionOutputFieldSecurity.js +47 -0
  116. package/dist/generic/actionOutputFieldSecurity.js.map +1 -0
  117. package/dist/generic/fieldSecurityTransport.d.ts +30 -0
  118. package/dist/generic/fieldSecurityTransport.d.ts.map +1 -0
  119. package/dist/generic/fieldSecurityTransport.js +30 -0
  120. package/dist/generic/fieldSecurityTransport.js.map +1 -0
  121. package/dist/globalCors.d.ts +33 -0
  122. package/dist/globalCors.d.ts.map +1 -0
  123. package/dist/globalCors.js +58 -0
  124. package/dist/globalCors.js.map +1 -0
  125. package/dist/index.d.ts +14 -0
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +230 -222
  128. package/dist/index.js.map +1 -1
  129. package/dist/integration/CustomColumnPromoter.d.ts.map +1 -1
  130. package/dist/integration/CustomColumnPromoter.js +6 -1
  131. package/dist/integration/CustomColumnPromoter.js.map +1 -1
  132. package/dist/logging/variablesLoggingMiddleware.d.ts +12 -0
  133. package/dist/logging/variablesLoggingMiddleware.d.ts.map +1 -1
  134. package/dist/logging/variablesLoggingMiddleware.js +50 -1
  135. package/dist/logging/variablesLoggingMiddleware.js.map +1 -1
  136. package/dist/multiTenancy/index.d.ts.map +1 -1
  137. package/dist/multiTenancy/index.js +22 -2
  138. package/dist/multiTenancy/index.js.map +1 -1
  139. package/dist/realtimeSessions/RealtimeSessionVerificationService.d.ts.map +1 -1
  140. package/dist/realtimeSessions/RealtimeSessionVerificationService.js +2 -1
  141. package/dist/realtimeSessions/RealtimeSessionVerificationService.js.map +1 -1
  142. package/dist/realtimeSessions/RealtimeVerifyRouter.d.ts.map +1 -1
  143. package/dist/realtimeSessions/RealtimeVerifyRouter.js +2 -1
  144. package/dist/realtimeSessions/RealtimeVerifyRouter.js.map +1 -1
  145. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts +100 -0
  146. package/dist/realtimeSessions/RecordingAssemblyScheduler.d.ts.map +1 -0
  147. package/dist/realtimeSessions/RecordingAssemblyScheduler.js +173 -0
  148. package/dist/realtimeSessions/RecordingAssemblyScheduler.js.map +1 -0
  149. package/dist/realtimeSessions/SessionVerificationPortsBase.d.ts.map +1 -1
  150. package/dist/realtimeSessions/SessionVerificationPortsBase.js +1 -0
  151. package/dist/realtimeSessions/SessionVerificationPortsBase.js.map +1 -1
  152. package/dist/realtimeSessions/index.d.ts +2 -0
  153. package/dist/realtimeSessions/index.d.ts.map +1 -1
  154. package/dist/realtimeSessions/index.js +2 -0
  155. package/dist/realtimeSessions/index.js.map +1 -1
  156. package/dist/realtimeSessions/ownedRealtimeSession.d.ts +32 -0
  157. package/dist/realtimeSessions/ownedRealtimeSession.d.ts.map +1 -0
  158. package/dist/realtimeSessions/ownedRealtimeSession.js +56 -0
  159. package/dist/realtimeSessions/ownedRealtimeSession.js.map +1 -0
  160. package/dist/realtimeSessions/sessionAccess.d.ts +91 -8
  161. package/dist/realtimeSessions/sessionAccess.d.ts.map +1 -1
  162. package/dist/realtimeSessions/sessionAccess.js +127 -20
  163. package/dist/realtimeSessions/sessionAccess.js.map +1 -1
  164. package/dist/realtimeSessions/sessionConfigStamps.js +1 -1
  165. package/dist/realtimeSessions/sessionConfigStamps.js.map +1 -1
  166. package/dist/realtimeSessions/subscriptionAuthorization.d.ts.map +1 -1
  167. package/dist/realtimeSessions/subscriptionAuthorization.js +5 -2
  168. package/dist/realtimeSessions/subscriptionAuthorization.js.map +1 -1
  169. package/dist/realtimeSessions/verificationWorkflow.d.ts +2 -0
  170. package/dist/realtimeSessions/verificationWorkflow.d.ts.map +1 -1
  171. package/dist/realtimeSessions/verificationWorkflow.js +1 -1
  172. package/dist/realtimeSessions/verificationWorkflow.js.map +1 -1
  173. package/dist/realtimeWidget/WidgetRouter.d.ts.map +1 -1
  174. package/dist/realtimeWidget/WidgetRouter.js +19 -3
  175. package/dist/realtimeWidget/WidgetRouter.js.map +1 -1
  176. package/dist/realtimeWidget/WidgetSessionService.d.ts +67 -7
  177. package/dist/realtimeWidget/WidgetSessionService.d.ts.map +1 -1
  178. package/dist/realtimeWidget/WidgetSessionService.js +201 -19
  179. package/dist/realtimeWidget/WidgetSessionService.js.map +1 -1
  180. package/dist/realtimeWidget/host-identity.d.ts +1 -1
  181. package/dist/realtimeWidget/host-identity.js +1 -1
  182. package/dist/realtimeWidget/widgetCore.d.ts +20 -1
  183. package/dist/realtimeWidget/widgetCore.d.ts.map +1 -1
  184. package/dist/realtimeWidget/widgetCore.js +17 -1
  185. package/dist/realtimeWidget/widgetCore.js.map +1 -1
  186. package/dist/realtimeWidget/widgetGuestElevation.d.ts +1 -1
  187. package/dist/realtimeWidget/widgetGuestElevation.d.ts.map +1 -1
  188. package/dist/realtimeWidget/widgetGuestElevation.js +2 -1
  189. package/dist/realtimeWidget/widgetGuestElevation.js.map +1 -1
  190. package/dist/resolvers/ActionResolver.d.ts +19 -1
  191. package/dist/resolvers/ActionResolver.d.ts.map +1 -1
  192. package/dist/resolvers/ActionResolver.js +63 -12
  193. package/dist/resolvers/ActionResolver.js.map +1 -1
  194. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  195. package/dist/resolvers/AdhocQueryResolver.js +1 -0
  196. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  197. package/dist/resolvers/AgentRunStatusPublisher.d.ts +18 -4
  198. package/dist/resolvers/AgentRunStatusPublisher.d.ts.map +1 -1
  199. package/dist/resolvers/AgentRunStatusPublisher.js +32 -8
  200. package/dist/resolvers/AgentRunStatusPublisher.js.map +1 -1
  201. package/dist/resolvers/AgentSessionResolver.d.ts +10 -4
  202. package/dist/resolvers/AgentSessionResolver.d.ts.map +1 -1
  203. package/dist/resolvers/AgentSessionResolver.js +40 -17
  204. package/dist/resolvers/AgentSessionResolver.js.map +1 -1
  205. package/dist/resolvers/ArtifactFileResolver.d.ts +5 -1
  206. package/dist/resolvers/ArtifactFileResolver.d.ts.map +1 -1
  207. package/dist/resolvers/ArtifactFileResolver.js +9 -7
  208. package/dist/resolvers/ArtifactFileResolver.js.map +1 -1
  209. package/dist/resolvers/ConversationRunEventsResolver.d.ts +8 -4
  210. package/dist/resolvers/ConversationRunEventsResolver.d.ts.map +1 -1
  211. package/dist/resolvers/ConversationRunEventsResolver.js +6 -6
  212. package/dist/resolvers/ConversationRunEventsResolver.js.map +1 -1
  213. package/dist/resolvers/DatasetResolver.d.ts +24 -3
  214. package/dist/resolvers/DatasetResolver.d.ts.map +1 -1
  215. package/dist/resolvers/DatasetResolver.js +57 -8
  216. package/dist/resolvers/DatasetResolver.js.map +1 -1
  217. package/dist/resolvers/EntityCommunicationsResolver.d.ts +13 -1
  218. package/dist/resolvers/EntityCommunicationsResolver.d.ts.map +1 -1
  219. package/dist/resolvers/EntityCommunicationsResolver.js +50 -14
  220. package/dist/resolvers/EntityCommunicationsResolver.js.map +1 -1
  221. package/dist/resolvers/EntityRecordNameResolver.d.ts +2 -1
  222. package/dist/resolvers/EntityRecordNameResolver.d.ts.map +1 -1
  223. package/dist/resolvers/EntityRecordNameResolver.js +3 -2
  224. package/dist/resolvers/EntityRecordNameResolver.js.map +1 -1
  225. package/dist/resolvers/FetchEntityVectorsResolver.d.ts +46 -3
  226. package/dist/resolvers/FetchEntityVectorsResolver.d.ts.map +1 -1
  227. package/dist/resolvers/FetchEntityVectorsResolver.js +211 -50
  228. package/dist/resolvers/FetchEntityVectorsResolver.js.map +1 -1
  229. package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
  230. package/dist/resolvers/FileCategoryResolver.js +1 -0
  231. package/dist/resolvers/FileCategoryResolver.js.map +1 -1
  232. package/dist/resolvers/FileResolver.d.ts +87 -11
  233. package/dist/resolvers/FileResolver.d.ts.map +1 -1
  234. package/dist/resolvers/FileResolver.js +292 -105
  235. package/dist/resolvers/FileResolver.js.map +1 -1
  236. package/dist/resolvers/GetDataContextDataResolver.d.ts +33 -7
  237. package/dist/resolvers/GetDataContextDataResolver.d.ts.map +1 -1
  238. package/dist/resolvers/GetDataContextDataResolver.js +117 -38
  239. package/dist/resolvers/GetDataContextDataResolver.js.map +1 -1
  240. package/dist/resolvers/GetDataResolver.d.ts.map +1 -1
  241. package/dist/resolvers/GetDataResolver.js +6 -3
  242. package/dist/resolvers/GetDataResolver.js.map +1 -1
  243. package/dist/resolvers/IntegrationDiscoveryResolver.d.ts.map +1 -1
  244. package/dist/resolvers/IntegrationDiscoveryResolver.js +49 -9
  245. package/dist/resolvers/IntegrationDiscoveryResolver.js.map +1 -1
  246. package/dist/resolvers/MergeRecordsResolver.d.ts +8 -1
  247. package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
  248. package/dist/resolvers/MergeRecordsResolver.js +31 -3
  249. package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
  250. package/dist/resolvers/PipelineProgressResolver.d.ts +6 -0
  251. package/dist/resolvers/PipelineProgressResolver.d.ts.map +1 -1
  252. package/dist/resolvers/PipelineProgressResolver.js +5 -3
  253. package/dist/resolvers/PipelineProgressResolver.js.map +1 -1
  254. package/dist/resolvers/QueryResolver.d.ts +2 -0
  255. package/dist/resolvers/QueryResolver.d.ts.map +1 -1
  256. package/dist/resolvers/QueryResolver.js +33 -6
  257. package/dist/resolvers/QueryResolver.js.map +1 -1
  258. package/dist/resolvers/QuerySystemUserResolver.d.ts +2 -0
  259. package/dist/resolvers/QuerySystemUserResolver.d.ts.map +1 -1
  260. package/dist/resolvers/QuerySystemUserResolver.js +15 -6
  261. package/dist/resolvers/QuerySystemUserResolver.js.map +1 -1
  262. package/dist/resolvers/RSUResolver.d.ts.map +1 -1
  263. package/dist/resolvers/RSUResolver.js +12 -0
  264. package/dist/resolvers/RSUResolver.js.map +1 -1
  265. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +18 -10
  266. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  267. package/dist/resolvers/RealtimeClientSessionResolver.js +92 -54
  268. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  269. package/dist/resolvers/RemoteBrowserActionResolver.d.ts.map +1 -1
  270. package/dist/resolvers/RemoteBrowserActionResolver.js +11 -9
  271. package/dist/resolvers/RemoteBrowserActionResolver.js.map +1 -1
  272. package/dist/resolvers/RunAIAgentResolver.d.ts +56 -8
  273. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  274. package/dist/resolvers/RunAIAgentResolver.js +241 -67
  275. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  276. package/dist/resolvers/RunTemplateResolver.d.ts.map +1 -1
  277. package/dist/resolvers/RunTemplateResolver.js +4 -4
  278. package/dist/resolvers/RunTemplateResolver.js.map +1 -1
  279. package/dist/resolvers/RunTestResolver.d.ts.map +1 -1
  280. package/dist/resolvers/RunTestResolver.js +3 -1
  281. package/dist/resolvers/RunTestResolver.js.map +1 -1
  282. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts +12 -1
  283. package/dist/resolvers/SearchKnowledgeStreamResolver.d.ts.map +1 -1
  284. package/dist/resolvers/SearchKnowledgeStreamResolver.js +15 -2
  285. package/dist/resolvers/SearchKnowledgeStreamResolver.js.map +1 -1
  286. package/dist/resolvers/SqlLoggingConfigResolver.d.ts.map +1 -1
  287. package/dist/resolvers/SqlLoggingConfigResolver.js +2 -3
  288. package/dist/resolvers/SqlLoggingConfigResolver.js.map +1 -1
  289. package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
  290. package/dist/resolvers/SyncDataResolver.js +4 -0
  291. package/dist/resolvers/SyncDataResolver.js.map +1 -1
  292. package/dist/resolvers/TaskGraphFrameResolver.d.ts +2 -1
  293. package/dist/resolvers/TaskGraphFrameResolver.d.ts.map +1 -1
  294. package/dist/resolvers/TaskGraphFrameResolver.js +28 -1
  295. package/dist/resolvers/TaskGraphFrameResolver.js.map +1 -1
  296. package/dist/resolvers/TestQuerySQLResolver.d.ts +24 -0
  297. package/dist/resolvers/TestQuerySQLResolver.d.ts.map +1 -1
  298. package/dist/resolvers/TestQuerySQLResolver.js +66 -13
  299. package/dist/resolvers/TestQuerySQLResolver.js.map +1 -1
  300. package/dist/resolvers/TransactionGroupResolver.d.ts +34 -2
  301. package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
  302. package/dist/resolvers/TransactionGroupResolver.js +150 -27
  303. package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
  304. package/dist/resolvers/UserViewResolver.d.ts +1 -1
  305. package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
  306. package/dist/resolvers/UserViewResolver.js +2 -1
  307. package/dist/resolvers/UserViewResolver.js.map +1 -1
  308. package/dist/resolvers/agent-run-data-guard.d.ts +31 -0
  309. package/dist/resolvers/agent-run-data-guard.d.ts.map +1 -0
  310. package/dist/resolvers/agent-run-data-guard.js +72 -0
  311. package/dist/resolvers/agent-run-data-guard.js.map +1 -0
  312. package/dist/rest/EntityCRUDHandler.d.ts +6 -0
  313. package/dist/rest/EntityCRUDHandler.d.ts.map +1 -1
  314. package/dist/rest/EntityCRUDHandler.js +19 -5
  315. package/dist/rest/EntityCRUDHandler.js.map +1 -1
  316. package/dist/rest/RESTEndpointHandler.d.ts.map +1 -1
  317. package/dist/rest/RESTEndpointHandler.js +8 -5
  318. package/dist/rest/RESTEndpointHandler.js.map +1 -1
  319. package/dist/rest/RealtimeRecordingHandler.d.ts +49 -0
  320. package/dist/rest/RealtimeRecordingHandler.d.ts.map +1 -0
  321. package/dist/rest/RealtimeRecordingHandler.js +383 -0
  322. package/dist/rest/RealtimeRecordingHandler.js.map +1 -0
  323. package/dist/rest/ViewOperationsHandler.d.ts +9 -1
  324. package/dist/rest/ViewOperationsHandler.d.ts.map +1 -1
  325. package/dist/rest/ViewOperationsHandler.js +43 -17
  326. package/dist/rest/ViewOperationsHandler.js.map +1 -1
  327. package/dist/rest/setupRESTEndpoints.d.ts +6 -0
  328. package/dist/rest/setupRESTEndpoints.d.ts.map +1 -1
  329. package/dist/rest/setupRESTEndpoints.js +6 -0
  330. package/dist/rest/setupRESTEndpoints.js.map +1 -1
  331. package/dist/serverExtensionReservedRoots.d.ts +12 -10
  332. package/dist/serverExtensionReservedRoots.d.ts.map +1 -1
  333. package/dist/serverExtensionReservedRoots.js +14 -17
  334. package/dist/serverExtensionReservedRoots.js.map +1 -1
  335. package/dist/serverRoleConfigUnits.d.ts +29 -0
  336. package/dist/serverRoleConfigUnits.d.ts.map +1 -0
  337. package/dist/serverRoleConfigUnits.js +33 -0
  338. package/dist/serverRoleConfigUnits.js.map +1 -0
  339. package/dist/services/MJStorageBlobStore.d.ts +8 -1
  340. package/dist/services/MJStorageBlobStore.d.ts.map +1 -1
  341. package/dist/services/MJStorageBlobStore.js +25 -19
  342. package/dist/services/MJStorageBlobStore.js.map +1 -1
  343. package/dist/services/StartTaskGraphDispatcher.js +2 -2
  344. package/dist/services/StartTaskGraphDispatcher.js.map +1 -1
  345. package/dist/services/TaskGraphActionRunner.d.ts +5 -3
  346. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  347. package/dist/services/TaskGraphActionRunner.js +27 -5
  348. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  349. package/dist/services/TaskGraphAgentRunner.d.ts +14 -2
  350. package/dist/services/TaskGraphAgentRunner.d.ts.map +1 -1
  351. package/dist/services/TaskGraphAgentRunner.js +157 -9
  352. package/dist/services/TaskGraphAgentRunner.js.map +1 -1
  353. package/dist/services/TaskGraphContinuationDeliverer.d.ts +59 -2
  354. package/dist/services/TaskGraphContinuationDeliverer.d.ts.map +1 -1
  355. package/dist/services/TaskGraphContinuationDeliverer.js +626 -16
  356. package/dist/services/TaskGraphContinuationDeliverer.js.map +1 -1
  357. package/dist/sharedCache.d.ts.map +1 -1
  358. package/dist/sharedCache.js +3 -0
  359. package/dist/sharedCache.js.map +1 -1
  360. package/dist/types.d.ts +23 -1
  361. package/dist/types.d.ts.map +1 -1
  362. package/dist/types.js.map +1 -1
  363. package/package.json +99 -98
  364. package/src/__tests__/ActionResolver.fieldSecurity.test.ts +237 -0
  365. package/src/__tests__/AdhocQueryResolver.dialect.test.ts +137 -0
  366. package/src/__tests__/AgentRunStatusPublisher.test.ts +49 -0
  367. package/src/__tests__/AgentSessionResolver.ownership.test.ts +137 -0
  368. package/src/__tests__/CustomColumnPromoterOnePass.test.ts +15 -1
  369. package/src/__tests__/DatasetResolver.itemFilters.test.ts +201 -0
  370. package/src/__tests__/EntityCommunicationsResolver.actingUser.test.ts +151 -0
  371. package/src/__tests__/EntityRecordNameResolver.rowSecurity.test.ts +152 -0
  372. package/src/__tests__/EvolutionActsOnWhatItDetects.test.ts +113 -0
  373. package/src/__tests__/FetchEntityVectorsResolver.test.ts +369 -18
  374. package/src/__tests__/FileResolver.fieldSecurity.test.ts +82 -0
  375. package/src/__tests__/FileResolver.storageAccess.test.ts +562 -0
  376. package/src/__tests__/GetDataContextDataResolver.sqlItems.test.ts +416 -0
  377. package/src/__tests__/ListOperationsResolver.adhocScreen.test.ts +137 -0
  378. package/src/__tests__/LoginScreenEngine.test.ts +86 -0
  379. package/src/__tests__/MJStorageBlobStore.storageGate.test.ts +63 -0
  380. package/src/__tests__/PipelineProgressResolver.filter.test.ts +58 -0
  381. package/src/__tests__/QuerySystemUserResolver.fieldSecurity.test.ts +49 -0
  382. package/src/__tests__/RESTEndpointHandler.test.ts +25 -0
  383. package/src/__tests__/RealtimeClientSessionResolver.configTamper.test.ts +23 -3
  384. package/src/__tests__/RealtimeClientSessionResolver.test.ts +324 -46
  385. package/src/__tests__/RecordingAssemblyScheduler.test.ts +178 -0
  386. package/src/__tests__/RemoteBrowserActionResolver.ownership.test.ts +98 -0
  387. package/src/__tests__/ResolverBase.adhocReadScope.test.ts +133 -2
  388. package/src/__tests__/ResolverBase.balancedClause.test.ts +155 -0
  389. package/src/__tests__/ResolverBase.clauseUnscopedRead.test.ts +127 -0
  390. package/src/__tests__/ResolverBase.clientOldValues.test.ts +243 -7
  391. package/src/__tests__/ResolverBase.deleteReturnProjection.test.ts +52 -0
  392. package/src/__tests__/ResolverBase.entityMessageRelay.test.ts +176 -0
  393. package/src/__tests__/ResolverBase.filterEscaping.test.ts +5 -2
  394. package/src/__tests__/ResolverBase.includeBinaryFields.test.ts +23 -1
  395. package/src/__tests__/ResolverBase.publishStatusUpdate.test.ts +68 -0
  396. package/src/__tests__/ResolverBase.userViewCacheAndDedup.test.ts +130 -0
  397. package/src/__tests__/RunAIAgentResolver.branch.test.ts +69 -13
  398. package/src/__tests__/RunAIAgentResolver.conversationWriter.test.ts +210 -0
  399. package/src/__tests__/RunAIAgentResolver.fireAndForgetCompletion.test.ts +209 -0
  400. package/src/__tests__/RunAIAgentResolver.historyFrom.test.ts +20 -28
  401. package/src/__tests__/RunAIAgentResolver.runDataGuard.test.ts +264 -0
  402. package/src/__tests__/RunAIAgentResolver.serverReply.test.ts +358 -0
  403. package/src/__tests__/RunAIAgentResolver.stoppedPredecessor.test.ts +4 -1
  404. package/src/__tests__/RunTemplateResolver.test.ts +35 -2
  405. package/src/__tests__/RunViewResolver.cacheCheckForwarding.test.ts +11 -0
  406. package/src/__tests__/RunViewResolver.cacheCheckScreen.test.ts +165 -0
  407. package/src/__tests__/SearchKnowledgeStreamResolver.test.ts +161 -0
  408. package/src/__tests__/SessionJanitor.test.ts +365 -10
  409. package/src/__tests__/SessionManager.test.ts +122 -0
  410. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +25 -0
  411. package/src/__tests__/TaskGraphAgentRunner.test.ts +266 -0
  412. package/src/__tests__/TaskGraphContinuationDeliverer.test.ts +468 -23
  413. package/src/__tests__/TaskGraphFrameResolver.test.ts +22 -0
  414. package/src/__tests__/TestQuerySQLResolver.test.ts +274 -0
  415. package/src/__tests__/TransactionGroupResolver.fieldSecurity.test.ts +199 -0
  416. package/src/__tests__/TransactionGroupResolver.refusals.test.ts +98 -1
  417. package/src/__tests__/UpdateMJDataContextItem.oldValues.test.ts +220 -0
  418. package/src/__tests__/UserViewResolver.updateWhereClause.test.ts +15 -0
  419. package/src/__tests__/ViewOperationsHandler.clauseScreen.test.ts +157 -0
  420. package/src/__tests__/ViewOperationsHandler.test.ts +7 -2
  421. package/src/__tests__/WidgetSessionService.test.ts +583 -4
  422. package/src/__tests__/agent-run-data-guard.test.ts +130 -0
  423. package/src/__tests__/apiRootBoot.test.ts +202 -0
  424. package/src/__tests__/buildMagicLinkSessionUser.test.ts +96 -0
  425. package/src/__tests__/cacheBroadcastProviders.test.ts +403 -0
  426. package/src/__tests__/cacheInvalidationRecordData.test.ts +109 -0
  427. package/src/__tests__/conversationRunEvents.test.ts +56 -14
  428. package/src/__tests__/fieldSecurityFixtures.ts +91 -0
  429. package/src/__tests__/globalCors.test.ts +217 -0
  430. package/src/__tests__/localDevAuth.test.ts +196 -0
  431. package/src/__tests__/multiTenancy.postgresRewrite.test.ts +181 -0
  432. package/src/__tests__/multiTenancy.security.test.ts +51 -0
  433. package/src/__tests__/multiTenancy.test.ts +1 -1
  434. package/src/__tests__/orphanedConversationDetailReconciler.test.ts +10 -0
  435. package/src/__tests__/ownedRealtimeSession.test.ts +39 -0
  436. package/src/__tests__/pushStatusResolver.filter.test.ts +64 -1
  437. package/src/__tests__/realtimeRecordingHandler.test.ts +669 -0
  438. package/src/__tests__/realtimeSessions/RealtimeSessionEventsResolver.test.ts +29 -1
  439. package/src/__tests__/realtimeSessions/ownedRealtimeSession.anonymous.test.ts +31 -0
  440. package/src/__tests__/realtimeSessions/ownedRealtimeSession.namedScoped.test.ts +37 -0
  441. package/src/__tests__/realtimeSessions/sessionAccess.test.ts +146 -7
  442. package/src/__tests__/realtimeSessions/sessionConfigStamps.test.ts +1 -1
  443. package/src/__tests__/realtimeSessions/verificationWorkflow.test.ts +25 -4
  444. package/src/__tests__/resolverBase.cloudEventChangedFields.test.ts +157 -0
  445. package/src/__tests__/resolverBase.fieldSecurityTransport.test.ts +222 -0
  446. package/src/__tests__/resolverBase.fls.test.ts +146 -97
  447. package/src/__tests__/restTransport.fieldSecurity.test.ts +148 -0
  448. package/src/__tests__/runParamsTimeZone.test.ts +179 -0
  449. package/src/__tests__/runStreams.fieldSecurity.test.ts +100 -0
  450. package/src/__tests__/runViewProperties.test.ts +114 -0
  451. package/src/__tests__/scalabilityBenchmarks.test.ts +765 -0
  452. package/src/__tests__/scalabilityDatabaseIntegration.test.ts +207 -0
  453. package/src/__tests__/serverExtensionHostOverlay.test.ts +66 -0
  454. package/src/__tests__/serverExtensionReservedRoots.test.ts +11 -98
  455. package/src/__tests__/sessionUserClone.test.ts +5 -1
  456. package/src/__tests__/sharedCache.test.ts +5 -3
  457. package/src/__tests__/startupSweepOrder.test.ts +40 -0
  458. package/src/__tests__/unifiedAuth.test.ts +28 -0
  459. package/src/__tests__/widgetGuestElevation.test.ts +2 -0
  460. package/src/agentSessions/SessionJanitor.ts +369 -93
  461. package/src/agentSessions/SessionManager.ts +45 -10
  462. package/src/apiRoot.ts +78 -0
  463. package/src/auth/AuthProviderCatalogRouter.ts +29 -0
  464. package/src/auth/LoginScreenEngine.ts +50 -0
  465. package/src/auth/index.ts +57 -12
  466. package/src/auth/initializeProviders.ts +43 -1
  467. package/src/auth/localDevAuth.ts +528 -0
  468. package/src/auth/magicLink/MagicLinkKeys.ts +2 -2
  469. package/src/auth/magicLink/MagicLinkRouter.ts +3 -2
  470. package/src/auth/magicLink/types.ts +10 -0
  471. package/src/auth/sessionUserClone.ts +3 -2
  472. package/src/broadcast/BaseCacheInvalidationBroadcastProvider.ts +674 -0
  473. package/src/broadcast/index.ts +5 -0
  474. package/src/broadcast/providers/AWSIoTCoreBroadcastProvider.ts +180 -0
  475. package/src/broadcast/providers/AzureWebPubSubBroadcastProvider.ts +182 -0
  476. package/src/broadcast/providers/GCPPubSubBroadcastProvider.ts +169 -0
  477. package/src/broadcast/providers/SequencedRoleBucketBroadcastProvider.ts +57 -0
  478. package/src/cache.ts +2 -1
  479. package/src/config.ts +115 -5
  480. package/src/context.ts +32 -8
  481. package/src/coreRoutes.ts +181 -0
  482. package/src/generated/graphql-schemas/__mj.ts +3684 -284
  483. package/src/generic/CacheInvalidationResolver.ts +172 -60
  484. package/src/generic/OrphanedConversationDetailReconciler.ts +4 -2
  485. package/src/generic/PubSubManager.ts +54 -1
  486. package/src/generic/PushStatusResolver.ts +109 -12
  487. package/src/generic/ResolverBase.ts +540 -431
  488. package/src/generic/RunViewResolver.ts +97 -15
  489. package/src/generic/actionOutputFieldSecurity.ts +75 -0
  490. package/src/generic/fieldSecurityTransport.ts +62 -0
  491. package/src/globalCors.ts +71 -0
  492. package/src/index.ts +239 -238
  493. package/src/integration/CustomColumnPromoter.ts +6 -1
  494. package/src/logging/variablesLoggingMiddleware.ts +59 -3
  495. package/src/multiTenancy/index.ts +24 -2
  496. package/src/realtimeSessions/README.md +7 -3
  497. package/src/realtimeSessions/RealtimeSessionVerificationService.ts +2 -1
  498. package/src/realtimeSessions/RealtimeVerifyRouter.ts +2 -1
  499. package/src/realtimeSessions/RecordingAssemblyScheduler.ts +234 -0
  500. package/src/realtimeSessions/SessionVerificationPortsBase.ts +1 -0
  501. package/src/realtimeSessions/index.ts +2 -0
  502. package/src/realtimeSessions/ownedRealtimeSession.ts +69 -0
  503. package/src/realtimeSessions/sessionAccess.ts +183 -23
  504. package/src/realtimeSessions/sessionConfigStamps.ts +1 -1
  505. package/src/realtimeSessions/subscriptionAuthorization.ts +4 -2
  506. package/src/realtimeSessions/verificationWorkflow.ts +3 -1
  507. package/src/realtimeWidget/WidgetRouter.ts +22 -4
  508. package/src/realtimeWidget/WidgetSessionService.ts +252 -17
  509. package/src/realtimeWidget/host-identity.ts +1 -1
  510. package/src/realtimeWidget/widgetCore.ts +30 -1
  511. package/src/realtimeWidget/widgetGuestElevation.ts +2 -1
  512. package/src/resolvers/ActionResolver.ts +78 -15
  513. package/src/resolvers/AdhocQueryResolver.ts +1 -0
  514. package/src/resolvers/AgentRunStatusPublisher.ts +36 -8
  515. package/src/resolvers/AgentSessionResolver.ts +46 -18
  516. package/src/resolvers/ArtifactFileResolver.ts +9 -8
  517. package/src/resolvers/ConversationRunEventsResolver.ts +15 -11
  518. package/src/resolvers/DatasetResolver.ts +70 -10
  519. package/src/resolvers/EntityCommunicationsResolver.ts +56 -15
  520. package/src/resolvers/EntityRecordNameResolver.ts +3 -2
  521. package/src/resolvers/FetchEntityVectorsResolver.ts +248 -55
  522. package/src/resolvers/FileCategoryResolver.ts +1 -0
  523. package/src/resolvers/FileResolver.ts +334 -109
  524. package/src/resolvers/GetDataContextDataResolver.ts +139 -41
  525. package/src/resolvers/GetDataResolver.ts +6 -3
  526. package/src/resolvers/IntegrationDiscoveryResolver.ts +53 -9
  527. package/src/resolvers/MergeRecordsResolver.ts +23 -2
  528. package/src/resolvers/PipelineProgressResolver.ts +12 -3
  529. package/src/resolvers/QueryResolver.ts +31 -6
  530. package/src/resolvers/QuerySystemUserResolver.ts +15 -6
  531. package/src/resolvers/RSUResolver.ts +12 -0
  532. package/src/resolvers/RealtimeClientSessionResolver.ts +114 -66
  533. package/src/resolvers/RemoteBrowserActionResolver.ts +15 -10
  534. package/src/resolvers/RunAIAgentResolver.ts +296 -85
  535. package/src/resolvers/RunTemplateResolver.ts +6 -4
  536. package/src/resolvers/RunTestResolver.ts +3 -1
  537. package/src/resolvers/SearchKnowledgeStreamResolver.ts +19 -3
  538. package/src/resolvers/SqlLoggingConfigResolver.ts +2 -4
  539. package/src/resolvers/SyncDataResolver.ts +4 -0
  540. package/src/resolvers/TaskGraphFrameResolver.ts +33 -1
  541. package/src/resolvers/TestQuerySQLResolver.ts +69 -13
  542. package/src/resolvers/TransactionGroupResolver.ts +185 -30
  543. package/src/resolvers/UserViewResolver.ts +2 -1
  544. package/src/resolvers/__tests__/GetDataResolver.validation.test.ts +95 -0
  545. package/src/resolvers/__tests__/MergeRecordsResolver.test.ts +43 -0
  546. package/src/resolvers/agent-run-data-guard.ts +89 -0
  547. package/src/rest/EntityCRUDHandler.ts +22 -5
  548. package/src/rest/RESTEndpointHandler.ts +8 -5
  549. package/src/rest/RealtimeRecordingHandler.ts +467 -0
  550. package/src/rest/ViewOperationsHandler.ts +52 -18
  551. package/src/rest/setupRESTEndpoints.ts +6 -0
  552. package/src/serverExtensionReservedRoots.ts +14 -17
  553. package/src/serverRoleConfigUnits.ts +48 -0
  554. package/src/services/MJStorageBlobStore.ts +31 -30
  555. package/src/services/StartTaskGraphDispatcher.ts +2 -2
  556. package/src/services/TaskGraphActionRunner.ts +25 -5
  557. package/src/services/TaskGraphAgentRunner.ts +188 -11
  558. package/src/services/TaskGraphContinuationDeliverer.ts +738 -16
  559. package/src/sharedCache.ts +3 -0
  560. package/src/types.ts +23 -1
@@ -1,18 +1,22 @@
1
1
  import { Resolver, Mutation, Query, Arg, Ctx, ObjectType, Field, PubSub, PubSubEngine, Subscription, Root, ResolverFilterData, ID, Int } from 'type-graphql';
2
2
  import { AppContext, UserPayload } from '../types.js';
3
3
  import { DatabaseProviderBase, LogError, LogStatus, Metadata, RunView, UserInfo, IMetadataProvider } from '@memberjunction/core';
4
- import { MJConversationDetailEntity, MJConversationDetailAttachmentEntity, MJConversationDetailArtifactEntity, MJArtifactVersionEntity, MJAIAgentRequestEntity, ArtifactMetadataEngine, ConversationEngine } from '@memberjunction/core-entities';
4
+ import { MJConversationDetailEntity, MJConversationDetailEntityExtended, MJConversationDetailAttachmentEntity, MJConversationDetailArtifactEntity, MJArtifactVersionEntity, MJAIAgentRequestEntity, ArtifactMetadataEngine, ConversationEngine } from '@memberjunction/core-entities';
5
5
  import { RouteArtifact } from './artifact-routing.js';
6
6
  import { AgentRunner, ArtifactToolManager } from '@memberjunction/ai-agents';
7
- import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended, ExecuteAgentResult, ConversationUtility, AttachmentData } from '@memberjunction/ai-core-plus';
7
+ import { MJAIAgentEntityExtended, MJAIAgentRunEntityExtended, ExecuteAgentResult, ConversationUtility, AttachmentData, ContinuationAnnouncementText } from '@memberjunction/ai-core-plus';
8
8
  import { AIEngine } from '@memberjunction/aiengine';
9
9
  import { ChatMessage, ChatMessageContent } from '@memberjunction/ai';
10
10
  import { ResolverBase } from '../generic/ResolverBase.js';
11
11
  import { AgentRunStatusPublisher } from './AgentRunStatusPublisher.js';
12
+ import { ProjectEntityObjectForCaller } from '../generic/fieldSecurityTransport.js';
12
13
  import { StartLivenessPulse } from '../generic/FireAndForgetHeartbeat.js';
14
+ import { StatusUpdateOwnerID } from '../generic/PushStatusResolver.js';
13
15
  import { RequireSystemUser } from '../directives/RequireSystemUser.js';
14
16
  import { GetReadWriteProvider } from '../util.js';
15
17
  import { ResolveWidgetGuestRunContext, ElevateUserPayload } from '../realtimeWidget/widgetGuestElevation.js';
18
+ import { AuthorizeConversationTurn } from '../realtimeSessions/sessionAccess.js';
19
+ import { IsTrustedAgentRunCaller } from './agent-run-data-guard.js';
16
20
  import { SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
17
21
  import { GetAttachmentService } from '@memberjunction/aiengine';
18
22
  import { NotificationEngine } from '@memberjunction/notifications';
@@ -31,6 +35,17 @@ function isAgentRunEntity(value: unknown): value is MJAIAgentRunEntityExtended {
31
35
  return typeof value === 'object' && value !== null && 'ID' in value;
32
36
  }
33
37
 
38
+ /** What a conversation turn asks for, before its agent runs (see `RunAIAgentFromConversationDetail`). */
39
+ interface ConversationTurnRequest {
40
+ UserMessageId: string;
41
+ AgentId: string;
42
+ MaxHistoryMessages: number;
43
+ HistoryFrom?: Date;
44
+ ReplyParentId?: string;
45
+ AnnouncedByAgentId?: string;
46
+ ReplyBranchId?: string | null;
47
+ }
48
+
34
49
  @ObjectType()
35
50
  export class AIAgentRunResult {
36
51
  @Field()
@@ -172,7 +187,7 @@ export class RunAIAgentResolver extends ResolverBase {
172
187
  * Sanitize ExecuteAgentResult for JSON serialization
173
188
  * Removes circular references and non-serializable objects
174
189
  */
175
- private sanitizeAgentResult(result: ExecuteAgentResult): any {
190
+ private sanitizeAgentResult(result: ExecuteAgentResult, recipient?: UserInfo): any {
176
191
  const sanitized: any = {
177
192
  success: result.success,
178
193
  payload: result.payload,
@@ -188,8 +203,9 @@ export class RunAIAgentResolver extends ResolverBase {
188
203
 
189
204
  // Safely extract agent run data using GetAll() for proper serialization
190
205
  if (result.agentRun && typeof result.agentRun.GetAll === 'function') {
191
- // Use GetAll() to get the full serialized object including extended properties
192
- sanitized.agentRun = result.agentRun.GetAll();
206
+ // GetAll() for the full serialized object including extended properties, projected for
207
+ // the recipient: the run comes from the agent engine, not from a load bound to them
208
+ sanitized.agentRun = ProjectEntityObjectForCaller(result.agentRun, recipient);
193
209
  }
194
210
  else {
195
211
  // shouldn't ever get here
@@ -252,6 +268,14 @@ export class RunAIAgentResolver extends ResolverBase {
252
268
  throw new Error(`AI Agent "${agentEntity.Name}" is not active (Status: ${agentEntity.Status})`);
253
269
  }
254
270
 
271
+ // Enforce agent run permissions for the calling user
272
+ if (currentUser && typeof AIEngine.Instance.CanUserRunAgent === 'function') {
273
+ const canRun = await AIEngine.Instance.CanUserRunAgent(agentEntity.ID, currentUser);
274
+ if (!canRun) {
275
+ throw new Error(`User does not have permission to run AI Agent "${agentEntity.Name}" (${agentEntity.ID})`);
276
+ }
277
+ }
278
+
255
279
  return agentEntity;
256
280
  }
257
281
 
@@ -294,8 +318,13 @@ export class RunAIAgentResolver extends ResolverBase {
294
318
  /** History floor for a conversation run — threaded into ExecuteAgentParams.ConversationHistoryFrom,
295
319
  * so the framework's own conversation reads (retrieval tools, artifacts, compaction) honour it too. */
296
320
  conversationHistoryFrom?: Date,
321
+ /** ExecuteAgentParams.TrustReservedRunData: true only for a caller IsTrustedAgentRunCaller accepts. */
322
+ trustReservedRunData: boolean = false,
297
323
  /** The conversation branch of the run — threaded into ExecuteAgentParams.ConversationBranchID. */
298
- conversationBranchId?: string | null
324
+ conversationBranchId?: string | null,
325
+ /** The reply row this request created on the server for the run (`conversationDetailId` is its ID). The run
326
+ * writes into this instance, so its writes carry the server-authored marker and the user it was made as. */
327
+ replyDetail?: MJConversationDetailEntityExtended
299
328
  ): Promise<AIAgentRunResult> {
300
329
  const startTime = Date.now();
301
330
  // Best-effort handle for persistInFlightAgentFailure. Populated from a
@@ -304,6 +333,8 @@ export class RunAIAgentResolver extends ResolverBase {
304
333
  // run is not marked Failed — the early-failure case we most want to
305
334
  // persist, but we have no run object yet.
306
335
  const agentRunRef = runRef ?? { current: null as MJAIAgentRunEntityExtended | null };
336
+ // The publisher owns every status message, including the failure completion the catch below sends.
337
+ const statusPublisher = new AgentRunStatusPublisher(pubSub, userPayload, sessionId, conversationDetailId);
307
338
 
308
339
  try {
309
340
  LogStatus(`=== RUNNING AI AGENT FOR ID: ${agentId} ===`);
@@ -337,9 +368,8 @@ export class RunAIAgentResolver extends ResolverBase {
337
368
 
338
369
  console.log(`🚀 Starting agent execution with sessionId: ${sessionId}`);
339
370
 
340
- // The publisher owns every status message. The resolver still copies the run into
341
- // agentRunRef, including noise steps, for the fire-and-forget liveness pulse.
342
- const statusPublisher = new AgentRunStatusPublisher(pubSub, userPayload, sessionId);
371
+ // The resolver still copies the run into agentRunRef, including noise steps, for the
372
+ // fire-and-forget liveness pulse.
343
373
  const publishProgress = statusPublisher.OnProgress;
344
374
 
345
375
  // Execute the agent in conversation context - handles conversation, artifacts, etc.
@@ -366,15 +396,20 @@ export class RunAIAgentResolver extends ResolverBase {
366
396
  ConversationHistoryFrom: conversationHistoryFrom,
367
397
  ...(conversationBranchId ? { ConversationBranchID: conversationBranchId } : {}),
368
398
  data: parsedData,
399
+ // Whether the run may read the reserved data keys (scope, agent-type params); BaseAgent drops them otherwise.
400
+ TrustReservedRunData: trustReservedRunData,
369
401
  context: {
370
402
  dataSource: dataSource
371
403
  }
372
404
  }, {
373
405
  conversationDetailId: conversationDetailId, // Use existing if provided
406
+ agentResponseDetail: replyDetail, // the reply row this request created, when it did
374
407
  conversationId: conversationId, // LATENCY OPT #2: pre-resolved to skip redundant load in AgentRunner
375
408
  userMessage: userMessage, // Provide user message when conversationDetailId not provided
376
409
  createArtifacts: createArtifacts || false,
377
- sourceArtifactId: sourceArtifactId
410
+ sourceArtifactId: sourceArtifactId,
411
+ // A widget guest runs as the system user, but its conversation stays the guest's to write (MJ#4791).
412
+ ConversationWriter: userPayload.ElevatedFrom,
378
413
  });
379
414
 
380
415
  const result = conversationResult.agentResult;
@@ -437,7 +472,7 @@ export class RunAIAgentResolver extends ResolverBase {
437
472
  }
438
473
 
439
474
  // Create sanitized payload for JSON serialization
440
- const sanitizedResult = this.sanitizeAgentResult(result);
475
+ const sanitizedResult = this.sanitizeAgentResult(result, currentUser);
441
476
  const returnResult = JSON.stringify(sanitizedResult);
442
477
 
443
478
  // Publish final events with enriched result data for fire-and-forget clients
@@ -460,11 +495,18 @@ export class RunAIAgentResolver extends ResolverBase {
460
495
  } catch (error) {
461
496
  const executionTime = Date.now() - startTime;
462
497
  LogError(`AI Agent run failed:`, undefined, error);
463
- const errorMessage = (error as Error).message || 'Unknown error occurred';
498
+ // Never dereference a non-Error throw: this catch must not itself throw, since executeAIAgent resolves on
499
+ // every failure (executeAgentInBackground relies on it).
500
+ const errorMessage = (error instanceof Error && error.message) || 'Unknown error occurred';
464
501
 
465
502
  // Fire-and-forget clients otherwise leave the run Running and the
466
503
  // conversation detail In-Progress (Explorer red-pill timer).
467
- await this.persistInFlightAgentFailure(p, userPayload, agentRunRef.current, conversationDetailId, errorMessage);
504
+ await this.persistInFlightAgentFailure(p, userPayload, agentRunRef.current, conversationDetailId, errorMessage, replyDetail);
505
+ // A fire-and-forget client has only this message to learn the run ended: without it, it waits out its
506
+ // idle timeout and then reconciles the run as a success. Published after the rows are closed, so a
507
+ // client that reloads the reply on this message reads the error. PublishFinal is the try's last step
508
+ // that can throw, so a run gets one completion or the other, never both.
509
+ statusPublisher.PublishFailure(conversationDetailId, errorMessage);
468
510
 
469
511
  const errorResult = {
470
512
  success: false,
@@ -490,7 +532,9 @@ export class RunAIAgentResolver extends ResolverBase {
490
532
  userPayload: UserPayload,
491
533
  run: MJAIAgentRunEntityExtended | null | undefined,
492
534
  conversationDetailId: string | undefined,
493
- errorMessage: string
535
+ errorMessage: string,
536
+ /** The run's reply row, when this request created it: written in place, as the server. */
537
+ replyDetail?: MJConversationDetailEntityExtended
494
538
  ): Promise<void> {
495
539
  try {
496
540
  if (run && run.Status === 'Running') {
@@ -507,10 +551,11 @@ export class RunAIAgentResolver extends ResolverBase {
507
551
  return;
508
552
  }
509
553
  if (conversationDetailId) {
510
- const detail = await provider.GetEntityObject<MJConversationDetailEntity>(
554
+ const detail = replyDetail ?? await provider.GetEntityObject<MJConversationDetailEntity>(
511
555
  'MJ: Conversation Details',
512
556
  user
513
557
  );
558
+ await detail.EnsureSaveComplete(); // the run may still be saving into the same reply instance
514
559
  if (await detail.Load(conversationDetailId) && detail.Status === 'In-Progress') {
515
560
  await detail.EnsureSaveComplete();
516
561
  detail.Status = 'Error';
@@ -564,6 +609,9 @@ export class RunAIAgentResolver extends ResolverBase {
564
609
  await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
565
610
 
566
611
  const p = GetReadWriteProvider(providers);
612
+ // Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
613
+ // params through data; for anyone else BaseAgent drops those keys (ExecuteAgentParams.TrustReservedRunData).
614
+ const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
567
615
 
568
616
  if (fireAndForget) {
569
617
  // Fire-and-forget mode: start execution in background, return immediately.
@@ -572,7 +620,8 @@ export class RunAIAgentResolver extends ResolverBase {
572
620
  p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
573
621
  data, payload, lastRunId, autoPopulateLastRunPayload, configurationId,
574
622
  conversationDetailId, createArtifacts || false, createNotification || false,
575
- sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug
623
+ sourceArtifactId, sourceArtifactVersionId, undefined /*conversationId*/, planMode, requestedSkillIDs, taskGraphDebug,
624
+ undefined /*conversationHistoryFrom*/, trustRunData
576
625
  );
577
626
 
578
627
  LogStatus(`🔥 Fire-and-forget: Agent ${agentId} execution started in background for session ${sessionId}`);
@@ -607,7 +656,9 @@ export class RunAIAgentResolver extends ResolverBase {
607
656
  undefined, // runRef
608
657
  planMode,
609
658
  requestedSkillIDs,
610
- taskGraphDebug
659
+ taskGraphDebug,
660
+ undefined, // conversationHistoryFrom
661
+ trustRunData
611
662
  );
612
663
  }
613
664
 
@@ -640,6 +691,9 @@ export class RunAIAgentResolver extends ResolverBase {
640
691
  @Arg('requestedSkillIDs', () => [String], { nullable: true }) requestedSkillIDs?: string[]
641
692
  ): Promise<AIAgentRunResult> {
642
693
  const p = GetReadWriteProvider(providers);
694
+ // @RequireSystemUser admits only the system user, whom the rule trusts; it is still asked, so every
695
+ // resolver entry that takes a client's data decides the same way.
696
+ const trustRunData = await IsTrustedAgentRunCaller({ UserPayload: userPayload, IsWidgetGuestRun: false, AgentID: agentId });
643
697
  return this.executeAIAgent(
644
698
  p,
645
699
  dataSource,
@@ -662,7 +716,10 @@ export class RunAIAgentResolver extends ResolverBase {
662
716
  undefined, // conversationId (not pre-resolved on this path)
663
717
  undefined, // runRef
664
718
  planMode,
665
- requestedSkillIDs
719
+ requestedSkillIDs,
720
+ undefined, // taskGraphDebug
721
+ undefined, // conversationHistoryFrom
722
+ trustRunData
666
723
  );
667
724
  }
668
725
 
@@ -900,16 +957,27 @@ export class RunAIAgentResolver extends ResolverBase {
900
957
  }
901
958
 
902
959
  /**
903
- * Optimized mutation that loads conversation history server-side.
904
- * This avoids sending large attachment data from client to server.
960
+ * Runs an agent's turn in a conversation: the server loads the history (attachments included, so the client never
961
+ * sends them), creates the agent's reply row, and runs the agent into it.
962
+ *
963
+ * Only the server writes agent replies (A19). The reply row (`Role` `AI`, In-Progress, its `ParentID` the user's
964
+ * message) is created here, as the person asking, before the run starts. In fire-and-forget mode the
965
+ * acknowledgement names it, `{ accepted, fireAndForget, conversationDetailId, createdAt }`, and is returned before
966
+ * the run publishes anything; every progress, streaming and completion message carries the same
967
+ * `conversationDetailId`. In synchronous mode the result's `agentRun.ConversationDetailID` names it.
905
968
  *
906
- * @param conversationDetailId - The conversation detail ID (user's message already saved)
969
+ * Threading, both optional: `replyParentId` puts the reply under another message of the same conversation the
970
+ * caller can read (MJ's chat threads a delegate's reply under the manager's); `announcedByAgentId` has the server
971
+ * first post that agent's fixed line "Continuing with **{agent}** for refinement..." and thread the reply under
972
+ * it, and the acknowledgement then also carries `announcementDetailId`.
973
+ *
974
+ * @param userMessageId - The person's message this turn answers, already saved.
907
975
  * @param agentId - The agent to execute
908
976
  * @param maxHistoryMessages - Maximum number of history messages to include (default: 20)
909
977
  */
910
978
  @Mutation(() => AIAgentRunResult)
911
979
  async RunAIAgentFromConversationDetail(
912
- @Arg('conversationDetailId') conversationDetailId: string,
980
+ @Arg('userMessageId') userMessageId: string,
913
981
  @Arg('agentId') agentId: string,
914
982
  @Ctx() { userPayload, providers, dataSource }: AppContext,
915
983
  @Arg('sessionId') sessionId: string,
@@ -932,11 +1000,17 @@ export class RunAIAgentResolver extends ResolverBase {
932
1000
  * run's own conversation reads honour it too. Omitted (clients send it only when set, so an
933
1001
  * older client never does), the run reads the whole conversation as before. An unreadable
934
1002
  * value fails the request rather than being dropped. */
935
- @Arg('agentHistoryFrom', { nullable: true }) agentHistoryFrom?: string
1003
+ @Arg('agentHistoryFrom', { nullable: true }) agentHistoryFrom?: string,
1004
+ /** The message the reply threads under, when not the user's message: one in the same conversation the
1005
+ * caller can read. */
1006
+ @Arg('replyParentId', { nullable: true }) replyParentId?: string,
1007
+ /** An active agent (MJ's chat passes its conversation manager) whose fixed line "Continuing with
1008
+ * **{agent}** for refinement..." the server posts before the reply, which then threads under it. */
1009
+ @Arg('announcedByAgentId', { nullable: true }) announcedByAgentId?: string,
1010
+ /** The fork the reply and history run on, when the turn forks from `userMessageId` (such as Regenerate).
1011
+ * Checked to be a branch of the conversation whose path holds `userMessageId`. */
1012
+ @Arg('replyBranchId', { nullable: true }) replyBranchId?: string
936
1013
  ): Promise<AIAgentRunResult> {
937
- // Check API key scope authorization for agent execution
938
- await this.CheckAPIKeyScopeAuthorization('agent:execute', agentId, userPayload);
939
-
940
1014
  const p = GetReadWriteProvider(providers);
941
1015
  const currentUser = this.GetUserFromPayload(userPayload);
942
1016
 
@@ -953,31 +1027,44 @@ export class RunAIAgentResolver extends ResolverBase {
953
1027
  // AUTHORITATIVELY from the widget instance (never the client-supplied arg) — so a guest needs
954
1028
  // no grants to WRITE the AI run entities and cannot run an arbitrary agent under elevation.
955
1029
  // Conversation OWNERSHIP is still enforced under the guest principal below: the guest loads its
956
- // own ConversationDetail through the Widget Guest RLS filters, so a detail id from another
957
- // session resolves to "not found" before any elevated work happens.
1030
+ // own ConversationDetail through its role's RLS filters, and startConversationTurn then checks
1031
+ // the conversation's scope stamp against the visitor (MJ#6032), so a detail id from another
1032
+ // visitor's session is refused before any elevated work happens. The reply row is written
1033
+ // as the guest too, never as the elevated principal, which owns no guest's conversation.
958
1034
  const widgetElevation = await ResolveWidgetGuestRunContext(userPayload, p);
959
1035
  const effectiveAgentId = widgetElevation ? widgetElevation.PinnedAgentId : agentId;
1036
+ // Check API key scope authorization for agent execution against the resolved agent id.
1037
+ await this.CheckAPIKeyScopeAuthorization('agent:execute', effectiveAgentId, userPayload);
1038
+ // A widget guest has one pinned agent and never posts a continuation announcement as another agent;
1039
+ // an API-key caller must hold agent:execute for the announcing agent as well as the running agent.
1040
+ const effectiveAnnouncedByAgentId = widgetElevation ? undefined : announcedByAgentId;
1041
+ if (effectiveAnnouncedByAgentId) {
1042
+ await this.CheckAPIKeyScopeAuthorization('agent:execute', effectiveAnnouncedByAgentId, userPayload);
1043
+ }
960
1044
  const effectiveUserPayload = widgetElevation ? ElevateUserPayload(userPayload, widgetElevation.ElevatedUser) : userPayload;
1045
+ // Only the system user or an API key holding the agent:trusted scope may set a run's scope and agent-type
1046
+ // params through data (ExecuteAgentParams.TrustReservedRunData). Judged on the caller's own payload: a widget
1047
+ // guest runs under an elevated server principal but is never trusted.
1048
+ const trustRunData = await IsTrustedAgentRunCaller({
1049
+ UserPayload: userPayload, IsWidgetGuestRun: widgetElevation !== null, AgentID: agentId,
1050
+ });
961
1051
 
962
1052
  try {
963
1053
  // Parsed before anything loads: a floor the caller asked for must never be dropped.
964
1054
  const historyFrom = parseAgentHistoryFrom(agentHistoryFrom);
965
-
966
- // LATENCY OPTIMIZATION (Opt #2 + #3): Load ConversationDetail once here to extract
967
- // conversationId, then pass it downstream. Previously this record was loaded multiple
968
- // times: once in loadConversationHistoryWithAttachments (just to get conversationId),
969
- // once in AgentRunner (same reason), and once in createCompletionNotification. Now we
970
- // load it a single time and thread conversationId through the call chain.
971
- const currentDetail = await p.GetEntityObject<MJConversationDetailEntity>(
972
- 'MJ: Conversation Details',
973
- currentUser
974
- );
975
- if (!await currentDetail.Load(conversationDetailId)) {
976
- throw new Error(`Conversation detail ${conversationDetailId} not found`);
977
- }
978
- const conversationId = currentDetail.ConversationID;
979
- // The branch the placeholder row was created on decides which path the run reads.
980
- const branchId: string | null = currentDetail.BranchID ?? null;
1055
+ const turn = await this.startConversationTurn(p, currentUser, {
1056
+ UserMessageId: userMessageId,
1057
+ AgentId: effectiveAgentId,
1058
+ MaxHistoryMessages: maxHistoryMessages || 20,
1059
+ HistoryFrom: historyFrom,
1060
+ ReplyParentId: replyParentId,
1061
+ AnnouncedByAgentId: effectiveAnnouncedByAgentId,
1062
+ ReplyBranchId: replyBranchId
1063
+ });
1064
+ const reply = turn.Reply;
1065
+ // The turn's branch (the message's own branch, or a validated fork whose path holds the message)
1066
+ // decides which path the run reads.
1067
+ const branchId = turn.BranchId;
981
1068
 
982
1069
  // A turn that follows a run the user STOPPED continues that run rather than starting
983
1070
  // over: chain it by LastRunID (the chat client never sends one) and, when the caller
@@ -985,7 +1072,7 @@ export class RunAIAgentResolver extends ResolverBase {
985
1072
  let effectiveLastRunId = lastRunId;
986
1073
  let effectiveAutoPopulate = autoPopulateLastRunPayload;
987
1074
  if (!effectiveLastRunId) {
988
- const stoppedRunId = await this.findUserStoppedPredecessorRunId(conversationId, effectiveAgentId, branchId, currentUser, p);
1075
+ const stoppedRunId = await this.findUserStoppedPredecessorRunId(turn.ConversationId, effectiveAgentId, branchId, currentUser, p);
989
1076
  if (stoppedRunId) {
990
1077
  effectiveLastRunId = stoppedRunId;
991
1078
  if (effectiveAutoPopulate === undefined && payload == null) {
@@ -995,40 +1082,32 @@ export class RunAIAgentResolver extends ResolverBase {
995
1082
  }
996
1083
  }
997
1084
 
998
- // Load conversation history with attachments from DB
999
- const messages = await this.loadConversationHistoryWithAttachments(
1000
- conversationId,
1001
- currentUser,
1002
- maxHistoryMessages || 20,
1003
- p,
1004
- // The UI creates the agent-response placeholder row ('⏳ ...') before invoking
1005
- // this mutation — exclude it so the model never sees an empty assistant turn.
1006
- [conversationDetailId],
1007
- historyFrom,
1008
- branchId
1009
- );
1010
-
1011
- // Convert to JSON string for the existing executeAIAgent method
1012
- const messagesJson = JSON.stringify(messages);
1013
-
1014
1085
  if (fireAndForget) {
1015
1086
  // Fire-and-forget mode: start execution in background, return immediately.
1016
1087
  // The client will receive the result via WebSocket PubSub completion event.
1017
1088
  this.executeAgentInBackground(
1018
- p, dataSource, effectiveAgentId, effectiveUserPayload, messagesJson, sessionId, pubSub,
1089
+ p, dataSource, effectiveAgentId, effectiveUserPayload, turn.MessagesJson, sessionId, pubSub,
1019
1090
  data, payload, effectiveLastRunId, effectiveAutoPopulate, configurationId,
1020
- conversationDetailId, createArtifacts || false, createNotification || false,
1021
- sourceArtifactId, sourceArtifactVersionId, conversationId, planMode, requestedSkillIDs,
1091
+ reply.ID, createArtifacts || false, createNotification || false,
1092
+ sourceArtifactId, sourceArtifactVersionId, turn.ConversationId, planMode, requestedSkillIDs,
1022
1093
  undefined, // taskGraphDebug
1023
1094
  historyFrom,
1024
- branchId
1095
+ trustRunData,
1096
+ branchId,
1097
+ reply
1025
1098
  );
1026
1099
 
1027
1100
  LogStatus(`🔥 Fire-and-forget: Agent ${effectiveAgentId} execution started in background for session ${sessionId}`);
1028
1101
 
1029
1102
  return {
1030
1103
  success: true,
1031
- result: JSON.stringify({ accepted: true, fireAndForget: true })
1104
+ result: JSON.stringify({
1105
+ accepted: true,
1106
+ fireAndForget: true,
1107
+ conversationDetailId: reply.ID,
1108
+ createdAt: reply.__mj_CreatedAt,
1109
+ ...(turn.Announcement ? { announcementDetailId: turn.Announcement.ID } : {})
1110
+ })
1032
1111
  };
1033
1112
  }
1034
1113
 
@@ -1038,7 +1117,7 @@ export class RunAIAgentResolver extends ResolverBase {
1038
1117
  dataSource,
1039
1118
  effectiveAgentId,
1040
1119
  effectiveUserPayload,
1041
- messagesJson,
1120
+ turn.MessagesJson,
1042
1121
  sessionId,
1043
1122
  pubSub,
1044
1123
  data,
@@ -1047,18 +1126,20 @@ export class RunAIAgentResolver extends ResolverBase {
1047
1126
  effectiveLastRunId,
1048
1127
  effectiveAutoPopulate,
1049
1128
  configurationId,
1050
- conversationDetailId,
1129
+ reply.ID,
1051
1130
  createArtifacts || false,
1052
1131
  createNotification || false,
1053
1132
  sourceArtifactId,
1054
1133
  sourceArtifactVersionId,
1055
- conversationId, // LATENCY OPT #2: pass pre-resolved conversationId
1134
+ turn.ConversationId, // LATENCY OPT #2: pass pre-resolved conversationId
1056
1135
  undefined, // runRef
1057
1136
  planMode,
1058
1137
  requestedSkillIDs,
1059
1138
  undefined, // taskGraphDebug
1060
1139
  historyFrom,
1061
- branchId
1140
+ trustRunData,
1141
+ branchId,
1142
+ reply
1062
1143
  );
1063
1144
  } catch (error) {
1064
1145
  const errorMessage = (error as Error).message || 'Unknown error loading conversation history';
@@ -1071,6 +1152,137 @@ export class RunAIAgentResolver extends ResolverBase {
1071
1152
  }
1072
1153
  }
1073
1154
 
1155
+ /**
1156
+ * Everything a conversation turn needs before its agent runs: the user's message (read as the caller, so a
1157
+ * message they can't see is "not found", and for an anonymous visitor also checked against the conversation's
1158
+ * scope stamp), the conversation history, the optional announcement line, and the reply
1159
+ * row, created last so the history never holds the empty reply. Every row is written as `user`, the person asking,
1160
+ * and marked as server-authored by {@link AgentRunner.CreateAgentReplyDetail}.
1161
+ */
1162
+ private async startConversationTurn(
1163
+ p: DatabaseProviderBase,
1164
+ user: UserInfo,
1165
+ request: ConversationTurnRequest
1166
+ ): Promise<{ ConversationId: string; BranchId: string | null; MessagesJson: string; Reply: MJConversationDetailEntityExtended; Announcement?: MJConversationDetailEntityExtended }> {
1167
+ // LATENCY OPTIMIZATION (Opt #2 + #3): the user's message is loaded once here for its conversation and
1168
+ // branch, which are threaded through the call chain rather than reloaded downstream.
1169
+ const placement = await this.loadPlacementOf(p, user, request.UserMessageId);
1170
+ const conversationId = placement.ConversationId;
1171
+ // Loading the message as the caller is the whole ownership check for a named user. It is not for an
1172
+ // anonymous visitor: every visitor is the one shared Anonymous user, so under a guest role whose row
1173
+ // filters key on UserID another visitor's message loads fine (MJ#6032). The conversation's scope stamp
1174
+ // decides instead, exactly as it does for the realtime gates — and before any row is written.
1175
+ const access = await AuthorizeConversationTurn(conversationId, user, p);
1176
+ if (!access.Allowed) {
1177
+ LogError(`RunAIAgentFromConversationDetail: anonymous visitor ${user.AnonymousVisitorID ?? '(no visitor id)'} refused a turn in conversation ${conversationId} (${access.Reason})`);
1178
+ throw new Error('Not authorized: you do not own this conversation');
1179
+ }
1180
+ const branchId = request.ReplyBranchId
1181
+ ? await this.validateReplyBranch(p, user, conversationId, placement, request.ReplyBranchId)
1182
+ : placement.BranchId;
1183
+ const parentId = request.ReplyParentId
1184
+ ? await this.validateReplyParent(p, user, request.ReplyParentId, conversationId)
1185
+ : request.UserMessageId;
1186
+ const messages = await this.loadConversationHistoryWithAttachments(conversationId, user, request.MaxHistoryMessages, p, undefined, request.HistoryFrom, branchId);
1187
+ const runner = new AgentRunner(p);
1188
+ const announcement = request.AnnouncedByAgentId
1189
+ ? await this.postContinuationAnnouncement(runner, user, conversationId, branchId, parentId, request.AnnouncedByAgentId, request.AgentId)
1190
+ : undefined;
1191
+ const reply = await runner.CreateAgentReplyDetail({
1192
+ conversationId,
1193
+ branchId,
1194
+ agentId: request.AgentId,
1195
+ contextUser: user,
1196
+ parentId: announcement?.ID ?? parentId,
1197
+ provider: p
1198
+ });
1199
+ return { ConversationId: conversationId, BranchId: branchId, MessagesJson: JSON.stringify(messages), Reply: reply, Announcement: announcement };
1200
+ }
1201
+
1202
+ /** The conversation, branch (null is Main) and sequence of a message, read as `user`; throws when they can't read it. */
1203
+ private async loadPlacementOf(
1204
+ p: DatabaseProviderBase,
1205
+ user: UserInfo,
1206
+ messageId: string
1207
+ ): Promise<{ ConversationId: string; BranchId: string | null; Sequence: number }> {
1208
+ const message = await p.GetEntityObject<MJConversationDetailEntity>('MJ: Conversation Details', user);
1209
+ if (!await message.Load(messageId)) {
1210
+ throw new Error(`Conversation detail ${messageId} not found`);
1211
+ }
1212
+ return { ConversationId: message.ConversationID, BranchId: message.BranchID ?? null, Sequence: message.Sequence ?? -1 };
1213
+ }
1214
+
1215
+ /**
1216
+ * When a turn forks from an earlier message (such as Regenerate), the reply and history run on the fork while the
1217
+ * user's message stays on the branch it was written on. Checks that `replyBranchId` is a branch of the turn's
1218
+ * conversation whose path holds the user's message (`IsRowOnBranchPath` rather than exact `ForkFromSequence`
1219
+ * equality is deliberate: `ConversationEngine.ForkPointFrom` sets `ForkFromSequence = message.Sequence` and the
1220
+ * fork belongs to this conversation); returns `replyBranchId`, or throws before any row is created.
1221
+ */
1222
+ private async validateReplyBranch(
1223
+ p: DatabaseProviderBase,
1224
+ user: UserInfo,
1225
+ conversationId: string,
1226
+ userMessage: { BranchId: string | null; Sequence: number },
1227
+ replyBranchId: string
1228
+ ): Promise<string> {
1229
+ if (UUIDsEqual(replyBranchId, userMessage.BranchId)) {
1230
+ return replyBranchId;
1231
+ }
1232
+ if (userMessage.Sequence < 0) {
1233
+ throw new Error(`Conversation detail is not on branch ${replyBranchId}'s path, so the reply cannot be written on that branch`);
1234
+ }
1235
+ const branches = await ConversationEngine.LoadBranchesFresh(conversationId, user, p);
1236
+ const chain = ConversationEngine.BuildBranchChain(branches, replyBranchId);
1237
+ if (!ConversationEngine.IsRowOnBranchPath({ BranchID: userMessage.BranchId, Sequence: userMessage.Sequence }, chain)) {
1238
+ throw new Error(`Conversation detail is not on branch ${replyBranchId}'s path, so the reply cannot be written on that branch`);
1239
+ }
1240
+ return replyBranchId;
1241
+ }
1242
+
1243
+ /**
1244
+ * A reply's parent is part of what the reply says, so the server sets it, from a checked input: a message the
1245
+ * caller can read, in the turn's own conversation. Returns its ID; throws otherwise.
1246
+ */
1247
+ private async validateReplyParent(p: DatabaseProviderBase, user: UserInfo, parentId: string, conversationId: string): Promise<string> {
1248
+ const { ConversationId: parentConversationId } = await this.loadPlacementOf(p, user, parentId);
1249
+ if (!UUIDsEqual(parentConversationId, conversationId)) {
1250
+ throw new Error(`Conversation detail ${parentId} is not in this turn's conversation, so the reply cannot thread under it`);
1251
+ }
1252
+ return parentId;
1253
+ }
1254
+
1255
+ /**
1256
+ * Posts the announcing agent's line, "Continuing with **{agent}** for refinement...", as a completed reply of the
1257
+ * announcing agent. Its text is fixed and names the agent from metadata, so a caller chooses only whether it is
1258
+ * posted and by which active agent, never what it says.
1259
+ */
1260
+ private async postContinuationAnnouncement(
1261
+ runner: AgentRunner,
1262
+ user: UserInfo,
1263
+ conversationId: string,
1264
+ branchId: string | null,
1265
+ parentId: string,
1266
+ announcerId: string,
1267
+ agentId: string
1268
+ ): Promise<MJConversationDetailEntityExtended> {
1269
+ await AIEngine.Instance.Config(false, user);
1270
+ const announcer = AIEngine.Instance.GetAgentByID(announcerId);
1271
+ if (!announcer || announcer.Status !== 'Active') {
1272
+ throw new Error(`Agent ${announcerId} cannot announce the turn: it is not an active agent`);
1273
+ }
1274
+ const agentName = AIEngine.Instance.GetAgentByID(agentId)?.Name ?? 'the agent';
1275
+ return runner.CreateAgentReplyDetail({
1276
+ conversationId,
1277
+ branchId,
1278
+ agentId: announcer.ID,
1279
+ contextUser: user,
1280
+ parentId,
1281
+ message: ContinuationAnnouncementText(agentName),
1282
+ status: 'Complete'
1283
+ });
1284
+ }
1285
+
1074
1286
  /**
1075
1287
  * Respond to a pending AIAgentRequest from the dashboard or API.
1076
1288
  * Updates the request record with the response and optionally spawns a
@@ -1250,9 +1462,8 @@ export class RunAIAgentResolver extends ResolverBase {
1250
1462
 
1251
1463
  /**
1252
1464
  * Execute agent in background (fire-and-forget).
1253
- * Handles errors by publishing error completion events via PubSub,
1254
- * so the client receives them via WebSocket even though the HTTP response
1255
- * has already been sent.
1465
+ * The client learns the outcome only from the run's completion status message (executeAIAgent publishes it,
1466
+ * failure included), since the HTTP response has already been sent. A liveness pulse runs until the run ends.
1256
1467
  */
1257
1468
  private executeAgentInBackground(
1258
1469
  p: DatabaseProviderBase,
@@ -1281,37 +1492,37 @@ export class RunAIAgentResolver extends ResolverBase {
1281
1492
  taskGraphDebug?: string,
1282
1493
  /** History floor — threaded through to ExecuteAgentParams.ConversationHistoryFrom. */
1283
1494
  conversationHistoryFrom?: Date,
1495
+ /** ExecuteAgentParams.TrustReservedRunData — see executeAIAgent. */
1496
+ trustReservedRunData: boolean = false,
1284
1497
  /** The conversation branch of the run — threaded through to ExecuteAgentParams.ConversationBranchID. */
1285
- conversationBranchId?: string | null
1498
+ conversationBranchId?: string | null,
1499
+ /** The reply row this request created for the run — see executeAIAgent. */
1500
+ replyDetail?: MJConversationDetailEntityExtended
1286
1501
  ): void {
1287
1502
  // Ref the liveness pulse reads to enrich heartbeats once the run is created.
1288
1503
  const runRef: { current: MJAIAgentRunEntityExtended | null } = { current: null };
1289
1504
  const pulse = StartLivenessPulse({
1290
1505
  pubSub,
1291
1506
  sessionId,
1292
- ownerUserId: userPayload.userRecord.ID,
1507
+ ownerUserId: StatusUpdateOwnerID(userPayload),
1293
1508
  resolver: 'RunAIAgentResolver',
1294
1509
  readStatus: () => runRef.current
1295
1510
  ? { runId: runRef.current.ID, status: runRef.current.Status }
1296
1511
  : undefined,
1297
1512
  });
1298
1513
 
1299
- // Execute in background - errors are handled within, not propagated
1514
+ // executeAIAgent resolves on every failure and publishes the run's completion itself (PublishFinal, or
1515
+ // PublishFailure from its catch), so nothing here publishes one.
1300
1516
  this.executeAIAgent(
1301
1517
  p, dataSource, agentId, userPayload, messagesJson, sessionId, pubSub,
1302
1518
  data, payload, undefined, lastRunId, autoPopulateLastRunPayload,
1303
1519
  configurationId, conversationDetailId, createArtifacts, createNotification,
1304
1520
  sourceArtifactId, sourceArtifactVersionId, conversationId, runRef, planMode, requestedSkillIDs, taskGraphDebug,
1305
- conversationHistoryFrom, conversationBranchId
1521
+ conversationHistoryFrom, trustReservedRunData, conversationBranchId, replyDetail
1306
1522
  ).catch((error: unknown) => {
1307
- // Background execution failed unexpectedly (executeAIAgent has its own try-catch,
1308
- // so this would only fire for truly unexpected errors).
1309
- const errorMessage = (error instanceof Error) ? error.message : 'Unknown background execution error';
1310
- LogError(`🔥 Fire-and-forget background execution failed: ${errorMessage}`, undefined, error);
1311
-
1312
- // Publish error completion event so the client knows the agent failed.
1313
- // The publisher is created inside executeAIAgent, which rejected before returning one.
1314
- new AgentRunStatusPublisher(pubSub, userPayload, sessionId).PublishFailure(conversationDetailId, errorMessage);
1523
+ // Only a broken executeAIAgent contract lands here. Logged rather than left as an unhandled rejection;
1524
+ // no completion is published, because executeAIAgent may already have sent one.
1525
+ LogError(`🔥 Fire-and-forget run of agent ${agentId} for session ${sessionId} rejected, which executeAIAgent never should`, undefined, error);
1315
1526
  }).finally(() => pulse.Stop());
1316
1527
  }
1317
1528