agents 0.0.0-2cc0f02 → 0.0.0-2e73791

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 (68) hide show
  1. package/README.md +126 -3
  2. package/dist/ai-chat-agent.d.ts +231 -22
  3. package/dist/ai-chat-agent.js +691 -121
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/{ai-chat-v5-migration-gdyLiTd8.js → ai-chat-v5-migration-DguhuLKF.js} +2 -2
  6. package/dist/{ai-chat-v5-migration-gdyLiTd8.js.map → ai-chat-v5-migration-DguhuLKF.js.map} +1 -1
  7. package/dist/ai-chat-v5-migration.js +1 -1
  8. package/dist/ai-react.d.ts +145 -16
  9. package/dist/ai-react.js +389 -75
  10. package/dist/ai-react.js.map +1 -1
  11. package/dist/{ai-types-B0GBFDwi.js → ai-types-DEtF_8Km.js} +10 -2
  12. package/dist/ai-types-DEtF_8Km.js.map +1 -0
  13. package/dist/{ai-types-BWW4umHY.d.ts → ai-types-U8lYA0o8.d.ts} +41 -9
  14. package/dist/ai-types.d.ts +4 -4
  15. package/dist/ai-types.js +1 -1
  16. package/dist/cli/index.d.ts +1 -0
  17. package/dist/cli/index.js +28 -0
  18. package/dist/cli/index.js.map +1 -0
  19. package/dist/client-Cfw92Wb_.d.ts +834 -0
  20. package/dist/{client-CmMi85Sj.d.ts → client-ClORm6f0.d.ts} +10 -10
  21. package/dist/{client-zS-OCVJA.js → client-DjTPRM8-.js} +3 -3
  22. package/dist/{client-zS-OCVJA.js.map → client-DjTPRM8-.js.map} +1 -1
  23. package/dist/client-QZa2Rq0l.js +1105 -0
  24. package/dist/client-QZa2Rq0l.js.map +1 -0
  25. package/dist/client.d.ts +8 -8
  26. package/dist/client.js +2 -2
  27. package/dist/codemode/ai.js +7 -6
  28. package/dist/codemode/ai.js.map +1 -1
  29. package/dist/context-BkKbAa1R.js +8 -0
  30. package/dist/context-BkKbAa1R.js.map +1 -0
  31. package/dist/context-_sPQqJWv.d.ts +24 -0
  32. package/dist/context.d.ts +6 -0
  33. package/dist/context.js +3 -0
  34. package/dist/{do-oauth-client-provider-CCwGwnrA.d.ts → do-oauth-client-provider-B-ryFIPr.d.ts} +21 -6
  35. package/dist/{do-oauth-client-provider-B2jr6UNq.js → do-oauth-client-provider-B1fVIshX.js} +71 -9
  36. package/dist/do-oauth-client-provider-B1fVIshX.js.map +1 -0
  37. package/dist/{index-W4JUkafc.d.ts → index-CyDpAVHZ.d.ts} +7 -3
  38. package/dist/{index-DWcUTPtX.d.ts → index-xIS9I1YX.d.ts} +83 -65
  39. package/dist/index.d.ts +36 -36
  40. package/dist/index.js +6 -5
  41. package/dist/mcp/client.d.ts +4 -4
  42. package/dist/mcp/client.js +2 -1
  43. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  44. package/dist/mcp/do-oauth-client-provider.js +1 -1
  45. package/dist/mcp/index.d.ts +140 -12
  46. package/dist/mcp/index.js +636 -41
  47. package/dist/mcp/index.js.map +1 -1
  48. package/dist/mcp/x402.js +10 -6
  49. package/dist/mcp/x402.js.map +1 -1
  50. package/dist/{mcp-BEwaCsxO.d.ts → mcp-CzbSsLfc.d.ts} +2 -2
  51. package/dist/observability/index.d.ts +2 -2
  52. package/dist/observability/index.js +6 -5
  53. package/dist/{react-B8BT6PYZ.d.ts → react-ElpIreHg.d.ts} +35 -17
  54. package/dist/react.d.ts +15 -10
  55. package/dist/react.js +57 -57
  56. package/dist/react.js.map +1 -1
  57. package/dist/{serializable-gtr9YMhp.d.ts → serializable-C4GLimgv.d.ts} +8 -3
  58. package/dist/serializable.d.ts +5 -5
  59. package/dist/{src-C9xZ0CrH.js → src-BZDh910Z.js} +130 -128
  60. package/dist/src-BZDh910Z.js.map +1 -0
  61. package/package.json +61 -44
  62. package/dist/ai-types-B0GBFDwi.js.map +0 -1
  63. package/dist/client-C-u-lCFT.d.ts +0 -5311
  64. package/dist/client-WbaRgKYN.js +0 -788
  65. package/dist/client-WbaRgKYN.js.map +0 -1
  66. package/dist/do-oauth-client-provider-B2jr6UNq.js.map +0 -1
  67. package/dist/src-C9xZ0CrH.js.map +0 -1
  68. package/src/index.ts +0 -2031
