@copilotkit/runtime 1.54.1 → 1.55.0-next.7

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 (337) hide show
  1. package/.eslintrc.js +4 -4
  2. package/CHANGELOG.md +113 -113
  3. package/dist/_virtual/_rolldown/runtime.mjs +25 -1
  4. package/dist/agent/index.cjs +643 -0
  5. package/dist/agent/index.cjs.map +1 -0
  6. package/dist/agent/index.d.cts +263 -0
  7. package/dist/agent/index.d.cts.map +1 -0
  8. package/dist/agent/index.d.mts +263 -0
  9. package/dist/agent/index.d.mts.map +1 -0
  10. package/dist/agent/index.mjs +635 -0
  11. package/dist/agent/index.mjs.map +1 -0
  12. package/dist/graphql/message-conversion/agui-to-gql.cjs.map +1 -1
  13. package/dist/graphql/message-conversion/agui-to-gql.mjs.map +1 -1
  14. package/dist/lib/integrations/nextjs/app-router.cjs +2 -2
  15. package/dist/lib/integrations/nextjs/app-router.cjs.map +1 -1
  16. package/dist/lib/integrations/nextjs/app-router.mjs +1 -1
  17. package/dist/lib/integrations/nextjs/app-router.mjs.map +1 -1
  18. package/dist/lib/integrations/node-http/index.cjs +2 -3
  19. package/dist/lib/integrations/node-http/index.cjs.map +1 -1
  20. package/dist/lib/integrations/node-http/index.mjs +1 -1
  21. package/dist/lib/integrations/node-http/index.mjs.map +1 -1
  22. package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs +1 -1
  23. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts +2 -2
  24. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
  25. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts +3 -3
  26. package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
  27. package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +1 -1
  28. package/dist/lib/runtime/copilot-runtime.cjs +7 -5
  29. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  30. package/dist/lib/runtime/copilot-runtime.d.cts +10 -8
  31. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  32. package/dist/lib/runtime/copilot-runtime.d.mts +10 -8
  33. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  34. package/dist/lib/runtime/copilot-runtime.mjs +7 -5
  35. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  36. package/dist/lib/runtime/telemetry-agent-runner.cjs +2 -2
  37. package/dist/lib/runtime/telemetry-agent-runner.cjs.map +1 -1
  38. package/dist/lib/runtime/telemetry-agent-runner.d.cts +2 -1
  39. package/dist/lib/runtime/telemetry-agent-runner.d.cts.map +1 -1
  40. package/dist/lib/runtime/telemetry-agent-runner.d.mts +2 -1
  41. package/dist/lib/runtime/telemetry-agent-runner.d.mts.map +1 -1
  42. package/dist/lib/runtime/telemetry-agent-runner.mjs +1 -1
  43. package/dist/lib/runtime/telemetry-agent-runner.mjs.map +1 -1
  44. package/dist/lib/telemetry-client.cjs +1 -1
  45. package/dist/lib/telemetry-client.mjs +1 -1
  46. package/dist/package.cjs +21 -4
  47. package/dist/package.mjs +21 -4
  48. package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +1 -1
  49. package/dist/v2/index.cjs +41 -15
  50. package/dist/v2/index.d.cts +14 -2
  51. package/dist/v2/index.d.mts +14 -2
  52. package/dist/v2/index.mjs +13 -4
  53. package/dist/v2/runtime/endpoints/express-single.cjs +190 -0
  54. package/dist/v2/runtime/endpoints/express-single.cjs.map +1 -0
  55. package/dist/v2/runtime/endpoints/express-single.d.cts +16 -0
  56. package/dist/v2/runtime/endpoints/express-single.d.cts.map +1 -0
  57. package/dist/v2/runtime/endpoints/express-single.d.mts +16 -0
  58. package/dist/v2/runtime/endpoints/express-single.d.mts.map +1 -0
  59. package/dist/v2/runtime/endpoints/express-single.mjs +187 -0
  60. package/dist/v2/runtime/endpoints/express-single.mjs.map +1 -0
  61. package/dist/v2/runtime/endpoints/express-utils.cjs +119 -0
  62. package/dist/v2/runtime/endpoints/express-utils.cjs.map +1 -0
  63. package/dist/v2/runtime/endpoints/express-utils.mjs +117 -0
  64. package/dist/v2/runtime/endpoints/express-utils.mjs.map +1 -0
  65. package/dist/v2/runtime/endpoints/express.cjs +217 -0
  66. package/dist/v2/runtime/endpoints/express.cjs.map +1 -0
  67. package/dist/v2/runtime/endpoints/express.d.cts +16 -0
  68. package/dist/v2/runtime/endpoints/express.d.cts.map +1 -0
  69. package/dist/v2/runtime/endpoints/express.d.mts +16 -0
  70. package/dist/v2/runtime/endpoints/express.d.mts.map +1 -0
  71. package/dist/v2/runtime/endpoints/express.mjs +214 -0
  72. package/dist/v2/runtime/endpoints/express.mjs.map +1 -0
  73. package/dist/v2/runtime/endpoints/hono-single.cjs +141 -0
  74. package/dist/v2/runtime/endpoints/hono-single.cjs.map +1 -0
  75. package/dist/v2/runtime/endpoints/hono-single.d.cts +41 -0
  76. package/dist/v2/runtime/endpoints/hono-single.d.cts.map +1 -0
  77. package/dist/v2/runtime/endpoints/hono-single.d.mts +41 -0
  78. package/dist/v2/runtime/endpoints/hono-single.d.mts.map +1 -0
  79. package/dist/v2/runtime/endpoints/hono-single.mjs +140 -0
  80. package/dist/v2/runtime/endpoints/hono-single.mjs.map +1 -0
  81. package/dist/v2/runtime/endpoints/hono.cjs +248 -0
  82. package/dist/v2/runtime/endpoints/hono.cjs.map +1 -0
  83. package/dist/v2/runtime/endpoints/hono.d.cts +164 -0
  84. package/dist/v2/runtime/endpoints/hono.d.cts.map +1 -0
  85. package/dist/v2/runtime/endpoints/hono.d.mts +164 -0
  86. package/dist/v2/runtime/endpoints/hono.d.mts.map +1 -0
  87. package/dist/v2/runtime/endpoints/hono.mjs +247 -0
  88. package/dist/v2/runtime/endpoints/hono.mjs.map +1 -0
  89. package/dist/v2/runtime/endpoints/index.d.cts +5 -0
  90. package/dist/v2/runtime/endpoints/index.d.mts +5 -0
  91. package/dist/v2/runtime/endpoints/single-route-helpers.cjs +68 -0
  92. package/dist/v2/runtime/endpoints/single-route-helpers.cjs.map +1 -0
  93. package/dist/v2/runtime/endpoints/single-route-helpers.mjs +65 -0
  94. package/dist/v2/runtime/endpoints/single-route-helpers.mjs.map +1 -0
  95. package/dist/v2/runtime/handlers/get-runtime-info.cjs +51 -0
  96. package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -0
  97. package/dist/v2/runtime/handlers/get-runtime-info.mjs +51 -0
  98. package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -0
  99. package/dist/v2/runtime/handlers/handle-connect.cjs +49 -0
  100. package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -0
  101. package/dist/v2/runtime/handlers/handle-connect.mjs +49 -0
  102. package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -0
  103. package/dist/v2/runtime/handlers/handle-run.cjs +61 -0
  104. package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -0
  105. package/dist/v2/runtime/handlers/handle-run.mjs +61 -0
  106. package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -0
  107. package/dist/v2/runtime/handlers/handle-stop.cjs +47 -0
  108. package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -0
  109. package/dist/v2/runtime/handlers/handle-stop.mjs +46 -0
  110. package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -0
  111. package/dist/v2/runtime/handlers/handle-transcribe.cjs +112 -0
  112. package/dist/v2/runtime/handlers/handle-transcribe.cjs.map +1 -0
  113. package/dist/v2/runtime/handlers/handle-transcribe.mjs +111 -0
  114. package/dist/v2/runtime/handlers/handle-transcribe.mjs.map +1 -0
  115. package/dist/v2/runtime/handlers/header-utils.cjs +26 -0
  116. package/dist/v2/runtime/handlers/header-utils.cjs.map +1 -0
  117. package/dist/v2/runtime/handlers/header-utils.mjs +25 -0
  118. package/dist/v2/runtime/handlers/header-utils.mjs.map +1 -0
  119. package/dist/v2/runtime/handlers/intelligence/connect.cjs +37 -0
  120. package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -0
  121. package/dist/v2/runtime/handlers/intelligence/connect.mjs +37 -0
  122. package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -0
  123. package/dist/v2/runtime/handlers/intelligence/run.cjs +89 -0
  124. package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -0
  125. package/dist/v2/runtime/handlers/intelligence/run.mjs +88 -0
  126. package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -0
  127. package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +146 -0
  128. package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -0
  129. package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +145 -0
  130. package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -0
  131. package/dist/v2/runtime/handlers/intelligence/threads.cjs +159 -0
  132. package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -0
  133. package/dist/v2/runtime/handlers/intelligence/threads.mjs +154 -0
  134. package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -0
  135. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +74 -0
  136. package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -0
  137. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +70 -0
  138. package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -0
  139. package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +21 -0
  140. package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -0
  141. package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +20 -0
  142. package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -0
  143. package/dist/v2/runtime/handlers/shared/json-response.cjs +12 -0
  144. package/dist/v2/runtime/handlers/shared/json-response.cjs.map +1 -0
  145. package/dist/v2/runtime/handlers/shared/json-response.mjs +10 -0
  146. package/dist/v2/runtime/handlers/shared/json-response.mjs.map +1 -0
  147. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +20 -0
  148. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -0
  149. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +20 -0
  150. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -0
  151. package/dist/v2/runtime/handlers/shared/sse-response.cjs +69 -0
  152. package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -0
  153. package/dist/v2/runtime/handlers/shared/sse-response.mjs +68 -0
  154. package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -0
  155. package/dist/v2/runtime/handlers/sse/connect.cjs +18 -0
  156. package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -0
  157. package/dist/v2/runtime/handlers/sse/connect.mjs +18 -0
  158. package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -0
  159. package/dist/v2/runtime/handlers/sse/run.cjs +18 -0
  160. package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -0
  161. package/dist/v2/runtime/handlers/sse/run.mjs +18 -0
  162. package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -0
  163. package/dist/v2/runtime/index.d.cts +13 -0
  164. package/dist/v2/runtime/index.d.mts +14 -0
  165. package/dist/v2/runtime/intelligence-platform/client.cjs +333 -0
  166. package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -0
  167. package/dist/v2/runtime/intelligence-platform/client.d.cts +336 -0
  168. package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -0
  169. package/dist/v2/runtime/intelligence-platform/client.d.mts +336 -0
  170. package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -0
  171. package/dist/v2/runtime/intelligence-platform/client.mjs +331 -0
  172. package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -0
  173. package/dist/v2/runtime/intelligence-platform/index.d.mts +2 -0
  174. package/dist/v2/runtime/middleware-sse-parser.cjs +138 -0
  175. package/dist/v2/runtime/middleware-sse-parser.cjs.map +1 -0
  176. package/dist/v2/runtime/middleware-sse-parser.d.cts +22 -0
  177. package/dist/v2/runtime/middleware-sse-parser.d.cts.map +1 -0
  178. package/dist/v2/runtime/middleware-sse-parser.d.mts +22 -0
  179. package/dist/v2/runtime/middleware-sse-parser.d.mts.map +1 -0
  180. package/dist/v2/runtime/middleware-sse-parser.mjs +137 -0
  181. package/dist/v2/runtime/middleware-sse-parser.mjs.map +1 -0
  182. package/dist/v2/runtime/middleware.cjs +35 -0
  183. package/dist/v2/runtime/middleware.cjs.map +1 -0
  184. package/dist/v2/runtime/middleware.d.cts +32 -0
  185. package/dist/v2/runtime/middleware.d.cts.map +1 -0
  186. package/dist/v2/runtime/middleware.d.mts +32 -0
  187. package/dist/v2/runtime/middleware.d.mts.map +1 -0
  188. package/dist/v2/runtime/middleware.mjs +33 -0
  189. package/dist/v2/runtime/middleware.mjs.map +1 -0
  190. package/dist/v2/runtime/runner/agent-runner.cjs +8 -0
  191. package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -0
  192. package/dist/v2/runtime/runner/agent-runner.d.cts +32 -0
  193. package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -0
  194. package/dist/v2/runtime/runner/agent-runner.d.mts +32 -0
  195. package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -0
  196. package/dist/v2/runtime/runner/agent-runner.mjs +7 -0
  197. package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -0
  198. package/dist/v2/runtime/runner/in-memory.cjs +223 -0
  199. package/dist/v2/runtime/runner/in-memory.cjs.map +1 -0
  200. package/dist/v2/runtime/runner/in-memory.d.cts +15 -0
  201. package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -0
  202. package/dist/v2/runtime/runner/in-memory.d.mts +15 -0
  203. package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -0
  204. package/dist/v2/runtime/runner/in-memory.mjs +222 -0
  205. package/dist/v2/runtime/runner/in-memory.mjs.map +1 -0
  206. package/dist/v2/runtime/runner/index.d.cts +6 -0
  207. package/dist/v2/runtime/runner/index.d.mts +6 -0
  208. package/dist/v2/runtime/runner/index.mjs +7 -0
  209. package/dist/v2/runtime/runner/intelligence.cjs +246 -0
  210. package/dist/v2/runtime/runner/intelligence.cjs.map +1 -0
  211. package/dist/v2/runtime/runner/intelligence.d.cts +57 -0
  212. package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -0
  213. package/dist/v2/runtime/runner/intelligence.d.mts +57 -0
  214. package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -0
  215. package/dist/v2/runtime/runner/intelligence.mjs +245 -0
  216. package/dist/v2/runtime/runner/intelligence.mjs.map +1 -0
  217. package/dist/v2/runtime/runtime.cjs +101 -0
  218. package/dist/v2/runtime/runtime.cjs.map +1 -0
  219. package/dist/v2/runtime/runtime.d.cts +132 -0
  220. package/dist/v2/runtime/runtime.d.cts.map +1 -0
  221. package/dist/v2/runtime/runtime.d.mts +133 -0
  222. package/dist/v2/runtime/runtime.d.mts.map +1 -0
  223. package/dist/v2/runtime/runtime.mjs +97 -0
  224. package/dist/v2/runtime/runtime.mjs.map +1 -0
  225. package/dist/v2/runtime/telemetry/scarf-client.cjs +32 -0
  226. package/dist/v2/runtime/telemetry/scarf-client.cjs.map +1 -0
  227. package/dist/v2/runtime/telemetry/scarf-client.mjs +32 -0
  228. package/dist/v2/runtime/telemetry/scarf-client.mjs.map +1 -0
  229. package/dist/v2/runtime/telemetry/telemetry-client.cjs +35 -0
  230. package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -0
  231. package/dist/v2/runtime/telemetry/telemetry-client.mjs +35 -0
  232. package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -0
  233. package/dist/v2/runtime/transcription-service/transcription-service.cjs +8 -0
  234. package/dist/v2/runtime/transcription-service/transcription-service.cjs.map +1 -0
  235. package/dist/v2/runtime/transcription-service/transcription-service.d.cts +15 -0
  236. package/dist/v2/runtime/transcription-service/transcription-service.d.cts.map +1 -0
  237. package/dist/v2/runtime/transcription-service/transcription-service.d.mts +15 -0
  238. package/dist/v2/runtime/transcription-service/transcription-service.d.mts.map +1 -0
  239. package/dist/v2/runtime/transcription-service/transcription-service.mjs +7 -0
  240. package/dist/v2/runtime/transcription-service/transcription-service.mjs.map +1 -0
  241. package/package.json +24 -7
  242. package/src/agent/__tests__/ai-sdk-v6-compat.test.ts +116 -0
  243. package/src/agent/__tests__/basic-agent.test.ts +1248 -0
  244. package/src/agent/__tests__/config-tools-execution.test.ts +516 -0
  245. package/src/agent/__tests__/mcp-clients.test.ts +260 -0
  246. package/src/agent/__tests__/property-overrides.test.ts +598 -0
  247. package/src/agent/__tests__/standard-schema-tools.test.ts +313 -0
  248. package/src/agent/__tests__/standard-schema-types.test.ts +158 -0
  249. package/src/agent/__tests__/state-tools.test.ts +436 -0
  250. package/src/agent/__tests__/test-helpers.ts +178 -0
  251. package/src/agent/__tests__/utils.test.ts +536 -0
  252. package/src/agent/__tests__/zod-regression.test.ts +350 -0
  253. package/src/agent/index.ts +1305 -0
  254. package/src/graphql/message-conversion/agui-to-gql.test.ts +1 -1
  255. package/src/graphql/message-conversion/agui-to-gql.ts +1 -1
  256. package/src/graphql/message-conversion/gql-to-agui.ts +1 -1
  257. package/src/graphql/message-conversion/roundtrip-conversion.test.ts +1 -1
  258. package/src/lib/integrations/nextjs/app-router.ts +2 -2
  259. package/src/lib/integrations/node-http/index.ts +2 -2
  260. package/src/lib/runtime/copilot-runtime.ts +3 -5
  261. package/src/lib/runtime/telemetry-agent-runner.ts +1 -1
  262. package/src/service-adapters/conversion.test.ts +1 -1
  263. package/src/service-adapters/conversion.ts +1 -28
  264. package/src/v2/index.ts +5 -2
  265. package/src/v2/runtime/__tests__/cors-credentials.test.ts +320 -0
  266. package/src/v2/runtime/__tests__/express-abort-signal.test.ts +25 -0
  267. package/src/v2/runtime/__tests__/express-body-order.test.ts +76 -0
  268. package/src/v2/runtime/__tests__/express-single-sse.test.ts +122 -0
  269. package/src/v2/runtime/__tests__/get-runtime-info.test.ts +141 -0
  270. package/src/v2/runtime/__tests__/handle-connect.test.ts +423 -0
  271. package/src/v2/runtime/__tests__/handle-run.test.ts +910 -0
  272. package/src/v2/runtime/__tests__/handle-threads.test.ts +388 -0
  273. package/src/v2/runtime/__tests__/handle-transcribe.test.ts +301 -0
  274. package/src/v2/runtime/__tests__/header-utils.test.ts +88 -0
  275. package/src/v2/runtime/__tests__/in-process-agent-runner-messages.test.ts +230 -0
  276. package/src/v2/runtime/__tests__/in-process-agent-runner.test.ts +1030 -0
  277. package/src/v2/runtime/__tests__/middleware-express.test.ts +206 -0
  278. package/src/v2/runtime/__tests__/middleware-single-express.test.ts +211 -0
  279. package/src/v2/runtime/__tests__/middleware-single.test.ts +225 -0
  280. package/src/v2/runtime/__tests__/middleware-sse-parser.test.ts +187 -0
  281. package/src/v2/runtime/__tests__/middleware.test.ts +251 -0
  282. package/src/v2/runtime/__tests__/routing-express.test.ts +174 -0
  283. package/src/v2/runtime/__tests__/routing-single-express.test.ts +168 -0
  284. package/src/v2/runtime/__tests__/routing-single.test.ts +193 -0
  285. package/src/v2/runtime/__tests__/routing.test.ts +257 -0
  286. package/src/v2/runtime/__tests__/runtime.test.ts +123 -0
  287. package/src/v2/runtime/__tests__/telemetry.test.ts +167 -0
  288. package/src/v2/runtime/__tests__/thread-names.test.ts +188 -0
  289. package/src/v2/runtime/endpoints/express-single.ts +231 -0
  290. package/src/v2/runtime/endpoints/express-utils.ts +182 -0
  291. package/src/v2/runtime/endpoints/express.ts +275 -0
  292. package/src/v2/runtime/endpoints/hono-single.ts +212 -0
  293. package/src/v2/runtime/endpoints/hono.ts +314 -0
  294. package/src/v2/runtime/endpoints/index.ts +4 -0
  295. package/src/v2/runtime/endpoints/single-route-helpers.ts +125 -0
  296. package/src/v2/runtime/express.ts +2 -0
  297. package/src/v2/runtime/handler.ts +3 -0
  298. package/src/v2/runtime/handlers/get-runtime-info.ts +79 -0
  299. package/src/v2/runtime/handlers/handle-connect.ts +76 -0
  300. package/src/v2/runtime/handlers/handle-run.ts +89 -0
  301. package/src/v2/runtime/handlers/handle-stop.ts +76 -0
  302. package/src/v2/runtime/handlers/handle-threads.ts +7 -0
  303. package/src/v2/runtime/handlers/handle-transcribe.ts +256 -0
  304. package/src/v2/runtime/handlers/header-utils.ts +24 -0
  305. package/src/v2/runtime/handlers/intelligence/connect.ts +65 -0
  306. package/src/v2/runtime/handlers/intelligence/run.ts +152 -0
  307. package/src/v2/runtime/handlers/intelligence/thread-names.ts +246 -0
  308. package/src/v2/runtime/handlers/intelligence/threads.ts +233 -0
  309. package/src/v2/runtime/handlers/shared/agent-utils.ts +136 -0
  310. package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -0
  311. package/src/v2/runtime/handlers/shared/json-response.ts +6 -0
  312. package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +25 -0
  313. package/src/v2/runtime/handlers/shared/sse-response.ts +100 -0
  314. package/src/v2/runtime/handlers/sse/connect.ts +24 -0
  315. package/src/v2/runtime/handlers/sse/run.ts +27 -0
  316. package/src/v2/runtime/index.ts +20 -0
  317. package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +605 -0
  318. package/src/v2/runtime/intelligence-platform/client.ts +659 -0
  319. package/src/v2/runtime/intelligence-platform/index.ts +10 -0
  320. package/src/v2/runtime/middleware-sse-parser.ts +200 -0
  321. package/src/v2/runtime/middleware.ts +115 -0
  322. package/src/v2/runtime/runner/__tests__/finalize-events.test.ts +109 -0
  323. package/src/v2/runtime/runner/__tests__/in-memory-runner.e2e.test.ts +775 -0
  324. package/src/v2/runtime/runner/__tests__/in-memory-runner.test.ts +363 -0
  325. package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +981 -0
  326. package/src/v2/runtime/runner/agent-runner.ts +36 -0
  327. package/src/v2/runtime/runner/in-memory.ts +381 -0
  328. package/src/v2/runtime/runner/index.ts +4 -0
  329. package/src/v2/runtime/runner/intelligence.ts +429 -0
  330. package/src/v2/runtime/runtime.ts +260 -0
  331. package/src/v2/runtime/telemetry/events.ts +35 -0
  332. package/src/v2/runtime/telemetry/index.ts +7 -0
  333. package/src/v2/runtime/telemetry/scarf-client.ts +39 -0
  334. package/src/v2/runtime/telemetry/telemetry-client.ts +70 -0
  335. package/src/v2/runtime/transcription-service/transcription-service.ts +11 -0
  336. package/tsconfig.json +9 -2
  337. package/tsdown.config.ts +1 -0
