@copilotkit/runtime 1.55.0-next.9 → 1.55.1-next.0

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 (345) hide show
  1. package/CHANGELOG.md +31 -2
  2. package/dist/agent/index.cjs +101 -12
  3. package/dist/agent/index.cjs.map +1 -1
  4. package/dist/agent/index.d.cts.map +1 -1
  5. package/dist/agent/index.d.mts.map +1 -1
  6. package/dist/agent/index.mjs +102 -13
  7. package/dist/agent/index.mjs.map +1 -1
  8. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs.map +1 -1
  9. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts +4 -841
  10. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
  11. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts +4 -841
  12. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
  13. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs.map +1 -1
  14. package/dist/lib/runtime/copilot-runtime.cjs +3 -2
  15. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  16. package/dist/lib/runtime/copilot-runtime.d.cts +1 -1
  17. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  18. package/dist/lib/runtime/copilot-runtime.d.mts +3 -3
  19. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  20. package/dist/lib/runtime/copilot-runtime.mjs +3 -2
  21. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  22. package/dist/package.cjs +70 -47
  23. package/dist/package.mjs +70 -47
  24. package/dist/v2/express.cjs +8 -0
  25. package/dist/v2/express.d.cts +5 -0
  26. package/dist/v2/express.d.mts +5 -0
  27. package/dist/v2/express.mjs +5 -0
  28. package/dist/v2/hono.cjs +9 -0
  29. package/dist/v2/hono.d.cts +5 -0
  30. package/dist/v2/hono.d.mts +5 -0
  31. package/dist/v2/hono.mjs +5 -0
  32. package/dist/v2/index.cjs +8 -3
  33. package/dist/v2/index.d.cts +8 -5
  34. package/dist/v2/index.d.mts +8 -5
  35. package/dist/v2/index.mjs +5 -4
  36. package/dist/v2/node.cjs +8 -0
  37. package/dist/v2/node.d.cts +5 -0
  38. package/dist/v2/node.d.mts +5 -0
  39. package/dist/v2/node.mjs +5 -0
  40. package/dist/v2/runtime/core/fetch-cors.cjs +72 -0
  41. package/dist/v2/runtime/core/fetch-cors.cjs.map +1 -0
  42. package/dist/v2/runtime/core/fetch-cors.d.cts +20 -0
  43. package/dist/v2/runtime/core/fetch-cors.d.cts.map +1 -0
  44. package/dist/v2/runtime/core/fetch-cors.d.mts +20 -0
  45. package/dist/v2/runtime/core/fetch-cors.d.mts.map +1 -0
  46. package/dist/v2/runtime/core/fetch-cors.mjs +70 -0
  47. package/dist/v2/runtime/core/fetch-cors.mjs.map +1 -0
  48. package/dist/v2/runtime/core/fetch-handler.cjs +232 -0
  49. package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -0
  50. package/dist/v2/runtime/core/fetch-handler.d.cts +40 -0
  51. package/dist/v2/runtime/core/fetch-handler.d.cts.map +1 -0
  52. package/dist/v2/runtime/core/fetch-handler.d.mts +40 -0
  53. package/dist/v2/runtime/core/fetch-handler.d.mts.map +1 -0
  54. package/dist/v2/runtime/core/fetch-handler.mjs +231 -0
  55. package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -0
  56. package/dist/v2/runtime/core/fetch-router.cjs +68 -0
  57. package/dist/v2/runtime/core/fetch-router.cjs.map +1 -0
  58. package/dist/v2/runtime/core/fetch-router.mjs +67 -0
  59. package/dist/v2/runtime/core/fetch-router.mjs.map +1 -0
  60. package/dist/v2/runtime/core/hooks.cjs +29 -0
  61. package/dist/v2/runtime/core/hooks.cjs.map +1 -0
  62. package/dist/v2/runtime/core/hooks.d.cts +78 -0
  63. package/dist/v2/runtime/core/hooks.d.cts.map +1 -0
  64. package/dist/v2/runtime/core/hooks.d.mts +78 -0
  65. package/dist/v2/runtime/core/hooks.d.mts.map +1 -0
  66. package/dist/v2/runtime/core/hooks.mjs +25 -0
  67. package/dist/v2/runtime/core/hooks.mjs.map +1 -0
  68. package/dist/v2/runtime/{middleware-sse-parser.cjs → core/middleware-sse-parser.cjs} +2 -2
  69. package/dist/v2/runtime/core/middleware-sse-parser.cjs.map +1 -0
  70. package/dist/v2/runtime/{middleware-sse-parser.d.cts → core/middleware-sse-parser.d.cts} +1 -1
  71. package/dist/v2/runtime/core/middleware-sse-parser.d.cts.map +1 -0
  72. package/dist/v2/runtime/{middleware-sse-parser.d.mts → core/middleware-sse-parser.d.mts} +1 -1
  73. package/dist/v2/runtime/core/middleware-sse-parser.d.mts.map +1 -0
  74. package/dist/v2/runtime/{middleware-sse-parser.mjs → core/middleware-sse-parser.mjs} +1 -1
  75. package/dist/v2/runtime/core/middleware-sse-parser.mjs.map +1 -0
  76. package/dist/v2/runtime/{middleware.cjs → core/middleware.cjs} +2 -2
  77. package/dist/v2/runtime/core/middleware.cjs.map +1 -0
  78. package/dist/v2/runtime/{middleware.d.cts → core/middleware.d.cts} +1 -1
  79. package/dist/v2/runtime/core/middleware.d.cts.map +1 -0
  80. package/dist/v2/runtime/{middleware.d.mts → core/middleware.d.mts} +1 -1
  81. package/dist/v2/runtime/core/middleware.d.mts.map +1 -0
  82. package/dist/v2/runtime/{middleware.mjs → core/middleware.mjs} +1 -1
  83. package/dist/v2/runtime/core/middleware.mjs.map +1 -0
  84. package/dist/v2/runtime/{runtime.cjs → core/runtime.cjs} +35 -10
  85. package/dist/v2/runtime/core/runtime.cjs.map +1 -0
  86. package/dist/v2/runtime/{runtime.d.cts → core/runtime.d.cts} +41 -7
  87. package/dist/v2/runtime/core/runtime.d.cts.map +1 -0
  88. package/dist/v2/runtime/{runtime.d.mts → core/runtime.d.mts} +42 -8
  89. package/dist/v2/runtime/core/runtime.d.mts.map +1 -0
  90. package/dist/v2/runtime/{runtime.mjs → core/runtime.mjs} +36 -11
  91. package/dist/v2/runtime/core/runtime.mjs.map +1 -0
  92. package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs +83 -0
  93. package/dist/v2/runtime/endpoints/express-fetch-bridge.cjs.map +1 -0
  94. package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs +82 -0
  95. package/dist/v2/runtime/endpoints/express-fetch-bridge.mjs.map +1 -0
  96. package/dist/v2/runtime/endpoints/express-single.cjs +35 -181
  97. package/dist/v2/runtime/endpoints/express-single.cjs.map +1 -1
  98. package/dist/v2/runtime/endpoints/express-single.d.cts +35 -2
  99. package/dist/v2/runtime/endpoints/express-single.d.cts.map +1 -1
  100. package/dist/v2/runtime/endpoints/express-single.d.mts +35 -2
  101. package/dist/v2/runtime/endpoints/express-single.d.mts.map +1 -1
  102. package/dist/v2/runtime/endpoints/express-single.mjs +35 -178
  103. package/dist/v2/runtime/endpoints/express-single.mjs.map +1 -1
  104. package/dist/v2/runtime/endpoints/express.cjs +41 -195
  105. package/dist/v2/runtime/endpoints/express.cjs.map +1 -1
  106. package/dist/v2/runtime/endpoints/express.d.cts +26 -4
  107. package/dist/v2/runtime/endpoints/express.d.cts.map +1 -1
  108. package/dist/v2/runtime/endpoints/express.d.mts +26 -4
  109. package/dist/v2/runtime/endpoints/express.d.mts.map +1 -1
  110. package/dist/v2/runtime/endpoints/express.mjs +41 -195
  111. package/dist/v2/runtime/endpoints/express.mjs.map +1 -1
  112. package/dist/v2/runtime/endpoints/hono-single.cjs +11 -123
  113. package/dist/v2/runtime/endpoints/hono-single.cjs.map +1 -1
  114. package/dist/v2/runtime/endpoints/hono-single.d.cts +14 -11
  115. package/dist/v2/runtime/endpoints/hono-single.d.cts.map +1 -1
  116. package/dist/v2/runtime/endpoints/hono-single.d.mts +14 -11
  117. package/dist/v2/runtime/endpoints/hono-single.d.mts.map +1 -1
  118. package/dist/v2/runtime/endpoints/hono-single.mjs +11 -123
  119. package/dist/v2/runtime/endpoints/hono-single.mjs.map +1 -1
  120. package/dist/v2/runtime/endpoints/hono.cjs +23 -237
  121. package/dist/v2/runtime/endpoints/hono.cjs.map +1 -1
  122. package/dist/v2/runtime/endpoints/hono.d.cts +29 -120
  123. package/dist/v2/runtime/endpoints/hono.d.cts.map +1 -1
  124. package/dist/v2/runtime/endpoints/hono.d.mts +29 -120
  125. package/dist/v2/runtime/endpoints/hono.d.mts.map +1 -1
  126. package/dist/v2/runtime/endpoints/hono.mjs +22 -238
  127. package/dist/v2/runtime/endpoints/hono.mjs.map +1 -1
  128. package/dist/v2/runtime/endpoints/index.d.cts +2 -2
  129. package/dist/v2/runtime/endpoints/index.d.mts +2 -2
  130. package/dist/v2/runtime/endpoints/node-fetch-handler.cjs +26 -0
  131. package/dist/v2/runtime/endpoints/node-fetch-handler.cjs.map +1 -0
  132. package/dist/v2/runtime/endpoints/node-fetch-handler.d.cts +12 -0
  133. package/dist/v2/runtime/endpoints/node-fetch-handler.d.cts.map +1 -0
  134. package/dist/v2/runtime/endpoints/node-fetch-handler.d.mts +12 -0
  135. package/dist/v2/runtime/endpoints/node-fetch-handler.d.mts.map +1 -0
  136. package/dist/v2/runtime/endpoints/node-fetch-handler.mjs +24 -0
  137. package/dist/v2/runtime/endpoints/node-fetch-handler.mjs.map +1 -0
  138. package/dist/v2/runtime/endpoints/node.cjs +30 -0
  139. package/dist/v2/runtime/endpoints/node.cjs.map +1 -0
  140. package/dist/v2/runtime/endpoints/node.d.cts +27 -0
  141. package/dist/v2/runtime/endpoints/node.d.cts.map +1 -0
  142. package/dist/v2/runtime/endpoints/node.d.mts +27 -0
  143. package/dist/v2/runtime/endpoints/node.d.mts.map +1 -0
  144. package/dist/v2/runtime/endpoints/node.mjs +30 -0
  145. package/dist/v2/runtime/endpoints/node.mjs.map +1 -0
  146. package/dist/v2/runtime/express.d.cts +3 -0
  147. package/dist/v2/runtime/express.d.mts +3 -0
  148. package/dist/v2/runtime/handlers/get-runtime-info.cjs +2 -1
  149. package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -1
  150. package/dist/v2/runtime/handlers/get-runtime-info.mjs +2 -1
  151. package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -1
  152. package/dist/v2/runtime/handlers/handle-connect.cjs +6 -3
  153. package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
  154. package/dist/v2/runtime/handlers/handle-connect.mjs +6 -3
  155. package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
  156. package/dist/v2/runtime/handlers/handle-run.cjs +6 -3
  157. package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
  158. package/dist/v2/runtime/handlers/handle-run.mjs +6 -3
  159. package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
  160. package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -1
  161. package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -1
  162. package/dist/v2/runtime/handlers/handle-transcribe.cjs.map +1 -1
  163. package/dist/v2/runtime/handlers/handle-transcribe.mjs.map +1 -1
  164. package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -1
  165. package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -1
  166. package/dist/v2/runtime/handlers/intelligence/run.cjs +22 -1
  167. package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
  168. package/dist/v2/runtime/handlers/intelligence/run.mjs +22 -1
  169. package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
  170. package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +1 -1
  171. package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -1
  172. package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +1 -1
  173. package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -1
  174. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +21 -6
  175. package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -1
  176. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +21 -6
  177. package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -1
  178. package/dist/v2/runtime/handlers/shared/json-response.cjs +4 -1
  179. package/dist/v2/runtime/handlers/shared/json-response.cjs.map +1 -1
  180. package/dist/v2/runtime/handlers/shared/json-response.mjs +4 -1
  181. package/dist/v2/runtime/handlers/shared/json-response.mjs.map +1 -1
  182. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -1
  183. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -1
  184. package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
  185. package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
  186. package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
  187. package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
  188. package/dist/v2/runtime/hono.d.cts +3 -0
  189. package/dist/v2/runtime/hono.d.mts +3 -0
  190. package/dist/v2/runtime/index.d.cts +16 -4
  191. package/dist/v2/runtime/index.d.cts.map +1 -0
  192. package/dist/v2/runtime/index.d.mts +16 -4
  193. package/dist/v2/runtime/index.d.mts.map +1 -0
  194. package/dist/v2/runtime/intelligence-platform/client.cjs +10 -1
  195. package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
  196. package/dist/v2/runtime/intelligence-platform/client.d.cts +22 -0
  197. package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
  198. package/dist/v2/runtime/intelligence-platform/client.d.mts +22 -0
  199. package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
  200. package/dist/v2/runtime/intelligence-platform/client.mjs +10 -1
  201. package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
  202. package/dist/v2/runtime/node.d.cts +3 -0
  203. package/dist/v2/runtime/node.d.mts +3 -0
  204. package/dist/v2/runtime/open-generative-ui-middleware.cjs +282 -0
  205. package/dist/v2/runtime/open-generative-ui-middleware.cjs.map +1 -0
  206. package/dist/v2/runtime/open-generative-ui-middleware.mjs +280 -0
  207. package/dist/v2/runtime/open-generative-ui-middleware.mjs.map +1 -0
  208. package/dist/v2/runtime/runner/intelligence.cjs +4 -4
  209. package/dist/v2/runtime/runner/intelligence.cjs.map +1 -1
  210. package/dist/v2/runtime/runner/intelligence.d.cts +6 -2
  211. package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -1
  212. package/dist/v2/runtime/runner/intelligence.d.mts +6 -2
  213. package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -1
  214. package/dist/v2/runtime/runner/intelligence.mjs +4 -4
  215. package/dist/v2/runtime/runner/intelligence.mjs.map +1 -1
  216. package/dist/v2/runtime/telemetry/telemetry-client.cjs +37 -0
  217. package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
  218. package/dist/v2/runtime/telemetry/telemetry-client.mjs +36 -0
  219. package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
  220. package/dist/v2/runtime/telemetry/utils.cjs +15 -0
  221. package/dist/v2/runtime/telemetry/utils.cjs.map +1 -0
  222. package/dist/v2/runtime/telemetry/utils.mjs +14 -0
  223. package/dist/v2/runtime/telemetry/utils.mjs.map +1 -0
  224. package/package.json +81 -48
  225. package/src/agent/__tests__/multimodal.test.ts +176 -0
  226. package/src/agent/index.ts +130 -19
  227. package/src/lib/runtime/agent-integrations/langgraph/agent.ts +3 -3
  228. package/src/lib/runtime/copilot-runtime.ts +1 -0
  229. package/src/v2/express.ts +1 -0
  230. package/src/v2/hono.ts +1 -0
  231. package/src/v2/node.ts +1 -0
  232. package/src/v2/runtime/__tests__/backward-compat.test.ts +261 -0
  233. package/src/v2/runtime/__tests__/code-review-fixes.test.ts +500 -0
  234. package/src/v2/runtime/__tests__/cors-credentials.test.ts +2 -2
  235. package/src/v2/runtime/__tests__/express-adapter.test.ts +188 -0
  236. package/src/v2/runtime/__tests__/express-body-order.test.ts +1 -1
  237. package/src/v2/runtime/__tests__/express-fetch-bridge.test.ts +344 -0
  238. package/src/v2/runtime/__tests__/express-single-sse.test.ts +1 -1
  239. package/src/v2/runtime/__tests__/fetch-cors.test.ts +205 -0
  240. package/src/v2/runtime/__tests__/fetch-handler-validation.test.ts +372 -0
  241. package/src/v2/runtime/__tests__/fetch-handler.test.ts +456 -0
  242. package/src/v2/runtime/__tests__/fetch-router.test.ts +132 -0
  243. package/src/v2/runtime/__tests__/get-runtime-info.test.ts +4 -1
  244. package/src/v2/runtime/__tests__/handle-connect.test.ts +15 -13
  245. package/src/v2/runtime/__tests__/handle-run.test.ts +21 -17
  246. package/src/v2/runtime/__tests__/handle-threads.test.ts +1 -1
  247. package/src/v2/runtime/__tests__/handle-transcribe.test.ts +1 -1
  248. package/src/v2/runtime/__tests__/hono-adapter.test.ts +150 -0
  249. package/src/v2/runtime/__tests__/hooks-edge-cases.test.ts +457 -0
  250. package/src/v2/runtime/__tests__/hooks.test.ts +557 -0
  251. package/src/v2/runtime/__tests__/integration/bun/bun-servers.integration.test.ts +27 -0
  252. package/src/v2/runtime/__tests__/integration/bun/elysia-multi.ts +32 -0
  253. package/src/v2/runtime/__tests__/integration/bun/elysia-single.ts +33 -0
  254. package/src/v2/runtime/__tests__/integration/bun/hono-bun-multi.ts +25 -0
  255. package/src/v2/runtime/__tests__/integration/bun/hono-bun-single.ts +32 -0
  256. package/src/v2/runtime/__tests__/integration/helpers/create-test-runtime.ts +15 -0
  257. package/src/v2/runtime/__tests__/integration/helpers/sse-reader.ts +45 -0
  258. package/src/v2/runtime/__tests__/integration/helpers/test-agent.ts +58 -0
  259. package/src/v2/runtime/__tests__/integration/node-servers.integration.test.ts +39 -0
  260. package/src/v2/runtime/__tests__/integration/servers/express-multi.ts +35 -0
  261. package/src/v2/runtime/__tests__/integration/servers/express-single.ts +36 -0
  262. package/src/v2/runtime/__tests__/integration/servers/fetch-direct.ts +39 -0
  263. package/src/v2/runtime/__tests__/integration/servers/hono-multi.ts +30 -0
  264. package/src/v2/runtime/__tests__/integration/servers/hono-single.ts +37 -0
  265. package/src/v2/runtime/__tests__/integration/servers/node-multi.ts +45 -0
  266. package/src/v2/runtime/__tests__/integration/servers/node-single.ts +46 -0
  267. package/src/v2/runtime/__tests__/integration/servers/types.ts +18 -0
  268. package/src/v2/runtime/__tests__/integration/suites/multi-endpoint.suite.ts +358 -0
  269. package/src/v2/runtime/__tests__/integration/suites/single-endpoint.suite.ts +363 -0
  270. package/src/v2/runtime/__tests__/middleware-express.test.ts +1 -1
  271. package/src/v2/runtime/__tests__/middleware-single-express.test.ts +1 -1
  272. package/src/v2/runtime/__tests__/middleware-single.test.ts +1 -1
  273. package/src/v2/runtime/__tests__/middleware-sse-parser.test.ts +1 -1
  274. package/src/v2/runtime/__tests__/middleware.test.ts +1 -2
  275. package/src/v2/runtime/__tests__/node-fetch-handler.test.ts +157 -0
  276. package/src/v2/runtime/__tests__/open-generative-ui-middleware.e2e.test.ts +728 -0
  277. package/src/v2/runtime/__tests__/router-edge-cases.test.ts +217 -0
  278. package/src/v2/runtime/__tests__/routing-express.test.ts +1 -1
  279. package/src/v2/runtime/__tests__/routing-single-express.test.ts +1 -1
  280. package/src/v2/runtime/__tests__/routing-single.test.ts +1 -1
  281. package/src/v2/runtime/__tests__/routing.test.ts +1 -1
  282. package/src/v2/runtime/__tests__/runtime.test.ts +110 -1
  283. package/src/v2/runtime/__tests__/telemetry.test.ts +62 -1
  284. package/src/v2/runtime/core/fetch-cors.ts +136 -0
  285. package/src/v2/runtime/core/fetch-handler.ts +415 -0
  286. package/src/v2/runtime/core/fetch-router.ts +112 -0
  287. package/src/v2/runtime/core/hooks.ts +151 -0
  288. package/src/v2/runtime/{runtime.ts → core/runtime.ts} +79 -10
  289. package/src/v2/runtime/endpoints/express-fetch-bridge.ts +137 -0
  290. package/src/v2/runtime/endpoints/express-single.ts +42 -219
  291. package/src/v2/runtime/endpoints/express.ts +128 -230
  292. package/src/v2/runtime/endpoints/hono-single.ts +19 -171
  293. package/src/v2/runtime/endpoints/hono.ts +45 -270
  294. package/src/v2/runtime/endpoints/node-fetch-handler.ts +48 -0
  295. package/src/v2/runtime/endpoints/node.ts +28 -0
  296. package/src/v2/runtime/handlers/get-runtime-info.ts +3 -2
  297. package/src/v2/runtime/handlers/handle-connect.ts +7 -4
  298. package/src/v2/runtime/handlers/handle-run.ts +7 -4
  299. package/src/v2/runtime/handlers/handle-stop.ts +1 -1
  300. package/src/v2/runtime/handlers/handle-transcribe.ts +1 -1
  301. package/src/v2/runtime/handlers/intelligence/connect.ts +1 -1
  302. package/src/v2/runtime/handlers/intelligence/run.ts +31 -1
  303. package/src/v2/runtime/handlers/intelligence/thread-names.ts +2 -2
  304. package/src/v2/runtime/handlers/intelligence/threads.ts +1 -1
  305. package/src/v2/runtime/handlers/shared/agent-utils.ts +29 -10
  306. package/src/v2/runtime/handlers/shared/json-response.ts +4 -1
  307. package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +1 -1
  308. package/src/v2/runtime/handlers/sse/connect.ts +1 -1
  309. package/src/v2/runtime/handlers/sse/run.ts +1 -1
  310. package/src/v2/runtime/hono.ts +2 -0
  311. package/src/v2/runtime/index.ts +27 -1
  312. package/src/v2/runtime/intelligence-platform/client.ts +50 -1
  313. package/src/v2/runtime/node.ts +6 -0
  314. package/src/v2/runtime/open-generative-ui-middleware.ts +373 -0
  315. package/src/v2/runtime/runner/intelligence.ts +14 -4
  316. package/src/v2/runtime/telemetry/telemetry-client.ts +56 -0
  317. package/src/v2/runtime/telemetry/utils.ts +15 -0
  318. package/tsdown.config.ts +8 -1
  319. package/vitest.config.mjs +2 -5
  320. package/.eslintrc.js +0 -7
  321. package/dist/v2/runtime/endpoints/express-utils.cjs +0 -119
  322. package/dist/v2/runtime/endpoints/express-utils.cjs.map +0 -1
  323. package/dist/v2/runtime/endpoints/express-utils.mjs +0 -117
  324. package/dist/v2/runtime/endpoints/express-utils.mjs.map +0 -1
  325. package/dist/v2/runtime/handlers/intelligence/threads.cjs +0 -159
  326. package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +0 -1
  327. package/dist/v2/runtime/handlers/intelligence/threads.mjs +0 -154
  328. package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +0 -1
  329. package/dist/v2/runtime/middleware-sse-parser.cjs.map +0 -1
  330. package/dist/v2/runtime/middleware-sse-parser.d.cts.map +0 -1
  331. package/dist/v2/runtime/middleware-sse-parser.d.mts.map +0 -1
  332. package/dist/v2/runtime/middleware-sse-parser.mjs.map +0 -1
  333. package/dist/v2/runtime/middleware.cjs.map +0 -1
  334. package/dist/v2/runtime/middleware.d.cts.map +0 -1
  335. package/dist/v2/runtime/middleware.d.mts.map +0 -1
  336. package/dist/v2/runtime/middleware.mjs.map +0 -1
  337. package/dist/v2/runtime/runtime.cjs.map +0 -1
  338. package/dist/v2/runtime/runtime.d.cts.map +0 -1
  339. package/dist/v2/runtime/runtime.d.mts.map +0 -1
  340. package/dist/v2/runtime/runtime.mjs.map +0 -1
  341. package/src/v2/runtime/__tests__/express-abort-signal.test.ts +0 -25
  342. package/src/v2/runtime/endpoints/express-utils.ts +0 -182
  343. package/src/v2/runtime/handler.ts +0 -3
  344. /package/src/v2/runtime/{middleware-sse-parser.ts → core/middleware-sse-parser.ts} +0 -0
  345. /package/src/v2/runtime/{middleware.ts → core/middleware.ts} +0 -0
