agents 0.0.0-19a3a25 → 0.0.0-1a3d226

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 (71) hide show
  1. package/README.md +126 -3
  2. package/dist/ai-chat-agent.d.ts +229 -22
  3. package/dist/ai-chat-agent.js +692 -106
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-chat-v5-migration.js +154 -2
  6. package/dist/ai-chat-v5-migration.js.map +1 -0
  7. package/dist/ai-react.d.ts +141 -16
  8. package/dist/ai-react.js +381 -68
  9. package/dist/ai-react.js.map +1 -1
  10. package/dist/{ai-types-D5YoPrBZ.d.ts → ai-types-0OnT3FHg.d.ts} +40 -8
  11. package/dist/{ai-types-B3aQaFv3.js → ai-types-DEtF_8Km.js} +9 -1
  12. package/dist/ai-types-DEtF_8Km.js.map +1 -0
  13. package/dist/ai-types.d.ts +1 -1
  14. package/dist/ai-types.js +1 -1
  15. package/dist/cli/index.d.ts +1 -0
  16. package/dist/{cli.js → cli/index.js} +7 -6
  17. package/dist/cli/index.js.map +1 -0
  18. package/dist/client-BINtT7y-.d.ts +834 -0
  19. package/dist/{client-CbWe9FBd.d.ts → client-CdM5I962.d.ts} +2 -2
  20. package/dist/{client-BfiZ3HQd.js → client-DjTPRM8-.js} +2 -2
  21. package/dist/{client-BfiZ3HQd.js.map → client-DjTPRM8-.js.map} +1 -1
  22. package/dist/client-QZa2Rq0l.js +1105 -0
  23. package/dist/client-QZa2Rq0l.js.map +1 -0
  24. package/dist/client.d.ts +1 -2
  25. package/dist/client.js +1 -2
  26. package/dist/codemode/ai.js +6 -6
  27. package/dist/codemode/ai.js.map +1 -1
  28. package/dist/context-BkKbAa1R.js +8 -0
  29. package/dist/context-BkKbAa1R.js.map +1 -0
  30. package/dist/context-DcbQ8o7k.d.ts +24 -0
  31. package/dist/context.d.ts +6 -0
  32. package/dist/context.js +3 -0
  33. package/dist/{do-oauth-client-provider-DGc5pP0l.d.ts → do-oauth-client-provider--To1Tsjj.d.ts} +20 -5
  34. package/dist/{do-oauth-client-provider-CswoD5Lu.js → do-oauth-client-provider-B1fVIshX.js} +70 -8
  35. package/dist/do-oauth-client-provider-B1fVIshX.js.map +1 -0
  36. package/dist/{index-CuqiHyhT.d.ts → index-CfZ2mfMI.d.ts} +80 -64
  37. package/dist/{index-DhJCaDWd.d.ts → index-DLuxm_9W.d.ts} +2 -2
  38. package/dist/index.d.ts +31 -34
  39. package/dist/index.js +5 -5
  40. package/dist/mcp/client.d.ts +2 -4
  41. package/dist/mcp/client.js +2 -1
  42. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  43. package/dist/mcp/do-oauth-client-provider.js +1 -1
  44. package/dist/mcp/index.d.ts +23 -16
  45. package/dist/mcp/index.js +71 -69
  46. package/dist/mcp/index.js.map +1 -1
  47. package/dist/mcp/x402.js +10 -6
  48. package/dist/mcp/x402.js.map +1 -1
  49. package/dist/{mcp-Dw5vDrY8.d.ts → mcp-CPSfGUgd.d.ts} +1 -1
  50. package/dist/observability/index.d.ts +1 -2
  51. package/dist/observability/index.js +5 -5
  52. package/dist/react.d.ts +134 -10
  53. package/dist/react.js +57 -57
  54. package/dist/react.js.map +1 -1
  55. package/dist/schedule.d.ts +18 -72
  56. package/dist/{serializable-CymX8ovI.d.ts → serializable-Crsj26mx.d.ts} +1 -1
  57. package/dist/serializable.d.ts +1 -1
  58. package/dist/{src-CwIW7tU2.js → src-BZDh910Z.js} +104 -139
  59. package/dist/src-BZDh910Z.js.map +1 -0
  60. package/package.json +31 -16
  61. package/dist/ai-chat-v5-migration-DBHGW4Hv.js +0 -155
  62. package/dist/ai-chat-v5-migration-DBHGW4Hv.js.map +0 -1
  63. package/dist/ai-types-B3aQaFv3.js.map +0 -1
  64. package/dist/cli.d.ts +0 -8
  65. package/dist/cli.js.map +0 -1
  66. package/dist/client-BnO9jNtu.d.ts +0 -5283
  67. package/dist/client-DZhjV_XA.js +0 -719
  68. package/dist/client-DZhjV_XA.js.map +0 -1
  69. package/dist/do-oauth-client-provider-CswoD5Lu.js.map +0 -1
  70. package/dist/react-Cx9uE2Jd.d.ts +0 -113
  71. package/dist/src-CwIW7tU2.js.map +0 -1
