@adonis-agora/agent 0.61.0 → 0.63.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 (664) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +12 -7
  3. package/dist/configure.d.ts +7 -5
  4. package/dist/configure.d.ts.map +1 -1
  5. package/dist/configure.js +7 -5
  6. package/dist/configure.js.map +1 -1
  7. package/dist/providers/a2a_provider.d.ts +14 -0
  8. package/dist/providers/a2a_provider.d.ts.map +1 -0
  9. package/dist/providers/a2a_provider.js +136 -0
  10. package/dist/providers/a2a_provider.js.map +1 -0
  11. package/dist/providers/agent_provider.d.ts.map +1 -1
  12. package/dist/providers/agent_provider.js +81 -25
  13. package/dist/providers/agent_provider.js.map +1 -1
  14. package/dist/providers/mcp_provider.d.ts +3 -0
  15. package/dist/providers/mcp_provider.d.ts.map +1 -1
  16. package/dist/providers/mcp_provider.js +147 -62
  17. package/dist/providers/mcp_provider.js.map +1 -1
  18. package/dist/src/a2a/auth.d.ts +67 -0
  19. package/dist/src/a2a/auth.d.ts.map +1 -0
  20. package/dist/src/a2a/auth.js +47 -0
  21. package/dist/src/a2a/auth.js.map +1 -0
  22. package/dist/src/a2a/define_config.d.ts +74 -0
  23. package/dist/src/a2a/define_config.d.ts.map +1 -0
  24. package/dist/src/a2a/define_config.js +5 -0
  25. package/dist/src/a2a/define_config.js.map +1 -0
  26. package/dist/src/a2a/gate.d.ts +23 -0
  27. package/dist/src/a2a/gate.d.ts.map +1 -0
  28. package/dist/src/a2a/gate.js +56 -0
  29. package/dist/src/a2a/gate.js.map +1 -0
  30. package/dist/src/a2a/handler.d.ts +65 -0
  31. package/dist/src/a2a/handler.d.ts.map +1 -0
  32. package/dist/src/a2a/handler.js +322 -0
  33. package/dist/src/a2a/handler.js.map +1 -0
  34. package/dist/src/a2a/index.d.ts +15 -0
  35. package/dist/src/a2a/index.d.ts.map +1 -0
  36. package/dist/src/a2a/index.js +9 -0
  37. package/dist/src/a2a/index.js.map +1 -0
  38. package/dist/src/a2a/permission-tool.d.ts +17 -0
  39. package/dist/src/a2a/permission-tool.d.ts.map +1 -0
  40. package/dist/src/a2a/permission-tool.js +70 -0
  41. package/dist/src/a2a/permission-tool.js.map +1 -0
  42. package/dist/src/a2a/protocol.d.ts +100 -0
  43. package/dist/src/a2a/protocol.d.ts.map +1 -0
  44. package/dist/src/a2a/protocol.js +106 -0
  45. package/dist/src/a2a/protocol.js.map +1 -0
  46. package/dist/src/a2a/runtime.d.ts +6 -0
  47. package/dist/src/a2a/runtime.d.ts.map +1 -0
  48. package/dist/src/a2a/runtime.js +13 -0
  49. package/dist/src/a2a/runtime.js.map +1 -0
  50. package/dist/src/a2a/server_middleware.d.ts +13 -0
  51. package/dist/src/a2a/server_middleware.d.ts.map +1 -0
  52. package/dist/src/a2a/server_middleware.js +18 -0
  53. package/dist/src/a2a/server_middleware.js.map +1 -0
  54. package/dist/src/a2a/store.d.ts +79 -0
  55. package/dist/src/a2a/store.d.ts.map +1 -0
  56. package/dist/src/a2a/store.js +151 -0
  57. package/dist/src/a2a/store.js.map +1 -0
  58. package/dist/src/a2a/turn.d.ts +80 -0
  59. package/dist/src/a2a/turn.d.ts.map +1 -0
  60. package/dist/src/a2a/turn.js +211 -0
  61. package/dist/src/a2a/turn.js.map +1 -0
  62. package/dist/src/action-proposal-executor.d.ts +3 -0
  63. package/dist/src/action-proposal-executor.d.ts.map +1 -1
  64. package/dist/src/action-proposal-executor.js +10 -0
  65. package/dist/src/action-proposal-executor.js.map +1 -1
  66. package/dist/src/action-proposal-service.d.ts +7 -2
  67. package/dist/src/action-proposal-service.d.ts.map +1 -1
  68. package/dist/src/action-proposal-service.js +21 -16
  69. package/dist/src/action-proposal-service.js.map +1 -1
  70. package/dist/src/action-proposal-text.d.ts +42 -3
  71. package/dist/src/action-proposal-text.d.ts.map +1 -1
  72. package/dist/src/action-proposal-text.js +80 -12
  73. package/dist/src/action-proposal-text.js.map +1 -1
  74. package/dist/src/action-proposal-worker.d.ts +2 -1
  75. package/dist/src/action-proposal-worker.d.ts.map +1 -1
  76. package/dist/src/action-proposal-worker.js +9 -2
  77. package/dist/src/action-proposal-worker.js.map +1 -1
  78. package/dist/src/actor-resolver.d.ts +12 -4
  79. package/dist/src/actor-resolver.d.ts.map +1 -1
  80. package/dist/src/actor-resolver.js +24 -7
  81. package/dist/src/actor-resolver.js.map +1 -1
  82. package/dist/src/ag-ui/adapter.d.ts.map +1 -1
  83. package/dist/src/ag-ui/adapter.js +115 -17
  84. package/dist/src/ag-ui/adapter.js.map +1 -1
  85. package/dist/src/ag-ui/core/encoder.d.ts +106 -0
  86. package/dist/src/ag-ui/core/encoder.d.ts.map +1 -0
  87. package/dist/src/ag-ui/core/encoder.js +534 -0
  88. package/dist/src/ag-ui/core/encoder.js.map +1 -0
  89. package/dist/src/ag-ui/core/index.d.ts +12 -0
  90. package/dist/src/ag-ui/core/index.d.ts.map +1 -0
  91. package/dist/src/ag-ui/core/index.js +12 -0
  92. package/dist/src/ag-ui/core/index.js.map +1 -0
  93. package/dist/src/ag-ui/core/input.d.ts +92 -0
  94. package/dist/src/ag-ui/core/input.d.ts.map +1 -0
  95. package/dist/src/ag-ui/core/input.js +246 -0
  96. package/dist/src/ag-ui/core/input.js.map +1 -0
  97. package/dist/src/ag-ui/core/interrupt-id.d.ts +31 -0
  98. package/dist/src/ag-ui/core/interrupt-id.d.ts.map +1 -0
  99. package/dist/src/ag-ui/core/interrupt-id.js +48 -0
  100. package/dist/src/ag-ui/core/interrupt-id.js.map +1 -0
  101. package/dist/src/ag-ui/{proposal-decision.d.ts → core/proposal-decision.d.ts} +1 -1
  102. package/dist/src/ag-ui/core/proposal-decision.d.ts.map +1 -0
  103. package/dist/src/ag-ui/{proposal-decision.js → core/proposal-decision.js} +3 -6
  104. package/dist/src/ag-ui/core/proposal-decision.js.map +1 -0
  105. package/dist/src/ag-ui/core/stream.d.ts +49 -0
  106. package/dist/src/ag-ui/core/stream.d.ts.map +1 -0
  107. package/dist/src/ag-ui/core/stream.js +90 -0
  108. package/dist/src/ag-ui/core/stream.js.map +1 -0
  109. package/dist/src/ag-ui/core/types.d.ts +249 -0
  110. package/dist/src/ag-ui/core/types.d.ts.map +1 -0
  111. package/dist/src/ag-ui/core/types.js +35 -0
  112. package/dist/src/ag-ui/core/types.js.map +1 -0
  113. package/dist/src/ag-ui/encoder.d.ts +3 -4
  114. package/dist/src/ag-ui/encoder.d.ts.map +1 -1
  115. package/dist/src/ag-ui/encoder.js +10 -11
  116. package/dist/src/ag-ui/encoder.js.map +1 -1
  117. package/dist/src/ag-ui/frames.d.ts +8 -5
  118. package/dist/src/ag-ui/frames.d.ts.map +1 -1
  119. package/dist/src/ag-ui/frames.js +21 -7
  120. package/dist/src/ag-ui/frames.js.map +1 -1
  121. package/dist/src/ag-ui/index.d.ts +3 -5
  122. package/dist/src/ag-ui/index.d.ts.map +1 -1
  123. package/dist/src/ag-ui/index.js +3 -5
  124. package/dist/src/ag-ui/index.js.map +1 -1
  125. package/dist/src/ag-ui/stream.d.ts +3 -4
  126. package/dist/src/ag-ui/stream.d.ts.map +1 -1
  127. package/dist/src/ag-ui/stream.js +4 -5
  128. package/dist/src/ag-ui/stream.js.map +1 -1
  129. package/dist/src/agent-deps-factory.d.ts +3 -0
  130. package/dist/src/agent-deps-factory.d.ts.map +1 -1
  131. package/dist/src/agent-deps-factory.js +3 -0
  132. package/dist/src/agent-deps-factory.js.map +1 -1
  133. package/dist/src/agent-deps.d.ts +3 -0
  134. package/dist/src/agent-deps.d.ts.map +1 -1
  135. package/dist/src/agent-deps.js.map +1 -1
  136. package/dist/src/agent-loop.d.ts +4 -3
  137. package/dist/src/agent-loop.d.ts.map +1 -1
  138. package/dist/src/agent-loop.js +50 -25
  139. package/dist/src/agent-loop.js.map +1 -1
  140. package/dist/src/agent-service.d.ts +46 -4
  141. package/dist/src/agent-service.d.ts.map +1 -1
  142. package/dist/src/agent-service.js +87 -11
  143. package/dist/src/agent-service.js.map +1 -1
  144. package/dist/src/ai-sdk/ai-sdk-model.js +4 -1
  145. package/dist/src/ai-sdk/ai-sdk-model.js.map +1 -1
  146. package/dist/src/ai-tool-ref.d.ts +4 -0
  147. package/dist/src/ai-tool-ref.d.ts.map +1 -1
  148. package/dist/src/ai-tool-ref.js +10 -14
  149. package/dist/src/ai-tool-ref.js.map +1 -1
  150. package/dist/src/attachment-limits.d.ts +10 -0
  151. package/dist/src/attachment-limits.d.ts.map +1 -0
  152. package/dist/src/attachment-limits.js +13 -0
  153. package/dist/src/attachment-limits.js.map +1 -0
  154. package/dist/src/channels/adapters/evolution_api.d.ts +49 -0
  155. package/dist/src/channels/adapters/evolution_api.d.ts.map +1 -0
  156. package/dist/src/channels/adapters/evolution_api.js +241 -0
  157. package/dist/src/channels/adapters/evolution_api.js.map +1 -0
  158. package/dist/src/channels/adapters/telegram.d.ts +34 -0
  159. package/dist/src/channels/adapters/telegram.d.ts.map +1 -0
  160. package/dist/src/channels/adapters/telegram.js +196 -0
  161. package/dist/src/channels/adapters/telegram.js.map +1 -0
  162. package/dist/src/channels/adapters/whatsapp_cloud.d.ts +31 -0
  163. package/dist/src/channels/adapters/whatsapp_cloud.d.ts.map +1 -0
  164. package/dist/src/channels/adapters/whatsapp_cloud.js +177 -0
  165. package/dist/src/channels/adapters/whatsapp_cloud.js.map +1 -0
  166. package/dist/src/channels/handler.d.ts +167 -0
  167. package/dist/src/channels/handler.d.ts.map +1 -0
  168. package/dist/src/channels/handler.js +569 -0
  169. package/dist/src/channels/handler.js.map +1 -0
  170. package/dist/src/channels/http.d.ts +45 -0
  171. package/dist/src/channels/http.d.ts.map +1 -0
  172. package/dist/src/channels/http.js +147 -0
  173. package/dist/src/channels/http.js.map +1 -0
  174. package/dist/src/channels/index.d.ts +16 -0
  175. package/dist/src/channels/index.d.ts.map +1 -0
  176. package/dist/src/channels/index.js +15 -0
  177. package/dist/src/channels/index.js.map +1 -0
  178. package/dist/src/channels/markdown.d.ts +12 -0
  179. package/dist/src/channels/markdown.d.ts.map +1 -0
  180. package/dist/src/channels/markdown.js +120 -0
  181. package/dist/src/channels/markdown.js.map +1 -0
  182. package/dist/src/channels/questions.d.ts +43 -0
  183. package/dist/src/channels/questions.d.ts.map +1 -0
  184. package/dist/src/channels/questions.js +90 -0
  185. package/dist/src/channels/questions.js.map +1 -0
  186. package/dist/src/channels/split.d.ts +8 -0
  187. package/dist/src/channels/split.d.ts.map +1 -0
  188. package/dist/src/channels/split.js +45 -0
  189. package/dist/src/channels/split.js.map +1 -0
  190. package/dist/src/channels/store.d.ts +78 -0
  191. package/dist/src/channels/store.d.ts.map +1 -0
  192. package/dist/src/channels/store.js +151 -0
  193. package/dist/src/channels/store.js.map +1 -0
  194. package/dist/src/channels/types.d.ts +138 -0
  195. package/dist/src/channels/types.d.ts.map +1 -0
  196. package/dist/src/channels/types.js +7 -0
  197. package/dist/src/channels/types.js.map +1 -0
  198. package/dist/src/chat-queue-service.d.ts.map +1 -1
  199. package/dist/src/chat-queue-service.js +2 -0
  200. package/dist/src/chat-queue-service.js.map +1 -1
  201. package/dist/src/define_config.d.ts +61 -12
  202. package/dist/src/define_config.d.ts.map +1 -1
  203. package/dist/src/define_config.js.map +1 -1
  204. package/dist/src/engine.d.ts +77 -0
  205. package/dist/src/engine.d.ts.map +1 -0
  206. package/dist/src/engine.js +27 -0
  207. package/dist/src/engine.js.map +1 -0
  208. package/dist/src/genui/builtins.d.ts +73 -3
  209. package/dist/src/genui/builtins.d.ts.map +1 -1
  210. package/dist/src/genui/builtins.js +357 -3
  211. package/dist/src/genui/builtins.js.map +1 -1
  212. package/dist/src/genui/capabilities.d.ts +24 -0
  213. package/dist/src/genui/capabilities.d.ts.map +1 -0
  214. package/dist/src/genui/capabilities.js +81 -0
  215. package/dist/src/genui/capabilities.js.map +1 -0
  216. package/dist/src/genui/catalog.d.ts +86 -0
  217. package/dist/src/genui/catalog.d.ts.map +1 -0
  218. package/dist/src/genui/catalog.js +96 -0
  219. package/dist/src/genui/catalog.js.map +1 -0
  220. package/dist/src/genui/factory.d.ts +7 -14
  221. package/dist/src/genui/factory.d.ts.map +1 -1
  222. package/dist/src/genui/factory.js.map +1 -1
  223. package/dist/src/genui/index.d.ts +4 -12
  224. package/dist/src/genui/index.d.ts.map +1 -1
  225. package/dist/src/genui/index.js +5 -18
  226. package/dist/src/genui/index.js.map +1 -1
  227. package/dist/src/genui/public.d.ts +9 -0
  228. package/dist/src/genui/public.d.ts.map +1 -0
  229. package/dist/src/genui/public.js +9 -0
  230. package/dist/src/genui/public.js.map +1 -0
  231. package/dist/src/genui/registry.d.ts +65 -0
  232. package/dist/src/genui/registry.d.ts.map +1 -0
  233. package/dist/src/genui/registry.js +151 -0
  234. package/dist/src/genui/registry.js.map +1 -0
  235. package/dist/src/genui/schema.d.ts +71 -0
  236. package/dist/src/genui/schema.d.ts.map +1 -0
  237. package/dist/src/genui/schema.js +304 -0
  238. package/dist/src/genui/schema.js.map +1 -0
  239. package/dist/src/genui/text.d.ts +36 -0
  240. package/dist/src/genui/text.d.ts.map +1 -0
  241. package/dist/src/genui/text.js +157 -0
  242. package/dist/src/genui/text.js.map +1 -0
  243. package/dist/src/genui/tools.d.ts +92 -0
  244. package/dist/src/genui/tools.d.ts.map +1 -0
  245. package/dist/src/genui/tools.js +291 -0
  246. package/dist/src/genui/tools.js.map +1 -0
  247. package/dist/src/genui/tree.d.ts +56 -0
  248. package/dist/src/genui/tree.d.ts.map +1 -0
  249. package/dist/src/genui/tree.js +188 -0
  250. package/dist/src/genui/tree.js.map +1 -0
  251. package/dist/src/index.d.ts +6 -3
  252. package/dist/src/index.d.ts.map +1 -1
  253. package/dist/src/index.js +4 -2
  254. package/dist/src/index.js.map +1 -1
  255. package/dist/src/mcp/auth.d.ts +17 -1
  256. package/dist/src/mcp/auth.d.ts.map +1 -1
  257. package/dist/src/mcp/auth.js +14 -3
  258. package/dist/src/mcp/auth.js.map +1 -1
  259. package/dist/src/mcp/define_config.d.ts +81 -2
  260. package/dist/src/mcp/define_config.d.ts.map +1 -1
  261. package/dist/src/mcp/define_config.js.map +1 -1
  262. package/dist/src/mcp/index.d.ts +1 -1
  263. package/dist/src/mcp/index.d.ts.map +1 -1
  264. package/dist/src/mcp/index.js.map +1 -1
  265. package/dist/src/mcp/oauth-resource.d.ts +9 -0
  266. package/dist/src/mcp/oauth-resource.d.ts.map +1 -0
  267. package/dist/src/mcp/oauth-resource.js +16 -0
  268. package/dist/src/mcp/oauth-resource.js.map +1 -0
  269. package/dist/src/mcp/server.d.ts +5 -0
  270. package/dist/src/mcp/server.d.ts.map +1 -1
  271. package/dist/src/mcp/server.js +48 -16
  272. package/dist/src/mcp/server.js.map +1 -1
  273. package/dist/src/negotiated-tool-ui.d.ts.map +1 -1
  274. package/dist/src/negotiated-tool-ui.js +12 -8
  275. package/dist/src/negotiated-tool-ui.js.map +1 -1
  276. package/dist/src/opencode/client.d.ts +202 -0
  277. package/dist/src/opencode/client.d.ts.map +1 -0
  278. package/dist/src/opencode/client.js +2 -0
  279. package/dist/src/opencode/client.js.map +1 -0
  280. package/dist/src/opencode/durable/index.d.ts +33 -0
  281. package/dist/src/opencode/durable/index.d.ts.map +1 -0
  282. package/dist/src/opencode/durable/index.js +38 -0
  283. package/dist/src/opencode/durable/index.js.map +1 -0
  284. package/dist/src/opencode/durable/runner.d.ts +36 -0
  285. package/dist/src/opencode/durable/runner.d.ts.map +1 -0
  286. package/dist/src/opencode/durable/runner.js +88 -0
  287. package/dist/src/opencode/durable/runner.js.map +1 -0
  288. package/dist/src/opencode/durable/workflow.d.ts +40 -0
  289. package/dist/src/opencode/durable/workflow.d.ts.map +1 -0
  290. package/dist/src/opencode/durable/workflow.js +106 -0
  291. package/dist/src/opencode/durable/workflow.js.map +1 -0
  292. package/dist/src/opencode/engine.d.ts +48 -0
  293. package/dist/src/opencode/engine.d.ts.map +1 -0
  294. package/dist/src/opencode/engine.js +98 -0
  295. package/dist/src/opencode/engine.js.map +1 -0
  296. package/dist/src/opencode/event-hub.d.ts +23 -0
  297. package/dist/src/opencode/event-hub.d.ts.map +1 -0
  298. package/dist/src/opencode/event-hub.js +99 -0
  299. package/dist/src/opencode/event-hub.js.map +1 -0
  300. package/dist/src/opencode/forms.d.ts +19 -0
  301. package/dist/src/opencode/forms.d.ts.map +1 -0
  302. package/dist/src/opencode/forms.js +82 -0
  303. package/dist/src/opencode/forms.js.map +1 -0
  304. package/dist/src/opencode/host.d.ts +179 -0
  305. package/dist/src/opencode/host.d.ts.map +1 -0
  306. package/dist/src/opencode/host.js +34 -0
  307. package/dist/src/opencode/host.js.map +1 -0
  308. package/dist/src/opencode/index.d.ts +15 -0
  309. package/dist/src/opencode/index.d.ts.map +1 -0
  310. package/dist/src/opencode/index.js +9 -0
  311. package/dist/src/opencode/index.js.map +1 -0
  312. package/dist/src/opencode/log.d.ts +9 -0
  313. package/dist/src/opencode/log.d.ts.map +1 -0
  314. package/dist/src/opencode/log.js +15 -0
  315. package/dist/src/opencode/log.js.map +1 -0
  316. package/dist/src/opencode/mcp.d.ts +60 -0
  317. package/dist/src/opencode/mcp.d.ts.map +1 -0
  318. package/dist/src/opencode/mcp.js +258 -0
  319. package/dist/src/opencode/mcp.js.map +1 -0
  320. package/dist/src/opencode/runner.d.ts +40 -0
  321. package/dist/src/opencode/runner.d.ts.map +1 -0
  322. package/dist/src/opencode/runner.js +125 -0
  323. package/dist/src/opencode/runner.js.map +1 -0
  324. package/dist/src/opencode/turn.d.ts +167 -0
  325. package/dist/src/opencode/turn.d.ts.map +1 -0
  326. package/dist/src/opencode/turn.js +761 -0
  327. package/dist/src/opencode/turn.js.map +1 -0
  328. package/dist/src/opencode/turns.d.ts +247 -0
  329. package/dist/src/opencode/turns.d.ts.map +1 -0
  330. package/dist/src/opencode/turns.js +867 -0
  331. package/dist/src/opencode/turns.js.map +1 -0
  332. package/dist/src/personas.d.ts.map +1 -1
  333. package/dist/src/personas.js +4 -1
  334. package/dist/src/personas.js.map +1 -1
  335. package/dist/src/react/ag-ui.d.ts +4 -2
  336. package/dist/src/react/ag-ui.d.ts.map +1 -1
  337. package/dist/src/react/ag-ui.js +2 -2
  338. package/dist/src/react/ag-ui.js.map +1 -1
  339. package/dist/src/react/client.d.ts +1 -1
  340. package/dist/src/react/client.d.ts.map +1 -1
  341. package/dist/src/react/client.js +1 -1
  342. package/dist/src/react/client.js.map +1 -1
  343. package/dist/src/react/core/ag-ui-backend.d.ts +109 -0
  344. package/dist/src/react/core/ag-ui-backend.d.ts.map +1 -0
  345. package/dist/src/react/core/ag-ui-backend.js +574 -0
  346. package/dist/src/react/core/ag-ui-backend.js.map +1 -0
  347. package/dist/src/react/core/agent-chat-transport.d.ts +187 -0
  348. package/dist/src/react/core/agent-chat-transport.d.ts.map +1 -0
  349. package/dist/src/react/core/agent-chat-transport.js +817 -0
  350. package/dist/src/react/core/agent-chat-transport.js.map +1 -0
  351. package/dist/src/react/core/approvals/countdown.d.ts +22 -0
  352. package/dist/src/react/core/approvals/countdown.d.ts.map +1 -0
  353. package/dist/src/react/core/approvals/countdown.js +39 -0
  354. package/dist/src/react/core/approvals/countdown.js.map +1 -0
  355. package/dist/src/react/core/approvals/proposals.d.ts +15 -0
  356. package/dist/src/react/core/approvals/proposals.d.ts.map +1 -0
  357. package/dist/src/react/core/approvals/proposals.js +82 -0
  358. package/dist/src/react/core/approvals/proposals.js.map +1 -0
  359. package/dist/src/react/core/approvals/use-action-proposals.d.ts +10 -0
  360. package/dist/src/react/core/approvals/use-action-proposals.d.ts.map +1 -0
  361. package/dist/src/react/core/approvals/use-action-proposals.js +86 -0
  362. package/dist/src/react/core/approvals/use-action-proposals.js.map +1 -0
  363. package/dist/src/react/core/attachments/files.d.ts +39 -0
  364. package/dist/src/react/core/attachments/files.d.ts.map +1 -0
  365. package/dist/src/react/core/attachments/files.js +89 -0
  366. package/dist/src/react/core/attachments/files.js.map +1 -0
  367. package/dist/src/react/core/attachments/use-attachments.d.ts +106 -0
  368. package/dist/src/react/core/attachments/use-attachments.d.ts.map +1 -0
  369. package/dist/src/react/core/attachments/use-attachments.js +217 -0
  370. package/dist/src/react/core/attachments/use-attachments.js.map +1 -0
  371. package/dist/src/react/core/backend.d.ts +245 -0
  372. package/dist/src/react/core/backend.d.ts.map +1 -0
  373. package/dist/src/react/core/backend.js +21 -0
  374. package/dist/src/react/core/backend.js.map +1 -0
  375. package/dist/src/react/core/background-runs.d.ts +32 -0
  376. package/dist/src/react/core/background-runs.d.ts.map +1 -0
  377. package/dist/src/react/core/background-runs.js +47 -0
  378. package/dist/src/react/core/background-runs.js.map +1 -0
  379. package/dist/src/react/core/catalog/use-agents.d.ts +31 -0
  380. package/dist/src/react/core/catalog/use-agents.d.ts.map +1 -0
  381. package/dist/src/react/core/catalog/use-agents.js +28 -0
  382. package/dist/src/react/core/catalog/use-agents.js.map +1 -0
  383. package/dist/src/react/core/catalog/use-models.d.ts +41 -0
  384. package/dist/src/react/core/catalog/use-models.d.ts.map +1 -0
  385. package/dist/src/react/core/catalog/use-models.js +35 -0
  386. package/dist/src/react/core/catalog/use-models.js.map +1 -0
  387. package/dist/src/react/core/catalog/use-resource.d.ts +12 -0
  388. package/dist/src/react/core/catalog/use-resource.d.ts.map +1 -0
  389. package/dist/src/react/core/catalog/use-resource.js +41 -0
  390. package/dist/src/react/core/catalog/use-resource.js.map +1 -0
  391. package/dist/src/react/core/client-wire.d.ts +14 -0
  392. package/dist/src/react/core/client-wire.d.ts.map +1 -0
  393. package/dist/src/react/core/client-wire.js +2 -0
  394. package/dist/src/react/core/client-wire.js.map +1 -0
  395. package/dist/src/react/core/client.d.ts +222 -0
  396. package/dist/src/react/core/client.d.ts.map +1 -0
  397. package/dist/src/react/core/client.js +435 -0
  398. package/dist/src/react/core/client.js.map +1 -0
  399. package/dist/src/react/core/components/ambient-ui.d.ts +22 -0
  400. package/dist/src/react/core/components/ambient-ui.d.ts.map +1 -0
  401. package/dist/src/react/core/components/ambient-ui.js +30 -0
  402. package/dist/src/react/core/components/ambient-ui.js.map +1 -0
  403. package/dist/src/react/core/components/chat-input.d.ts +44 -0
  404. package/dist/src/react/core/components/chat-input.d.ts.map +1 -0
  405. package/dist/src/react/core/components/chat-input.js +69 -0
  406. package/dist/src/react/core/components/chat-input.js.map +1 -0
  407. package/dist/src/react/core/components/index.d.ts +7 -0
  408. package/dist/src/react/core/components/index.d.ts.map +1 -0
  409. package/dist/src/react/core/components/index.js +7 -0
  410. package/dist/src/react/core/components/index.js.map +1 -0
  411. package/dist/src/react/core/components/message-item.d.ts +101 -0
  412. package/dist/src/react/core/components/message-item.d.ts.map +1 -0
  413. package/dist/src/react/core/components/message-item.js +118 -0
  414. package/dist/src/react/core/components/message-item.js.map +1 -0
  415. package/dist/src/react/core/components/message-list.d.ts +85 -0
  416. package/dist/src/react/core/components/message-list.d.ts.map +1 -0
  417. package/dist/src/react/core/components/message-list.js +45 -0
  418. package/dist/src/react/core/components/message-list.js.map +1 -0
  419. package/dist/src/react/core/components/speech-languages.d.ts +22 -0
  420. package/dist/src/react/core/components/speech-languages.d.ts.map +1 -0
  421. package/dist/src/react/core/components/speech-languages.js +38 -0
  422. package/dist/src/react/core/components/speech-languages.js.map +1 -0
  423. package/dist/src/react/core/components/use-speech-recognition.d.ts +19 -0
  424. package/dist/src/react/core/components/use-speech-recognition.d.ts.map +1 -0
  425. package/dist/src/react/core/components/use-speech-recognition.js +92 -0
  426. package/dist/src/react/core/components/use-speech-recognition.js.map +1 -0
  427. package/dist/src/react/core/composer/index.d.ts +4 -0
  428. package/dist/src/react/core/composer/index.d.ts.map +1 -0
  429. package/dist/src/react/core/composer/index.js +4 -0
  430. package/dist/src/react/core/composer/index.js.map +1 -0
  431. package/dist/src/react/core/composer/model.d.ts +83 -0
  432. package/dist/src/react/core/composer/model.d.ts.map +1 -0
  433. package/dist/src/react/core/composer/model.js +53 -0
  434. package/dist/src/react/core/composer/model.js.map +1 -0
  435. package/dist/src/react/core/composer/skills-source.d.ts +29 -0
  436. package/dist/src/react/core/composer/skills-source.d.ts.map +1 -0
  437. package/dist/src/react/core/composer/skills-source.js +61 -0
  438. package/dist/src/react/core/composer/skills-source.js.map +1 -0
  439. package/dist/src/react/core/composer/use-composer-autocomplete.d.ts +78 -0
  440. package/dist/src/react/core/composer/use-composer-autocomplete.d.ts.map +1 -0
  441. package/dist/src/react/core/composer/use-composer-autocomplete.js +244 -0
  442. package/dist/src/react/core/composer/use-composer-autocomplete.js.map +1 -0
  443. package/dist/src/react/core/config/use-agent-config.d.ts +21 -0
  444. package/dist/src/react/core/config/use-agent-config.d.ts.map +1 -0
  445. package/dist/src/react/core/config/use-agent-config.js +57 -0
  446. package/dist/src/react/core/config/use-agent-config.js.map +1 -0
  447. package/dist/src/react/core/elicitation/answers.d.ts +22 -0
  448. package/dist/src/react/core/elicitation/answers.d.ts.map +1 -0
  449. package/dist/src/react/core/elicitation/answers.js +65 -0
  450. package/dist/src/react/core/elicitation/answers.js.map +1 -0
  451. package/dist/src/react/core/feedback/use-message-feedback.d.ts +32 -0
  452. package/dist/src/react/core/feedback/use-message-feedback.d.ts.map +1 -0
  453. package/dist/src/react/core/feedback/use-message-feedback.js +106 -0
  454. package/dist/src/react/core/feedback/use-message-feedback.js.map +1 -0
  455. package/dist/src/react/core/genui/generative-ui.d.ts +76 -0
  456. package/dist/src/react/core/genui/generative-ui.d.ts.map +1 -0
  457. package/dist/src/react/core/genui/generative-ui.js +210 -0
  458. package/dist/src/react/core/genui/generative-ui.js.map +1 -0
  459. package/dist/src/react/core/genui/index.d.ts +5 -0
  460. package/dist/src/react/core/genui/index.d.ts.map +1 -0
  461. package/dist/src/react/core/genui/index.js +5 -0
  462. package/dist/src/react/core/genui/index.js.map +1 -0
  463. package/dist/src/react/core/genui/json-render.d.ts +54 -0
  464. package/dist/src/react/core/genui/json-render.d.ts.map +1 -0
  465. package/dist/src/react/core/genui/json-render.js +64 -0
  466. package/dist/src/react/core/genui/json-render.js.map +1 -0
  467. package/dist/src/react/core/genui/playwright.d.ts +12 -0
  468. package/dist/src/react/core/genui/playwright.d.ts.map +1 -0
  469. package/dist/src/react/core/genui/playwright.js +141 -0
  470. package/dist/src/react/core/genui/playwright.js.map +1 -0
  471. package/dist/src/react/core/genui/react-registry.d.ts +22 -0
  472. package/dist/src/react/core/genui/react-registry.d.ts.map +1 -0
  473. package/dist/src/react/core/genui/react-registry.js +72 -0
  474. package/dist/src/react/core/genui/react-registry.js.map +1 -0
  475. package/dist/src/react/core/genui/server.d.ts +32 -0
  476. package/dist/src/react/core/genui/server.d.ts.map +1 -0
  477. package/dist/src/react/core/genui/server.js +66 -0
  478. package/dist/src/react/core/genui/server.js.map +1 -0
  479. package/dist/src/react/core/genui/types.d.ts +98 -0
  480. package/dist/src/react/core/genui/types.d.ts.map +1 -0
  481. package/dist/src/react/core/genui/types.js +3 -0
  482. package/dist/src/react/core/genui/types.js.map +1 -0
  483. package/dist/src/react/core/genui/use-generative-ui.d.ts +42 -0
  484. package/dist/src/react/core/genui/use-generative-ui.d.ts.map +1 -0
  485. package/dist/src/react/core/genui/use-generative-ui.js +186 -0
  486. package/dist/src/react/core/genui/use-generative-ui.js.map +1 -0
  487. package/dist/src/react/core/http-error.d.ts +33 -0
  488. package/dist/src/react/core/http-error.d.ts.map +1 -0
  489. package/dist/src/react/core/http-error.js +47 -0
  490. package/dist/src/react/core/http-error.js.map +1 -0
  491. package/dist/src/react/core/index.d.ts +35 -0
  492. package/dist/src/react/core/index.d.ts.map +1 -0
  493. package/dist/src/react/core/index.js +34 -0
  494. package/dist/src/react/core/index.js.map +1 -0
  495. package/dist/src/react/core/markdown/agent-markdown.d.ts +39 -0
  496. package/dist/src/react/core/markdown/agent-markdown.d.ts.map +1 -0
  497. package/dist/src/react/core/markdown/agent-markdown.js +22 -0
  498. package/dist/src/react/core/markdown/agent-markdown.js.map +1 -0
  499. package/dist/src/react/core/markdown/index.d.ts +2 -0
  500. package/dist/src/react/core/markdown/index.d.ts.map +1 -0
  501. package/dist/src/react/core/markdown/index.js +2 -0
  502. package/dist/src/react/core/markdown/index.js.map +1 -0
  503. package/dist/src/react/core/media/index.d.ts +64 -0
  504. package/dist/src/react/core/media/index.d.ts.map +1 -0
  505. package/dist/src/react/core/media/index.js +135 -0
  506. package/dist/src/react/core/media/index.js.map +1 -0
  507. package/dist/src/react/core/media/tus.d.ts +13 -0
  508. package/dist/src/react/core/media/tus.d.ts.map +1 -0
  509. package/dist/src/react/core/media/tus.js +59 -0
  510. package/dist/src/react/core/media/tus.js.map +1 -0
  511. package/dist/src/react/core/presentation/phrasing.d.ts +25 -0
  512. package/dist/src/react/core/presentation/phrasing.d.ts.map +1 -0
  513. package/dist/src/react/core/presentation/phrasing.js +58 -0
  514. package/dist/src/react/core/presentation/phrasing.js.map +1 -0
  515. package/dist/src/react/core/presentation/result-view.d.ts +43 -0
  516. package/dist/src/react/core/presentation/result-view.d.ts.map +1 -0
  517. package/dist/src/react/core/presentation/result-view.js +90 -0
  518. package/dist/src/react/core/presentation/result-view.js.map +1 -0
  519. package/dist/src/react/core/presentation/tool-activity.d.ts +106 -0
  520. package/dist/src/react/core/presentation/tool-activity.d.ts.map +1 -0
  521. package/dist/src/react/core/presentation/tool-activity.js +165 -0
  522. package/dist/src/react/core/presentation/tool-activity.js.map +1 -0
  523. package/dist/src/react/core/presentation/use-tool-catalog.d.ts +39 -0
  524. package/dist/src/react/core/presentation/use-tool-catalog.d.ts.map +1 -0
  525. package/dist/src/react/core/presentation/use-tool-catalog.js +77 -0
  526. package/dist/src/react/core/presentation/use-tool-catalog.js.map +1 -0
  527. package/dist/src/react/core/provider.d.ts +68 -0
  528. package/dist/src/react/core/provider.d.ts.map +1 -0
  529. package/dist/src/react/core/provider.js +61 -0
  530. package/dist/src/react/core/provider.js.map +1 -0
  531. package/dist/src/react/core/queue/model.d.ts +73 -0
  532. package/dist/src/react/core/queue/model.d.ts.map +1 -0
  533. package/dist/src/react/core/queue/model.js +2 -0
  534. package/dist/src/react/core/queue/model.js.map +1 -0
  535. package/dist/src/react/core/quota/use-quota.d.ts +35 -0
  536. package/dist/src/react/core/quota/use-quota.d.ts.map +1 -0
  537. package/dist/src/react/core/quota/use-quota.js +47 -0
  538. package/dist/src/react/core/quota/use-quota.js.map +1 -0
  539. package/dist/src/react/core/reasoning/timing.d.ts +38 -0
  540. package/dist/src/react/core/reasoning/timing.d.ts.map +1 -0
  541. package/dist/src/react/core/reasoning/timing.js +73 -0
  542. package/dist/src/react/core/reasoning/timing.js.map +1 -0
  543. package/dist/src/react/core/run-errors.d.ts +37 -0
  544. package/dist/src/react/core/run-errors.d.ts.map +1 -0
  545. package/dist/src/react/core/run-errors.js +37 -0
  546. package/dist/src/react/core/run-errors.js.map +1 -0
  547. package/dist/src/react/core/stored-message-to-ui-message.d.ts +4 -0
  548. package/dist/src/react/core/stored-message-to-ui-message.d.ts.map +1 -0
  549. package/dist/src/react/core/stored-message-to-ui-message.js +216 -0
  550. package/dist/src/react/core/stored-message-to-ui-message.js.map +1 -0
  551. package/dist/src/react/core/stored-thread-to-ui-messages.d.ts +82 -0
  552. package/dist/src/react/core/stored-thread-to-ui-messages.d.ts.map +1 -0
  553. package/dist/src/react/core/stored-thread-to-ui-messages.js +116 -0
  554. package/dist/src/react/core/stored-thread-to-ui-messages.js.map +1 -0
  555. package/dist/src/react/core/threads/threads-events.d.ts +22 -0
  556. package/dist/src/react/core/threads/threads-events.d.ts.map +1 -0
  557. package/dist/src/react/core/threads/threads-events.js +21 -0
  558. package/dist/src/react/core/threads/threads-events.js.map +1 -0
  559. package/dist/src/react/core/threads/use-threads.d.ts +31 -0
  560. package/dist/src/react/core/threads/use-threads.d.ts.map +1 -0
  561. package/dist/src/react/core/threads/use-threads.js +81 -0
  562. package/dist/src/react/core/threads/use-threads.js.map +1 -0
  563. package/dist/src/react/core/transcript/index.d.ts +4 -0
  564. package/dist/src/react/core/transcript/index.d.ts.map +1 -0
  565. package/dist/src/react/core/transcript/index.js +4 -0
  566. package/dist/src/react/core/transcript/index.js.map +1 -0
  567. package/dist/src/react/core/transcript/model.d.ts +399 -0
  568. package/dist/src/react/core/transcript/model.d.ts.map +1 -0
  569. package/dist/src/react/core/transcript/model.js +725 -0
  570. package/dist/src/react/core/transcript/model.js.map +1 -0
  571. package/dist/src/react/core/transcript/use-chat-transcript.d.ts +254 -0
  572. package/dist/src/react/core/transcript/use-chat-transcript.d.ts.map +1 -0
  573. package/dist/src/react/core/transcript/use-chat-transcript.js +572 -0
  574. package/dist/src/react/core/transcript/use-chat-transcript.js.map +1 -0
  575. package/dist/src/react/core/transcript/use-stick-to-bottom.d.ts +33 -0
  576. package/dist/src/react/core/transcript/use-stick-to-bottom.d.ts.map +1 -0
  577. package/dist/src/react/core/transcript/use-stick-to-bottom.js +48 -0
  578. package/dist/src/react/core/transcript/use-stick-to-bottom.js.map +1 -0
  579. package/dist/src/react/core/use-agent-chat.d.ts +341 -0
  580. package/dist/src/react/core/use-agent-chat.d.ts.map +1 -0
  581. package/dist/src/react/core/use-agent-chat.js +1118 -0
  582. package/dist/src/react/core/use-agent-chat.js.map +1 -0
  583. package/dist/src/react/genui/index.d.ts +1 -7
  584. package/dist/src/react/genui/index.d.ts.map +1 -1
  585. package/dist/src/react/genui/index.js +1 -7
  586. package/dist/src/react/genui/index.js.map +1 -1
  587. package/dist/src/react/genui/json-render.d.ts +1 -5
  588. package/dist/src/react/genui/json-render.d.ts.map +1 -1
  589. package/dist/src/react/genui/json-render.js +1 -5
  590. package/dist/src/react/genui/json-render.js.map +1 -1
  591. package/dist/src/react/genui/server.d.ts +2 -0
  592. package/dist/src/react/genui/server.d.ts.map +1 -0
  593. package/dist/src/react/genui/server.js +2 -0
  594. package/dist/src/react/genui/server.js.map +1 -0
  595. package/dist/src/react/genui/server_playwright.d.ts +2 -0
  596. package/dist/src/react/genui/server_playwright.d.ts.map +1 -0
  597. package/dist/src/react/genui/server_playwright.js +2 -0
  598. package/dist/src/react/genui/server_playwright.js.map +1 -0
  599. package/dist/src/react/index.d.ts +5 -7
  600. package/dist/src/react/index.d.ts.map +1 -1
  601. package/dist/src/react/index.js +5 -7
  602. package/dist/src/react/index.js.map +1 -1
  603. package/dist/src/react/markdown.d.ts +1 -6
  604. package/dist/src/react/markdown.d.ts.map +1 -1
  605. package/dist/src/react/markdown.js +1 -6
  606. package/dist/src/react/markdown.js.map +1 -1
  607. package/dist/src/react/media.d.ts +1 -17
  608. package/dist/src/react/media.d.ts.map +1 -1
  609. package/dist/src/react/media.js +1 -17
  610. package/dist/src/react/media.js.map +1 -1
  611. package/dist/src/refusal.d.ts +3 -0
  612. package/dist/src/refusal.d.ts.map +1 -0
  613. package/dist/src/refusal.js +3 -0
  614. package/dist/src/refusal.js.map +1 -0
  615. package/dist/src/spi/agent-runner.d.ts +6 -0
  616. package/dist/src/spi/agent-runner.d.ts.map +1 -1
  617. package/dist/src/spi/chat-queue.d.ts +4 -1
  618. package/dist/src/spi/chat-queue.d.ts.map +1 -1
  619. package/dist/src/spi/chat-queue.js.map +1 -1
  620. package/dist/src/spi/protocol-adapter.d.ts +3 -3
  621. package/dist/src/spi/roles-policy.d.ts +7 -0
  622. package/dist/src/spi/roles-policy.d.ts.map +1 -1
  623. package/dist/src/spi/tool.d.ts +18 -3
  624. package/dist/src/spi/tool.d.ts.map +1 -1
  625. package/dist/src/stores/lucid-schema.d.ts +24 -6
  626. package/dist/src/stores/lucid-schema.d.ts.map +1 -1
  627. package/dist/src/stores/lucid-schema.js +49 -6
  628. package/dist/src/stores/lucid-schema.js.map +1 -1
  629. package/dist/src/stores/lucid.d.ts +2 -0
  630. package/dist/src/stores/lucid.d.ts.map +1 -1
  631. package/dist/src/stores/lucid.js +7 -0
  632. package/dist/src/stores/lucid.js.map +1 -1
  633. package/dist/src/testing/chat-queue-store-contract.d.ts.map +1 -1
  634. package/dist/src/testing/chat-queue-store-contract.js +4 -0
  635. package/dist/src/testing/chat-queue-store-contract.js.map +1 -1
  636. package/dist/src/testing/in-memory-store.d.ts.map +1 -1
  637. package/dist/src/testing/in-memory-store.js +1 -0
  638. package/dist/src/testing/in-memory-store.js.map +1 -1
  639. package/dist/src/tool-discovery.d.ts +1 -1
  640. package/dist/src/tool-discovery.d.ts.map +1 -1
  641. package/dist/src/tool-discovery.js +5 -1
  642. package/dist/src/tool-discovery.js.map +1 -1
  643. package/dist/src/tool-registry.d.ts +3 -0
  644. package/dist/src/tool-registry.d.ts.map +1 -1
  645. package/dist/src/tool-registry.js +15 -3
  646. package/dist/src/tool-registry.js.map +1 -1
  647. package/dist/src/tool-result-presentation.d.ts +12 -0
  648. package/dist/src/tool-result-presentation.d.ts.map +1 -0
  649. package/dist/src/tool-result-presentation.js +44 -0
  650. package/dist/src/tool-result-presentation.js.map +1 -0
  651. package/dist/src/types.d.ts +20 -0
  652. package/dist/src/types.d.ts.map +1 -1
  653. package/dist/src/ui-capabilities.d.ts +1 -8
  654. package/dist/src/ui-capabilities.d.ts.map +1 -1
  655. package/dist/src/ui-capabilities.js +3 -24
  656. package/dist/src/ui-capabilities.js.map +1 -1
  657. package/package.json +128 -22
  658. package/skills/agent-governance/SKILL.md +12 -4
  659. package/skills/agent-personas-agents/SKILL.md +2 -1
  660. package/skills/agent-setup/SKILL.md +73 -14
  661. package/skills/agent-testing/SKILL.md +22 -0
  662. package/skills/agent-tools/SKILL.md +57 -9
  663. package/dist/src/ag-ui/proposal-decision.d.ts.map +0 -1
  664. package/dist/src/ag-ui/proposal-decision.js.map +0 -1
