agents 0.0.0-293b546 → 0.0.0-29938d4

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 +121 -0
  2. package/dist/ai-chat-agent.d.ts +158 -24
  3. package/dist/ai-chat-agent.js +380 -60
  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 +136 -16
  8. package/dist/ai-react.js +252 -74
  9. package/dist/ai-react.js.map +1 -1
  10. package/dist/{ai-types-81H_-Uxh.d.ts → ai-types-0OnT3FHg.d.ts} +26 -2
  11. package/dist/{ai-types-CrMqkwc_.js → ai-types-DEtF_8Km.js} +5 -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-BAQA84dr.d.ts → client-CdM5I962.d.ts} +2 -2
  19. package/dist/client-DFotUKH_.d.ts +834 -0
  20. package/dist/{client-B3SR12TQ.js → client-DjTPRM8-.js} +2 -2
  21. package/dist/{client-B3SR12TQ.js.map → client-DjTPRM8-.js.map} +1 -1
  22. package/dist/{client-C8VrzljV.js → client-QZa2Rq0l.js} +371 -187
  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-C2CHH5x-.d.ts → do-oauth-client-provider--To1Tsjj.d.ts} +20 -5
  34. package/dist/{do-oauth-client-provider-CwqK5SXm.js → do-oauth-client-provider-B1fVIshX.js} +69 -8
  35. package/dist/do-oauth-client-provider-B1fVIshX.js.map +1 -0
  36. package/dist/{index-7kI1zprE.d.ts → index-CT2tCrLr.d.ts} +59 -60
  37. package/dist/{index-BUle9RiP.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 -2
  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 +19 -12
  45. package/dist/mcp/index.js +55 -60
  46. package/dist/mcp/index.js.map +1 -1
  47. package/dist/{mcp-BwPscEiF.d.ts → mcp-CPSfGUgd.d.ts} +1 -1
  48. package/dist/observability/index.d.ts +1 -2
  49. package/dist/observability/index.js +5 -5
  50. package/dist/react.d.ts +134 -10
  51. package/dist/react.js +56 -56
  52. package/dist/react.js.map +1 -1
  53. package/dist/schedule.d.ts +18 -72
  54. package/dist/{serializable-faDkMCai.d.ts → serializable-Crsj26mx.d.ts} +1 -1
  55. package/dist/serializable.d.ts +1 -1
  56. package/dist/{src-xjQt2wBU.js → src-BZDh910Z.js} +26 -25
  57. package/dist/src-BZDh910Z.js.map +1 -0
  58. package/package.json +29 -14
  59. package/dist/ai-chat-v5-migration-BSiGZmYU.js +0 -155
  60. package/dist/ai-chat-v5-migration-BSiGZmYU.js.map +0 -1
  61. package/dist/ai-types-CrMqkwc_.js.map +0 -1
  62. package/dist/cli.d.ts +0 -8
  63. package/dist/cli.js.map +0 -1
  64. package/dist/client-BG2wUgN5.d.ts +0 -1462
  65. package/dist/client-C8VrzljV.js.map +0 -1
  66. package/dist/do-oauth-client-provider-CwqK5SXm.js.map +0 -1
  67. package/dist/react-9nVfoERh.d.ts +0 -113
  68. package/dist/src-xjQt2wBU.js.map +0 -1
package/dist/ai-react.js CHANGED
@@ -1,10 +1,28 @@
1
- import { t as MessageType } from "./ai-types-CrMqkwc_.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, resume = 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,6 +96,7 @@ 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,
@@ -87,6 +106,7 @@ function useAgentChat(options) {
87
106
  try {
88
107
  controller.close();
89
108
  } catch {}
109
+ localRequestIdsRef.current.delete(id);
90
110
  });
91
111
  currentAgent.addEventListener("message", (event) => {
92
112
  let data;
@@ -99,6 +119,7 @@ function useAgentChat(options) {
99
119
  if (data.id === id) if (data.error) {
100
120
  controller.error(new Error(data.body));
101
121
  abortController.abort();
122
+ localRequestIdsRef.current.delete(id);
102
123
  } else {
103
124
  if (data.body?.trim()) controller.enqueue(new TextEncoder().encode(`data: ${data.body}\n\n`));
104
125
  if (data.done) {
@@ -106,6 +127,7 @@ function useAgentChat(options) {
106
127
  controller.close();
107
128
  } catch {}
108
129
  abortController.abort();
130
+ localRequestIdsRef.current.delete(id);
109
131
  }
110
132
  }
111
133
  }
@@ -138,12 +160,45 @@ function useAgentChat(options) {
138
160
  }));