@@ -0,0 +1,728 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import {
3
+ AbstractAgent,
4
+ BaseEvent,
5
+ EventType,
6
+ RunAgentInput,
7
+ ActivitySnapshotEvent,
8
+ ActivityDeltaEvent,
9
+ } from "@ag-ui/client";
10
+ import { Observable, firstValueFrom } from "rxjs";
11
+ import { toArray } from "rxjs/operators";
12
+ import {
13
+ OpenGenerativeUIMiddleware,
14
+ ArgsParser,
15
+ } from "../open-generative-ui-middleware";
16
+
17
+ /**
18
+ * A minimal agent that records the input it receives and emits scripted events.
19
+ */
20
+ class MockAgent extends AbstractAgent {
21
+ public receivedInput: RunAgentInput | null = null;
22
+
23
+ constructor(private readonly events: BaseEvent[]) {
24
+ super();
25
+ }
26
+
27
+ run(input: RunAgentInput): Observable<BaseEvent> {
28
+ this.receivedInput = input;
29
+ return new Observable<BaseEvent>((subscriber) => {
30
+ for (const event of this.events) {
31
+ subscriber.next(event);
32
+ }
33
+ subscriber.complete();
34
+ });
35
+ }
36
+
37
+ clone(): AbstractAgent {
38
+ return new MockAgent([...this.events]);
39
+ }
40
+
41
+ protected connect(): ReturnType<AbstractAgent["connect"]> {
42
+ throw new Error("not used");
43
+ }
44
+ }
45
+
46
+ function createRunInput(overrides: Partial<RunAgentInput> = {}): RunAgentInput {
47
+ return {
48
+ threadId: "thread-1",
49
+ runId: "run-1",
50
+ state: {},
51
+ messages: [],
52
+ tools: [],
53
+ context: [],
54
+ forwardedProps: undefined,
55
+ ...overrides,
56
+ };
57
+ }
58
+
59
+ async function collectEvents(
60
+ observable: Observable<BaseEvent>,
61
+ ): Promise<BaseEvent[]> {
62
+ return firstValueFrom(observable.pipe(toArray()));
63
+ }
64
+
65
+ describe("OpenGenerativeUIMiddleware e2e", () => {
66
+ describe("Tool passthrough", () => {
67
+ it("does not modify the tools list", async () => {
68
+ const middleware = new OpenGenerativeUIMiddleware();
69
+ const agent = new MockAgent([
70
+ {
71
+ type: EventType.RUN_STARTED,
72
+ threadId: "thread-1",
73
+ runId: "run-1",
74
+ } as BaseEvent,
75
+ {
76
+ type: EventType.RUN_FINISHED,
77
+ threadId: "thread-1",
78
+ runId: "run-1",
79
+ } as BaseEvent,
80
+ ]);
81
+
82
+ const input = createRunInput();
83
+ await collectEvents(middleware.run(input, agent));
84
+
85
+ expect(agent.receivedInput!.tools).toEqual(input.tools);
86
+ });
87
+ });
88
+
89
+ describe("ArgsParser (streaming JSON via clarinet)", () => {
90
+ const noop = () => {};
91
+
92
+ it("parses a complete JSON object in one chunk", () => {
93
+ const parser = new ArgsParser("tc-1", noop);
94
+ parser.write(
95
+ '{"initialHeight":400,"html":"<div>hi</div>","jsFunctions":"function foo(){}","jsExpressions":["expr1","expr2"]}',
96
+ );
97
+
98
+ expect(parser.params).toEqual({
99
+ initialHeight: 400,
100
+ html: "<div>hi</div>",
101
+ jsFunctions: "function foo(){}",
102
+ jsExpressions: ["expr1", "expr2"],
103
+ });
104
+ });
105
+
106
+ it("streams html as incremental chunks via textNode", () => {
107
+ const emitted: BaseEvent[] = [];
108
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
109
+
110
+ parser.write('{"initialHeight":200,');
111
+ emitted.length = 0; // clear snapshot
112
+
113
+ // Start streaming html — first chunk
114
+ parser.write('"html":"<div');
115
+ const htmlDeltas1 = emitted.filter(
116
+ (e) => e.type === EventType.ACTIVITY_DELTA,
117
+ ) as ActivityDeltaEvent[];
118
+ // Should have array creation + first chunk
119
+ expect(htmlDeltas1.length).toBeGreaterThanOrEqual(1);
120
+ expect(htmlDeltas1[0].patch).toEqual([
121
+ { op: "add", path: "/html", value: [] },
122
+ ]);
123
+
124
+ emitted.length = 0;
125
+ // More html content — note: clarinet needs a delimiter after the
126
+ // closing quote to emit onvalue, so include the trailing }
127
+ parser.write('>hello</div>"}');
128
+ // Should have more chunk(s) + htmlComplete
129
+ const completeDelta = emitted.find(
130
+ (e) =>
131
+ e.type === EventType.ACTIVITY_DELTA &&
132
+ (e as ActivityDeltaEvent).patch.some(
133
+ (p) => p.path === "/htmlComplete",
134
+ ),
135
+ );
136
+ expect(completeDelta).toBeDefined();
137
+
138
+ // Final params should have the complete html
139
+ expect(parser.params.html).toBe("<div>hello</div>");
140
+ });
141
+
142
+ it("parses JSON streamed in small chunks", () => {
143
+ const parser = new ArgsParser("tc-1", noop);
144
+ const json = '{"initialHeight":300,"html":"<p>hello</p>"}';
145
+
146
+ for (const ch of json) {
147
+ parser.write(ch);
148
+ }
149
+
150
+ expect(parser.params.initialHeight).toBe(300);
151
+ expect(parser.params.html).toBe("<p>hello</p>");
152
+ });
153
+
154
+ it("parses jsExpressions array streamed incrementally", () => {
155
+ const parser = new ArgsParser("tc-1", noop);
156
+
157
+ parser.write('{"jsExpressions":');
158
+ expect(parser.params.jsExpressions).toBeUndefined();
159
+
160
+ parser.write('["alert(1)",');
161
+ expect(parser.params.jsExpressions).toEqual(["alert(1)"]);
162
+
163
+ parser.write('"console.log(2)",');
164
+ expect(parser.params.jsExpressions).toEqual([
165
+ "alert(1)",
166
+ "console.log(2)",
167
+ ]);
168
+
169
+ parser.write('"document.title"]}');
170
+ expect(parser.params.jsExpressions).toEqual([
171
+ "alert(1)",
172
+ "console.log(2)",
173
+ "document.title",
174
+ ]);
175
+ });
176
+
177
+ it("handles partial chunks that split across keys and values", () => {
178
+ const parser = new ArgsParser("tc-1", noop);
179
+
180
+ parser.write('{"ini');
181
+ parser.write('tialHeight":');
182
+ parser.write("25");
183
+ parser.write('0,"ht');
184
+ parser.write('ml":"<div');
185
+ parser.write('>test</div>"}');
186
+
187
+ expect(parser.params.initialHeight).toBe(250);
188
+ expect(parser.params.html).toBe("<div>test</div>");
189
+ });
190
+
191
+ it("ignores unknown keys", () => {
192
+ const parser = new ArgsParser("tc-1", noop);
193
+ parser.write(
194
+ '{"initialHeight":100,"unknown_field":"ignored","html":"ok"}',
195
+ );
196
+
197
+ expect(parser.params.initialHeight).toBe(100);
198
+ expect(parser.params.html).toBe("ok");
199
+ expect(parser.params).not.toHaveProperty("unknown_field");
200
+ });
201
+ });
202
+
203
+ describe("Activity event emission", () => {
204
+ it("emits ACTIVITY_SNAPSHOT when initialHeight finishes", () => {
205
+ const emitted: BaseEvent[] = [];
206
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
207
+
208
+ parser.write('{"initialHeight":400}');
209
+
210
+ expect(emitted).toHaveLength(1);
211
+ const snapshot = emitted[0] as ActivitySnapshotEvent;
212
+ expect(snapshot.type).toBe(EventType.ACTIVITY_SNAPSHOT);
213
+ expect(snapshot.messageId).toBe("tc-1-activity");
214
+ expect(snapshot.activityType).toBe("open-generative-ui");
215
+ expect(snapshot.content).toEqual({
216
+ initialHeight: 400,
217
+ generating: true,
218
+ });
219
+ });
220
+
221
+ it("emits ACTIVITY_DELTA array for html and single delta for jsFunctions", () => {
222
+ const emitted: BaseEvent[] = [];
223
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
224
+
225
+ parser.write('{"initialHeight":200,');
226
+ emitted.length = 0; // clear snapshot
227
+
228
+ parser.write('"html":"<div/>",');
229
+ // Should have: array creation, chunk(s), htmlComplete
230
+ const htmlDeltas = emitted.filter(
231
+ (e) => e.type === EventType.ACTIVITY_DELTA,
232
+ ) as ActivityDeltaEvent[];
233
+ expect(htmlDeltas[0].patch).toEqual([
234
+ { op: "add", path: "/html", value: [] },
235
+ ]);
236
+ // Last html delta should be htmlComplete
237
+ const completeIdx = htmlDeltas.findIndex((d) =>
238
+ d.patch.some((p) => p.path === "/htmlComplete"),
239
+ );
240
+ expect(completeIdx).toBeGreaterThan(0);
241
+
242
+ emitted.length = 0;
243
+ parser.write('"jsFunctions":"fn(){}"}');
244
+ const fnDeltas = emitted.filter(
245
+ (e) => e.type === EventType.ACTIVITY_DELTA,
246
+ ) as ActivityDeltaEvent[];
247
+ expect(fnDeltas).toHaveLength(2);
248
+ expect(fnDeltas[0].patch).toEqual([
249
+ { op: "add", path: "/jsFunctions", value: "fn(){}" },
250
+ ]);
251
+ expect(fnDeltas[1].patch).toEqual([
252
+ { op: "add", path: "/jsFunctionsComplete", value: true },
253
+ ]);
254
+ });
255
+
256
+ it("emits ACTIVITY_DELTA with add op for each jsExpressions item", () => {
257
+ const emitted: BaseEvent[] = [];
258
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
259
+
260
+ parser.write('{"initialHeight":100,');
261
+ emitted.length = 0; // clear snapshot
262
+
263
+ parser.write('"jsExpressions":["expr1",');
264
+ // First: array-creation delta, then the first item append
265
+ expect(emitted).toHaveLength(2);
266
+ const arrayCreate = emitted[0] as ActivityDeltaEvent;
267
+ expect(arrayCreate.type).toBe(EventType.ACTIVITY_DELTA);
268
+ expect(arrayCreate.patch).toEqual([
269
+ { op: "add", path: "/jsExpressions", value: [] },
270
+ ]);
271
+ const delta1 = emitted[1] as ActivityDeltaEvent;
272
+ expect(delta1.type).toBe(EventType.ACTIVITY_DELTA);
273
+ expect(delta1.patch).toEqual([
274
+ { op: "add", path: "/jsExpressions/-", value: "expr1" },
275
+ ]);
276
+
277
+ emitted.length = 0;
278
+ parser.write('"expr2",');
279
+ expect(emitted).toHaveLength(1);
280
+ const delta2 = emitted[0] as ActivityDeltaEvent;
281
+ expect(delta2.patch).toEqual([
282
+ { op: "add", path: "/jsExpressions/-", value: "expr2" },
283
+ ]);
284
+
285
+ emitted.length = 0;
286
+ parser.write('"expr3"]}');
287
+ expect(emitted).toHaveLength(2);
288
+ const delta3 = emitted[0] as ActivityDeltaEvent;
289
+ expect(delta3.patch).toEqual([
290
+ { op: "add", path: "/jsExpressions/-", value: "expr3" },
291
+ ]);
292
+ expect((emitted[1] as ActivityDeltaEvent).patch).toEqual([
293
+ { op: "add", path: "/jsExpressionsComplete", value: true },
294
+ ]);
295
+ });
296
+
297
+ it("emits html chunks immediately without throttling", () => {
298
+ const emitted: BaseEvent[] = [];
299
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
300
+
301
+ parser.write('{"initialHeight":200,');
302
+ emitted.length = 0;
303
+
304
+ // Start html streaming — first write should emit
305
+ parser.write('"html":"chunk1');
306
+ const firstDeltas = emitted.filter(
307
+ (e) => e.type === EventType.ACTIVITY_DELTA,
308
+ ) as ActivityDeltaEvent[];
309
+ // Should have array creation + first chunk
310
+ expect(firstDeltas.length).toBeGreaterThanOrEqual(1);
311
+
312
+ // Immediate second write should also emit (no throttle)
313
+ emitted.length = 0;
314
+ parser.write("chunk2");
315
+ const secondDeltas = emitted.filter(
316
+ (e) => e.type === EventType.ACTIVITY_DELTA,
317
+ ) as ActivityDeltaEvent[];
318
+ expect(secondDeltas).toHaveLength(1);
319
+ expect(secondDeltas[0].patch[0].value).toContain("chunk2");
320
+
321
+ // Completing the html string should flush remaining + htmlComplete
322
+ emitted.length = 0;
323
+ parser.write('",');
324
+ const completeDeltas = emitted.filter(
325
+ (e) => e.type === EventType.ACTIVITY_DELTA,
326
+ ) as ActivityDeltaEvent[];
327
+ const completeDelta = completeDeltas.find((d) =>
328
+ d.patch.some((p) => p.path === "/htmlComplete"),
329
+ );
330
+ expect(completeDelta).toBeDefined();
331
+ });
332
+
333
+ it("emits snapshot only once even with multiple params", () => {
334
+ const emitted: BaseEvent[] = [];
335
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
336
+
337
+ parser.write('{"initialHeight":100,"html":"a","jsFunctions":"b"}');
338
+
339
+ const snapshots = emitted.filter(
340
+ (e) => e.type === EventType.ACTIVITY_SNAPSHOT,
341
+ );
342
+ expect(snapshots).toHaveLength(1);
343
+ });
344
+
345
+ it("produces patches that build complete content when applied sequentially", () => {
346
+ const emitted: BaseEvent[] = [];
347
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
348
+
349
+ // Simulate a full tool call with all parameter types
350
+ parser.write(
351
+ '{"initialHeight":400,"html":"<body>game</body>","jsFunctions":"function init(){}","jsExpressions":["init()","update()"]}',
352
+ );
353
+
354
+ // Reconstruct content by applying snapshot + deltas in order
355
+ let content: Record<string, unknown> = {};
356
+ for (const event of emitted) {
357
+ if (event.type === EventType.ACTIVITY_SNAPSHOT) {
358
+ content = { ...(event as ActivitySnapshotEvent).content } as Record<
359
+ string,
360
+ unknown
361
+ >;
362
+ } else if (event.type === EventType.ACTIVITY_DELTA) {
363
+ const delta = event as ActivityDeltaEvent;
364
+ for (const op of delta.patch) {
365
+ if (op.op === "add") {
366
+ if (op.path.endsWith("/-")) {
367
+ // Array append: path like "/jsExpressions/-" or "/html/-"
368
+ const arrayKey = op.path.slice(1, -2);
369
+ (content[arrayKey] as unknown[]).push(op.value);
370
+ } else {
371
+ // Direct property: path like "/htmlComplete"
372
+ content[op.path.slice(1)] = op.value;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ }
378
+
379
+ // html is now an array of chunks; join to verify full content
380
+ expect(Array.isArray(content.html)).toBe(true);
381
+ expect((content.html as string[]).join("")).toBe("<body>game</body>");
382
+ expect(content.htmlComplete).toBe(true);
383
+ expect(content.jsFunctions).toBe("function init(){}");
384
+ expect(content.jsExpressions).toEqual(["init()", "update()"]);
385
+ });
386
+
387
+ it("produces patches that build content correctly when streamed in chunks", () => {
388
+ const emitted: BaseEvent[] = [];
389
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
390
+
391
+ // Stream in small chunks like a real LLM would
392
+ parser.write('{"initialHeight":300,');
393
+ parser.write('"html":"<div>hi</div>",');
394
+ parser.write('"jsFunctions":"function go(){}",');
395
+ parser.write('"jsExpressions":["go()",');
396
+ parser.write('"render()","done()"]}');
397
+
398
+ // Reconstruct content
399
+ let content: Record<string, unknown> = {};
400
+ for (const event of emitted) {
401
+ if (event.type === EventType.ACTIVITY_SNAPSHOT) {
402
+ content = { ...(event as ActivitySnapshotEvent).content } as Record<
403
+ string,
404
+ unknown
405
+ >;
406
+ } else if (event.type === EventType.ACTIVITY_DELTA) {
407
+ const delta = event as ActivityDeltaEvent;
408
+ for (const op of delta.patch) {
409
+ if (op.op === "add") {
410
+ if (op.path.endsWith("/-")) {
411
+ const arrayKey = op.path.slice(1, -2);
412
+ (content[arrayKey] as unknown[]).push(op.value);
413
+ } else {
414
+ content[op.path.slice(1)] = op.value;
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+
421
+ // html is now an array of chunks
422
+ expect(Array.isArray(content.html)).toBe(true);
423
+ expect((content.html as string[]).join("")).toBe("<div>hi</div>");
424
+ expect(content.htmlComplete).toBe(true);
425
+ expect(content.jsFunctions).toBe("function go(){}");
426
+ expect(content.jsExpressions).toEqual(["go()", "render()", "done()"]);
427
+ });
428
+
429
+ it("emits array-creation delta before first jsExpressions item", () => {
430
+ const emitted: BaseEvent[] = [];
431
+ const parser = new ArgsParser("tc-1", (e) => emitted.push(e));
432
+
433
+ parser.write('{"initialHeight":100,');
434
+ emitted.length = 0; // clear snapshot
435
+
436
+ // Trailing comma needed — clarinet fires onvalue after a delimiter
437
+ parser.write('"jsExpressions":["first",');
438
+
439
+ // Should get array creation delta followed by item delta
440
+ expect(emitted).toHaveLength(2);
441
+ expect((emitted[0] as ActivityDeltaEvent).patch).toEqual([
442
+ { op: "add", path: "/jsExpressions", value: [] },
443
+ ]);
444
+ expect((emitted[1] as ActivityDeltaEvent).patch).toEqual([
445
+ { op: "add", path: "/jsExpressions/-", value: "first" },
446
+ ]);
447
+ });
448
+
449
+ it("holds genui tool call events and flushes after first activity event", async () => {
450
+ const middleware = new OpenGenerativeUIMiddleware();
451
+ const toolCallId = "tc-stream";
452
+ const parentMessageId = "msg-1";
453
+
454
+ const agent = new MockAgent([
455
+ {
456
+ type: EventType.RUN_STARTED,
457
+ threadId: "thread-1",
458
+ runId: "run-1",
459
+ } as BaseEvent,
460
+ {
461
+ type: EventType.TEXT_MESSAGE_START,
462
+ messageId: parentMessageId,
463
+ role: "assistant",
464
+ } as BaseEvent,
465
+ {
466
+ type: EventType.TEXT_MESSAGE_END,
467
+ messageId: parentMessageId,
468
+ } as BaseEvent,
469
+ {
470
+ type: EventType.TOOL_CALL_START,
471
+ toolCallId,
472
+ toolCallName: "generateSandboxedUi",
473
+ parentMessageId,
474
+ } as BaseEvent,
475
+ {
476
+ type: EventType.TOOL_CALL_ARGS,
477
+ toolCallId,
478
+ delta: '{"initialHeight":300,',
479
+ } as BaseEvent,
480
+ {
481
+ type: EventType.TOOL_CALL_ARGS,
482
+ toolCallId,
483
+ delta: '"html":"<p>hi</p>"}',
484
+ } as BaseEvent,
485
+ {
486
+ type: EventType.TOOL_CALL_END,
487
+ toolCallId,
488
+ } as BaseEvent,
489
+ {
490
+ type: EventType.RUN_FINISHED,
491
+ threadId: "thread-1",
492
+ runId: "run-1",
493
+ } as BaseEvent,
494
+ ]);
495
+
496
+ const events = await collectEvents(
497
+ middleware.run(createRunInput(), agent),
498
+ );
499
+
500
+ // ACTIVITY_SNAPSHOT should appear before any tool call events
501
+ const snapshotIdx = events.findIndex(
502
+ (e) => e.type === EventType.ACTIVITY_SNAPSHOT,
503
+ );
504
+ const toolCallStartIdx = events.findIndex(
505
+ (e) => e.type === EventType.TOOL_CALL_START,
506
+ );
507
+ expect(snapshotIdx).toBeGreaterThan(-1);
508
+ expect(toolCallStartIdx).toBeGreaterThan(-1);
509
+ expect(snapshotIdx).toBeLessThan(toolCallStartIdx);
510
+
511
+ // Activity content is correct
512
+ const snapshots = events.filter(
513
+ (e) => e.type === EventType.ACTIVITY_SNAPSHOT,
514
+ ) as ActivitySnapshotEvent[];
515
+ expect(snapshots).toHaveLength(1);
516
+ expect(snapshots[0].content).toEqual({
517
+ initialHeight: 300,
518
+ generating: true,
519
+ });
520
+
521
+ const deltas = events.filter(
522
+ (e) => e.type === EventType.ACTIVITY_DELTA,
523
+ ) as ActivityDeltaEvent[];
524
+ // html deltas: array creation, chunk(s), htmlComplete, then generating: false
525
+ expect(deltas.length).toBeGreaterThanOrEqual(3);
526
+ expect(deltas[0].patch).toEqual([
527
+ { op: "add", path: "/html", value: [] },
528
+ ]);
529
+ // Last delta should be generating: false
530
+ expect(deltas[deltas.length - 1].patch).toEqual([
531
+ { op: "add", path: "/generating", value: false },
532
+ ]);
533
+ // htmlComplete should be emitted
534
+ const htmlCompleteDelta = deltas.find((d) =>
535
+ d.patch.some((p) => p.path === "/htmlComplete" && p.value === true),
536
+ );
537
+ expect(htmlCompleteDelta).toBeDefined();
538
+ });
539
+
540
+ it("passes through tool call events for non-genui tools", async () => {
541
+ const middleware = new OpenGenerativeUIMiddleware();
542
+ const toolCallId = "tc-other";
543
+ const parentMessageId = "msg-1";
544
+
545
+ const agent = new MockAgent([
546
+ {
547
+ type: EventType.RUN_STARTED,
548
+ threadId: "thread-1",
549
+ runId: "run-1",
550
+ } as BaseEvent,
551
+ {
552
+ type: EventType.TEXT_MESSAGE_START,
553
+ messageId: parentMessageId,
554
+ role: "assistant",
555
+ } as BaseEvent,
556
+ {
557
+ type: EventType.TEXT_MESSAGE_END,
558
+ messageId: parentMessageId,
559
+ } as BaseEvent,
560
+ {
561
+ type: EventType.TOOL_CALL_START,
562
+ toolCallId,
563
+ toolCallName: "some_other_tool",
564
+ parentMessageId,
565
+ } as BaseEvent,
566
+ {
567
+ type: EventType.TOOL_CALL_ARGS,
568
+ toolCallId,
569
+ delta: "{}",
570
+ } as BaseEvent,
571
+ {
572
+ type: EventType.TOOL_CALL_END,
573
+ toolCallId,
574
+ } as BaseEvent,
575
+ {
576
+ type: EventType.RUN_FINISHED,
577
+ threadId: "thread-1",
578
+ runId: "run-1",
579
+ } as BaseEvent,
580
+ ]);
581
+
582
+ const events = await collectEvents(
583
+ middleware.run(createRunInput(), agent),
584
+ );
585
+
586
+ const types = events.map((e) => e.type);
587
+ expect(types).toEqual([
588
+ EventType.RUN_STARTED,
589
+ EventType.TEXT_MESSAGE_START,
590
+ EventType.TEXT_MESSAGE_END,
591
+ EventType.TOOL_CALL_START,
592
+ EventType.TOOL_CALL_ARGS,
593
+ EventType.TOOL_CALL_END,
594
+ EventType.RUN_FINISHED,
595
+ ]);
596
+ });
597
+
598
+ it("emits full activity events for jsFunctions and jsExpressions through middleware", async () => {
599
+ const middleware = new OpenGenerativeUIMiddleware();
600
+ const toolCallId = "tc-js";
601
+ const parentMessageId = "msg-1";
602
+
603
+ const agent = new MockAgent([
604
+ {
605
+ type: EventType.RUN_STARTED,
606
+ threadId: "thread-1",
607
+ runId: "run-1",
608
+ } as BaseEvent,
609
+ {
610
+ type: EventType.TEXT_MESSAGE_START,
611
+ messageId: parentMessageId,
612
+ role: "assistant",
613
+ } as BaseEvent,
614
+ {
615
+ type: EventType.TEXT_MESSAGE_END,
616
+ messageId: parentMessageId,
617
+ } as BaseEvent,
618
+ {
619
+ type: EventType.TOOL_CALL_START,
620
+ toolCallId,
621
+ toolCallName: "generateSandboxedUi",
622
+ parentMessageId,
623
+ } as BaseEvent,
624
+ {
625
+ type: EventType.TOOL_CALL_ARGS,
626
+ toolCallId,
627
+ delta: '{"initialHeight":400,',
628
+ } as BaseEvent,
629
+ {
630
+ type: EventType.TOOL_CALL_ARGS,
631
+ toolCallId,
632
+ delta: '"html":"<body>game</body>",',
633
+ } as BaseEvent,
634
+ {
635
+ type: EventType.TOOL_CALL_ARGS,
636
+ toolCallId,
637
+ delta: '"jsFunctions":"function init(){}",',
638
+ } as BaseEvent,
639
+ {
640
+ type: EventType.TOOL_CALL_ARGS,
641
+ toolCallId,
642
+ delta: '"jsExpressions":["init()",',
643
+ } as BaseEvent,
644
+ {
645
+ type: EventType.TOOL_CALL_ARGS,
646
+ toolCallId,
647
+ delta: '"render()"]}',
648
+ } as BaseEvent,
649
+ {
650
+ type: EventType.TOOL_CALL_END,
651
+ toolCallId,
652
+ } as BaseEvent,
653
+ {
654
+ type: EventType.RUN_FINISHED,
655
+ threadId: "thread-1",
656
+ runId: "run-1",
657
+ } as BaseEvent,
658
+ ]);
659
+
660
+ const events = await collectEvents(
661
+ middleware.run(createRunInput(), agent),
662
+ );
663
+
664
+ // Verify snapshot
665
+ const snapshots = events.filter(
666
+ (e) => e.type === EventType.ACTIVITY_SNAPSHOT,
667
+ ) as ActivitySnapshotEvent[];
668
+ expect(snapshots).toHaveLength(1);
669
+ expect(snapshots[0].content).toEqual({
670
+ initialHeight: 400,
671
+ generating: true,
672
+ });
673
+
674
+ // Verify deltas
675
+ const deltas = events.filter(
676
+ (e) => e.type === EventType.ACTIVITY_DELTA,
677
+ ) as ActivityDeltaEvent[];
678
+
679
+ // html is now streamed as array: creation, chunk(s), htmlComplete
680
+ // Then: jsFunctions, jsExpressions array creation, items, generating: false
681
+ // Verify key structural deltas exist
682
+ expect(deltas[0].patch).toEqual([
683
+ { op: "add", path: "/html", value: [] },
684
+ ]);
685
+ const htmlCompleteDelta = deltas.find((d) =>
686
+ d.patch.some((p) => p.path === "/htmlComplete" && p.value === true),
687
+ );
688
+ expect(htmlCompleteDelta).toBeDefined();
689
+ const jsFuncDelta = deltas.find((d) =>
690
+ d.patch.some((p) => p.path === "/jsFunctions"),
691
+ );
692
+ expect(jsFuncDelta).toBeDefined();
693
+ expect(deltas[deltas.length - 1].patch).toEqual([
694
+ { op: "add", path: "/generating", value: false },
695
+ ]);
696
+
697
+ // Reconstruct content to prove patches work end-to-end
698
+ let content: Record<string, unknown> = {};
699
+ for (const event of events) {
700
+ if (event.type === EventType.ACTIVITY_SNAPSHOT) {
701
+ content = { ...(event as ActivitySnapshotEvent).content } as Record<
702
+ string,
703
+ unknown
704
+ >;
705
+ } else if (event.type === EventType.ACTIVITY_DELTA) {
706
+ for (const op of (event as ActivityDeltaEvent).patch) {
707
+ if (op.op === "add") {
708
+ if (op.path.endsWith("/-")) {
709
+ const arrayKey = op.path.slice(1, -2);
710
+ (content[arrayKey] as unknown[]).push(op.value);
711
+ } else {
712
+ content[op.path.slice(1)] = op.value;
713
+ }
714
+ }
715
+ }
716
+ }
717
+ }
718
+
719
+ // html is now an array of chunks
720
+ expect(Array.isArray(content.html)).toBe(true);
721
+ expect((content.html as string[]).join("")).toBe("<body>game</body>");
722
+ expect(content.htmlComplete).toBe(true);
723
+ expect(content.generating).toBe(false);
724
+ expect(content.jsFunctions).toBe("function init(){}");
725
+ expect(content.jsExpressions).toEqual(["init()", "render()"]);
726
+ });
727
+ });
728
+ });