package/dist/ai-react.js CHANGED
@@ -1,10 +1,28 @@
1
- import { MessageType } from "./ai-types-B0GBFDwi.js";
2
- import { nanoid } from "nanoid";
1
+ import { t as MessageType } from "./ai-types-DEtF_8Km.js";
3
2
  import { DefaultChatTransport, getToolName, isToolUIPart } from "ai";
3
+ import { nanoid } from "nanoid";
4
4
  import { useChat } from "@ai-sdk/react";
5
- import { use, useCallback, useEffect, useMemo, useRef } from "react";
5
+ import { use, useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
 
7
7
  //#region src/ai-react.tsx
8
+ /**
9
+ * Extracts tool schemas from tools that have client-side execute functions.
10
+ * These schemas are automatically sent to the server with each request.
11
+ * @param tools - Record of tool name to tool definition
12
+ * @returns Array of tool schemas to send to server, or undefined if none
13
+ */
14
+ function extractClientToolSchemas(tools) {
15
+ if (!tools) return void 0;
16
+ const schemas = Object.entries(tools).filter(([_, tool$1]) => tool$1.execute).map(([name, tool$1]) => {
17
+ if (tool$1.inputSchema && !tool$1.parameters) console.warn(`[useAgentChat] Tool "${name}" uses deprecated 'inputSchema'. Please migrate to 'parameters'.`);
18
+ return {
19
+ name,
20
+ description: tool$1.description,
21
+ parameters: tool$1.parameters ?? tool$1.inputSchema
22
+ };
23
+ });
24
+ return schemas.length > 0 ? schemas : void 0;
25
+ }
8
26
  const requestCache = /* @__PURE__ */ new Map();
9
27
  /**
10
28
  * React hook for building AI chat interfaces using an Agent
@@ -22,11 +40,12 @@ function detectToolsRequiringConfirmation(tools) {
22
40
  return Object.entries(tools).filter(([_name, tool$1]) => !tool$1.execute).map(([name]) => name);
23
41
  }
24
42
  function useAgentChat(options) {
25
- const { agent, getInitialMessages, messages: optionsInitialMessages, experimental_automaticToolResolution, tools, toolsRequiringConfirmation: manualToolsRequiringConfirmation, autoSendAfterAllConfirmationsResolved = true,...rest } = options;
43
+ const { agent, getInitialMessages, messages: optionsInitialMessages, experimental_automaticToolResolution, tools, toolsRequiringConfirmation: manualToolsRequiringConfirmation, autoContinueAfterToolResult = false, autoSendAfterAllConfirmationsResolved = true, resume = true, prepareSendMessagesRequest, ...rest } = options;
26
44
  const toolsRequiringConfirmation = manualToolsRequiringConfirmation ?? detectToolsRequiringConfirmation(tools);
27
45
  const agentUrl = new URL(`${(agent._url || agent._pkurl)?.replace("ws://", "http://").replace("wss://", "https://")}`);
28
46
  agentUrl.searchParams.delete("_pk");
29
47
  const agentUrlString = agentUrl.toString();
48
+ const initialMessagesCacheKey = `${agentUrlString}|${agent.agent ?? ""}|${agent.name ?? ""}`;
30
49
  const agentRef = useRef(agent);
31
50
  useEffect(() => {
32
51
  agentRef.current = agent;
@@ -52,38 +71,42 @@ function useAgentChat(options) {
52
71
  }
53
72
  }
54
73
  const getInitialMessagesFetch = getInitialMessages || defaultGetInitialMessagesFetch;
55
- function doGetInitialMessages(getInitialMessagesOptions) {
56
- if (requestCache.has(agentUrlString)) return requestCache.get(agentUrlString);
74
+ function doGetInitialMessages(getInitialMessagesOptions, cacheKey) {
75
+ if (requestCache.has(cacheKey)) return requestCache.get(cacheKey);
57
76
  const promise = getInitialMessagesFetch(getInitialMessagesOptions);
58
- requestCache.set(agentUrlString, promise);
77
+ requestCache.set(cacheKey, promise);
59
78
  return promise;
60
79
  }
61
80
  const initialMessagesPromise = getInitialMessages === null ? null : doGetInitialMessages({
62
81
  agent: agent.agent,
63
82
  name: agent.name,
64
83
  url: agentUrlString
65
- });
84
+ }, initialMessagesCacheKey);
66
85
  const initialMessages = initialMessagesPromise ? use(initialMessagesPromise) : optionsInitialMessages ?? [];
67
86
  useEffect(() => {
68
87
  if (!initialMessagesPromise) return;
69
- requestCache.set(agentUrlString, initialMessagesPromise);
88
+ requestCache.set(initialMessagesCacheKey, initialMessagesPromise);
70
89
  return () => {
71
- if (requestCache.get(agentUrlString) === initialMessagesPromise) requestCache.delete(agentUrlString);
90
+ if (requestCache.get(initialMessagesCacheKey) === initialMessagesPromise) requestCache.delete(initialMessagesCacheKey);
72
91
  };
73
- }, [agentUrlString, initialMessagesPromise]);
92
+ }, [initialMessagesCacheKey, initialMessagesPromise]);
74
93
  const aiFetch = useCallback(async (request, options$1 = {}) => {
75
94
  const { method, keepalive, headers, body, redirect, integrity, signal, credentials, mode, referrer, referrerPolicy, window } = options$1;
76
95
  const id = nanoid(8);
77
96
  const abortController = new AbortController();
78
97
  let controller;
79
98
  const currentAgent = agentRef.current;
99
+ localRequestIdsRef.current.add(id);
80
100
  signal?.addEventListener("abort", () => {
81
101
  currentAgent.send(JSON.stringify({
82
102
  id,
83
103
  type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL
84
104
  }));
85
105
  abortController.abort();
86
- controller.close();
106
+ try {
107
+ controller.close();
108
+ } catch {}
109
+ localRequestIdsRef.current.delete(id);
87
110
  });
88
111
  currentAgent.addEventListener("message", (event) => {
89
112
  let data;
@@ -96,18 +119,27 @@ function useAgentChat(options) {
96
119
  if (data.id === id) if (data.error) {
97
120
  controller.error(new Error(data.body));
98
121
  abortController.abort();
122
+ localRequestIdsRef.current.delete(id);
99
123
  } else {
100
124
  if (data.body?.trim()) controller.enqueue(new TextEncoder().encode(`data: ${data.body}\n\n`));
101
125
  if (data.done) {
102
- controller.close();
126
+ try {
127
+ controller.close();
128
+ } catch {}
103
129
  abortController.abort();
130
+ localRequestIdsRef.current.delete(id);
104
131
  }
105
132
  }
106
133
  }
107
134
  }, { signal: abortController.signal });
108
- const stream = new ReadableStream({ start(c) {
109
- controller = c;
110
- } });
135
+ const stream = new ReadableStream({
136
+ start(c) {
137
+ controller = c;
138
+ },
139
+ cancel(reason) {
140
+ console.warn("[agents/ai-react] cancelling stream", id, reason || "no reason");
141
+ }
142
+ });
111
143
  currentAgent.send(JSON.stringify({
112
144
  id,
113
145
  init: {
@@ -128,19 +160,47 @@ function useAgentChat(options) {
128
160
  }));
129
161
  return new Response(stream);
130
162
  }, []);
163
+ const toolsRef = useRef(tools);
164
+ toolsRef.current = tools;
165
+ const prepareSendMessagesRequestRef = useRef(prepareSendMessagesRequest);
166
+ prepareSendMessagesRequestRef.current = prepareSendMessagesRequest;
131
167
  const customTransport = useMemo(() => ({
132
- sendMessages: async (options$1) => {
168
+ sendMessages: async (sendMessageOptions) => {
169
+ const clientToolSchemas = extractClientToolSchemas(toolsRef.current);
133
170
  return new DefaultChatTransport({
134
171
  api: agentUrlString,
135
- fetch: aiFetch
136
- }).sendMessages(options$1);
172
+ fetch: aiFetch,
173
+ prepareSendMessagesRequest: clientToolSchemas || prepareSendMessagesRequestRef.current ? async (prepareOptions) => {
174
+ let body = {};
175
+ let headers;
176
+ let credentials;
177
+ let api;
178
+ if (clientToolSchemas) body = {
179
+ id: prepareOptions.id,
180
+ messages: prepareOptions.messages,
181
+ trigger: prepareOptions.trigger,
182
+ clientTools: clientToolSchemas
183
+ };
184
+ if (prepareSendMessagesRequestRef.current) {
185
+ const userResult = await prepareSendMessagesRequestRef.current(prepareOptions);
186
+ headers = userResult.headers;
187
+ credentials = userResult.credentials;
188
+ api = userResult.api;
189
+ body = {
190
+ ...body,
191
+ ...userResult.body ?? {}
192
+ };
193
+ }
194
+ return {
195
+ body,
196
+ headers,
197
+ credentials,
198
+ api
199
+ };
200
+ } : void 0
201
+ }).sendMessages(sendMessageOptions);
137
202
  },
138
- reconnectToStream: async (options$1) => {
139
- return new DefaultChatTransport({
140
- api: agentUrlString,
141
- fetch: aiFetch
142
- }).reconnectToStream(options$1);
143
- }
203
+ reconnectToStream: async () => null
144
204
  }), [agentUrlString, aiFetch]);
145
205
  const useChatHelpers = useChat({
146
206
  ...rest,
@@ -149,6 +209,10 @@ function useAgentChat(options) {
149
209
  id: agent._pk
150
210
  });
151
211
  const processedToolCalls = useRef(/* @__PURE__ */ new Set());