@@ -0,0 +1,1248 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { z } from "zod";
3
+ import { BasicAgent, defineTool, type ToolDefinition } from "../index";
4
+ import { EventType, type RunAgentInput } from "@ag-ui/client";
5
+ import { streamText } from "ai";
6
+ import {
7
+ mockStreamTextResponse,
8
+ textStart,
9
+ textDelta,
10
+ finish,
11
+ collectEvents,
12
+ toolCallStreamingStart,
13
+ toolCallDelta,
14
+ toolCall,
15
+ toolResult,
16
+ reasoningStart,
17
+ reasoningDelta,
18
+ reasoningEnd,
19
+ } from "./test-helpers";
20
+
21
+ // Mock the ai module
22
+ vi.mock("ai", () => ({
23
+ streamText: vi.fn(),
24
+ tool: vi.fn((config) => config),
25
+ }));
26
+
27
+ // Mock the SDK clients
28
+ vi.mock("@ai-sdk/openai", () => ({
29
+ createOpenAI: vi.fn(() => (modelId: string) => ({
30
+ modelId,
31
+ provider: "openai",
32
+ })),
33
+ }));
34
+
35
+ vi.mock("@ai-sdk/anthropic", () => ({
36
+ createAnthropic: vi.fn(() => (modelId: string) => ({
37
+ modelId,
38
+ provider: "anthropic",
39
+ })),
40
+ }));
41
+
42
+ vi.mock("@ai-sdk/google", () => ({
43
+ createGoogleGenerativeAI: vi.fn(() => (modelId: string) => ({
44
+ modelId,
45
+ provider: "google",
46
+ })),
47
+ }));
48
+
49
+ describe("BasicAgent", () => {
50
+ const originalEnv = process.env;
51
+
52
+ beforeEach(() => {
53
+ vi.clearAllMocks();
54
+ process.env = { ...originalEnv };
55
+ process.env.OPENAI_API_KEY = "test-key";
56
+ process.env.ANTHROPIC_API_KEY = "test-key";
57
+ process.env.GOOGLE_API_KEY = "test-key";
58
+ });
59
+
60
+ afterEach(() => {
61
+ process.env = originalEnv;
62
+ });
63
+
64
+ describe("Basic Event Emission", () => {
65
+ it("should emit RUN_STARTED and RUN_FINISHED events", async () => {
66
+ const agent = new BasicAgent({
67
+ model: "openai/gpt-4o",
68
+ });
69
+
70
+ vi.mocked(streamText).mockReturnValue(
71
+ mockStreamTextResponse([textDelta("Hello"), finish()]) as any,
72
+ );
73
+
74
+ const input: RunAgentInput = {
75
+ threadId: "thread1",
76
+ runId: "run1",
77
+ messages: [],
78
+ tools: [],
79
+ context: [],
80
+ state: {},
81
+ };
82
+
83
+ const events = await collectEvents(agent["run"](input));
84
+
85
+ expect(events[0]).toMatchObject({
86
+ type: EventType.RUN_STARTED,
87
+ threadId: "thread1",
88
+ runId: "run1",
89
+ });
90
+
91
+ expect(events[events.length - 1]).toMatchObject({
92
+ type: EventType.RUN_FINISHED,
93
+ threadId: "thread1",
94
+ runId: "run1",
95
+ });
96
+ });
97
+
98
+ it("should emit TEXT_MESSAGE_CHUNK events for text deltas", async () => {
99
+ const agent = new BasicAgent({
100
+ model: "openai/gpt-4o",
101
+ });
102
+
103
+ vi.mocked(streamText).mockReturnValue(
104
+ mockStreamTextResponse([
105
+ textDelta("Hello"),
106
+ textDelta(" world"),
107
+ finish(),
108
+ ]) as any,
109
+ );
110
+
111
+ const input: RunAgentInput = {
112
+ threadId: "thread1",
113
+ runId: "run1",
114
+ messages: [],
115
+ tools: [],
116
+ context: [],
117
+ state: {},
118
+ };
119
+
120
+ const events = await collectEvents(agent["run"](input));
121
+
122
+ const textEvents = events.filter(
123
+ (e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
124
+ );
125
+ expect(textEvents).toHaveLength(2);
126
+ expect(textEvents[0]).toMatchObject({
127
+ type: EventType.TEXT_MESSAGE_CHUNK,
128
+ role: "assistant",
129
+ delta: "Hello",
130
+ });
131
+ expect(textEvents[1]).toMatchObject({
132
+ type: EventType.TEXT_MESSAGE_CHUNK,
133
+ delta: " world",
134
+ });
135
+ });
136
+
137
+ it("should generate unique messageId when provider returns id '0'", async () => {
138
+ const agent = new BasicAgent({
139
+ model: "openai/gpt-4o",
140
+ });
141
+
142
+ vi.mocked(streamText).mockReturnValue(
143
+ mockStreamTextResponse([
144
+ textStart("0"), // Simulate Google Gemini returning "0"
145
+ textDelta("First message"),
146
+ finish(),
147
+ ]) as any,
148
+ );
149
+
150
+ const input: RunAgentInput = {
151
+ threadId: "thread1",
152
+ runId: "run1",
153
+ messages: [],
154
+ tools: [],
155
+ context: [],
156
+ state: {},
157
+ };
158
+
159
+ const events = await collectEvents(agent["run"](input));
160
+
161
+ const textEvents = events.filter(
162
+ (e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
163
+ );
164
+ expect(textEvents).toHaveLength(1);
165
+
166
+ // Verify that messageId is NOT "0" - should be a UUID
167
+ expect(textEvents[0].messageId).not.toBe("0");
168
+ expect(textEvents[0].messageId).toMatch(
169
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
170
+ );
171
+ });
172
+
173
+ it("should use provider-supplied messageId when it's not '0'", async () => {
174
+ const agent = new BasicAgent({
175
+ model: "openai/gpt-4o",
176
+ });
177
+
178
+ const validId = "msg_abc123";
179
+ vi.mocked(streamText).mockReturnValue(
180
+ mockStreamTextResponse([
181
+ textStart(validId), // Valid ID from provider
182
+ textDelta("Test message"),
183
+ finish(),
184
+ ]) as any,
185
+ );
186
+
187
+ const input: RunAgentInput = {
188
+ threadId: "thread1",
189
+ runId: "run1",
190
+ messages: [],
191
+ tools: [],
192
+ context: [],
193
+ state: {},
194
+ };
195
+
196
+ const events = await collectEvents(agent["run"](input));
197
+
198
+ const textEvents = events.filter(
199
+ (e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
200
+ );
201
+ expect(textEvents).toHaveLength(1);
202
+
203
+ // Verify that the valid ID from provider is used
204
+ expect(textEvents[0].messageId).toBe(validId);
205
+ });
206
+ });
207
+
208
+ describe("Tool Call Events", () => {
209
+ it("should emit tool call lifecycle events", async () => {
210
+ const agent = new BasicAgent({
211
+ model: "openai/gpt-4o",
212
+ });
213
+
214
+ vi.mocked(streamText).mockReturnValue(
215
+ mockStreamTextResponse([
216
+ toolCallStreamingStart("call1", "testTool"),
217
+ toolCallDelta("call1", '{"arg'),
218
+ toolCallDelta("call1", '":"val"}'),
219
+ toolCall("call1", "testTool", { arg: "val" }),
220
+ toolResult("call1", "testTool", { result: "success" }),
221
+ finish(),
222
+ ]) as any,
223
+ );
224
+
225
+ const input: RunAgentInput = {
226
+ threadId: "thread1",
227
+ runId: "run1",
228
+ messages: [],
229
+ tools: [],
230
+ context: [],
231
+ state: {},
232
+ };
233
+
234
+ const events = await collectEvents(agent["run"](input));
235
+
236
+ // Check for TOOL_CALL_START
237
+ const startEvent = events.find(
238
+ (e: any) => e.type === EventType.TOOL_CALL_START,
239
+ );
240
+ expect(startEvent).toMatchObject({
241
+ type: EventType.TOOL_CALL_START,
242
+ toolCallId: "call1",
243
+ toolCallName: "testTool",
244
+ });
245
+
246
+ // Check for TOOL_CALL_ARGS
247
+ const argsEvents = events.filter(
248
+ (e: any) => e.type === EventType.TOOL_CALL_ARGS,
249
+ );
250
+ expect(argsEvents).toHaveLength(2);
251
+
252
+ // Check for TOOL_CALL_END
253
+ const endEvent = events.find(
254
+ (e: any) => e.type === EventType.TOOL_CALL_END,
255
+ );
256
+ expect(endEvent).toMatchObject({
257
+ type: EventType.TOOL_CALL_END,
258
+ toolCallId: "call1",
259
+ });
260
+
261
+ // Check for TOOL_CALL_RESULT
262
+ const resultEvent = events.find(
263
+ (e: any) => e.type === EventType.TOOL_CALL_RESULT,
264
+ );
265
+ expect(resultEvent).toMatchObject({
266
+ type: EventType.TOOL_CALL_RESULT,
267
+ role: "tool",
268
+ toolCallId: "call1",
269
+ });
270
+ });
271
+ });
272
+
273
+ describe("Prompt Building", () => {
274
+ it("should not add system message when no prompt, context, or state", async () => {
275
+ const agent = new BasicAgent({
276
+ model: "openai/gpt-4o",
277
+ });
278
+
279
+ vi.mocked(streamText).mockReturnValue(
280
+ mockStreamTextResponse([finish()]) as any,
281
+ );
282
+
283
+ const input: RunAgentInput = {
284
+ threadId: "thread1",
285
+ runId: "run1",
286
+ messages: [{ id: "1", role: "user", content: "Hello" }],
287
+ tools: [],
288
+ context: [],
289
+ state: {},
290
+ };
291
+
292
+ await collectEvents(agent["run"](input));
293
+
294
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
295
+ expect(callArgs.messages).toHaveLength(1);
296
+ expect(callArgs.messages[0].role).toBe("user");
297
+ });
298
+
299
+ it("should prepend system message with config prompt", async () => {
300
+ const agent = new BasicAgent({
301
+ model: "openai/gpt-4o",
302
+ prompt: "You are a helpful assistant.",
303
+ });
304
+
305
+ vi.mocked(streamText).mockReturnValue(
306
+ mockStreamTextResponse([finish()]) as any,
307
+ );
308
+
309
+ const input: RunAgentInput = {
310
+ threadId: "thread1",
311
+ runId: "run1",
312
+ messages: [{ id: "1", role: "user", content: "Hello" }],
313
+ tools: [],
314
+ context: [],
315
+ state: {},
316
+ };
317
+
318
+ await collectEvents(agent["run"](input));
319
+
320
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
321
+ expect(callArgs.messages).toHaveLength(2);
322
+ expect(callArgs.messages[0]).toMatchObject({
323
+ role: "system",
324
+ content: "You are a helpful assistant.",
325
+ });
326
+ });
327
+
328
+ it("should include context in system message", async () => {
329
+ const agent = new BasicAgent({
330
+ model: "openai/gpt-4o",
331
+ });
332
+
333
+ vi.mocked(streamText).mockReturnValue(
334
+ mockStreamTextResponse([finish()]) as any,
335
+ );
336
+
337
+ const input: RunAgentInput = {
338
+ threadId: "thread1",
339
+ runId: "run1",
340
+ messages: [],
341
+ tools: [],
342
+ context: [
343
+ { description: "User Name", value: "John Doe" },
344
+ { description: "Location", value: "New York" },
345
+ ],
346
+ state: {},
347
+ };
348
+
349
+ await collectEvents(agent["run"](input));
350
+
351
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
352
+ const systemMessage = callArgs.messages[0];
353
+ expect(systemMessage.role).toBe("system");
354
+ expect(systemMessage.content).toContain("Context from the application");
355
+ expect(systemMessage.content).toContain("User Name");
356
+ expect(systemMessage.content).toContain("John Doe");
357
+ expect(systemMessage.content).toContain("Location");
358
+ expect(systemMessage.content).toContain("New York");
359
+ });
360
+
361
+ it("should include state in system message", async () => {
362
+ const agent = new BasicAgent({
363
+ model: "openai/gpt-4o",
364
+ });
365
+
366
+ vi.mocked(streamText).mockReturnValue(
367
+ mockStreamTextResponse([finish()]) as any,
368
+ );
369
+
370
+ const input: RunAgentInput = {
371
+ threadId: "thread1",
372
+ runId: "run1",
373
+ messages: [],
374
+ tools: [],
375
+ context: [],
376
+ state: { counter: 0, items: ["a", "b"] },
377
+ };
378
+
379
+ await collectEvents(agent["run"](input));
380
+
381
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
382
+ const systemMessage = callArgs.messages[0];
383
+ expect(systemMessage.role).toBe("system");
384
+ expect(systemMessage.content).toContain("Application State");
385
+ expect(systemMessage.content).toContain("AGUISendStateSnapshot");
386
+ expect(systemMessage.content).toContain("AGUISendStateDelta");
387
+ expect(systemMessage.content).toContain('"counter": 0');
388
+ expect(systemMessage.content).toContain('"items"');
389
+ });
390
+
391
+ it("should combine prompt, context, and state", async () => {
392
+ const agent = new BasicAgent({
393
+ model: "openai/gpt-4o",
394
+ prompt: "You are helpful.",
395
+ });
396
+
397
+ vi.mocked(streamText).mockReturnValue(
398
+ mockStreamTextResponse([finish()]) as any,
399
+ );
400
+
401
+ const input: RunAgentInput = {
402
+ threadId: "thread1",
403
+ runId: "run1",
404
+ messages: [],
405
+ tools: [],
406
+ context: [{ description: "Context", value: "Data" }],
407
+ state: { value: 1 },
408
+ };
409
+
410
+ await collectEvents(agent["run"](input));
411
+
412
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
413
+ const systemMessage = callArgs.messages[0];
414
+ expect(systemMessage.content).toContain("You are helpful.");
415
+ expect(systemMessage.content).toContain("Context from the application");
416
+ expect(systemMessage.content).toContain("Application State");
417
+
418
+ // Check order: prompt, then context, then state
419
+ const promptIndex = systemMessage.content.indexOf("You are helpful.");
420
+ const contextIndex = systemMessage.content.indexOf(
421
+ "Context from the application",
422
+ );
423
+ const stateIndex = systemMessage.content.indexOf("Application State");
424
+
425
+ expect(promptIndex).toBeLessThan(contextIndex);
426
+ expect(contextIndex).toBeLessThan(stateIndex);
427
+ });
428
+ });
429
+
430
+ describe("Forward System/Developer Messages", () => {
431
+ it("should ignore system messages by default", async () => {
432
+ const agent = new BasicAgent({
433
+ model: "openai/gpt-4o",
434
+ });
435
+
436
+ vi.mocked(streamText).mockReturnValue(
437
+ mockStreamTextResponse([finish()]) as any,
438
+ );
439
+
440
+ const input: RunAgentInput = {
441
+ threadId: "thread1",
442
+ runId: "run1",
443
+ messages: [
444
+ { id: "sys1", role: "system", content: "System instruction" },
445
+ { id: "user1", role: "user", content: "Hello" },
446
+ ],
447
+ tools: [],
448
+ context: [],
449
+ state: {},
450
+ };
451
+
452
+ await collectEvents(agent["run"](input));
453
+
454
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
455
+ // Should only have the user message, system message ignored
456
+ expect(callArgs.messages).toHaveLength(1);
457
+ expect(callArgs.messages[0].role).toBe("user");
458
+ });
459
+
460
+ it("should ignore developer messages by default", async () => {
461
+ const agent = new BasicAgent({
462
+ model: "openai/gpt-4o",
463
+ });
464
+
465
+ vi.mocked(streamText).mockReturnValue(
466
+ mockStreamTextResponse([finish()]) as any,
467
+ );
468
+
469
+ const input: RunAgentInput = {
470
+ threadId: "thread1",
471
+ runId: "run1",
472
+ messages: [
473
+ { id: "dev1", role: "developer", content: "Developer hint" },
474
+ { id: "user1", role: "user", content: "Hello" },
475
+ ],
476
+ tools: [],
477
+ context: [],
478
+ state: {},
479
+ };
480
+
481
+ await collectEvents(agent["run"](input));
482
+
483
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
484
+ // Should only have the user message, developer message ignored
485
+ expect(callArgs.messages).toHaveLength(1);
486
+ expect(callArgs.messages[0].role).toBe("user");
487
+ });
488
+
489
+ it("should forward system messages when forwardSystemMessages is true", async () => {
490
+ const agent = new BasicAgent({
491
+ model: "openai/gpt-4o",
492
+ forwardSystemMessages: true,
493
+ });
494
+
495
+ vi.mocked(streamText).mockReturnValue(
496
+ mockStreamTextResponse([finish()]) as any,
497
+ );
498
+
499
+ const input: RunAgentInput = {
500
+ threadId: "thread1",
501
+ runId: "run1",
502
+ messages: [
503
+ { id: "sys1", role: "system", content: "System instruction" },
504
+ { id: "user1", role: "user", content: "Hello" },
505
+ ],
506
+ tools: [],
507
+ context: [],
508
+ state: {},
509
+ };
510
+
511
+ await collectEvents(agent["run"](input));
512
+
513
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
514
+ expect(callArgs.messages).toHaveLength(2);
515
+ expect(callArgs.messages[0]).toMatchObject({
516
+ role: "system",
517
+ content: "System instruction",
518
+ });
519
+ expect(callArgs.messages[1].role).toBe("user");
520
+ });
521
+
522
+ it("should forward developer messages as system when forwardDeveloperMessages is true", async () => {
523
+ const agent = new BasicAgent({
524
+ model: "openai/gpt-4o",
525
+ forwardDeveloperMessages: true,
526
+ });
527
+
528
+ vi.mocked(streamText).mockReturnValue(
529
+ mockStreamTextResponse([finish()]) as any,
530
+ );
531
+
532
+ const input: RunAgentInput = {
533
+ threadId: "thread1",
534
+ runId: "run1",
535
+ messages: [
536
+ { id: "dev1", role: "developer", content: "Developer hint" },
537
+ { id: "user1", role: "user", content: "Hello" },
538
+ ],
539
+ tools: [],
540
+ context: [],
541
+ state: {},
542
+ };
543
+
544
+ await collectEvents(agent["run"](input));
545
+
546
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
547
+ expect(callArgs.messages).toHaveLength(2);
548
+ // Developer messages are converted to system role
549
+ expect(callArgs.messages[0]).toMatchObject({
550
+ role: "system",
551
+ content: "Developer hint",
552
+ });
553
+ expect(callArgs.messages[1].role).toBe("user");
554
+ });
555
+
556
+ it("should forward both system and developer messages when both flags are true", async () => {
557
+ const agent = new BasicAgent({
558
+ model: "openai/gpt-4o",
559
+ forwardSystemMessages: true,
560
+ forwardDeveloperMessages: true,
561
+ });
562
+
563
+ vi.mocked(streamText).mockReturnValue(
564
+ mockStreamTextResponse([finish()]) as any,
565
+ );
566
+
567
+ const input: RunAgentInput = {
568
+ threadId: "thread1",
569
+ runId: "run1",
570
+ messages: [
571
+ { id: "sys1", role: "system", content: "System instruction" },
572
+ { id: "dev1", role: "developer", content: "Developer hint" },
573
+ { id: "user1", role: "user", content: "Hello" },
574
+ ],
575
+ tools: [],
576
+ context: [],
577
+ state: {},
578
+ };
579
+
580
+ await collectEvents(agent["run"](input));
581
+
582
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
583
+ expect(callArgs.messages).toHaveLength(3);
584
+ expect(callArgs.messages[0]).toMatchObject({
585
+ role: "system",
586
+ content: "System instruction",
587
+ });
588
+ expect(callArgs.messages[1]).toMatchObject({
589
+ role: "system",
590
+ content: "Developer hint",
591
+ });
592
+ expect(callArgs.messages[2].role).toBe("user");
593
+ });
594
+
595
+ it("should place config prompt before forwarded system/developer messages", async () => {
596
+ const agent = new BasicAgent({
597
+ model: "openai/gpt-4o",
598
+ prompt: "You are a helpful assistant.",
599
+ forwardSystemMessages: true,
600
+ forwardDeveloperMessages: true,
601
+ });
602
+
603
+ vi.mocked(streamText).mockReturnValue(
604
+ mockStreamTextResponse([finish()]) as any,
605
+ );
606
+
607
+ const input: RunAgentInput = {
608
+ threadId: "thread1",
609
+ runId: "run1",
610
+ messages: [
611
+ { id: "sys1", role: "system", content: "System instruction" },
612
+ { id: "dev1", role: "developer", content: "Developer hint" },
613
+ { id: "user1", role: "user", content: "Hello" },
614
+ ],
615
+ tools: [],
616
+ context: [],
617
+ state: {},
618
+ };
619
+
620
+ await collectEvents(agent["run"](input));
621
+
622
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
623
+ // Config prompt is prepended as first system message
624
+ expect(callArgs.messages).toHaveLength(4);
625
+ expect(callArgs.messages[0]).toMatchObject({
626
+ role: "system",
627
+ content: "You are a helpful assistant.",
628
+ });
629
+ expect(callArgs.messages[1]).toMatchObject({
630
+ role: "system",
631
+ content: "System instruction",
632
+ });
633
+ expect(callArgs.messages[2]).toMatchObject({
634
+ role: "system",
635
+ content: "Developer hint",
636
+ });
637
+ expect(callArgs.messages[3].role).toBe("user");
638
+ });
639
+ });
640
+
641
+ describe("Tool Configuration", () => {
642
+ it("should include tools from config", async () => {
643
+ const tool1 = defineTool({
644
+ name: "configTool",
645
+ description: "A config tool",
646
+ parameters: z.object({ input: z.string() }),
647
+ execute: async () => ({ result: "ok" }),
648
+ });
649
+
650
+ const agent = new BasicAgent({
651
+ model: "openai/gpt-4o",
652
+ tools: [tool1],
653
+ });
654
+
655
+ vi.mocked(streamText).mockReturnValue(
656
+ mockStreamTextResponse([finish()]) as any,
657
+ );
658
+
659
+ const input: RunAgentInput = {
660
+ threadId: "thread1",
661
+ runId: "run1",
662
+ messages: [],
663
+ tools: [],
664
+ context: [],
665
+ state: {},
666
+ };
667
+
668
+ await collectEvents(agent["run"](input));
669
+
670
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
671
+ expect(callArgs.tools).toHaveProperty("configTool");
672
+ });
673
+
674
+ it("should merge config tools with input tools", async () => {
675
+ const configTool = defineTool({
676
+ name: "configTool",
677
+ description: "From config",
678
+ parameters: z.object({}),
679
+ execute: async () => ({ result: "ok" }),
680
+ });
681
+
682
+ const agent = new BasicAgent({
683
+ model: "openai/gpt-4o",
684
+ tools: [configTool],
685
+ });
686
+
687
+ vi.mocked(streamText).mockReturnValue(
688
+ mockStreamTextResponse([finish()]) as any,
689
+ );
690
+
691
+ const input: RunAgentInput = {
692
+ threadId: "thread1",
693
+ runId: "run1",
694
+ messages: [],
695
+ tools: [
696
+ {
697
+ name: "inputTool",
698
+ description: "From input",
699
+ parameters: { type: "object", properties: {} },
700
+ },
701
+ ],
702
+ context: [],
703
+ state: {},
704
+ };
705
+
706
+ await collectEvents(agent["run"](input));
707
+
708
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
709
+ expect(callArgs.tools).toHaveProperty("configTool");
710
+ expect(callArgs.tools).toHaveProperty("inputTool");
711
+ });
712
+
713
+ it("should always include state update tools", async () => {
714
+ const agent = new BasicAgent({
715
+ model: "openai/gpt-4o",
716
+ });
717
+
718
+ vi.mocked(streamText).mockReturnValue(
719
+ mockStreamTextResponse([finish()]) as any,
720
+ );
721
+
722
+ const input: RunAgentInput = {
723
+ threadId: "thread1",
724
+ runId: "run1",
725
+ messages: [],
726
+ tools: [],
727
+ context: [],
728
+ state: {},
729
+ };
730
+
731
+ await collectEvents(agent["run"](input));
732
+
733
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
734
+ expect(callArgs.tools).toHaveProperty("AGUISendStateSnapshot");
735
+ expect(callArgs.tools).toHaveProperty("AGUISendStateDelta");
736
+ });
737
+ });
738
+
739
+ describe("Property Overrides", () => {
740
+ it("should respect overridable properties", async () => {
741
+ const agent = new BasicAgent({
742
+ model: "openai/gpt-4o",
743
+ temperature: 0.5,
744
+ overridableProperties: ["temperature"],
745
+ });
746
+
747
+ vi.mocked(streamText).mockReturnValue(
748
+ mockStreamTextResponse([finish()]) as any,
749
+ );
750
+
751
+ const input: RunAgentInput = {
752
+ threadId: "thread1",
753
+ runId: "run1",
754
+ messages: [],
755
+ tools: [],
756
+ context: [],
757
+ state: {},
758
+ forwardedProps: { temperature: 0.9 },
759
+ };
760
+
761
+ await collectEvents(agent["run"](input));
762
+
763
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
764
+ expect(callArgs.temperature).toBe(0.9);
765
+ });
766
+
767
+ it("should ignore non-overridable properties", async () => {
768
+ const agent = new BasicAgent({
769
+ model: "openai/gpt-4o",
770
+ temperature: 0.5,
771
+ overridableProperties: [], // No properties can be overridden
772
+ });
773
+
774
+ vi.mocked(streamText).mockReturnValue(
775
+ mockStreamTextResponse([finish()]) as any,
776
+ );
777
+
778
+ const input: RunAgentInput = {
779
+ threadId: "thread1",
780
+ runId: "run1",
781
+ messages: [],
782
+ tools: [],
783
+ context: [],
784
+ state: {},
785
+ forwardedProps: { temperature: 0.9 },
786
+ };
787
+
788
+ await collectEvents(agent["run"](input));
789
+
790
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
791
+ expect(callArgs.temperature).toBe(0.5); // Original value, not overridden
792
+ });
793
+ });
794
+
795
+ describe("Error Handling", () => {
796
+ it("should emit RUN_ERROR event on failure", async () => {
797
+ const agent = new BasicAgent({
798
+ model: "openai/gpt-4o",
799
+ });
800
+
801
+ vi.mocked(streamText).mockImplementation(() => {
802
+ throw new Error("Test error");
803
+ });
804
+
805
+ const input: RunAgentInput = {
806
+ threadId: "thread1",
807
+ runId: "run1",
808
+ messages: [],
809
+ tools: [],
810
+ context: [],
811
+ state: {},
812
+ };
813
+
814
+ try {
815
+ await collectEvents(agent["run"](input));
816
+ expect.fail("Should have thrown");
817
+ } catch (error: any) {
818
+ // Error is expected - check that we got a RUN_ERROR event
819
+ // Note: The error is thrown after emitting the event
820
+ expect(error.message).toContain("Test error");
821
+ }
822
+ });
823
+ });
824
+
825
+ describe("Reasoning Event Emission", () => {
826
+ it("should emit full reasoning lifecycle events", async () => {
827
+ const agent = new BasicAgent({
828
+ model: "openai/gpt-4o",
829
+ });
830
+
831
+ vi.mocked(streamText).mockReturnValue(
832
+ mockStreamTextResponse([
833
+ reasoningStart(),
834
+ reasoningDelta("Let me think..."),
835
+ reasoningDelta(" about this."),
836
+ reasoningEnd(),
837
+ finish(),
838
+ ]) as any,
839
+ );
840
+
841
+ const input: RunAgentInput = {
842
+ threadId: "thread1",
843
+ runId: "run1",
844
+ messages: [],
845
+ tools: [],
846
+ context: [],
847
+ state: {},
848
+ };
849
+
850
+ const events = await collectEvents(agent["run"](input));
851
+
852
+ // Verify event order
853
+ const eventTypes = events.map((e: any) => e.type);
854
+ expect(eventTypes[0]).toBe(EventType.RUN_STARTED);
855
+
856
+ const reasoningStartIdx = eventTypes.indexOf(EventType.REASONING_START);
857
+ const reasoningMsgStartIdx = eventTypes.indexOf(
858
+ EventType.REASONING_MESSAGE_START,
859
+ );
860
+ const reasoningContentIndices = eventTypes.reduce(
861
+ (acc: number[], type: string, idx: number) =>
862
+ type === EventType.REASONING_MESSAGE_CONTENT ? [...acc, idx] : acc,
863
+ [],
864
+ );
865
+ const reasoningMsgEndIdx = eventTypes.indexOf(
866
+ EventType.REASONING_MESSAGE_END,
867
+ );
868
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
869
+
870
+ expect(reasoningStartIdx).toBeGreaterThan(0);
871
+ expect(reasoningMsgStartIdx).toBeGreaterThan(reasoningStartIdx);
872
+ expect(reasoningContentIndices).toHaveLength(2);
873
+ expect(reasoningContentIndices[0]).toBeGreaterThan(reasoningMsgStartIdx);
874
+ expect(reasoningMsgEndIdx).toBeGreaterThan(
875
+ reasoningContentIndices[reasoningContentIndices.length - 1],
876
+ );
877
+ expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
878
+
879
+ // Verify consistent messageId across all reasoning events
880
+ const reasoningEvents = events.filter((e: any) =>
881
+ [
882
+ EventType.REASONING_START,
883
+ EventType.REASONING_MESSAGE_START,
884
+ EventType.REASONING_MESSAGE_CONTENT,
885
+ EventType.REASONING_MESSAGE_END,
886
+ EventType.REASONING_END,
887
+ ].includes(e.type),
888
+ );
889
+ const messageIds = reasoningEvents.map((e: any) => e.messageId);
890
+ expect(new Set(messageIds).size).toBe(1);
891
+
892
+ // Verify REASONING_MESSAGE_START has role "reasoning"
893
+ const msgStartEvent = events.find(
894
+ (e: any) => e.type === EventType.REASONING_MESSAGE_START,
895
+ );
896
+ expect(msgStartEvent).toMatchObject({ role: "reasoning" });
897
+
898
+ // Verify content deltas
899
+ const contentEvents = events.filter(
900
+ (e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
901
+ );
902
+ expect(contentEvents[0]).toMatchObject({ delta: "Let me think..." });
903
+ expect(contentEvents[1]).toMatchObject({ delta: " about this." });
904
+
905
+ // Verify last event is RUN_FINISHED
906
+ expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
907
+ });
908
+
909
+ it("should emit reasoning events followed by text events", async () => {
910
+ const agent = new BasicAgent({
911
+ model: "openai/gpt-4o",
912
+ });
913
+
914
+ vi.mocked(streamText).mockReturnValue(
915
+ mockStreamTextResponse([
916
+ reasoningStart(),
917
+ reasoningDelta("thinking"),
918
+ reasoningEnd(),
919
+ textDelta("Hello"),
920
+ finish(),
921
+ ]) as any,
922
+ );
923
+
924
+ const input: RunAgentInput = {
925
+ threadId: "thread1",
926
+ runId: "run1",
927
+ messages: [],
928
+ tools: [],
929
+ context: [],
930
+ state: {},
931
+ };
932
+
933
+ const events = await collectEvents(agent["run"](input));
934
+ const eventTypes = events.map((e: any) => e.type);
935
+
936
+ // Reasoning events should come before text events
937
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
938
+ const textChunkIdx = eventTypes.indexOf(EventType.TEXT_MESSAGE_CHUNK);
939
+ expect(reasoningEndIdx).toBeLessThan(textChunkIdx);
940
+
941
+ // Reasoning messageId should differ from text messageId
942
+ const reasoningEvent = events.find(
943
+ (e: any) => e.type === EventType.REASONING_START,
944
+ );
945
+ const textEvent = events.find(
946
+ (e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
947
+ );
948
+ expect(reasoningEvent.messageId).not.toBe(textEvent.messageId);
949
+ });
950
+
951
+ it("should use provider-supplied reasoning id", async () => {
952
+ const agent = new BasicAgent({
953
+ model: "openai/gpt-4o",
954
+ });
955
+
956
+ vi.mocked(streamText).mockReturnValue(
957
+ mockStreamTextResponse([
958
+ reasoningStart("reasoning-msg-123"),
959
+ reasoningDelta("content"),
960
+ reasoningEnd(),
961
+ finish(),
962
+ ]) as any,
963
+ );
964
+
965
+ const input: RunAgentInput = {
966
+ threadId: "thread1",
967
+ runId: "run1",
968
+ messages: [],
969
+ tools: [],
970
+ context: [],
971
+ state: {},
972
+ };
973
+
974
+ const events = await collectEvents(agent["run"](input));
975
+
976
+ const reasoningEvents = events.filter((e: any) =>
977
+ [
978
+ EventType.REASONING_START,
979
+ EventType.REASONING_MESSAGE_START,
980
+ EventType.REASONING_MESSAGE_CONTENT,
981
+ EventType.REASONING_MESSAGE_END,
982
+ EventType.REASONING_END,
983
+ ].includes(e.type),
984
+ );
985
+
986
+ for (const event of reasoningEvents) {
987
+ expect(event.messageId).toBe("reasoning-msg-123");
988
+ }
989
+ });
990
+
991
+ it("should generate unique reasoningMessageId when provider returns id '0'", async () => {
992
+ const agent = new BasicAgent({
993
+ model: "openai/gpt-4o",
994
+ });
995
+
996
+ vi.mocked(streamText).mockReturnValue(
997
+ mockStreamTextResponse([
998
+ reasoningStart("0"),
999
+ reasoningDelta("content"),
1000
+ reasoningEnd(),
1001
+ finish(),
1002
+ ]) as any,
1003
+ );
1004
+
1005
+ const input: RunAgentInput = {
1006
+ threadId: "thread1",
1007
+ runId: "run1",
1008
+ messages: [],
1009
+ tools: [],
1010
+ context: [],
1011
+ state: {},
1012
+ };
1013
+
1014
+ const events = await collectEvents(agent["run"](input));
1015
+
1016
+ const reasoningEvent = events.find(
1017
+ (e: any) => e.type === EventType.REASONING_START,
1018
+ );
1019
+ expect(reasoningEvent.messageId).not.toBe("0");
1020
+ expect(reasoningEvent.messageId).toMatch(
1021
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
1022
+ );
1023
+ });
1024
+
1025
+ it("should handle empty reasoning content", async () => {
1026
+ const agent = new BasicAgent({
1027
+ model: "openai/gpt-4o",
1028
+ });
1029
+
1030
+ vi.mocked(streamText).mockReturnValue(
1031
+ mockStreamTextResponse([
1032
+ reasoningStart(),
1033
+ reasoningDelta(""),
1034
+ reasoningEnd(),
1035
+ finish(),
1036
+ ]) as any,
1037
+ );
1038
+
1039
+ const input: RunAgentInput = {
1040
+ threadId: "thread1",
1041
+ runId: "run1",
1042
+ messages: [],
1043
+ tools: [],
1044
+ context: [],
1045
+ state: {},
1046
+ };
1047
+
1048
+ const events = await collectEvents(agent["run"](input));
1049
+
1050
+ const contentEvent = events.find(
1051
+ (e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
1052
+ );
1053
+ expect(contentEvent).toMatchObject({ delta: "" });
1054
+
1055
+ // Full lifecycle should still complete
1056
+ const eventTypes = events.map((e: any) => e.type);
1057
+ expect(eventTypes).toContain(EventType.REASONING_START);
1058
+ expect(eventTypes).toContain(EventType.REASONING_MESSAGE_START);
1059
+ expect(eventTypes).toContain(EventType.REASONING_MESSAGE_END);
1060
+ expect(eventTypes).toContain(EventType.REASONING_END);
1061
+ expect(eventTypes).toContain(EventType.RUN_FINISHED);
1062
+ });
1063
+
1064
+ it("should handle reasoning-only stream (no text output)", async () => {
1065
+ const agent = new BasicAgent({
1066
+ model: "openai/gpt-4o",
1067
+ });
1068
+
1069
+ vi.mocked(streamText).mockReturnValue(
1070
+ mockStreamTextResponse([
1071
+ reasoningStart(),
1072
+ reasoningDelta("Deep thought"),
1073
+ reasoningEnd(),
1074
+ finish(),
1075
+ ]) as any,
1076
+ );
1077
+
1078
+ const input: RunAgentInput = {
1079
+ threadId: "thread1",
1080
+ runId: "run1",
1081
+ messages: [],
1082
+ tools: [],
1083
+ context: [],
1084
+ state: {},
1085
+ };
1086
+
1087
+ const events = await collectEvents(agent["run"](input));
1088
+
1089
+ // No TEXT_MESSAGE_CHUNK events
1090
+ const textEvents = events.filter(
1091
+ (e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
1092
+ );
1093
+ expect(textEvents).toHaveLength(0);
1094
+
1095
+ // Reasoning events are present
1096
+ const reasoningContentEvents = events.filter(
1097
+ (e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
1098
+ );
1099
+ expect(reasoningContentEvents).toHaveLength(1);
1100
+ expect(reasoningContentEvents[0]).toMatchObject({
1101
+ delta: "Deep thought",
1102
+ });
1103
+ });
1104
+
1105
+ it("should handle reasoning interleaved with tool calls", async () => {
1106
+ const agent = new BasicAgent({
1107
+ model: "openai/gpt-4o",
1108
+ });
1109
+
1110
+ vi.mocked(streamText).mockReturnValue(
1111
+ mockStreamTextResponse([
1112
+ reasoningStart(),
1113
+ reasoningDelta("I need to call a tool"),
1114
+ reasoningEnd(),
1115
+ toolCallStreamingStart("call1", "testTool"),
1116
+ toolCallDelta("call1", '{"arg":"val"}'),
1117
+ toolCall("call1", "testTool", { arg: "val" }),
1118
+ toolResult("call1", "testTool", { result: "success" }),
1119
+ finish(),
1120
+ ]) as any,
1121
+ );
1122
+
1123
+ const input: RunAgentInput = {
1124
+ threadId: "thread1",
1125
+ runId: "run1",
1126
+ messages: [],
1127
+ tools: [],
1128
+ context: [],
1129
+ state: {},
1130
+ };
1131
+
1132
+ const events = await collectEvents(agent["run"](input));
1133
+ const eventTypes = events.map((e: any) => e.type);
1134
+
1135
+ // Reasoning events precede tool call events
1136
+ const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
1137
+ const toolCallStartIdx = eventTypes.indexOf(EventType.TOOL_CALL_START);
1138
+ expect(reasoningEndIdx).toBeLessThan(toolCallStartIdx);
1139
+
1140
+ // Both lifecycles complete
1141
+ expect(eventTypes).toContain(EventType.REASONING_START);
1142
+ expect(eventTypes).toContain(EventType.REASONING_END);
1143
+ expect(eventTypes).toContain(EventType.TOOL_CALL_START);
1144
+ expect(eventTypes).toContain(EventType.TOOL_CALL_END);
1145
+ });
1146
+ });
1147
+
1148
+ describe("Provider Options", () => {
1149
+ it("should pass providerOptions to streamText", async () => {
1150
+ const agent = new BasicAgent({
1151
+ model: "openai/gpt-4o",
1152
+ providerOptions: {
1153
+ openai: { reasoningEffort: "high", reasoningSummary: "detailed" },
1154
+ },
1155
+ });
1156
+
1157
+ vi.mocked(streamText).mockReturnValue(
1158
+ mockStreamTextResponse([finish()]) as any,
1159
+ );
1160
+
1161
+ const input: RunAgentInput = {
1162
+ threadId: "thread1",
1163
+ runId: "run1",
1164
+ messages: [],
1165
+ tools: [],
1166
+ context: [],
1167
+ state: {},
1168
+ };
1169
+
1170
+ await collectEvents(agent["run"](input));
1171
+
1172
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
1173
+ expect(callArgs.providerOptions).toEqual({
1174
+ openai: { reasoningEffort: "high", reasoningSummary: "detailed" },
1175
+ });
1176
+ });
1177
+
1178
+ it("should allow providerOptions override via forwardedProps when overridable", async () => {
1179
+ const agent = new BasicAgent({
1180
+ model: "openai/gpt-4o",
1181
+ providerOptions: {
1182
+ openai: { reasoningEffort: "low" },
1183
+ },
1184
+ overridableProperties: ["providerOptions"],
1185
+ });
1186
+
1187
+ vi.mocked(streamText).mockReturnValue(
1188
+ mockStreamTextResponse([finish()]) as any,
1189
+ );
1190
+
1191
+ const input: RunAgentInput = {
1192
+ threadId: "thread1",
1193
+ runId: "run1",
1194
+ messages: [],
1195
+ tools: [],
1196
+ context: [],
1197
+ state: {},
1198
+ forwardedProps: {
1199
+ providerOptions: {
1200
+ openai: { reasoningEffort: "high" },
1201
+ },
1202
+ },
1203
+ };
1204
+
1205
+ await collectEvents(agent["run"](input));
1206
+
1207
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
1208
+ expect(callArgs.providerOptions).toEqual({
1209
+ openai: { reasoningEffort: "high" },
1210
+ });
1211
+ });
1212
+
1213
+ it("should NOT allow providerOptions override when not in overridableProperties", async () => {
1214
+ const agent = new BasicAgent({
1215
+ model: "openai/gpt-4o",
1216
+ providerOptions: {
1217
+ openai: { reasoningEffort: "low" },
1218
+ },
1219
+ overridableProperties: [],
1220
+ });
1221
+
1222
+ vi.mocked(streamText).mockReturnValue(
1223
+ mockStreamTextResponse([finish()]) as any,
1224
+ );
1225
+
1226
+ const input: RunAgentInput = {
1227
+ threadId: "thread1",
1228
+ runId: "run1",
1229
+ messages: [],
1230
+ tools: [],
1231
+ context: [],
1232
+ state: {},
1233
+ forwardedProps: {
1234
+ providerOptions: {
1235
+ openai: { reasoningEffort: "high" },
1236
+ },
1237
+ },
1238
+ };
1239
+
1240
+ await collectEvents(agent["run"](input));
1241
+
1242
+ const callArgs = vi.mocked(streamText).mock.calls[0][0];
1243
+ expect(callArgs.providerOptions).toEqual({
1244
+ openai: { reasoningEffort: "low" },
1245
+ });
1246
+ });
1247
+ });
1248
+ });