agents 0.0.0-d40512c → 0.0.0-d72c6a2

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 (50) hide show
  1. package/README.md +234 -6
  2. package/dist/ai-chat-agent.d.ts +12 -9
  3. package/dist/ai-chat-agent.js +150 -59
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-chat-v5-migration.d.ts +152 -0
  6. package/dist/ai-chat-v5-migration.js +19 -0
  7. package/dist/ai-chat-v5-migration.js.map +1 -0
  8. package/dist/ai-react.d.ts +62 -71
  9. package/dist/ai-react.js +144 -37
  10. package/dist/ai-react.js.map +1 -1
  11. package/dist/ai-types.d.ts +36 -19
  12. package/dist/ai-types.js +6 -0
  13. package/dist/chunk-AVYJQSLW.js +17 -0
  14. package/dist/chunk-AVYJQSLW.js.map +1 -0
  15. package/dist/{chunk-PVQZBKN7.js → chunk-LL2AFX7V.js} +5 -2
  16. package/dist/chunk-LL2AFX7V.js.map +1 -0
  17. package/dist/{chunk-4RBEYCWK.js → chunk-MH46VMM4.js} +163 -20
  18. package/dist/chunk-MH46VMM4.js.map +1 -0
  19. package/dist/{chunk-KUH345EY.js → chunk-QEVM4BVL.js} +5 -5
  20. package/dist/chunk-QEVM4BVL.js.map +1 -0
  21. package/dist/chunk-UJVEAURM.js +150 -0
  22. package/dist/chunk-UJVEAURM.js.map +1 -0
  23. package/dist/{chunk-LU2RSO54.js → chunk-YDUDMOL6.js} +515 -129
  24. package/dist/chunk-YDUDMOL6.js.map +1 -0
  25. package/dist/client-CvaJdLQA.d.ts +5015 -0
  26. package/dist/client.js +2 -1
  27. package/dist/index.d.ts +557 -24
  28. package/dist/index.js +13 -4
  29. package/dist/mcp/client.d.ts +9 -1053
  30. package/dist/mcp/client.js +1 -1
  31. package/dist/mcp/do-oauth-client-provider.d.ts +1 -0
  32. package/dist/mcp/do-oauth-client-provider.js +1 -1
  33. package/dist/mcp/index.d.ts +68 -55
  34. package/dist/mcp/index.js +854 -608
  35. package/dist/mcp/index.js.map +1 -1
  36. package/dist/observability/index.d.ts +46 -12
  37. package/dist/observability/index.js +5 -4
  38. package/dist/react.d.ts +7 -3
  39. package/dist/react.js +7 -5
  40. package/dist/react.js.map +1 -1
  41. package/dist/schedule.d.ts +83 -9
  42. package/dist/schedule.js +15 -2
  43. package/dist/schedule.js.map +1 -1
  44. package/package.json +19 -8
  45. package/src/index.ts +731 -149
  46. package/dist/chunk-4RBEYCWK.js.map +0 -1
  47. package/dist/chunk-KUH345EY.js.map +0 -1
  48. package/dist/chunk-LU2RSO54.js.map +0 -1
  49. package/dist/chunk-PVQZBKN7.js.map +0 -1
  50. package/dist/index-CITGJflw.d.ts +0 -486
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ### 🧠 `agents` - A Framework for Digital Intelligence
2
2
 