212
+ const isResolvingToolsRef = useRef(false);
213
+ const [clientToolResults, setClientToolResults] = useState(/* @__PURE__ */ new Map());
214
+ const messagesRef = useRef(useChatHelpers.messages);
215
+ messagesRef.current = useChatHelpers.messages;
152
216
  const lastMessage = useChatHelpers.messages[useChatHelpers.messages.length - 1];
153
217
  const pendingConfirmations = (() => {
154
218
  if (!lastMessage || lastMessage.role !== "assistant") return {
@@ -166,40 +230,82 @@ function useAgentChat(options) {
166
230
  pendingConfirmationsRef.current = pendingConfirmations;
167
231
  useEffect(() => {
168
232
  if (!experimental_automaticToolResolution) return;
233
+ if (isResolvingToolsRef.current) return;
169
234
  const lastMessage$1 = useChatHelpers.messages[useChatHelpers.messages.length - 1];
170
235
  if (!lastMessage$1 || lastMessage$1.role !== "assistant") return;
171
236
  const toolCalls = lastMessage$1.parts.filter((part) => isToolUIPart(part) && part.state === "input-available" && !processedToolCalls.current.has(part.toolCallId));
172
- if (toolCalls.length > 0) (async () => {
173
- const toolCallsToResolve = toolCalls.filter((part) => isToolUIPart(part) && !toolsRequiringConfirmation.includes(getToolName(part)) && tools?.[getToolName(part)]?.execute);
237
+ if (toolCalls.length > 0) {
238
+ const currentTools = toolsRef.current;
239
+ const toolCallsToResolve = toolCalls.filter((part) => isToolUIPart(part) && !toolsRequiringConfirmation.includes(getToolName(part)) && currentTools?.[getToolName(part)]?.execute);
174
240
  if (toolCallsToResolve.length > 0) {
175
- for (const part of toolCallsToResolve) if (isToolUIPart(part)) {
176
- processedToolCalls.current.add(part.toolCallId);
177
- let toolOutput = null;
178
- const toolName = getToolName(part);
179
- const tool$1 = tools?.[toolName];
180
- if (tool$1?.execute && part.input) try {
181
- toolOutput = await tool$1.execute(part.input);
182
- } catch (error) {
183
- toolOutput = `Error executing tool: ${error instanceof Error ? error.message : String(error)}`;
241
+ isResolvingToolsRef.current = true;
242
+ (async () => {
243
+ try {
244
+ const toolResults = [];
245
+ for (const part of toolCallsToResolve) if (isToolUIPart(part)) {
246
+ let toolOutput = null;
247
+ const toolName = getToolName(part);
248
+ const tool$1 = currentTools?.[toolName];
249
+ if (tool$1?.execute && part.input !== void 0) try {
250
+ toolOutput = await tool$1.execute(part.input);
251
+ } catch (error) {
252
+ toolOutput = `Error executing tool: ${error instanceof Error ? error.message : String(error)}`;
253
+ }
254
+ processedToolCalls.current.add(part.toolCallId);
255
+ toolResults.push({
256
+ toolCallId: part.toolCallId,
257
+ toolName,
258
+ output: toolOutput
259
+ });
260
+ }
261
+ if (toolResults.length > 0) {
262
+ for (const result of toolResults) agentRef.current.send(JSON.stringify({
263
+ type: MessageType.CF_AGENT_TOOL_RESULT,
264
+ toolCallId: result.toolCallId,
265
+ toolName: result.toolName,
266
+ output: result.output,
267
+ autoContinue: autoContinueAfterToolResult
268
+ }));
269
+ await Promise.all(toolResults.map((result) => useChatHelpers.addToolResult({
270
+ tool: result.toolName,
271
+ toolCallId: result.toolCallId,
272
+ output: result.output
273
+ })));
274
+ setClientToolResults((prev) => {
275
+ const newMap = new Map(prev);
276
+ for (const result of toolResults) newMap.set(result.toolCallId, result.output);
277
+ return newMap;
278
+ });
279
+ }
280
+ } finally {
281
+ isResolvingToolsRef.current = false;
184
282
  }
185
- await useChatHelpers.addToolResult({
186
- toolCallId: part.toolCallId,
187
- tool: toolName,
188
- output: toolOutput
189
- });
190
- }
191
- if (pendingConfirmationsRef.current.toolCallIds.size === 0) useChatHelpers.sendMessage();
283
+ })();
192
284
  }
193
- })();
285
+ }
194
286
  }, [
195
287
  useChatHelpers.messages,
196
288
  experimental_automaticToolResolution,
197
289
  useChatHelpers.addToolResult,
198
- useChatHelpers.sendMessage,
199
- toolsRequiringConfirmation
290
+ toolsRequiringConfirmation,
291
+ autoContinueAfterToolResult
200
292
  ]);
293
+ /**
294
+ * Contains the request ID, accumulated message parts, and a unique message ID.
295
+ * Used for both resumed streams and real-time broadcasts from other tabs.
296
+ */
297
+ const activeStreamRef = useRef(null);
298
+ /**
299
+ * Tracks request IDs initiated by this tab via aiFetch.
300
+ * Used to distinguish local requests from broadcasts.
301
+ */
302
+ const localRequestIdsRef = useRef(/* @__PURE__ */ new Set());
201
303
  useEffect(() => {
202
- function onClearHistory(event) {
304
+ /**
305
+ * Unified message handler that parses JSON once and dispatches based on type.
306
+ * Avoids duplicate parsing overhead from separate listeners.
307
+ */
308
+ function onAgentMessage(event) {
203
309
  if (typeof event.data !== "string") return;
204
310
  let data;
205
311
  try {
@@ -207,46 +313,254 @@ function useAgentChat(options) {
207
313
  } catch (_error) {
208
314
  return;
209
315
  }
210
- if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) useChatHelpers.setMessages([]);
211
- }
212
- function onMessages(event) {
213
- if (typeof event.data !== "string") return;
214
- let data;
215
- try {
216
- data = JSON.parse(event.data);
217
- } catch (_error) {
218
- return;
316
+ switch (data.type) {
317
+ case MessageType.CF_AGENT_CHAT_CLEAR:
318
+ useChatHelpers.setMessages([]);
319
+ break;
320
+ case MessageType.CF_AGENT_CHAT_MESSAGES:
321
+ useChatHelpers.setMessages(data.messages);
322
+ break;
323
+ case MessageType.CF_AGENT_MESSAGE_UPDATED:
324
+ useChatHelpers.setMessages((prevMessages) => {
325
+ const updatedMessage = data.message;
326
+ let idx = prevMessages.findIndex((m) => m.id === updatedMessage.id);
327
+ if (idx < 0) {
328
+ const updatedToolCallIds = new Set(updatedMessage.parts.filter((p) => "toolCallId" in p && p.toolCallId).map((p) => p.toolCallId));
329
+ if (updatedToolCallIds.size > 0) idx = prevMessages.findIndex((m) => m.parts.some((p) => "toolCallId" in p && updatedToolCallIds.has(p.toolCallId)));
330
+ }
331
+ if (idx >= 0) {
332
+ const updated = [...prevMessages];
333
+ updated[idx] = {
334
+ ...updatedMessage,
335
+ id: prevMessages[idx].id
336
+ };
337
+ return updated;
338
+ }
339
+ return [...prevMessages, updatedMessage];
340
+ });
341
+ break;
342
+ case MessageType.CF_AGENT_STREAM_RESUMING:
343
+ if (!resume) return;
344
+ activeStreamRef.current = null;
345
+ activeStreamRef.current = {
346
+ id: data.id,
347
+ messageId: nanoid(),
348
+ parts: []
349
+ };
350
+ agentRef.current.send(JSON.stringify({
351
+ type: MessageType.CF_AGENT_STREAM_RESUME_ACK,
352
+ id: data.id
353
+ }));
354
+ break;
355
+ case MessageType.CF_AGENT_USE_CHAT_RESPONSE: {
356
+ if (localRequestIdsRef.current.has(data.id)) return;
357
+ const isContinuation = data.continuation === true;
358
+ if (!activeStreamRef.current || activeStreamRef.current.id !== data.id) {
359
+ let messageId = nanoid();
360
+ let existingParts = [];
361
+ if (isContinuation) {
362
+ const currentMessages = messagesRef.current;
363
+ for (let i = currentMessages.length - 1; i >= 0; i--) if (currentMessages[i].role === "assistant") {
364
+ messageId = currentMessages[i].id;
365
+ existingParts = [...currentMessages[i].parts];
366
+ break;
367
+ }
368
+ }
369
+ activeStreamRef.current = {
370
+ id: data.id,
371
+ messageId,
372
+ parts: existingParts
373
+ };
374
+ }
375
+ const activeMsg = activeStreamRef.current;
376
+ if (data.body?.trim()) try {
377
+ const chunkData = JSON.parse(data.body);
378
+ switch (chunkData.type) {
379
+ case "text-start":
380
+ activeMsg.parts.push({
381
+ type: "text",
382
+ text: "",
383
+ state: "streaming"
384
+ });
385
+ break;
386
+ case "text-delta": {
387
+ const lastTextPart = [...activeMsg.parts].reverse().find((p) => p.type === "text");
388
+ if (lastTextPart && lastTextPart.type === "text") lastTextPart.text += chunkData.delta;
389
+ else activeMsg.parts.push({
390
+ type: "text",
391
+ text: chunkData.delta
392
+ });
393
+ break;
394
+ }
395
+ case "text-end": {
396
+ const lastTextPart = [...activeMsg.parts].reverse().find((p) => p.type === "text");
397
+ if (lastTextPart && "state" in lastTextPart) lastTextPart.state = "done";
398
+ break;
399
+ }
400
+ case "reasoning-start":
401
+ activeMsg.parts.push({
402
+ type: "reasoning",
403
+ text: "",
404
+ state: "streaming"
405
+ });
406
+ break;
407
+ case "reasoning-delta": {
408
+ const lastReasoningPart = [...activeMsg.parts].reverse().find((p) => p.type === "reasoning");
409
+ if (lastReasoningPart && lastReasoningPart.type === "reasoning") lastReasoningPart.text += chunkData.delta;
410
+ break;
411
+ }
412
+ case "reasoning-end": {
413
+ const lastReasoningPart = [...activeMsg.parts].reverse().find((p) => p.type === "reasoning");
414
+ if (lastReasoningPart && "state" in lastReasoningPart) lastReasoningPart.state = "done";
415
+ break;
416
+ }
417
+ case "file":
418
+ activeMsg.parts.push({
419
+ type: "file",
420
+ mediaType: chunkData.mediaType,
421
+ url: chunkData.url
422
+ });
423
+ break;
424
+ case "source-url":
425
+ activeMsg.parts.push({
426
+ type: "source-url",
427
+ sourceId: chunkData.sourceId,
428
+ url: chunkData.url,
429
+ title: chunkData.title
430
+ });
431
+ break;
432
+ case "source-document":
433
+ activeMsg.parts.push({
434
+ type: "source-document",
435
+ sourceId: chunkData.sourceId,
436
+ mediaType: chunkData.mediaType,
437
+ title: chunkData.title,
438
+ filename: chunkData.filename
439
+ });
440
+ break;
441
+ case "tool-input-available":
442
+ activeMsg.parts.push({
443
+ type: `tool-${chunkData.toolName}`,
444
+ toolCallId: chunkData.toolCallId,
445
+ toolName: chunkData.toolName,
446
+ state: "input-available",
447
+ input: chunkData.input
448
+ });
449
+ break;
450
+ case "tool-output-available":
451
+ activeMsg.parts = activeMsg.parts.map((p) => {
452
+ if ("toolCallId" in p && p.toolCallId === chunkData.toolCallId && "state" in p) return {
453
+ ...p,
454
+ state: "output-available",
455
+ output: chunkData.output
456
+ };
457
+ return p;
458
+ });
459
+ break;
460
+ case "step-start":
461
+ activeMsg.parts.push({ type: "step-start" });
462
+ break;
463
+ }
464
+ useChatHelpers.setMessages((prevMessages) => {
465
+ if (!activeMsg) return prevMessages;
466
+ const existingIdx = prevMessages.findIndex((m) => m.id === activeMsg.messageId);
467
+ const partialMessage = {
468
+ id: activeMsg.messageId,
469
+ role: "assistant",
470
+ parts: [...activeMsg.parts]
471
+ };
472
+ if (existingIdx >= 0) {
473
+ const updated = [...prevMessages];
474
+ updated[existingIdx] = partialMessage;
475
+ return updated;
476
+ }
477
+ return [...prevMessages, partialMessage];
478
+ });
479
+ } catch (parseError) {
480
+ console.warn("[useAgentChat] Failed to parse stream chunk:", parseError instanceof Error ? parseError.message : parseError, "body:", data.body?.slice(0, 100));
481
+ }
482
+ if (data.done || data.error) activeStreamRef.current = null;
483
+ break;
484
+ }
219
485
  }
220
- if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) useChatHelpers.setMessages(data.messages);
221
486
  }
222
- agent.addEventListener("message", onClearHistory);
223
- agent.addEventListener("message", onMessages);
487
+ agent.addEventListener("message", onAgentMessage);
224
488
  return () => {
225
- agent.removeEventListener("message", onClearHistory);
226
- agent.removeEventListener("message", onMessages);
489
+ agent.removeEventListener("message", onAgentMessage);
490
+ activeStreamRef.current = null;
227
491
  };
228
- }, [agent, useChatHelpers.setMessages]);
492
+ }, [
493
+ agent,
494
+ useChatHelpers.setMessages,
495
+ resume
496
+ ]);
229
497
  const addToolResultAndSendMessage = async (args) => {
230
498
  const { toolCallId } = args;
231
- await useChatHelpers.addToolResult(args);
232
- if (!autoSendAfterAllConfirmationsResolved) {
233
- useChatHelpers.sendMessage();
234
- return;
235
- }
236
- const pending = pendingConfirmationsRef.current?.toolCallIds;
237
- if (!pending) {
238
- useChatHelpers.sendMessage();
239
- return;
499
+ const toolName = "tool" in args ? args.tool : "";
500
+ const output = "output" in args ? args.output : void 0;
501
+ agentRef.current.send(JSON.stringify({
502
+ type: MessageType.CF_AGENT_TOOL_RESULT,
503
+ toolCallId,
504
+ toolName,
505
+ output,
506
+ autoContinue: autoContinueAfterToolResult
507
+ }));
508
+ setClientToolResults((prev) => new Map(prev).set(toolCallId, output));
509
+ useChatHelpers.addToolResult(args);
510
+ if (!autoContinueAfterToolResult) {
511
+ if (!autoSendAfterAllConfirmationsResolved) {
512
+ useChatHelpers.sendMessage();
513
+ return;
514
+ }
515
+ const pending = pendingConfirmationsRef.current?.toolCallIds;
516
+ if (!pending) {
517
+ useChatHelpers.sendMessage();
518
+ return;
519
+ }
520
+ const wasLast = pending.size === 1 && pending.has(toolCallId);
521
+ if (pending.has(toolCallId)) pending.delete(toolCallId);
522
+ if (wasLast || pending.size === 0) useChatHelpers.sendMessage();
240
523
  }
241
- const wasLast = pending.size === 1 && pending.has(toolCallId);
242
- if (pending.has(toolCallId)) pending.delete(toolCallId);
243
- if (wasLast || pending.size === 0) useChatHelpers.sendMessage();
244
524
  };
525
+ const messagesWithToolResults = useMemo(() => {
526
+ if (clientToolResults.size === 0) return useChatHelpers.messages;
527
+ return useChatHelpers.messages.map((msg) => ({
528
+ ...msg,
529
+ parts: msg.parts.map((p) => {
530
+ if (!("toolCallId" in p) || !("state" in p) || p.state !== "input-available" || !clientToolResults.has(p.toolCallId)) return p;
531
+ return {
532
+ ...p,
533
+ state: "output-available",
534
+ output: clientToolResults.get(p.toolCallId)
535
+ };
536
+ })
537
+ }));
538
+ }, [useChatHelpers.messages, clientToolResults]);
539
+ useEffect(() => {
540
+ const currentToolCallIds = /* @__PURE__ */ new Set();
541
+ for (const msg of useChatHelpers.messages) for (const part of msg.parts) if ("toolCallId" in part && part.toolCallId) currentToolCallIds.add(part.toolCallId);
542
+ setClientToolResults((prev) => {
543
+ if (prev.size === 0) return prev;
544
+ let hasStaleEntries = false;
545
+ for (const toolCallId of prev.keys()) if (!currentToolCallIds.has(toolCallId)) {
546
+ hasStaleEntries = true;
547
+ break;
548
+ }
549
+ if (!hasStaleEntries) return prev;
550
+ const newMap = /* @__PURE__ */ new Map();
551
+ for (const [id, output] of prev) if (currentToolCallIds.has(id)) newMap.set(id, output);
552
+ return newMap;
553
+ });
554
+ for (const toolCallId of processedToolCalls.current) if (!currentToolCallIds.has(toolCallId)) processedToolCalls.current.delete(toolCallId);
555
+ }, [useChatHelpers.messages]);
245
556
  return {
246
557
  ...useChatHelpers,
558
+ messages: messagesWithToolResults,
247
559
  addToolResult: addToolResultAndSendMessage,
248
560
  clearHistory: () => {
249
561
  useChatHelpers.setMessages([]);
562
+ setClientToolResults(/* @__PURE__ */ new Map());
563
+ processedToolCalls.current.clear();
250
564
  agent.send(JSON.stringify({ type: MessageType.CF_AGENT_CHAT_CLEAR }));
251
565
  },
252
566
  setMessages: (messages) => {
@@ -260,5 +574,5 @@ function useAgentChat(options) {
260
574
  }
261
575
 
262
576
  //#endregion
263
- export { detectToolsRequiringConfirmation, useAgentChat };
577
+ export { detectToolsRequiringConfirmation, extractClientToolSchemas, useAgentChat };
264
578
  //# sourceMappingURL=ai-react.js.map