package/dist/ai-react.js CHANGED
@@ -1,10 +1,28 @@
1
- import { t as MessageType } from "./ai-types-B3aQaFv3.js";
1
+ import { t as MessageType } from "./ai-types-DEtF_8Km.js";
2
+ import { DefaultChatTransport, getToolName, isToolUIPart } from "ai";
2
3
  import { nanoid } from "nanoid";
3
4
  import { useChat } from "@ai-sdk/react";
4
- import { DefaultChatTransport, getToolName, isToolUIPart } from "ai";
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,7 +40,7 @@ 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");
@@ -78,13 +96,17 @@ function useAgentChat(options) {
78
96
  const abortController = new AbortController();
79
97
  let controller;
80
98
  const currentAgent = agentRef.current;
99
+ localRequestIdsRef.current.add(id);
81
100
  signal?.addEventListener("abort", () => {
82
101
  currentAgent.send(JSON.stringify({
83
102
  id,
84
103
  type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL
85
104
  }));
86
105
  abortController.abort();
87
- controller.close();
106
+ try {
107
+ controller.close();
108
+ } catch {}
109
+ localRequestIdsRef.current.delete(id);
88
110
  });
89
111
  currentAgent.addEventListener("message", (event) => {
90
112
  let data;
@@ -97,18 +119,27 @@ function useAgentChat(options) {
97
119
  if (data.id === id) if (data.error) {
98
120
  controller.error(new Error(data.body));
99
121
  abortController.abort();
122
+ localRequestIdsRef.current.delete(id);
100
123
  } else {
101
124
  if (data.body?.trim()) controller.enqueue(new TextEncoder().encode(`data: ${data.body}\n\n`));
102
125
  if (data.done) {
103
- controller.close();
126
+ try {
127
+ controller.close();
128
+ } catch {}
104
129
  abortController.abort();
130
+ localRequestIdsRef.current.delete(id);
105
131
  }
106
132
  }
107
133
  }
108
134
  }, { signal: abortController.signal });
109
- const stream = new ReadableStream({ start(c) {
110
- controller = c;
111
- } });
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
+ });
112
143
  currentAgent.send(JSON.stringify({
113
144
  id,
114
145
  init: {
@@ -129,19 +160,47 @@ function useAgentChat(options) {
129
160
  }));
130
161
  return new Response(stream);
131
162
  }, []);
163
+ const toolsRef = useRef(tools);
164
+ toolsRef.current = tools;
165
+ const prepareSendMessagesRequestRef = useRef(prepareSendMessagesRequest);
166
+ prepareSendMessagesRequestRef.current = prepareSendMessagesRequest;
132
167
  const customTransport = useMemo(() => ({
133
- sendMessages: async (options$1) => {
168
+ sendMessages: async (sendMessageOptions) => {
169
+ const clientToolSchemas = extractClientToolSchemas(toolsRef.current);
134
170
  return new DefaultChatTransport({
135
171
  api: agentUrlString,
136
- fetch: aiFetch
137
- }).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);
138
202
  },
139
- reconnectToStream: async (options$1) => {
140
- return new DefaultChatTransport({
141
- api: agentUrlString,
142
- fetch: aiFetch
143
- }).reconnectToStream(options$1);
144
- }
203
+ reconnectToStream: async () => null
145
204
  }), [agentUrlString, aiFetch]);