@@ -0,0 +1,1118 @@
1
+ import { useChat } from '@ai-sdk/react';
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { AgentChatTransport, } from './agent-chat-transport.js';
4
+ import { useActionProposals } from './approvals/use-action-proposals.js';
5
+ import { attachmentFile } from './attachments/files.js';
6
+ import { useAttachments, } from './attachments/use-attachments.js';
7
+ import { AgentBackendUnsupportedError, requireBackendMethod, } from './backend.js';
8
+ import { backgroundRunsFromThread } from './background-runs.js';
9
+ import { useModels } from './catalog/use-models.js';
10
+ import { useToolCatalog } from './presentation/use-tool-catalog.js';
11
+ import { useAgentBackend, useAgentUiCapabilities } from './provider.js';
12
+ import { useQuota } from './quota/use-quota.js';
13
+ import { storedMessageToUiMessage } from './stored-message-to-ui-message.js';
14
+ import { storedThreadToUiMessages, } from './stored-thread-to-ui-messages.js';
15
+ import { notifyThreads } from './threads/threads-events.js';
16
+ import { useChatTranscript, } from './transcript/use-chat-transcript.js';
17
+ const EMPTY_QUEUE = { items: [], paused: null };
18
+ let localQueueSequence = 0;
19
+ /** The user message a queued message becomes once its turn starts. */
20
+ function queuedUserMessage(turn) {
21
+ return {
22
+ id: turn.messageId,
23
+ role: 'user',
24
+ metadata: { createdAt: new Date().toISOString() },
25
+ parts: [
26
+ ...turn.attachments.map((attachment) => ({
27
+ type: 'file',
28
+ mediaType: attachment.contentType,
29
+ filename: attachment.name,
30
+ url: attachment.url,
31
+ providerMetadata: { agent: { mediaId: attachment.mediaId } },
32
+ })),
33
+ ...(turn.text.length > 0 ? [{ type: 'text', text: turn.text }] : []),
34
+ ],
35
+ };
36
+ }
37
+ /** The text and staged files of whatever `sendMessage` was handed, for a send that is queued. */
38
+ function draftOf(message) {
39
+ if (typeof message !== 'object' || message === null) {
40
+ return { text: '', attachments: [] };
41
+ }
42
+ const draft = message;
43
+ let text = typeof draft.text === 'string' ? draft.text : '';
44
+ if (text === '' && Array.isArray(draft.parts)) {
45
+ text = draft.parts
46
+ .filter((part) => part.type === 'text' && typeof part.text === 'string')
47
+ .map((part) => part.text)
48
+ .join('');
49
+ }
50
+ const files = Array.isArray(draft.files)
51
+ ? draft.files
52
+ : Array.isArray(draft.parts)
53
+ ? draft.parts.filter((part) => part.type === 'file')
54
+ : [];
55
+ const attachments = files.flatMap((file) => {
56
+ const mediaId = file.providerMetadata?.agent
57
+ ?.mediaId;
58
+ return typeof mediaId === 'string'
59
+ ? [
60
+ {
61
+ mediaId,
62
+ url: String(file.url ?? ''),
63
+ contentType: String(file.mediaType ?? 'application/octet-stream'),
64
+ name: String(file.filename ?? mediaId),
65
+ },
66
+ ]
67
+ : [];
68
+ });
69
+ return { text, attachments };
70
+ }
71
+ function lastUserIndex(messages) {
72
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
73
+ if (messages[index]?.role === 'user')
74
+ return index;
75
+ }
76
+ return -1;
77
+ }
78
+ let localChatSequence = 0;
79
+ function localChatId() {
80
+ localChatSequence += 1;
81
+ return `local-chat-${localChatSequence}`;
82
+ }
83
+ /**
84
+ * The agent chat, wired: the AI SDK v7 `useChat` over `AgentChatTransport`, a thread's history
85
+ * loaded and a streaming turn re-attached on its own, a quota send gate, a model picker, a headless
86
+ * composer with attachments, and a transcript whose approve/reject/answer/skip/stop/fork/regenerate
87
+ * are already bound. Every piece is also a hook of its own (`useChatTranscript`, `useAttachments`,
88
+ * `useModels`, `useQuota`, `useThreads`) for a host that wants to wire it differently.
89
+ */
90
+ export function useAgentChat(options = {}) {
91
+ const providerCapabilities = useAgentUiCapabilities();
92
+ const capabilitiesRef = useRef(providerCapabilities);
93
+ capabilitiesRef.current = providerCapabilities;
94
+ const latest = useRef(options);
95
+ latest.current = options;
96
+ // Identity-stable: the first backend this chat mounted with is the one it keeps.
97
+ const resolved = useAgentBackend(options.backend);
98
+ const client = useRef(resolved).current;
99
+ // The thread the backend created for a threadless chat (or a fork moved to), captured from the
100
+ // `meta` frame. Every send after the first reuses it; an explicit `threadId` option always wins.
101
+ const createdThreadId = useRef(undefined);
102
+ // Which conversation `useChat` holds. A new `threadId` is a different conversation — except the
103
+ // one this chat itself created, which a host passes back once it syncs its URL.
104
+ const chatIdRef = useRef(options.threadId ?? localChatId());
105
+ const boundThreadRef = useRef(options.threadId);
106
+ if (options.threadId !== boundThreadRef.current) {
107
+ boundThreadRef.current = options.threadId;
108
+ const adopting = options.threadId !== undefined && options.threadId === createdThreadId.current;
109
+ if (!adopting) {
110
+ chatIdRef.current = options.threadId ?? localChatId();
111
+ createdThreadId.current = undefined;
112
+ }
113
+ }
114
+ const chatId = chatIdRef.current;
115
+ const [runId, setRunId] = useState(options.resumeRunId);
116
+ const runIdRef = useRef(runId);
117
+ runIdRef.current = runId;
118
+ // The run id learned (via the `meta` frame) during the CURRENT in-flight attempt only — reset by
119
+ // the transport's `onAttemptStart`. `onRunSettled` reads THIS so an attempt that fails before
120
+ // learning a run id never misattributes its outcome to the previous run.
121
+ const settlingRunIdRef = useRef(undefined);
122
+ // The run id discovered from the thread's `activeRunId`, read by the transport's
123
+ // `getResumeRunId` alongside the explicit `resumeRunId` option.
124
+ const autoResumeRunIdRef = useRef(undefined);
125
+ // The loaded thread's active run, if any — `null` once read with none.
126
+ const [activeRunId, setActiveRunId] = useState(null);
127
+ // The thread whose history read has settled (loaded or failed). The history is loading until it
128
+ // is the bound thread — derived, so it already reads `true` on the first render, before the
129
+ // effect below has asked for anything, and a page never flashes its empty state.
130
+ const [historyFor, setHistoryFor] = useState(undefined);
131
+ const [historyError, setHistoryError] = useState(null);
132
+ // How the last run's stream said it failed (`event: error`), until the next attempt starts.
133
+ const [runError, setRunError] = useState(null);
134
+ // The model pinned on the loaded thread.
135
+ const [threadModel, setThreadModel] = useState(null);
136
+ // The persona pinned on the thread — read with its history, and mirrored from each send that
137
+ // names one. `null` → none pinned (the agent's default persona applies).
138
+ const [threadPersona, setThreadPersona] = useState(null);
139
+ const [pickedModel, setPickedModel] = useState(undefined);
140
+ const pickedModelRef = useRef(pickedModel);
141
+ pickedModelRef.current = pickedModel;
142
+ // The agent is locked to one model (read off the catalog once it loads).
143
+ const lockedRef = useRef(false);
144
+ // A pin asked for before the chat had a thread — sent once the first send creates one.
145
+ const pendingPin = useRef(undefined);
146
+ // One-shot flag read (and cleared) by the transport's getBody so the next send carries
147
+ // `regenerate: true` — telling the backend to re-run the last exchange instead of appending.
148
+ const regenerateNext = useRef(false);
149
+ const currentThreadId = useCallback(() => latest.current.threadId ?? createdThreadId.current, []);
150
+ // ---- queue state (declared early: the transport's callbacks feed it) ------------------------
151
+ const [queueState, setQueueState] = useState(EMPTY_QUEUE);
152
+ const queueStateRef = useRef(queueState);
153
+ const applyQueue = useCallback((next) => {
154
+ queueStateRef.current = next;
155
+ setQueueState(next);
156
+ }, []);
157
+ // Sends on their way to the server, shown in the queue until it answers.
158
+ const [pendingSends, setPendingSends] = useState([]);
159
+ const [queueError, setQueueError] = useState(null);
160
+ // The queued message the running turn handed the thread to — attached to once that turn settles.
161
+ const handoff = useRef(undefined);
162
+ // A plain send the server queued instead of starting (another tab's turn was running).
163
+ const queuedSend = useRef(undefined);
164
+ const proposalRefreshRef = useRef(async () => { });
165
+ // Queue sends made before a new chat's first turn named its thread.
166
+ const threadWaiters = useRef([]);
167
+ /** The body fields every send carries: agent, persona, thread, model, page context. */
168
+ const turnBody = useCallback(() => {
169
+ const current = latest.current;
170
+ // The server pins a persona a send names; mirror it so a picker reads the thread's state.
171
+ if (current.persona !== undefined)
172
+ setThreadPersona(current.persona);
173
+ const pageContext = current.getPageContext?.() ?? null;
174
+ const threadId = currentThreadId();
175
+ // A locked agent runs on its own model: a pick is not sent (the server would refuse it).
176
+ const model = current.model ?? (lockedRef.current ? undefined : pickedModelRef.current);
177
+ return {
178
+ // Read per send: a host that switches agents before the first message (a picker on a new
179
+ // chat) sends the one picked now, not the one this chat mounted with.
180
+ ...(current.agent !== undefined ? { agent: current.agent } : {}),
181
+ ...(current.persona !== undefined ? { persona: current.persona } : {}),
182
+ ...(threadId !== undefined ? { threadId } : {}),
183
+ ...(model !== undefined ? { model } : {}),
184
+ ...(pageContext ? { pageContext } : {}),
185
+ ...((current.uiCapabilities ?? capabilitiesRef.current) === undefined
186
+ ? {}
187
+ : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }),
188
+ };
189
+ }, [currentThreadId]);
190
+ // Where the live stream stands — `reconnecting` while the transport retries a dropped one.
191
+ const [connection, setConnection] = useState({ status: 'live' });
192
+ // The run ended while the stream was away: what streamed is incomplete, the thread is not.
193
+ const resyncAfterSettle = useRef(false);
194
+ // Identity-stable: per-render config is read through `latest`.
195
+ // biome-ignore lint/correctness/useExhaustiveDependencies: stable by design
196
+ const transport = useMemo(() => {
197
+ function onMeta(meta) {
198
+ settlingRunIdRef.current = meta.runId;
199
+ setRunId(meta.runId);
200
+ if (meta.threadId) {
201
+ const waiting = threadWaiters.current;
202
+ threadWaiters.current = [];
203
+ for (const resolve of waiting)
204
+ resolve(meta.threadId);
205
+ }
206
+ if (latest.current.threadId === undefined &&
207
+ meta.threadId &&
208
+ createdThreadId.current !== meta.threadId) {
209
+ createdThreadId.current = meta.threadId;
210
+ const pin = pendingPin.current;
211
+ if (pin !== undefined) {
212
+ pendingPin.current = undefined;
213
+ void client.updateThread(meta.threadId, { model: pin.model }).catch(() => undefined);
214
+ }
215
+ latest.current.onThreadCreated?.(meta.threadId);
216
+ notifyThreads(client, { type: 'changed' });
217
+ }
218
+ }
219
+ return new AgentChatTransport({
220
+ backend: client,
221
+ ...(options.reconnect !== undefined ? { reconnect: options.reconnect } : {}),
222
+ onConnectionChange: (state) => {
223
+ if (state.status === 'gone')
224
+ resyncAfterSettle.current = true;
225
+ setConnection(state.status === 'gone' ? { status: 'live' } : state);
226
+ },
227
+ ...(options.agent !== undefined ? { agent: options.agent } : {}),
228
+ getBody: () => {
229
+ const regenerate = regenerateNext.current;
230
+ regenerateNext.current = false;
231
+ return { ...turnBody(), ...(regenerate ? { regenerate: true } : {}) };
232
+ },
233
+ getResumeRunId: () => latest.current.resumeRunId ?? autoResumeRunIdRef.current,
234
+ // A stream attached to after a reload carries no `meta` frame: without this the chat would
235
+ // be reading a run it cannot name, and `cancel()` would stop nothing.
236
+ onResumeAttached: (resumedRunId) => {
237
+ settlingRunIdRef.current = resumedRunId;
238
+ setRunId(resumedRunId);
239
+ },
240
+ onMeta,
241
+ onAttemptStart: () => {
242
+ settlingRunIdRef.current = undefined;
243
+ setRunError(null);
244
+ },
245
+ onRunError: (failure) => setRunError(failure),
246
+ // A queued turn this chat went to attach to had already finished: read what it wrote.
247
+ onResumeGone: () => {
248
+ void resyncFromThread();
249
+ },
250
+ });
251
+ }, []);
252
+ // Assigned once `refreshBackground` exists below.
253
+ const backgroundRef = useRef(() => Promise.resolve());
254
+ const chat = useChat({
255
+ transport,
256
+ id: chatId,
257
+ resume: options.resumeRunId !== undefined,
258
+ ...(options.initialMessages !== undefined ? { messages: options.initialMessages } : {}),
259
+ onData: (part) => {
260
+ latest.current.onData?.(part);
261
+ if (part.type === 'data-proposal-decision')
262
+ void proposalRefreshRef.current();
263
+ if (part.type === 'data-queue') {
264
+ onQueueData(part.data);
265
+ }
266
+ if (part.type === 'data-title') {
267
+ const title = part.data?.title;
268
+ if (typeof title === 'string') {
269
+ latest.current.onTitle?.(title);
270
+ const threadId = currentThreadId();
271
+ if (threadId !== undefined)
272
+ notifyThreads(client, { type: 'title', threadId, title });
273
+ }
274
+ }
275
+ },
276
+ onFinish: ({ isError }) => {
277
+ latest.current.onFinish?.();
278
+ if (latest.current.background === true) {
279
+ void backgroundRef.current();
280
+ }
281
+ const settledRunId = settlingRunIdRef.current;
282
+ if (settledRunId !== undefined) {
283
+ latest.current.onRunSettled?.({
284
+ runId: settledRunId,
285
+ status: isError ? 'failed' : 'completed',
286
+ });
287
+ notifyThreads(client, { type: 'changed' });
288
+ }
289
+ setConnection({ status: 'live' });
290
+ const queuedInstead = queuedSend.current;
291
+ if (queuedInstead !== undefined) {
292
+ queuedSend.current = undefined;
293
+ // The SDK already showed the send as a user message; it is waiting in the queue instead.
294
+ chatRef.current.setMessages((current) => {
295
+ const last = lastUserIndex(current);
296
+ return last === -1 ? current : current.slice(0, last);
297
+ });
298
+ }
299
+ const next = handoff.current;
300
+ handoff.current = undefined;
301
+ if (next !== undefined) {
302
+ attachTo(next);
303
+ return;
304
+ }
305
+ if (resyncAfterSettle.current) {
306
+ resyncAfterSettle.current = false;
307
+ void resyncFromThread();
308
+ }
309
+ },
310
+ });
311
+ const chatRef = useRef(chat);
312
+ chatRef.current = chat;
313
+ /** A `data-queue` part: the queue as it now stands, and maybe the turn this run handed over to. */
314
+ function onQueueData(data) {
315
+ const frame = (data ?? {});
316
+ const before = queueStateRef.current;
317
+ if (frame.queue !== undefined)
318
+ applyQueue(frame.queue);
319
+ const started = frame.started;
320
+ // A run's own stream may open by announcing itself (a queue kicked while idle): not a handoff.
321
+ if (started !== undefined && started.runId !== settlingRunIdRef.current) {
322
+ const waiting = before.items.find((item) => item.id === started.messageId);
323
+ handoff.current = {
324
+ ...started,
325
+ text: waiting?.content ?? '',
326
+ attachments: waiting?.attachments ?? [],
327
+ };
328
+ }
329
+ if (frame.queuedSend !== undefined) {
330
+ queuedSend.current = frame.queuedSend;
331
+ if (frame.queuedSend.runId !== undefined) {
332
+ handoff.current = {
333
+ messageId: frame.queuedSend.messageId,
334
+ runId: frame.queuedSend.runId,
335
+ ...draftOf(chatRef.current.messages[lastUserIndex(chatRef.current.messages)]),
336
+ };
337
+ }
338
+ }
339
+ }
340
+ /**
341
+ * Show a queued message as the user message it now is, and attach to the turn it started. After
342
+ * the SDK has fully settled the previous response — resuming from inside its `onFinish` would
343
+ * have that response's cleanup clobber this one.
344
+ */
345
+ function attachTo(turn) {
346
+ setTimeout(() => {
347
+ if (turn.text.length > 0 || turn.attachments.length > 0) {
348
+ chatRef.current.setMessages((current) => current.some((message) => message.id === turn.messageId)
349
+ ? current
350
+ : [...current, queuedUserMessage(turn)]);
351
+ }
352
+ else {
353
+ // Queued somewhere this chat never saw: the thread has it, once the turn has run.
354
+ resyncAfterSettle.current = true;
355
+ }
356
+ autoResumeRunIdRef.current = turn.runId;
357
+ void chatRef.current.resumeStream();
358
+ }, 0);
359
+ }
360
+ /** Replace the transcript with the persisted thread — after a run finished while we were away. */
361
+ async function resyncFromThread() {
362
+ const threadId = currentThreadId();
363
+ if (threadId === undefined)
364
+ return;
365
+ try {
366
+ const thread = await client.getThread(threadId);
367
+ chatRef.current.setMessages(storedThreadToUiMessages(thread.messages));
368
+ }
369
+ catch {
370
+ /* best-effort: the partial answer stays until the next load */
371
+ }
372
+ }
373
+ // A new conversation starts from rest: nothing of the previous thread's run state carries over.
374
+ const firstChatId = useRef(chatId);
375
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `applyQueue` is stable; `chatId` names the conversation
376
+ useEffect(() => {
377
+ if (chatId === firstChatId.current)
378
+ return;
379
+ firstChatId.current = chatId;
380
+ setRunId(undefined);
381
+ setActiveRunId(null);
382
+ setThreadModel(null);
383
+ setThreadPersona(null);
384
+ setPickedModel(undefined);
385
+ setBackgroundRuns([]);
386
+ setHistoryError(null);
387
+ setRunError(null);
388
+ autoResumeRunIdRef.current = undefined;
389
+ pendingPin.current = undefined;
390
+ applyQueue(EMPTY_QUEUE);
391
+ setPendingSends([]);
392
+ setQueueError(null);
393
+ handoff.current = undefined;
394
+ queuedSend.current = undefined;
395
+ }, [chatId]);
396
+ // A thread's history and its still-streaming turn, in one read. Re-runs per conversation; a
397
+ // stale response (the thread changed mid-flight) is dropped.
398
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation
399
+ useEffect(() => {
400
+ const threadId = options.threadId;
401
+ if (threadId === undefined)
402
+ return;
403
+ // Adopted: this chat created the thread, and its messages are the live ones.
404
+ if (threadId === createdThreadId.current)
405
+ return;
406
+ const current = latest.current;
407
+ const wantHistory = current.history !== false && current.initialMessages === undefined;
408
+ const wantResume = current.resume !== false && current.resumeRunId === undefined;
409
+ if (!wantHistory && !wantResume)
410
+ return;
411
+ let cancelled = false;
412
+ client
413
+ .getThread(threadId)
414
+ .then((thread) => {
415
+ if (cancelled || thread == null)
416
+ return;
417
+ const active = thread.activeRunId ?? null;
418
+ const stored = Array.isArray(thread.messages) ? thread.messages : [];
419
+ setActiveRunId(active);
420
+ setThreadModel(thread.model ?? null);
421
+ setThreadPersona(thread.persona ?? null);
422
+ setHistoryError(null);
423
+ const queue = thread.queue ?? EMPTY_QUEUE;
424
+ applyQueue(queue);
425
+ // Messages left waiting with nothing running and nothing pausing them — the process
426
+ // that would have started them went away. Start the head now.
427
+ if (queue.items.length > 0 &&
428
+ queue.paused === null &&
429
+ active === null &&
430
+ typeof client.resumeQueue === 'function') {
431
+ void resumeQueueRef.current().catch(() => undefined);
432
+ }
433
+ const resuming = wantResume && active !== null;
434
+ if (wantHistory && chatRef.current.messages.length === 0) {
435
+ // The run being resumed replays from its first frame, so its rows are left to the stream.
436
+ const rows = resuming
437
+ ? stored.filter((message) => !(message.role === 'assistant' && message.runId === active))
438
+ : stored;
439
+ chatRef.current.setMessages(storedThreadToUiMessages(rows));
440
+ }
441
+ if (resuming) {
442
+ autoResumeRunIdRef.current = active;
443
+ void chatRef.current.resumeStream();
444
+ }
445
+ }, (error) => {
446
+ if (cancelled)
447
+ return;
448
+ setHistoryError(error instanceof Error ? error : new Error(String(error)));
449
+ })
450
+ .finally(() => {
451
+ if (!cancelled)
452
+ setHistoryFor(threadId);
453
+ });
454
+ return () => {
455
+ cancelled = true;
456
+ };
457
+ }, [client, chatId, options.threadId]);
458
+ const isLoadingHistory = options.threadId !== undefined &&
459
+ options.threadId !== createdThreadId.current &&
460
+ options.history !== false &&
461
+ options.initialMessages === undefined &&
462
+ historyFor !== options.threadId;
463
+ /**
464
+ * One turn in flight per chat. The SDK commits its single in-flight response BEFORE it reaches
465
+ * the transport, so a second overlapping turn cannot be untangled downstream. The ref rather than
466
+ * `chat.status`: a double-submitted composer arrives in the same tick, before status moves.
467
+ */
468
+ const turnInFlight = useRef(false);
469
+ const isTurnInFlight = useCallback(() => turnInFlight.current || transport.isAttemptLive, [transport]);
470
+ // ---- quota ---------------------------------------------------------------------------------
471
+ const quota = useQuota({
472
+ backend: client,
473
+ enabled: options.quota !== false && typeof client.getQuota === 'function',
474
+ });
475
+ const blocked = options.blocked !== undefined ? options.blocked : quota.blocked;
476
+ const blockedRef = useRef(blocked);
477
+ blockedRef.current = blocked;
478
+ // ---- queue ---------------------------------------------------------------------------------
479
+ const whileRunning = typeof client.enqueueMessage === 'function' ? (options.whileRunning ?? 'queue') : 'block';
480
+ const whileRunningRef = useRef(whileRunning);
481
+ whileRunningRef.current = whileRunning;
482
+ const canQueueRef = useRef(false);
483
+ canQueueRef.current = typeof client.enqueueMessage === 'function';
484
+ /** This chat's thread — waiting for a new chat's first turn to name it, when one is in flight. */
485
+ const threadForQueue = useCallback(async () => {
486
+ const known = currentThreadId();
487
+ if (known !== undefined)
488
+ return known;
489
+ if (!isTurnInFlight())
490
+ throw new Error('queue: this chat has no thread yet');
491
+ return new Promise((resolve) => threadWaiters.current.push(resolve));
492
+ }, [currentThreadId, isTurnInFlight]);
493
+ /** Run a queue operation, keeping the last failure on `chat.queue.error`. */
494
+ const queueCall = useCallback(async (run) => {
495
+ try {
496
+ const result = await run();
497
+ setQueueError(null);
498
+ return result;
499
+ }
500
+ catch (error) {
501
+ setQueueError(error instanceof Error ? error : new Error(String(error)));
502
+ throw error;
503
+ }
504
+ }, []);
505
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only
506
+ const enqueue = useCallback(async (text, { attachments = [], mode = 'queue', } = {}) => {
507
+ const block = blockedRef.current;
508
+ if (block != null)
509
+ throw new QuotaBlockedError(block);
510
+ const send = client.enqueueMessage;
511
+ if (typeof send !== 'function')
512
+ throw new AgentBackendUnsupportedError('enqueueMessage');
513
+ localQueueSequence += 1;
514
+ const localId = `local-queued-${localQueueSequence}`;
515
+ setPendingSends((current) => [
516
+ ...current,
517
+ {
518
+ id: localId,
519
+ text,
520
+ attachments,
521
+ files: attachments.map(attachmentFile),
522
+ state: 'sending',
523
+ interrupt: mode === 'interrupt',
524
+ createdAt: new Date().toISOString(),
525
+ },
526
+ ]);
527
+ try {
528
+ await queueCall(async () => {
529
+ const threadId = await threadForQueue();
530
+ const result = await send.call(client, {
531
+ body: {
532
+ ...turnBody(),
533
+ threadId,
534
+ message: text,
535
+ mode,
536
+ ...(attachments.length > 0
537
+ ? { attachments: attachments.map(({ mediaId }) => ({ mediaId })) }
538
+ : {}),
539
+ },
540
+ });
541
+ applyQueue(result.queue);
542
+ if (result.runId !== undefined) {
543
+ // Nothing was running after all: it started at once.
544
+ const turn = { messageId: result.messageId, runId: result.runId, text, attachments };
545
+ if (isTurnInFlight())
546
+ handoff.current = turn;
547
+ else
548
+ attachTo(turn);
549
+ }
550
+ });
551
+ }
552
+ finally {
553
+ setPendingSends((current) => current.filter((item) => item.id !== localId));
554
+ }
555
+ }, [client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]);
556
+ const sendMessage = useCallback(async (message, options) => {
557
+ const block = blockedRef.current;
558
+ if (block != null)
559
+ throw new QuotaBlockedError(block);
560
+ // `mode` is this hook's, not the SDK's: it never reaches the request.
561
+ const { mode: ownMode, ...sdkOptions } = options ?? {};
562
+ if (isTurnInFlight()) {
563
+ // Mid-turn: the message waits in the thread's queue — unless this chat blocks instead. A
564
+ // backend that cannot queue blocks whatever was asked for.
565
+ const mode = canQueueRef.current ? (ownMode ?? whileRunningRef.current) : 'block';
566
+ if (mode === 'block')
567
+ return;
568
+ const draft = draftOf(message);
569
+ await enqueue(draft.text, { attachments: draft.attachments, mode });
570
+ return;
571
+ }
572
+ turnInFlight.current = true;
573
+ try {
574
+ await chatRef.current.sendMessage(message, options === undefined ? undefined : sdkOptions);
575
+ }
576
+ finally {
577
+ turnInFlight.current = false;
578
+ }
579
+ }, [isTurnInFlight, enqueue]);
580
+ const removeQueued = useCallback(async (id) => {
581
+ const previous = queueStateRef.current;
582
+ applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
583
+ try {
584
+ applyQueue(await queueCall(() => requireBackendMethod(client, 'removeQueuedMessage')(id)));
585
+ }
586
+ catch (error) {
587
+ applyQueue(previous);
588
+ throw error;
589
+ }
590
+ }, [client, queueCall, applyQueue]);
591
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only
592
+ const interruptQueued = useCallback(async (id) => {
593
+ const previous = queueStateRef.current;
594
+ const moving = previous.items.find((item) => item.id === id);
595
+ if (moving !== undefined) {
596
+ // Shown where it will be at once: at the head, as the interrupt, the pause lifted.
597
+ applyQueue({
598
+ paused: null,
599
+ items: [
600
+ { ...moving, interrupt: true },
601
+ ...previous.items.filter((item) => item.id !== id),
602
+ ],
603
+ });
604
+ }
605
+ try {
606
+ const result = await queueCall(() => requireBackendMethod(client, 'interruptQueuedMessage')(id));
607
+ applyQueue({ items: result.items, paused: result.paused });
608
+ if (result.runId !== undefined) {
609
+ // Nothing was running: it started at once.
610
+ const turn = {
611
+ messageId: result.runId,
612
+ runId: result.runId,
613
+ text: moving?.content ?? '',
614
+ attachments: moving?.attachments ?? [],
615
+ };
616
+ if (isTurnInFlight())
617
+ handoff.current = turn;
618
+ else
619
+ attachTo(turn);
620
+ }
621
+ }
622
+ catch (error) {
623
+ applyQueue(previous);
624
+ throw error;
625
+ }
626
+ }, [client, queueCall, applyQueue, isTurnInFlight]);
627
+ const editQueued = useCallback(async (id, text) => {
628
+ applyQueue(await queueCall(() => requireBackendMethod(client, 'updateQueuedMessage')(id, { message: text })));
629
+ }, [client, queueCall, applyQueue]);
630
+ const moveQueued = useCallback(async (id, index) => {
631
+ const previous = queueStateRef.current;
632
+ const moving = previous.items.find((item) => item.id === id);
633
+ if (moving !== undefined) {
634
+ const rest = previous.items.filter((item) => item.id !== id);
635
+ rest.splice(Math.max(0, Math.min(rest.length, index)), 0, moving);
636
+ applyQueue({ ...previous, items: rest });
637
+ }
638
+ try {
639
+ applyQueue(await queueCall(() => requireBackendMethod(client, 'updateQueuedMessage')(id, { position: index })));
640
+ }
641
+ catch (error) {
642
+ applyQueue(previous);
643
+ throw error;
644
+ }
645
+ }, [client, queueCall, applyQueue]);
646
+ const clearQueue = useCallback(async () => {
647
+ const threadId = currentThreadId();
648
+ if (threadId === undefined)
649
+ return;
650
+ applyQueue(await queueCall(() => requireBackendMethod(client, 'clearQueue')(threadId)));
651
+ }, [client, queueCall, currentThreadId, applyQueue]);
652
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `attachTo` reads refs only
653
+ const resumeQueue = useCallback(async () => {
654
+ const threadId = currentThreadId();
655
+ if (threadId === undefined)
656
+ return;
657
+ const before = queueStateRef.current;
658
+ const result = await queueCall(() => requireBackendMethod(client, 'resumeQueue')(threadId));
659
+ applyQueue({ items: result.items, paused: result.paused });
660
+ if (result.runId !== undefined) {
661
+ const head = before.items.find((item) => item.id === result.runId) ?? before.items[0];
662
+ const turn = {
663
+ messageId: result.runId,
664
+ runId: result.runId,
665
+ text: head?.content ?? '',
666
+ attachments: head?.attachments ?? [],
667
+ };
668
+ if (isTurnInFlight())
669
+ handoff.current = turn;
670
+ else
671
+ attachTo(turn);
672
+ }
673
+ }, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
674
+ const resumeQueueRef = useRef(resumeQueue);
675
+ resumeQueueRef.current = resumeQueue;
676
+ const queuedItems = [
677
+ ...pendingSends.filter((item) => item.interrupt),
678
+ ...queueState.items.map((item) => ({
679
+ id: item.id,
680
+ text: item.content,
681
+ attachments: item.attachments ?? [],
682
+ files: (item.attachments ?? []).map(attachmentFile),
683
+ state: 'queued',
684
+ interrupt: item.interrupt === true,
685
+ createdAt: item.createdAt,
686
+ })),
687
+ ...pendingSends.filter((item) => !item.interrupt),
688
+ ];
689
+ const queue = {
690
+ items: queuedItems,
691
+ paused: queueState.paused,
692
+ isSupported: typeof client.enqueueMessage === 'function',
693
+ add: enqueue,
694
+ remove: removeQueued,
695
+ interrupt: interruptQueued,
696
+ edit: editQueued,
697
+ move: moveQueued,
698
+ clear: clearQueue,
699
+ resume: resumeQueue,
700
+ error: queueError,
701
+ };
702
+ const addToolResult = useCallback(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
703
+ tool,
704
+ toolCallId,
705
+ output,
706
+ }), []);
707
+ // ---- background runs -----------------------------------------------------------------------
708
+ const [backgroundRuns, setBackgroundRuns] = useState([]);
709
+ /** Re-derive what is running in the background, and pull in anything that has landed since. */
710
+ const refreshBackground = useCallback(async () => {
711
+ const threadId = currentThreadId();
712
+ if (threadId === undefined) {
713
+ return;
714
+ }
715
+ const thread = await client.getThread(threadId);
716
+ const runs = backgroundRunsFromThread(thread.messages);
717
+ setBackgroundRuns(runs);
718
+ const landed = runs
719
+ .map((run) => run.message)
720
+ .filter((message) => message !== undefined);
721
+ if (landed.length === 0) {
722
+ return;
723
+ }
724
+ // Appended rather than re-seeding the list: the session's own messages hold live stream state
725
+ // that the persisted rows do not carry.
726
+ chatRef.current.setMessages((current) => {
727
+ const known = new Set(current.map((message) => message.id));
728
+ const missing = landed.filter((message) => !known.has(message.id));
729
+ return missing.length === 0
730
+ ? current
731
+ : [...current, ...missing.map((message) => storedMessageToUiMessage(message))];
732
+ });
733
+ }, [client, currentThreadId]);
734
+ backgroundRef.current = refreshBackground;
735
+ const isWorking = backgroundRuns.some((run) => run.status === 'running');
736
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `chatId` names the conversation
737
+ useEffect(() => {
738
+ if (options.background !== true || options.threadId === undefined) {
739
+ return;
740
+ }
741
+ void refreshBackground();
742
+ }, [options.background, options.threadId, chatId, refreshBackground]);
743
+ useEffect(() => {
744
+ const every = latest.current.backgroundPollMs ?? 5000;
745
+ if (latest.current.background !== true || !isWorking || every <= 0) {
746
+ return;
747
+ }
748
+ const timer = setInterval(() => void refreshBackground(), every);
749
+ return () => clearInterval(timer);
750
+ }, [isWorking, refreshBackground]);
751
+ const proposals = useActionProposals(client, options.proposals === false ||
752
+ (options.proposals !== true && options.history === false && options.resume === false)
753
+ ? undefined
754
+ : currentThreadId(), (update) => chatRef.current.setMessages(update), `${chat.status}:${connection.status}`, options.proposalPollMs);
755
+ proposalRefreshRef.current = proposals.refresh;
756
+ // ---- actions -------------------------------------------------------------------------------
757
+ const cancel = useCallback(async () => {
758
+ // Close the SSE on the client first so the UI flips out of streaming, then hard-abort
759
+ // server-side (a late terminal step can outlive the connection close alone).
760
+ chatRef.current.stop();
761
+ const active = runIdRef.current;
762
+ if (active) {
763
+ try {
764
+ await client.cancelStream(active);
765
+ }
766
+ catch {
767
+ /* best-effort — the SDK stop already flipped the UI */
768
+ }
769
+ }
770
+ // The stream that would have carried the `queue` frame was closed above, so a queue the stop
771
+ // just paused is read back: otherwise its messages keep saying "up next" with nothing coming.
772
+ const threadId = currentThreadId();
773
+ if (threadId !== undefined &&
774
+ queueStateRef.current.items.length > 0 &&
775
+ typeof client.getQueue === 'function') {
776
+ try {
777
+ applyQueue(await client.getQueue(threadId));
778
+ }
779
+ catch {
780
+ /* best-effort — the next thread read brings it */
781
+ }
782
+ }
783
+ }, [client, currentThreadId, applyQueue]);
784
+ // Approve / reject / answer / skip route by tool-call id alone — the server derives the run
785
+ // awaiting it (a sub-agent's own run when the call belongs to a delegated agent).
786
+ const approve = useCallback(async ({ toolCallId, target, remember, via }) => {
787
+ if (target?.kind === 'proposal') {
788
+ const threadId = target.threadId ?? currentThreadId();
789
+ if (threadId === undefined)
790
+ throw new Error('A proposal decision requires its thread scope');
791
+ await requireBackendMethod(client, 'approveActionProposal')({
792
+ threadId,
793
+ proposalId: target.proposalId,
794
+ ...(remember === true ? { remember: true } : {}),
795
+ });
796
+ await proposals.refresh();
797
+ return;
798
+ }
799
+ await requireBackendMethod(client, 'approveToolCall')({
800
+ toolCallId,
801
+ ...(remember === true ? { remember: true } : {}),
802
+ ...(via !== undefined ? { via } : {}),
803
+ });
804
+ }, [client, currentThreadId, proposals.refresh]);
805
+ const reject = useCallback(async ({ toolCallId, target, reason, via }) => {
806
+ if (target?.kind === 'proposal') {
807
+ const threadId = target.threadId ?? currentThreadId();
808
+ if (threadId === undefined)
809
+ throw new Error('A proposal decision requires its thread scope');
810
+ await requireBackendMethod(client, 'rejectActionProposal')({
811
+ threadId,
812
+ proposalId: target.proposalId,
813
+ ...(reason === undefined ? {} : { reason }),
814
+ });
815
+ await proposals.refresh();
816
+ return;
817
+ }
818
+ await requireBackendMethod(client, 'rejectToolCall')({
819
+ toolCallId,
820
+ ...(reason !== undefined ? { reason } : {}),
821
+ ...(via !== undefined ? { via } : {}),
822
+ });
823
+ }, [client, currentThreadId, proposals.refresh]);
824
+ const answer = useCallback(async ({ toolCallId, answers, via }) => {
825
+ await requireBackendMethod(client, 'answerToolCall')({
826
+ toolCallId,
827
+ ...(answers !== undefined ? { answers } : {}),
828
+ ...(via !== undefined ? { via } : {}),
829
+ });
830
+ }, [client]);
831
+ const skip = useCallback(async ({ toolCallId, via }) => {
832
+ await requireBackendMethod(client, 'skipToolCall')({ toolCallId, ...(via !== undefined ? { via } : {}) });
833
+ }, [client]);
834
+ // Re-run the last exchange: flag the next request as a regenerate (so the backend truncates and
835
+ // re-answers instead of appending) and let the SDK re-issue it.
836
+ const regenerate = useCallback((_input) => {
837
+ const block = blockedRef.current;
838
+ if (block != null)
839
+ throw new QuotaBlockedError(block);
840
+ if (isTurnInFlight())
841
+ return;
842
+ regenerateNext.current = true;
843
+ turnInFlight.current = true;
844
+ void chatRef.current.regenerate().finally(() => {
845
+ turnInFlight.current = false;
846
+ });
847
+ }, [isTurnInFlight]);
848
+ /**
849
+ * The persisted id of a message on screen. A message streamed in this session carries the
850
+ * client's own id, so the row it became is found by the run that wrote it.
851
+ */
852
+ const storedIdOf = useCallback(async (messageId, threadId) => {
853
+ const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
854
+ const runOf = message?.metadata?.runId;
855
+ if (runOf === undefined)
856
+ return messageId;
857
+ const thread = await client.getThread(threadId);
858
+ const row = [...thread.messages]
859
+ .reverse()
860
+ .find((candidate) => candidate.role === 'assistant' && candidate.runId === runOf);
861
+ return row?.id ?? messageId;
862
+ }, [client]);
863
+ /**
864
+ * Branch the conversation at `messageId` into a new thread (`onThreadCreated` gets its id).
865
+ * Defaults to this chat's thread.
866
+ */
867
+ const fork = useCallback(async ({ messageId, threadId, }) => {
868
+ const source = threadId ?? currentThreadId();
869
+ if (source === undefined)
870
+ throw new Error('fork: this chat has no thread yet');
871
+ const stored = await storedIdOf(messageId, source);
872
+ const forked = await requireBackendMethod(client, 'forkFromMessage')(source, stored);
873
+ notifyThreads(client, { type: 'changed' });
874
+ latest.current.onThreadCreated?.(forked.id);
875
+ return forked;
876
+ }, [client, currentThreadId, storedIdOf]);
877
+ /** Delete `messageId` and everything after it on the thread (default: this chat's). */
878
+ const truncateFrom = useCallback(async ({ messageId, threadId }) => {
879
+ const target = threadId ?? currentThreadId();
880
+ if (target === undefined)
881
+ throw new Error('truncateFrom: this chat has no thread yet');
882
+ const stored = await storedIdOf(messageId, target);
883
+ await requireBackendMethod(client, 'truncateFromMessage')(target, stored);
884
+ }, [client, currentThreadId, storedIdOf]);
885
+ /** Make a transient thread (default: this chat's) a regular one, listed by `useThreads`. */
886
+ const promote = useCallback(async ({ threadId } = {}) => {
887
+ const target = threadId ?? currentThreadId();
888
+ if (target === undefined)
889
+ throw new Error('promote: this chat has no thread yet');
890
+ await requireBackendMethod(client, 'promoteThread')(target);
891
+ notifyThreads(client, { type: 'changed' });
892
+ }, [client, currentThreadId]);
893
+ // ---- models --------------------------------------------------------------------------------
894
+ const [modelsWanted, setModelsWanted] = useState(false);
895
+ const modelsWantedRef = useRef(modelsWanted);
896
+ modelsWantedRef.current = modelsWanted;
897
+ const catalog = useModels({
898
+ backend: client,
899
+ ...(options.agent !== undefined ? { agent: options.agent } : {}),
900
+ enabled: modelsWanted && typeof client.listModels === 'function',
901
+ });
902
+ const wantModels = useCallback(() => {
903
+ if (modelsWantedRef.current)
904
+ return;
905
+ modelsWantedRef.current = true;
906
+ // After render: the getter may be read while a child renders.
907
+ queueMicrotask(() => setModelsWanted(true));
908
+ }, []);
909
+ lockedRef.current = catalog.locked !== null;
910
+ const selectModel = useCallback((id) => {
911
+ if (!lockedRef.current)
912
+ setPickedModel(id);
913
+ }, []);
914
+ const pinToThread = useCallback(async (model) => {
915
+ const threadId = currentThreadId();
916
+ setThreadModel(model);
917
+ // The pin is what later turns run on: a pick would override it on every send.
918
+ setPickedModel(undefined);
919
+ if (threadId === undefined) {
920
+ pendingPin.current = { model };
921
+ return;
922
+ }
923
+ await client.updateThread(threadId, { model });
924
+ notifyThreads(client, { type: 'changed' });
925
+ }, [client, currentThreadId]);
926
+ const models = {
927
+ get list() {
928
+ wantModels();
929
+ return catalog.models;
930
+ },
931
+ get providers() {
932
+ wantModels();
933
+ return catalog.providers;
934
+ },
935
+ selected: catalog.locked?.model ??
936
+ options.model ??
937
+ pickedModel ??
938
+ threadModel ??
939
+ catalog.defaultModel ??
940
+ null,
941
+ pinned: threadModel,
942
+ get defaultModel() {
943
+ wantModels();
944
+ return catalog.defaultModel;
945
+ },
946
+ get locked() {
947
+ wantModels();
948
+ return catalog.locked;
949
+ },
950
+ select: selectModel,
951
+ pinToThread,
952
+ isLoading: modelsWanted && catalog.isLoading,
953
+ error: catalog.error,
954
+ };
955
+ // A dropped stream the transport is retrying reads as its own status; every other moment is the
956
+ // SDK's. `reconnecting` is still a busy status to the transcript model (see `ChatStatus`).
957
+ const status = connection.status === 'reconnecting' ? 'reconnecting' : chat.status;
958
+ const isBusy = status === 'submitted' || status === 'streaming' || status === 'reconnecting';
959
+ const isBusyRef = useRef(isBusy);
960
+ isBusyRef.current = isBusy;
961
+ // ---- composer ------------------------------------------------------------------------------
962
+ const files = useAttachments({ ...options.composer, backend: client });
963
+ const [text, setText] = useState('');
964
+ const blockedBy = blocked != null
965
+ ? 'quota'
966
+ : files.isUploading
967
+ ? 'uploading'
968
+ : isBusy && whileRunning === 'block'
969
+ ? 'busy'
970
+ : text.trim().length === 0 && files.refs.length === 0
971
+ ? 'empty'
972
+ : null;
973
+ const composerRef = useRef({ text, files, blockedBy });
974
+ composerRef.current = { text, files, blockedBy };
975
+ const submit = useCallback(async (options) => {
976
+ const current = composerRef.current;
977
+ // A mode named for this call is an answer to "a turn is running": it lifts that one block.
978
+ const asked = canQueueRef.current ? options?.mode : undefined;
979
+ if (current.blockedBy !== null && !(current.blockedBy === 'busy' && asked !== undefined)) {
980
+ return;
981
+ }
982
+ if (current.text.trim().length === 0 && current.files.refs.length === 0)
983
+ return;
984
+ const refs = current.files.refs;
985
+ // The sent message shows its files right away, as the reloaded thread will (`messageFiles`).
986
+ const files = current.files.items.flatMap((item) => item.status === 'ready' && item.attachment !== undefined
987
+ ? [
988
+ {
989
+ type: 'file',
990
+ mediaType: item.attachment.contentType,
991
+ filename: item.attachment.name,
992
+ url: item.attachment.url,
993
+ providerMetadata: { agent: { mediaId: item.attachment.mediaId } },
994
+ },
995
+ ]
996
+ : []);
997
+ const draft = current.text.trim();
998
+ setText('');
999
+ current.files.clear();
1000
+ const mode = asked ?? whileRunningRef.current;
1001
+ if (mode !== 'block' && (isTurnInFlight() || isBusyRef.current)) {
1002
+ // Mid-turn: wait in the thread's queue (or, `interrupt`, cut in) instead of refusing.
1003
+ const attachments = current.files.items.flatMap((item) => item.status === 'ready' && item.attachment !== undefined ? [item.attachment] : []);
1004
+ await enqueue(draft, { attachments, mode });
1005
+ return;
1006
+ }
1007
+ await sendMessage(files.length > 0 ? { text: draft, files } : { text: draft }, refs.length > 0 ? { body: { attachments: refs } } : undefined);
1008
+ }, [sendMessage, enqueue, isTurnInFlight]);
1009
+ const composer = {
1010
+ text,
1011
+ setText,
1012
+ files,
1013
+ canSend: blockedBy === null,
1014
+ blockedBy,
1015
+ submit,
1016
+ };
1017
+ // ---- transcript ----------------------------------------------------------------------------
1018
+ const ownCatalog = options.transcript?.toolCatalog;
1019
+ const tools = useToolCatalog({
1020
+ backend: client,
1021
+ ...(options.agent !== undefined ? { agent: options.agent } : {}),
1022
+ enabled: ownCatalog === undefined && typeof client.listTools === 'function',
1023
+ });
1024
+ const canFork = typeof client.forkFromMessage === 'function';
1025
+ const transcript = useChatTranscript({
1026
+ messages: chat.messages,
1027
+ status,
1028
+ onStop: cancel,
1029
+ onApprove: approve,
1030
+ onReject: reject,
1031
+ onAnswer: answer,
1032
+ onSkip: skip,
1033
+ regeneratable: true,
1034
+ onRegenerate: regenerate,
1035
+ ...(canFork
1036
+ ? { onFork: (input) => fork(input).then(() => undefined) }
1037
+ : {}),
1038
+ ...(ownCatalog === undefined ? { toolCatalog: tools.catalog } : {}),
1039
+ queue: { items: queue.items, paused: queue.paused, remove: removeQueued },
1040
+ ...options.transcript,
1041
+ });
1042
+ const background = {
1043
+ runs: backgroundRuns,
1044
+ isWorking,
1045
+ refresh: refreshBackground,
1046
+ };
1047
+ return {
1048
+ ...chat,
1049
+ status,
1050
+ /** Where the live stream stands — see {@link StreamConnectionState}. */
1051
+ connection,
1052
+ sendMessage,
1053
+ addToolResult,
1054
+ /** Sub-agents this conversation started and did not wait for. */
1055
+ background,
1056
+ proposals,
1057
+ runId,
1058
+ /** The loaded thread's running turn, or `null` once read with none. */
1059
+ activeRunId,
1060
+ /** The thread's history is being read. */
1061
+ isLoadingHistory,
1062
+ /** Reading the thread's history failed. */
1063
+ historyError,
1064
+ /**
1065
+ * How the last run's stream said it failed — the `event: error` frame's `code` and `message` —
1066
+ * or `null`. Cleared when the next attempt starts and when the chat moves to another thread.
1067
+ * `chat.error` still carries the message; this is where the `code` is, so the app can word each
1068
+ * failure itself (`replay_diverged`, `model_no_output`, `run_failed`, `quota_exceeded`, …).
1069
+ */
1070
+ runError,
1071
+ /**
1072
+ * The thread this chat is on right now: the `threadId` option, else the one the backend created
1073
+ * on the first send. A getter, because the created id is learned mid-stream.
1074
+ */
1075
+ getThreadId: currentThreadId,
1076
+ /** The backend this chat talks to — the same one every other hook under the provider uses. */
1077
+ backend: client,
1078
+ /** The transcript model, with every action already bound to this chat. */
1079
+ transcript,
1080
+ /** A headless composer: draft, files, send gate, `submit()`. */
1081
+ composer,
1082
+ /**
1083
+ * Messages sent while a turn was running, waiting their turn (server-side): list, edit, move,
1084
+ * remove, clear, and resume a paused queue.
1085
+ */
1086
+ queue,
1087
+ /** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */
1088
+ models,
1089
+ /**
1090
+ * The persona pinned on this thread (`ThreadSummary.persona`), or `null` when none is — what a
1091
+ * persona picker on a reopened thread starts from (`?? agent.defaultPersona`).
1092
+ */
1093
+ threadPersona,
1094
+ /** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */
1095
+ quota,
1096
+ /** The window blocking sends right now (the `blocked` option, else the quota report's). */
1097
+ blocked,
1098
+ cancel,
1099
+ approve,
1100
+ reject,
1101
+ answer,
1102
+ skip,
1103
+ regenerate,
1104
+ fork,
1105
+ truncateFrom,
1106
+ promote,
1107
+ };
1108
+ }
1109
+ /** A send refused on the client because a quota window is exhausted. */
1110
+ export class QuotaBlockedError extends Error {
1111
+ block;
1112
+ constructor(block) {
1113
+ super(block.reason ?? `The ${block.period === 'day' ? 'daily' : 'monthly'} quota is used up`);
1114
+ this.block = block;
1115
+ this.name = 'QuotaBlockedError';
1116
+ }
1117
+ }
1118
+ //# sourceMappingURL=use-agent-chat.js.map