139
161
  return new Response(stream);
140
162
  }, []);
163
+ const toolsRef = useRef(tools);
164
+ toolsRef.current = tools;
165
+ const prepareSendMessagesRequestRef = useRef(prepareSendMessagesRequest);
166
+ prepareSendMessagesRequestRef.current = prepareSendMessagesRequest;
141
167
  const customTransport = useMemo(() => ({
142
- sendMessages: async (options$1) => {
168
+ sendMessages: async (sendMessageOptions) => {
169
+ const clientToolSchemas = extractClientToolSchemas(toolsRef.current);
143
170
  return new DefaultChatTransport({
144
171
  api: agentUrlString,
145
- fetch: aiFetch
146
- }).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);
147
202
  },
148
203
  reconnectToStream: async () => null
149
204
  }), [agentUrlString, aiFetch]);
@@ -154,6 +209,10 @@ function useAgentChat(options) {
154
209
  id: agent._pk
155
210
  });
156
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;
157
216
  const lastMessage = useChatHelpers.messages[useChatHelpers.messages.length - 1];
158
217
  const pendingConfirmations = (() => {
159
218
  if (!lastMessage || lastMessage.role !== "assistant") return {
@@ -171,42 +230,76 @@ function useAgentChat(options) {
171
230
  pendingConfirmationsRef.current = pendingConfirmations;
172
231
  useEffect(() => {
173
232
  if (!experimental_automaticToolResolution) return;
233
+ if (isResolvingToolsRef.current) return;
174
234
  const lastMessage$1 = useChatHelpers.messages[useChatHelpers.messages.length - 1];
175
235
  if (!lastMessage$1 || lastMessage$1.role !== "assistant") return;
176
236
  const toolCalls = lastMessage$1.parts.filter((part) => isToolUIPart(part) && part.state === "input-available" && !processedToolCalls.current.has(part.toolCallId));
177
- if (toolCalls.length > 0) (async () => {
178
- 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);
179
240
  if (toolCallsToResolve.length > 0) {
180
- for (const part of toolCallsToResolve) if (isToolUIPart(part)) {
181
- processedToolCalls.current.add(part.toolCallId);
182
- let toolOutput = null;
183
- const toolName = getToolName(part);
184
- const tool$1 = tools?.[toolName];
185
- if (tool$1?.execute && part.input) try {
186
- toolOutput = await tool$1.execute(part.input);
187
- } catch (error) {
188
- 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;
189
282
  }
190
- await useChatHelpers.addToolResult({
191
- toolCallId: part.toolCallId,
192
- tool: toolName,
193
- output: toolOutput
194
- });
195
- }
196
- if (pendingConfirmationsRef.current.toolCallIds.size === 0) useChatHelpers.sendMessage();
283
+ })();
197
284
  }
198
- })();
285
+ }
199
286
  }, [
200
287
  useChatHelpers.messages,
201
288
  experimental_automaticToolResolution,
202
289
  useChatHelpers.addToolResult,
203
- useChatHelpers.sendMessage,
204
- toolsRequiringConfirmation
290
+ toolsRequiringConfirmation,
291
+ autoContinueAfterToolResult
205
292
  ]);
206
293
  /**
207
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.
208
296
  */