3
- ![agents-header](https://github.com/user-attachments/assets/f6d99eeb-1803-4495-9c5e-3cf07a37b402)
3
+ ![npm install agents](../../assets/npm-install-agents.svg)
4
4
 
5
5
  Welcome to a new chapter in software development, where AI agents persist, think, and act with purpose. The `agents` framework creates an environment where artificial intelligence can flourish - maintaining state, engaging in meaningful interactions, and evolving over time.
6
6
 
@@ -166,7 +166,7 @@ export class DialogueAgent extends Agent {
166
166
  }
167
167
  ```
168
168
 
169
- #### Client Communion
169
+ #### Client Communication
170
170
 
171
171
  For direct connection to your agent:
172
172
 
@@ -317,24 +317,139 @@ Create meaningful conversations with intelligence:
317
317
  ```ts
318
318
  import { AIChatAgent } from "agents/ai-chat-agent";
319
319
  import { openai } from "@ai-sdk/openai";
320
+ import { streamText, generateText, createDataStreamResponse } from "ai";
320
321
 
321
322
  export class DialogueAgent extends AIChatAgent {
322
323
  async onChatMessage(onFinish) {
324
+ // Option 1: Streaming responses (recommended for real-time interaction)
323
325
  return createDataStreamResponse({
324
326
  execute: async (dataStream) => {
325
327
  const stream = streamText({
326
328
  model: openai("gpt-4o"),
327
329
  messages: this.messages,
328
- onFinish // call onFinish so that messages get saved
330
+ // Optional: onFinish is invoked by the AI SDK when generation completes.
331
+ // Persistence is handled automatically by AIChatAgent after streaming completes.
332
+ onFinish
329
333
  });
330
334
 
331
335
  stream.mergeIntoDataStream(dataStream);
332
336
  }
333
337
  });
338
+
339
+ // Option 2: Non-streaming responses (simpler, but no real-time updates)
340
+ // const result = await generateText({
341
+ // model: openai("gpt-4o"),
342
+ // messages: this.messages,
343
+ // });
344
+ //
345
+ // // For non-streaming with metadata, use toUIMessage:
346
+ // const message = result.toUIMessage({
347
+ // metadata: {
348
+ // model: 'gpt-4o',
349
+ // totalTokens: result.usage?.totalTokens,
350
+ // }
351
+ // });
352
+ //
353
+ // return new Response(JSON.stringify(message), {
354
+ // headers: { 'Content-Type': 'application/json' }
355
+ // });
356
+ }
357
+ }
358
+ ```
359
+
360
+ #### Metadata Support
361
+
362
+ The AI SDK provides native support for message metadata through the `messageMetadata` callback. This allows you to attach custom information to messages at the message level.
363
+
364
+ ##### AIChatAgent Integration
365
+
366
+ In the context of `AIChatAgent`, you can use metadata like this:
367
+
368
+ ```typescript
369
+ import { AIChatAgent } from "agents/ai-chat-agent";
370
+ import { streamText } from "ai";
371
+ import { openai } from "@ai-sdk/openai";
372
+
373
+ export class MyAgent extends AIChatAgent<Env> {
374
+ async onChatMessage(onFinish) {
375
+ const startTime = Date.now();
376
+
377
+ const result = streamText({
378
+ model: openai("gpt-4o"),
379
+ messages: this.messages,
380
+ onFinish
381
+ });
382
+
383
+ return result.toUIMessageStreamResponse({
384
+ messageMetadata: ({ part }) => {
385
+ if (part.type === "start") {
386
+ return {
387
+ model: "gpt-4o",
388
+ createdAt: Date.now(),
389
+ messageCount: this.messages.length
390
+ };
391
+ }
392
+ if (part.type === "finish") {
393
+ return {
394
+ responseTime: Date.now() - startTime,
395
+ totalTokens: part.totalUsage?.totalTokens
396
+ };
397
+ }
398
+ }
399
+ });
334
400
  }
335
401
  }
336
402
  ```
337
403
 
404
+ ##### Accessing Metadata on the Client
405
+
406
+ Access metadata through the `message.metadata` property:
407
+
408
+ ```typescript
409
+ 'use client';
410
+
411
+ import { useChat } from '@ai-sdk/react';
412
+ import { DefaultChatTransport } from 'ai';
413
+ import type { MyUIMessage } from '@/types';
414
+
415
+ export default function Chat() {
416
+ const { messages } = useChat<MyUIMessage>({
417
+ transport: new DefaultChatTransport({
418
+ api: '/api/chat',
419
+ }),
420
+ });
421
+
422
+ return (
423
+ <div>
424
+ {messages.map(message => (
425
+ <div key={message.id}>
426
+ <div>
427
+ {message.role === 'user' ? 'User: ' : 'AI: '}
428
+ {message.metadata?.createdAt && (
429
+ <span className="text-sm text-gray-500">
430
+ {new Date(message.metadata.createdAt).toLocaleTimeString()}
431
+ </span>
432
+ )}
433
+ </div>
434
+ {/* Render message content */}
435
+ {message.parts.map((part, index) =>
436
+ part.type === 'text' ? <div key={index}>{part.text}</div> : null,
437
+ )}
438
+ {/* Display additional metadata */}
439
+ {message.metadata?.totalTokens && (
440
+ <div className="text-xs text-gray-400">
441
+ {message.metadata.totalTokens} tokens
442
+ </div>
443
+ )}
444
+ </div>
445
+ ))}
446
+ </div>
447
+ );
448
+ }
449
+ ```
450
+
451
+ For more details, see the [AI SDK Message Metadata documentation](https://ai-sdk.dev/docs/ai-sdk-ui/message-metadata).
452
+
338
453
  #### Creating the Interface
339
454
 
340
455
  Connect with your agent through a React interface:
@@ -363,7 +478,14 @@ function ChatInterface() {
363
478
  {messages.map((message) => (
364
479
  <div key={message.id} className="message">
365
480
  <div className="role">{message.role}</div>
366
- <div className="content">{message.content}</div>
481
+ <div className="content">
482
+ {message.parts.map((part, i) => {
483
+ if (part.type === "text")
484
+ return <span key={i}>{part.text}</span>;
485
+ // Render other part types (e.g., files, tool calls) as desired
486
+ return null;
487
+ })}
488
+ </div>
367
489
  </div>
368
490
  ))}
369
491
  </div>
@@ -393,6 +515,112 @@ This creates:
393
515
  - Intuitive input handling
394
516
  - Easy conversation reset
395
517
 
518
+ ### 🔗 MCP (Model Context Protocol) Integration
519
+
520
+ Agents can seamlessly integrate with the Model Context Protocol, allowing them to act as both MCP servers (providing tools to AI assistants) and MCP clients (using tools from other services).
521
+
522
+ #### Creating an MCP Server
523
+
524
+ ```typescript
525
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
526
+ import { McpAgent } from "agents/mcp";
527
+ import { z } from "zod";
528
+
529
+ type Env = {
530
+ MyMCP: DurableObjectNamespace<MyMCP>;
531
+ };
532
+
533
+ type State = { counter: number };
534
+
535
+ export class MyMCP extends McpAgent<Env, State, {}> {
536
+ server = new McpServer({
537
+ name: "Demo",
538
+ version: "1.0.0"
539
+ });
540
+
541
+ initialState: State = {
542
+ counter: 1
543
+ };
544
+
545
+ async init() {
546
+ this.server.resource("counter", "mcp://resource/counter", (uri) => {
547
+ return {
548
+ contents: [{ text: String(this.state.counter), uri: uri.href }]
549
+ };
550
+ });
551
+
552
+ this.server.tool(
553
+ "add",
554
+ "Add to the counter, stored in the MCP",
555
+ { a: z.number() },
556
+ async ({ a }) => {
557
+ this.setState({ ...this.state, counter: this.state.counter + a });
558
+
559
+ return {
560
+ content: [
561
+ {
562
+ text: String(`Added ${a}, total is now ${this.state.counter}`),
563
+ type: "text"
564
+ }
565
+ ]
566
+ };
567
+ }
568
+ );
569
+ }
570
+
571
+ onStateUpdate(state: State) {
572
+ console.log({ stateUpdate: state });
573
+ }
574
+ }
575
+
576
+ // HTTP Streamable transport (recommended)
577
+ export default MyMCP.serve("/mcp", {
578
+ binding: "MyMCP"
579
+ });
580
+
581
+ // Or SSE transport for legacy compatibility
582
+ // export default MyMCP.serveSSE("/mcp", { binding: "MyMCP" });
583
+ ```
584
+
585
+ #### Using MCP Tools
586
+
587
+ ```typescript
588
+ import { MCPClientManager } from "agents/mcp";
589
+
590
+ const client = new MCPClientManager("my-app", "1.0.0");
591
+
592
+ // Connect to an MCP server
593
+ await client.connect("https://weather-service.com/mcp", {
594
+ transport: { type: "streamable-http" }
595
+ });
596
+
597
+ // Use tools from the server
598
+ const weather = await client.callTool({
599
+ serverId: "weather-service",
600
+ name: "getWeather",
601
+ arguments: { location: "San Francisco" }
602
+ });
603
+ ```
604
+
605
+ #### AI SDK Integration
606
+
607
+ ```typescript
608
+ import { generateText } from "ai";
609
+
610
+ // Convert MCP tools for AI use
611
+ const result = await generateText({
612
+ model: openai("gpt-4"),
613
+ tools: client.getAITools(),
614
+ prompt: "What's the weather in Tokyo?"
615
+ });
616
+ ```
617
+
618
+ **Transport Options:**
619
+
620
+ - **Auto**: Automatically determine the correct transport
621
+ - **HTTP Streamable**: Best performance, batch requests, session management
622
+ - **SSE**: Simple setup, legacy compatibility
623
+
396
624
  ### 💬 The Path Forward
397
625
 
398
626
  We're developing new dimensions of agent capability:
@@ -418,8 +646,8 @@ Welcome to the future of intelligent agents. Create something meaningful. 🌟
418
646
  Contributions are welcome, but are especially welcome when:
419
647
 
420
648
  - You have opened an issue as a Request for Comment (RFC) to discuss your proposal, show your thinking, and iterate together.
421
- - Is not "AI slop": LLMs are powerful tools, but contributions entirely authored by vibe coding are unlikely to meet the quality bar, and will be rejected.
422
- - You're willing to accept feedback and make sure the changes fit the goals of the `agents` sdk. Not everything will, and that's OK.
649
+ - Not "AI slop": LLMs are powerful tools, but contributions entirely authored by vibe coding are unlikely to meet the quality bar, and will be rejected.
650
+ - You're willing to accept feedback and make sure the changes fit the goals of the `agents` SDK. Not everything will, and that's OK.
423
651
 
424
652
  Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
425
653
 
@@ -1,15 +1,19 @@
1
- import { Message, StreamTextOnFinishCallback, ToolSet } from "ai";
2
- import { A as Agent, a as AgentContext } from "./index-CITGJflw.js";
1
+ import { UIMessage, StreamTextOnFinishCallback, ToolSet } from "ai";
2
+ import { Agent, AgentContext } from "./index.js";
3
3
  import { Connection, WSMessage } from "partyserver";
4
+ import "cloudflare:workers";
4
5
  import "@modelcontextprotocol/sdk/client/index.js";
5
6
  import "@modelcontextprotocol/sdk/types.js";
6
- import "./mcp/client.js";
7
+ import "./client-CvaJdLQA.js";
7
8
  import "zod";
8
- import "@modelcontextprotocol/sdk/client/sse.js";
9
9
  import "@modelcontextprotocol/sdk/shared/protocol.js";
10
+ import "@modelcontextprotocol/sdk/client/sse.js";
11
+ import "@modelcontextprotocol/sdk/client/streamableHttp.js";
10
12
  import "./mcp/do-oauth-client-provider.js";
11
13
  import "@modelcontextprotocol/sdk/client/auth.js";
12
14
  import "@modelcontextprotocol/sdk/shared/auth.js";
15
+ import "./observability/index.js";
16
+ import "./ai-types.js";
13
17
 
14
18
  /**
15
19
  * Extension of Agent with built-in chat capabilities
@@ -25,7 +29,7 @@ declare class AIChatAgent<Env = unknown, State = unknown> extends Agent<
25
29
  */
26
30
  private _chatMessageAbortControllers;
27
31
  /** Array of chat messages for the current conversation */
28
- messages: Message[];
32
+ messages: UIMessage[];
29
33
  constructor(ctx: AgentContext, env: Env);
30
34
  private _broadcastChatMessage;
31
35
  onMessage(connection: Connection, message: WSMessage): Promise<void>;
@@ -44,15 +48,14 @@ declare class AIChatAgent<Env = unknown, State = unknown> extends Agent<
44
48
  }
45
49
  ): Promise<Response | undefined>;
46
50
  /**
47
- * Save messages on the server side and trigger AI response
51
+ * Save messages on the server side
48
52
  * @param messages Chat messages to save
49
53
  */
50
- saveMessages(messages: Message[]): Promise<void>;
54
+ saveMessages(messages: UIMessage[]): Promise<void>;
51
55
  persistMessages(
52
- messages: Message[],
56
+ messages: UIMessage[],
53
57
  excludeBroadcastIds?: string[]
54
58
  ): Promise<void>;
55
- private _messagesNotAlreadyInAgent;
56
59
  private _reply;
57
60
  /**
58
61
  * For the given message id, look up its associated AbortController
@@ -1,12 +1,15 @@
1
+ import {
2
+ autoTransformMessages
3
+ } from "./chunk-UJVEAURM.js";
1
4
  import {
2
5
  Agent
3
- } from "./chunk-LU2RSO54.js";
4
- import "./chunk-4RBEYCWK.js";
5
- import "./chunk-PVQZBKN7.js";
6
- import "./chunk-KUH345EY.js";
6
+ } from "./chunk-YDUDMOL6.js";
7
+ import "./chunk-MH46VMM4.js";
8
+ import "./chunk-LL2AFX7V.js";
9
+ import "./chunk-QEVM4BVL.js";
10
+ import "./chunk-AVYJQSLW.js";
7
11
 
8
12
  // src/ai-chat-agent.ts
9
- import { appendResponseMessages } from "ai";
10
13
  var decoder = new TextDecoder();
11
14
  var AIChatAgent = class extends Agent {
12
15
  constructor(ctx, env) {
@@ -16,9 +19,10 @@ var AIChatAgent = class extends Agent {
16
19
  message text not null,
17
20
  created_at datetime default current_timestamp
18
21
  )`;
19
- this.messages = (this.sql`select * from cf_ai_chat_agent_messages` || []).map((row) => {
22
+ const rawMessages = (this.sql`select * from cf_ai_chat_agent_messages` || []).map((row) => {
20
23
  return JSON.parse(row.message);
21
24
  });
25
+ this.messages = autoTransformMessages(rawMessages);
22
26
  this._chatMessageAbortControllers = /* @__PURE__ */ new Map();
23
27
  }
24
28
  _broadcastChatMessage(message, exclude) {
@@ -32,7 +36,7 @@ var AIChatAgent = class extends Agent {
32
36
  } catch (_error) {
33
37
  return;
34
38
  }
35
- if (data.type === "cf_agent_use_chat_request" && data.init.method === "POST") {
39
+ if (data.type === "cf_agent_use_chat_request" /* CF_AGENT_USE_CHAT_REQUEST */ && data.init.method === "POST") {
36
40
  const {
37
41
  // method,
38
42
  // keepalive,
@@ -45,22 +49,20 @@ var AIChatAgent = class extends Agent {
45
49
  // duplex
46
50
  } = data.init;
47
51
  const { messages } = JSON.parse(body);
52
+ const transformedMessages = autoTransformMessages(messages);
48
53
  this._broadcastChatMessage(
49
54
  {
50
- messages,
51
- type: "cf_agent_chat_messages"
55
+ messages: transformedMessages,
56
+ type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
52
57
  },
53
58
  [connection.id]
54
59
  );
55
- const incomingMessages = this._messagesNotAlreadyInAgent(messages);
56
- await this.persistMessages(messages, [connection.id]);
60
+ await this.persistMessages(transformedMessages, [connection.id]);
57
61
  this.observability?.emit(
58
62
  {
59
63
  displayMessage: "Chat message request",
60
64
  id: data.id,
61
- payload: {
62
- message: incomingMessages
63
- },
65
+ payload: {},
64
66
  timestamp: Date.now(),
65
67
  type: "message:request"
66
68
  },
@@ -70,21 +72,13 @@ var AIChatAgent = class extends Agent {
70
72
  const abortSignal = this._getAbortSignal(chatMessageId);
71
73
  return this._tryCatchChat(async () => {
72
74
  const response = await this.onChatMessage(
73
- async ({ response: response2 }) => {
74
- const finalMessages = appendResponseMessages({
75
- messages,
76
- responseMessages: response2.messages
77
- });
78
- const outgoingMessages = this._messagesNotAlreadyInAgent(finalMessages);
79
- await this.persistMessages(finalMessages, [connection.id]);
75
+ async (_finishResult) => {
80
76
  this._removeAbortController(chatMessageId);
81
77
  this.observability?.emit(
82
78
  {
83
79
  displayMessage: "Chat message response",
84
80
  id: data.id,
85
- payload: {
86
- message: outgoingMessages
87
- },
81
+ payload: {},
88
82
  timestamp: Date.now(),
89
83
  type: "message:response"
90
84
  },
@@ -104,26 +98,27 @@ var AIChatAgent = class extends Agent {
104
98
  body: "No response was generated by the agent.",
105
99
  done: true,
106
100
  id: data.id,
107
- type: "cf_agent_use_chat_response"
101
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
108
102
  },
109
103
  [connection.id]
110
104
  );
111
105
  }
112
106
  });
113
107
  }
114
- if (data.type === "cf_agent_chat_clear") {
108
+ if (data.type === "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */) {
115
109
  this._destroyAbortControllers();
116
110
  this.sql`delete from cf_ai_chat_agent_messages`;
117
111
  this.messages = [];
118
112
  this._broadcastChatMessage(
119
113
  {
120
- type: "cf_agent_chat_clear"
114
+ type: "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */
121
115
  },
122
116
  [connection.id]
123
117
  );
124
- } else if (data.type === "cf_agent_chat_messages") {
125
- await this.persistMessages(data.messages, [connection.id]);
126
- } else if (data.type === "cf_agent_chat_request_cancel") {
118
+ } else if (data.type === "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */) {
119
+ const transformedMessages = autoTransformMessages(data.messages);
120
+ await this.persistMessages(transformedMessages, [connection.id]);
121
+ } else if (data.type === "cf_agent_chat_request_cancel" /* CF_AGENT_CHAT_REQUEST_CANCEL */) {
127
122
  this._cancelChatRequest(data.id);
128
123
  }
129
124
  }
@@ -159,24 +154,11 @@ var AIChatAgent = class extends Agent {
159
154
  );
160
155
  }
161
156
  /**
162
- * Save messages on the server side and trigger AI response
157
+ * Save messages on the server side
163
158
  * @param messages Chat messages to save
164
159
  */
165
160
  async saveMessages(messages) {
166
161
  await this.persistMessages(messages);
167
- const response = await this.onChatMessage(async ({ response: response2 }) => {
168
- const finalMessages = appendResponseMessages({
169
- messages,
170
- responseMessages: response2.messages
171
- });
172
- await this.persistMessages(finalMessages, []);
173
- });
174
- if (response) {
175
- for await (const chunk of response.body) {
176
- decoder.decode(chunk);
177
- }
178
- response.body?.cancel();
179
- }
180
162
  }
181
163
  async persistMessages(messages, excludeBroadcastIds = []) {
182
164
  this.sql`delete from cf_ai_chat_agent_messages`;
@@ -187,32 +169,141 @@ var AIChatAgent = class extends Agent {
187
169
  this._broadcastChatMessage(
188
170
  {
189
171
  messages,
190
- type: "cf_agent_chat_messages"
172
+ type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
191
173
  },
192
174
  excludeBroadcastIds
193
175
  );
194
176
  }
195
- _messagesNotAlreadyInAgent(messages) {
196
- const existingIds = new Set(this.messages.map((message) => message.id));
197
- return messages.filter((message) => !existingIds.has(message.id));
198
- }
199
177
  async _reply(id, response) {
200
178
  return this._tryCatchChat(async () => {
201
- for await (const chunk of response.body) {
202
- const body = decoder.decode(chunk);
179
+ if (!response.body) {
203
180
  this._broadcastChatMessage({
204
- body,
205
- done: false,
181
+ body: "",
182
+ done: true,
206
183
  id,
207
- type: "cf_agent_use_chat_response"
184
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
208
185
  });
186
+ return;
209
187
  }
210
- this._broadcastChatMessage({
211
- body: "",
212
- done: true,
213
- id,
214
- type: "cf_agent_use_chat_response"
188
+ const reader = response.body.getReader();
189
+ let fullResponseText = "";
190
+ let fullReasoningText = "";
191
+ const toolCalls = /* @__PURE__ */ new Map();
192
+ try {
193
+ while (true) {
194
+ const { done, value } = await reader.read();
195
+ if (done) {
196
+ this._broadcastChatMessage({
197
+ body: "",
198
+ done: true,
199
+ id,
200
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
201
+ });
202
+ break;
203
+ }
204
+ const chunk = decoder.decode(value);
205
+ const contentType = response.headers.get("content-type") || "";
206
+ const isSSE = contentType.includes("text/event-stream");
207
+ if (isSSE) {
208
+ const lines = chunk.split("\n");
209
+ for (const line of lines) {
210
+ if (line.startsWith("data: ") && line !== "data: [DONE]") {
211
+ try {
212
+ const data = JSON.parse(line.slice(6));
213
+ switch (data.type) {
214
+ // SSE event signaling the tool input is ready. We track by
215
+ // `toolCallId` so we can persist it as a tool part in the message.
216
+ case "tool-input-available": {
217
+ const { toolCallId, toolName, input } = data;
218
+ toolCalls.set(toolCallId, {
219
+ toolCallId,
220
+ toolName,
221
+ input,
222
+ type: toolName ? `tool-${toolName}` : "dynamic-tool",
223
+ state: "input-available"
224
+ });
225
+ break;
226
+ }
227
+ // SSE event signaling the tool output is ready. We should've
228
+ // already received the input in a previous event so an entry
229
+ // with `toolCallId` should already be present
230
+ case "tool-output-available": {
231
+ const { toolCallId, output, isError, errorText } = data;
232
+ const toolPart = toolCalls.get(toolCallId);
233
+ if (toolPart)
234
+ toolCalls.set(toolCallId, {
235
+ ...toolPart,
236
+ output,
237
+ isError,
238
+ errorText,
239
+ state: "output-available"
240
+ });
241
+ break;
242
+ }
243
+ case "error": {
244
+ this._broadcastChatMessage({
245
+ error: true,
246
+ body: data.errorText ?? JSON.stringify(data),
247
+ done: false,
248
+ id,
249
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
250
+ });
251
+ return;
252
+ }
253
+ case "reasoning-delta": {
254
+ if (data.delta) fullReasoningText += data.delta;
255
+ break;
256
+ }
257
+ case "text-delta": {
258
+ if (data.delta) fullResponseText += data.delta;
259
+ break;
260
+ }
261
+ }
262
+ this._broadcastChatMessage({
263
+ body: JSON.stringify(data),
264
+ done: false,
265
+ id,
266
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
267
+ });
268
+ } catch (_e) {
269
+ }
270
+ }
271
+ }
272
+ } else {
273
+ if (chunk.length > 0) {
274
+ fullResponseText += chunk;
275
+ this._broadcastChatMessage({
276
+ body: JSON.stringify({ type: "text-delta", delta: chunk }),
277
+ done: false,
278
+ id,
279
+ type: "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */
280
+ });
281
+ }
282
+ }
283
+ }
284
+ } finally {
285
+ reader.releaseLock();
286
+ }
287
+ const messageParts = [];
288
+ Array.from(toolCalls.values()).forEach((t) => {
289
+ messageParts.push(t);
215
290
  });
291
+ if (fullReasoningText.trim()) {
292
+ messageParts.push({ type: "reasoning", text: fullReasoningText });
293
+ }
294
+ if (fullResponseText.trim()) {
295
+ messageParts.push({ type: "text", text: fullResponseText });
296
+ }
297
+ if (messageParts.length > 0) {
298
+ await this.persistMessages([
299
+ ...this.messages,
300
+ {
301
+ id: `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,
302
+ role: "assistant",
303
+ parts: messageParts
304
+ }
305
+ ]);
306
+ }
216
307
  });
217
308
  }
218
309
  /**