146
205
  const useChatHelpers = useChat({
147
206
  ...rest,
@@ -150,6 +209,10 @@ function useAgentChat(options) {
150
209
  id: agent._pk
151
210
  });
152
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;
153
216
  const lastMessage = useChatHelpers.messages[useChatHelpers.messages.length - 1];
154
217
  const pendingConfirmations = (() => {
155
218
  if (!lastMessage || lastMessage.role !== "assistant") return {
@@ -167,40 +230,82 @@ function useAgentChat(options) {
167
230
  pendingConfirmationsRef.current = pendingConfirmations;
168
231
  useEffect(() => {
169
232
  if (!experimental_automaticToolResolution) return;
233
+ if (isResolvingToolsRef.current) return;
170
234
  const lastMessage$1 = useChatHelpers.messages[useChatHelpers.messages.length - 1];
171
235
  if (!lastMessage$1 || lastMessage$1.role !== "assistant") return;
172
236
  const toolCalls = lastMessage$1.parts.filter((part) => isToolUIPart(part) && part.state === "input-available" && !processedToolCalls.current.has(part.toolCallId));
173
- if (toolCalls.length > 0) (async () => {
174
- 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);
175
240
  if (toolCallsToResolve.length > 0) {
176
- for (const part of toolCallsToResolve) if (isToolUIPart(part)) {
177
- processedToolCalls.current.add(part.toolCallId);
178
- let toolOutput = null;
179
- const toolName = getToolName(part);
180
- const tool$1 = tools?.[toolName];
181
- if (tool$1?.execute && part.input) try {
182
- toolOutput = await tool$1.execute(part.input);
183
- } catch (error) {
184
- 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;
185
282
  }
186
- await useChatHelpers.addToolResult({
187
- toolCallId: part.toolCallId,
188
- tool: toolName,
189
- output: toolOutput
190
- });
191
- }
192
- if (pendingConfirmationsRef.current.toolCallIds.size === 0) useChatHelpers.sendMessage();
283
+ })();
193
284
  }
194
- })();
285
+ }
195
286
  }, [
196
287
  useChatHelpers.messages,
197
288
  experimental_automaticToolResolution,
198
289
  useChatHelpers.addToolResult,
199
- useChatHelpers.sendMessage,
200
- toolsRequiringConfirmation
290
+ toolsRequiringConfirmation,
291
+ autoContinueAfterToolResult
201
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());
202
303
  useEffect(() => {
203
- 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) {
204
309
  if (typeof event.data !== "string") return;
205
310
  let data;
206
311
  try {
@@ -208,46 +313,254 @@ function useAgentChat(options) {
208
313
  } catch (_error) {
209
314
  return;
210
315
  }
211
- if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) useChatHelpers.setMessages([]);
212
- }
213
- function onMessages(event) {
214
- if (typeof event.data !== "string") return;
215
- let data;
216
- try {
217
- data = JSON.parse(event.data);
218
- } catch (_error) {
219
- 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
+ }
220
485
  }
221
- if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) useChatHelpers.setMessages(data.messages);
222
486
  }
223
- agent.addEventListener("message", onClearHistory);
224
- agent.addEventListener("message", onMessages);
487
+ agent.addEventListener("message", onAgentMessage);
225
488
  return () => {
226
- agent.removeEventListener("message", onClearHistory);
227
- agent.removeEventListener("message", onMessages);
489
+ agent.removeEventListener("message", onAgentMessage);
490
+ activeStreamRef.current = null;
228
491
  };
229
- }, [agent, useChatHelpers.setMessages]);
492
+ }, [
493
+ agent,
494
+ useChatHelpers.setMessages,
495
+ resume
496
+ ]);
230
497
  const addToolResultAndSendMessage = async (args) => {
231
498
  const { toolCallId } = args;
232
- await useChatHelpers.addToolResult(args);
233
- if (!autoSendAfterAllConfirmationsResolved) {
234
- useChatHelpers.sendMessage();
235
- return;
236
- }
237
- const pending = pendingConfirmationsRef.current?.toolCallIds;
238
- if (!pending) {
239
- useChatHelpers.sendMessage();
240
- 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();
241
523
  }
242
- const wasLast = pending.size === 1 && pending.has(toolCallId);
243
- if (pending.has(toolCallId)) pending.delete(toolCallId);
244
- if (wasLast || pending.size === 0) useChatHelpers.sendMessage();
245
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]);
246
556
  return {
247
557
  ...useChatHelpers,
558
+ messages: messagesWithToolResults,
248
559
  addToolResult: addToolResultAndSendMessage,
249
560
  clearHistory: () => {
250
561
  useChatHelpers.setMessages([]);
562
+ setClientToolResults(/* @__PURE__ */ new Map());
563
+ processedToolCalls.current.clear();
251
564
  agent.send(JSON.stringify({ type: MessageType.CF_AGENT_CHAT_CLEAR }));
252
565
  },
253
566
  setMessages: (messages) => {
@@ -261,5 +574,5 @@ function useAgentChat(options) {
261
574
  }
262
575
 
263
576
  //#endregion
264
- export { detectToolsRequiringConfirmation, useAgentChat };
577
+ export { detectToolsRequiringConfirmation, extractClientToolSchemas, useAgentChat };
265
578
  //# sourceMappingURL=ai-react.js.map