209
- const resumedStreamRef = useRef(null);
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());
210
303
  useEffect(() => {
211
304
  /**
212
305
  * Unified message handler that parses JSON once and dispatches based on type.
@@ -227,10 +320,29 @@ function useAgentChat(options) {
227
320
  case MessageType.CF_AGENT_CHAT_MESSAGES:
228
321
  useChatHelpers.setMessages(data.messages);
229
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;
230
342
  case MessageType.CF_AGENT_STREAM_RESUMING:
231
343
  if (!resume) return;
232
- resumedStreamRef.current = null;
233
- resumedStreamRef.current = {
344
+ activeStreamRef.current = null;
345
+ activeStreamRef.current = {
234
346
  id: data.id,
235
347
  messageId: nanoid(),
236
348
  parts: []
@@ -240,60 +352,77 @@ function useAgentChat(options) {
240
352
  id: data.id
241
353
  }));
242
354
  break;
243
- case MessageType.CF_AGENT_USE_CHAT_RESPONSE:
244
- if (!resume || !resumedStreamRef.current) return;
245
- if (data.id !== resumedStreamRef.current.id) return;
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;
246
376
  if (data.body?.trim()) try {
247
377
  const chunkData = JSON.parse(data.body);
248
- const resumedMsg = resumedStreamRef.current;
249
378
  switch (chunkData.type) {
250
379
  case "text-start":
251
- resumedMsg.parts.push({
380
+ activeMsg.parts.push({
252
381
  type: "text",
253
382
  text: "",
254
383
  state: "streaming"
255
384
  });
256
385
  break;
257
386
  case "text-delta": {
258
- const lastTextPart = [...resumedMsg.parts].reverse().find((p) => p.type === "text");
387
+ const lastTextPart = [...activeMsg.parts].reverse().find((p) => p.type === "text");
259
388
  if (lastTextPart && lastTextPart.type === "text") lastTextPart.text += chunkData.delta;
260
- else resumedMsg.parts.push({
389
+ else activeMsg.parts.push({
261
390
  type: "text",
262
391
  text: chunkData.delta
263
392
  });
264
393
  break;
265
394
  }
266
395
  case "text-end": {
267
- const lastTextPart = [...resumedMsg.parts].reverse().find((p) => p.type === "text");
396
+ const lastTextPart = [...activeMsg.parts].reverse().find((p) => p.type === "text");
268
397
  if (lastTextPart && "state" in lastTextPart) lastTextPart.state = "done";
269
398
  break;
270
399
  }
271
400
  case "reasoning-start":
272
- resumedMsg.parts.push({
401
+ activeMsg.parts.push({
273
402
  type: "reasoning",
274
403
  text: "",
275
404
  state: "streaming"
276
405
  });
277
406
  break;
278
407
  case "reasoning-delta": {
279
- const lastReasoningPart = [...resumedMsg.parts].reverse().find((p) => p.type === "reasoning");
408
+ const lastReasoningPart = [...activeMsg.parts].reverse().find((p) => p.type === "reasoning");
280
409
  if (lastReasoningPart && lastReasoningPart.type === "reasoning") lastReasoningPart.text += chunkData.delta;
281
410
  break;
282
411
  }
283
412
  case "reasoning-end": {
284
- const lastReasoningPart = [...resumedMsg.parts].reverse().find((p) => p.type === "reasoning");
413
+ const lastReasoningPart = [...activeMsg.parts].reverse().find((p) => p.type === "reasoning");
285
414
  if (lastReasoningPart && "state" in lastReasoningPart) lastReasoningPart.state = "done";
286
415
  break;
287
416
  }
288
417
  case "file":
289
- resumedMsg.parts.push({
418
+ activeMsg.parts.push({
290
419
  type: "file",
291
420
  mediaType: chunkData.mediaType,
292
421
  url: chunkData.url
293
422
  });
294
423
  break;
295
424
  case "source-url":
296
- resumedMsg.parts.push({
425
+ activeMsg.parts.push({
297
426
  type: "source-url",
298
427
  sourceId: chunkData.sourceId,
299
428
  url: chunkData.url,
@@ -301,7 +430,7 @@ function useAgentChat(options) {
301
430
  });
302
431
  break;
303
432
  case "source-document":
304
- resumedMsg.parts.push({
433
+ activeMsg.parts.push({
305
434
  type: "source-document",
306
435
  sourceId: chunkData.sourceId,
307
436
  mediaType: chunkData.mediaType,
@@ -310,7 +439,7 @@ function useAgentChat(options) {
310
439
  });
311
440
  break;
312
441
  case "tool-input-available":
313
- resumedMsg.parts.push({
442
+ activeMsg.parts.push({
314
443
  type: `tool-${chunkData.toolName}`,
315
444
  toolCallId: chunkData.toolCallId,
316
445
  toolName: chunkData.toolName,
@@ -318,25 +447,27 @@ function useAgentChat(options) {
318
447
  input: chunkData.input
319
448
  });
320
449
  break;
321
- case "tool-output-available": {
322
- const toolPart = resumedMsg.parts.find((p) => "toolCallId" in p && p.toolCallId === chunkData.toolCallId);
323
- if (toolPart && "state" in toolPart) {
324
- toolPart.state = "output-available";
325
- toolPart.output = chunkData.output;
326
- }
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
+ });
327
459
  break;
328
- }
329
460
  case "step-start":
330
- resumedMsg.parts.push({ type: "step-start" });
461
+ activeMsg.parts.push({ type: "step-start" });
331
462
  break;
332
463
  }
333
464
  useChatHelpers.setMessages((prevMessages) => {
334
- if (!resumedMsg) return prevMessages;
335
- const existingIdx = prevMessages.findIndex((m) => m.id === resumedMsg.messageId);
465
+ if (!activeMsg) return prevMessages;
466
+ const existingIdx = prevMessages.findIndex((m) => m.id === activeMsg.messageId);
336
467
  const partialMessage = {
337
- id: resumedMsg.messageId,
468
+ id: activeMsg.messageId,
338
469
  role: "assistant",
339
- parts: [...resumedMsg.parts]
470
+ parts: [...activeMsg.parts]
340
471
  };
341
472
  if (existingIdx >= 0) {
342
473
  const updated = [...prevMessages];
@@ -346,16 +477,17 @@ function useAgentChat(options) {
346
477
  return [...prevMessages, partialMessage];
347
478
  });
348
479
  } catch (parseError) {
349
- console.warn("[useAgentChat] Failed to parse resumed stream chunk:", parseError instanceof Error ? parseError.message : parseError, "body:", data.body?.slice(0, 100));
480
+ console.warn("[useAgentChat] Failed to parse stream chunk:", parseError instanceof Error ? parseError.message : parseError, "body:", data.body?.slice(0, 100));
350
481
  }
351
- if (data.done || data.error) resumedStreamRef.current = null;
482
+ if (data.done || data.error) activeStreamRef.current = null;
352
483
  break;
484
+ }
353
485
  }
354
486
  }
355
487
  agent.addEventListener("message", onAgentMessage);
356
488
  return () => {
357
489
  agent.removeEventListener("message", onAgentMessage);
358
- resumedStreamRef.current = null;
490
+ activeStreamRef.current = null;
359
491
  };
360
492
  }, [
361
493
  agent,
@@ -364,25 +496,71 @@ function useAgentChat(options) {
364
496
  ]);
365
497
  const addToolResultAndSendMessage = async (args) => {
366
498
  const { toolCallId } = args;
367
- await useChatHelpers.addToolResult(args);
368
- if (!autoSendAfterAllConfirmationsResolved) {
369
- useChatHelpers.sendMessage();
370
- return;
371
- }
372
- const pending = pendingConfirmationsRef.current?.toolCallIds;
373
- if (!pending) {
374
- useChatHelpers.sendMessage();
375
- 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();
376
523
  }
377
- const wasLast = pending.size === 1 && pending.has(toolCallId);
378
- if (pending.has(toolCallId)) pending.delete(toolCallId);
379
- if (wasLast || pending.size === 0) useChatHelpers.sendMessage();
380
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]);
381
556
  return {
382
557
  ...useChatHelpers,
558
+ messages: messagesWithToolResults,
383
559
  addToolResult: addToolResultAndSendMessage,
384
560
  clearHistory: () => {
385
561
  useChatHelpers.setMessages([]);
562
+ setClientToolResults(/* @__PURE__ */ new Map());
563
+ processedToolCalls.current.clear();
386
564
  agent.send(JSON.stringify({ type: MessageType.CF_AGENT_CHAT_CLEAR }));
387
565
  },
388
566
  setMessages: (messages) => {
@@ -396,5 +574,5 @@ function useAgentChat(options) {
396
574
  }
397
575
 
398
576
  //#endregion
399
- export { detectToolsRequiringConfirmation, useAgentChat };
577
+ export { detectToolsRequiringConfirmation, extractClientToolSchemas, useAgentChat };
400
578
  //# sourceMappingURL=ai-react.js.map