agents 0.0.0-2a0b252 → 0.0.0-2b4c060
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.
- package/README.md +103 -5
- package/dist/ai-chat-agent.d.ts +1 -1
- package/dist/ai-chat-agent.js +10 -2
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +7 -1
- package/dist/ai-react.js +41 -8
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-VYENMKFS.js → chunk-MH46VMM4.js} +1 -1
- package/dist/chunk-MH46VMM4.js.map +1 -0
- package/dist/{chunk-PNF6ZMUA.js → chunk-YDUDMOL6.js} +4 -4
- package/dist/chunk-YDUDMOL6.js.map +1 -0
- package/dist/{client-CcIORE73.d.ts → client-CvaJdLQA.d.ts} +408 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.js +2 -2
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/index.d.ts +61 -76
- package/dist/mcp/index.js +809 -736
- package/dist/mcp/index.js.map +1 -1
- package/dist/observability/index.js +2 -2
- package/dist/react.d.ts +1 -1
- package/package.json +7 -5
- package/src/index.ts +13 -4
- package/dist/chunk-PNF6ZMUA.js.map +0 -1
- package/dist/chunk-VYENMKFS.js.map +0 -1
package/README.md
CHANGED
|
@@ -342,16 +342,114 @@ export class DialogueAgent extends AIChatAgent {
|
|
|
342
342
|
// messages: this.messages,
|
|
343
343
|
// });
|
|
344
344
|
//
|
|
345
|
-
// //
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
//
|
|
349
|
-
//
|
|
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' }
|
|
350
355
|
// });
|
|
351
356
|
}
|
|
352
357
|
}
|
|
353
358
|
```
|
|
354
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
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
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
|
+
|
|
355
453
|
#### Creating the Interface
|
|
356
454
|
|
|
357
455
|
Connect with your agent through a React interface:
|
package/dist/ai-chat-agent.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Connection, WSMessage } from "partyserver";
|
|
|
4
4
|
import "cloudflare:workers";
|
|
5
5
|
import "@modelcontextprotocol/sdk/client/index.js";
|
|
6
6
|
import "@modelcontextprotocol/sdk/types.js";
|
|
7
|
-
import "./client-
|
|
7
|
+
import "./client-CvaJdLQA.js";
|
|
8
8
|
import "zod";
|
|
9
9
|
import "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
10
10
|
import "@modelcontextprotocol/sdk/client/sse.js";
|
package/dist/ai-chat-agent.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
} from "./chunk-UJVEAURM.js";
|
|
4
4
|
import {
|
|
5
5
|
Agent
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-YDUDMOL6.js";
|
|
7
|
+
import "./chunk-MH46VMM4.js";
|
|
8
8
|
import "./chunk-LL2AFX7V.js";
|
|
9
9
|
import "./chunk-QEVM4BVL.js";
|
|
10
10
|
import "./chunk-AVYJQSLW.js";
|
|
@@ -187,6 +187,7 @@ var AIChatAgent = class extends Agent {
|
|
|
187
187
|
}
|
|
188
188
|
const reader = response.body.getReader();
|
|
189
189
|
let fullResponseText = "";
|
|
190
|
+
let fullReasoningText = "";
|
|
190
191
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
191
192
|
try {
|
|
192
193
|
while (true) {
|
|
@@ -249,6 +250,10 @@ var AIChatAgent = class extends Agent {
|
|
|
249
250
|
});
|
|
250
251
|
return;
|
|
251
252
|
}
|
|
253
|
+
case "reasoning-delta": {
|
|
254
|
+
if (data.delta) fullReasoningText += data.delta;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
252
257
|
case "text-delta": {
|
|
253
258
|
if (data.delta) fullResponseText += data.delta;
|
|
254
259
|
break;
|
|
@@ -283,6 +288,9 @@ var AIChatAgent = class extends Agent {
|
|
|
283
288
|
Array.from(toolCalls.values()).forEach((t) => {
|
|
284
289
|
messageParts.push(t);
|
|
285
290
|
});
|
|
291
|
+
if (fullReasoningText.trim()) {
|
|
292
|
+
messageParts.push({ type: "reasoning", text: fullReasoningText });
|
|
293
|
+
}
|
|
286
294
|
if (fullResponseText.trim()) {
|
|
287
295
|
messageParts.push({ type: "text", text: fullResponseText });
|
|
288
296
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import type {\n UIMessage as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet\n} from \"ai\";\nimport { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport {\n MessageType,\n type IncomingMessage,\n type OutgoingMessage\n} from \"./ai-types\";\nimport { autoTransformMessages } from \"./ai-chat-v5-migration\";\n\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /**\n * Map of message `id`s to `AbortController`s\n * useful to propagate request cancellation signals for any external calls made by the agent\n */\n private _chatMessageAbortControllers: Map<string, AbortController>;\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n\n // Load messages and automatically transform them to v5 format\n const rawMessages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n\n // Automatic migration following https://jhak.im/blog/ai-sdk-migration-handling-previously-saved-messages\n this.messages = autoTransformMessages(rawMessages);\n\n this._chatMessageAbortControllers = new Map();\n }\n\n private _broadcastChatMessage(message: OutgoingMessage, exclude?: string[]) {\n this.broadcast(JSON.stringify(message), exclude);\n }\n\n override async onMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n let data: IncomingMessage;\n try {\n data = JSON.parse(message) as IncomingMessage;\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (\n data.type === MessageType.CF_AGENT_USE_CHAT_REQUEST &&\n data.init.method === \"POST\"\n ) {\n const {\n // method,\n // keepalive,\n // headers,\n body // we're reading this\n //\n // // these might not exist?\n // dispatcher,\n // duplex\n } = data.init;\n const { messages } = JSON.parse(body as string);\n\n // Automatically transform any incoming messages\n const transformedMessages = autoTransformMessages(messages);\n\n this._broadcastChatMessage(\n {\n messages: transformedMessages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n [connection.id]\n );\n\n await this.persistMessages(transformedMessages, [connection.id]);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message request\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:request\"\n },\n this.ctx\n );\n\n const chatMessageId = data.id;\n const abortSignal = this._getAbortSignal(chatMessageId);\n\n return this._tryCatchChat(async () => {\n const response = await this.onChatMessage(\n async (_finishResult) => {\n this._removeAbortController(chatMessageId);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message response\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:response\"\n },\n this.ctx\n );\n\n // Note: Message persistence now happens in the _reply method\n // after the complete response text has been accumulated\n },\n abortSignal ? { abortSignal } : undefined\n );\n\n if (response) {\n await this._reply(data.id, response);\n } else {\n // Log a warning for observability\n console.warn(\n `[AIChatAgent] onChatMessage returned no response for chatMessageId: ${chatMessageId}`\n );\n // Send a fallback message to the client\n this._broadcastChatMessage(\n {\n body: \"No response was generated by the agent.\",\n done: true,\n id: data.id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n },\n [connection.id]\n );\n }\n });\n }\n if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) {\n this._destroyAbortControllers();\n this.sql`delete from cf_ai_chat_agent_messages`;\n this.messages = [];\n this._broadcastChatMessage(\n {\n type: MessageType.CF_AGENT_CHAT_CLEAR\n },\n [connection.id]\n );\n } else if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) {\n // replace the messages with the new ones, automatically transformed\n const transformedMessages = autoTransformMessages(data.messages);\n await this.persistMessages(transformedMessages, [connection.id]);\n } else if (data.type === MessageType.CF_AGENT_CHAT_REQUEST_CANCEL) {\n // propagate an abort signal for the associated request\n this._cancelChatRequest(data.id);\n }\n }\n }\n\n override async onRequest(request: Request): Promise<Response> {\n return this._tryCatchChat(() => {\n const url = new URL(request.url);\n if (url.pathname.endsWith(\"/get-messages\")) {\n const messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n return Response.json(messages);\n }\n return super.onRequest(request);\n });\n }\n\n private async _tryCatchChat<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n /**\n * Handle incoming chat messages and generate a response\n * @param onFinish Callback to be called when the response is finished\n * @param options.signal A signal to pass to any child requests which can be used to cancel them\n * @returns Response to send to the client or undefined\n */\n async onChatMessage(\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n onFinish: StreamTextOnFinishCallback<ToolSet>,\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n options?: { abortSignal: AbortSignal | undefined }\n ): Promise<Response | undefined> {\n throw new Error(\n \"recieved a chat message, override onChatMessage and return a Response to send to the client\"\n );\n }\n\n /**\n * Save messages on the server side\n * @param messages Chat messages to save\n */\n async saveMessages(messages: ChatMessage[]) {\n await this.persistMessages(messages);\n }\n\n async persistMessages(\n messages: ChatMessage[],\n excludeBroadcastIds: string[] = []\n ) {\n this.sql`delete from cf_ai_chat_agent_messages`;\n for (const message of messages) {\n this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${\n message.id\n },${JSON.stringify(message)})`;\n }\n this.messages = messages;\n this._broadcastChatMessage(\n {\n messages: messages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n excludeBroadcastIds\n );\n }\n\n private async _reply(id: string, response: Response) {\n return this._tryCatchChat(async () => {\n if (!response.body) {\n // Send empty response if no body\n this._broadcastChatMessage({\n body: \"\",\n done: true,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n return;\n }\n\n const reader = response.body.getReader();\n let fullResponseText = \"\"; // Accumulate the assistant's response text\n // Track tool calls by toolCallid, so we can persist them as parts later\n const toolCalls = new Map<\n string,\n {\n type: string;\n state: string;\n toolCallId: string;\n toolName: string;\n input?: unknown;\n output?: unknown;\n isError?: boolean;\n errorText?: string;\n }\n >();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n // Send final completion signal\n this._broadcastChatMessage({\n body: \"\",\n done: true,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n break;\n }\n\n const chunk = decoder.decode(value);\n\n // Determine response format based on content-type\n const contentType = response.headers.get(\"content-type\") || \"\";\n const isSSE = contentType.includes(\"text/event-stream\");\n\n if (isSSE) {\n // Parse AI SDK v5 SSE format and extract text deltas\n const lines = chunk.split(\"\\n\");\n for (const line of lines) {\n if (line.startsWith(\"data: \") && line !== \"data: [DONE]\") {\n try {\n const data = JSON.parse(line.slice(6)); // Remove 'data: ' prefix\n\n switch (data.type) {\n // SSE event signaling the tool input is ready. We track by\n // `toolCallId` so we can persist it as a tool part in the message.\n case \"tool-input-available\": {\n const { toolCallId, toolName, input } = data;\n toolCalls.set(toolCallId, {\n toolCallId,\n toolName,\n input,\n type: toolName ? `tool-${toolName}` : \"dynamic-tool\",\n state: \"input-available\"\n });\n break;\n }\n\n // SSE event signaling the tool output is ready. We should've\n // already received the input in a previous event so an entry\n // with `toolCallId` should already be present\n case \"tool-output-available\": {\n const { toolCallId, output, isError, errorText } = data;\n const toolPart = toolCalls.get(toolCallId);\n if (toolPart)\n toolCalls.set(toolCallId, {\n ...toolPart,\n output,\n isError,\n errorText,\n state: \"output-available\"\n });\n break;\n }\n\n case \"error\": {\n // Non-tool errors, we set `error: true` and terminate early\n this._broadcastChatMessage({\n error: true,\n body: data.errorText ?? JSON.stringify(data),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n return;\n }\n\n case \"text-delta\": {\n if (data.delta) fullResponseText += data.delta;\n break;\n }\n }\n\n // Always forward the raw part to the client\n this._broadcastChatMessage({\n body: JSON.stringify(data),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n } catch (_e) {\n // Skip malformed JSON lines silently\n }\n }\n }\n } else {\n // Handle plain text responses (e.g., from generateText)\n // Treat the entire chunk as a text delta to preserve exact formatting\n if (chunk.length > 0) {\n fullResponseText += chunk;\n // Synthesize a text-delta event so clients can stream-render\n this._broadcastChatMessage({\n body: JSON.stringify({ type: \"text-delta\", delta: chunk }),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // After streaming is complete, persist the complete assistant's response\n const messageParts: ChatMessage[\"parts\"] = [];\n\n Array.from(toolCalls.values()).forEach((t) => {\n messageParts.push(t as ChatMessage[\"parts\"][number]);\n });\n\n if (fullResponseText.trim()) {\n messageParts.push({ type: \"text\", text: fullResponseText });\n }\n\n if (messageParts.length > 0) {\n await this.persistMessages([\n ...this.messages,\n {\n id: `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,\n role: \"assistant\",\n parts: messageParts\n }\n ]);\n }\n });\n }\n\n /**\n * For the given message id, look up its associated AbortController\n * If the AbortController does not exist, create and store one in memory\n *\n * returns the AbortSignal associated with the AbortController\n */\n private _getAbortSignal(id: string): AbortSignal | undefined {\n // Defensive check, since we're coercing message types at the moment\n if (typeof id !== \"string\") {\n return undefined;\n }\n\n if (!this._chatMessageAbortControllers.has(id)) {\n this._chatMessageAbortControllers.set(id, new AbortController());\n }\n\n return this._chatMessageAbortControllers.get(id)?.signal;\n }\n\n /**\n * Remove an abort controller from the cache of pending message responses\n */\n private _removeAbortController(id: string) {\n this._chatMessageAbortControllers.delete(id);\n }\n\n /**\n * Propagate an abort signal for any requests associated with the given message id\n */\n private _cancelChatRequest(id: string) {\n if (this._chatMessageAbortControllers.has(id)) {\n const abortController = this._chatMessageAbortControllers.get(id);\n abortController?.abort();\n }\n }\n\n /**\n * Abort all pending requests and clear the cache of AbortControllers\n */\n private _destroyAbortControllers() {\n for (const controller of this._chatMessageAbortControllers.values()) {\n controller?.abort();\n }\n this._chatMessageAbortControllers.clear();\n }\n\n /**\n * When the DO is destroyed, cancel all pending requests\n */\n async destroy() {\n this._destroyAbortControllers();\n await super.destroy();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import type {\n UIMessage as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet\n} from \"ai\";\nimport { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport {\n MessageType,\n type IncomingMessage,\n type OutgoingMessage\n} from \"./ai-types\";\nimport { autoTransformMessages } from \"./ai-chat-v5-migration\";\n\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /**\n * Map of message `id`s to `AbortController`s\n * useful to propagate request cancellation signals for any external calls made by the agent\n */\n private _chatMessageAbortControllers: Map<string, AbortController>;\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n\n // Load messages and automatically transform them to v5 format\n const rawMessages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n\n // Automatic migration following https://jhak.im/blog/ai-sdk-migration-handling-previously-saved-messages\n this.messages = autoTransformMessages(rawMessages);\n\n this._chatMessageAbortControllers = new Map();\n }\n\n private _broadcastChatMessage(message: OutgoingMessage, exclude?: string[]) {\n this.broadcast(JSON.stringify(message), exclude);\n }\n\n override async onMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n let data: IncomingMessage;\n try {\n data = JSON.parse(message) as IncomingMessage;\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (\n data.type === MessageType.CF_AGENT_USE_CHAT_REQUEST &&\n data.init.method === \"POST\"\n ) {\n const {\n // method,\n // keepalive,\n // headers,\n body // we're reading this\n //\n // // these might not exist?\n // dispatcher,\n // duplex\n } = data.init;\n const { messages } = JSON.parse(body as string);\n\n // Automatically transform any incoming messages\n const transformedMessages = autoTransformMessages(messages);\n\n this._broadcastChatMessage(\n {\n messages: transformedMessages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n [connection.id]\n );\n\n await this.persistMessages(transformedMessages, [connection.id]);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message request\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:request\"\n },\n this.ctx\n );\n\n const chatMessageId = data.id;\n const abortSignal = this._getAbortSignal(chatMessageId);\n\n return this._tryCatchChat(async () => {\n const response = await this.onChatMessage(\n async (_finishResult) => {\n this._removeAbortController(chatMessageId);\n\n this.observability?.emit(\n {\n displayMessage: \"Chat message response\",\n id: data.id,\n payload: {},\n timestamp: Date.now(),\n type: \"message:response\"\n },\n this.ctx\n );\n\n // Note: Message persistence now happens in the _reply method\n // after the complete response text has been accumulated\n },\n abortSignal ? { abortSignal } : undefined\n );\n\n if (response) {\n await this._reply(data.id, response);\n } else {\n // Log a warning for observability\n console.warn(\n `[AIChatAgent] onChatMessage returned no response for chatMessageId: ${chatMessageId}`\n );\n // Send a fallback message to the client\n this._broadcastChatMessage(\n {\n body: \"No response was generated by the agent.\",\n done: true,\n id: data.id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n },\n [connection.id]\n );\n }\n });\n }\n if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) {\n this._destroyAbortControllers();\n this.sql`delete from cf_ai_chat_agent_messages`;\n this.messages = [];\n this._broadcastChatMessage(\n {\n type: MessageType.CF_AGENT_CHAT_CLEAR\n },\n [connection.id]\n );\n } else if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) {\n // replace the messages with the new ones, automatically transformed\n const transformedMessages = autoTransformMessages(data.messages);\n await this.persistMessages(transformedMessages, [connection.id]);\n } else if (data.type === MessageType.CF_AGENT_CHAT_REQUEST_CANCEL) {\n // propagate an abort signal for the associated request\n this._cancelChatRequest(data.id);\n }\n }\n }\n\n override async onRequest(request: Request): Promise<Response> {\n return this._tryCatchChat(() => {\n const url = new URL(request.url);\n if (url.pathname.endsWith(\"/get-messages\")) {\n const messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n return Response.json(messages);\n }\n return super.onRequest(request);\n });\n }\n\n private async _tryCatchChat<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n /**\n * Handle incoming chat messages and generate a response\n * @param onFinish Callback to be called when the response is finished\n * @param options.signal A signal to pass to any child requests which can be used to cancel them\n * @returns Response to send to the client or undefined\n */\n async onChatMessage(\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n onFinish: StreamTextOnFinishCallback<ToolSet>,\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later\n options?: { abortSignal: AbortSignal | undefined }\n ): Promise<Response | undefined> {\n throw new Error(\n \"recieved a chat message, override onChatMessage and return a Response to send to the client\"\n );\n }\n\n /**\n * Save messages on the server side\n * @param messages Chat messages to save\n */\n async saveMessages(messages: ChatMessage[]) {\n await this.persistMessages(messages);\n }\n\n async persistMessages(\n messages: ChatMessage[],\n excludeBroadcastIds: string[] = []\n ) {\n this.sql`delete from cf_ai_chat_agent_messages`;\n for (const message of messages) {\n this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${\n message.id\n },${JSON.stringify(message)})`;\n }\n this.messages = messages;\n this._broadcastChatMessage(\n {\n messages: messages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n },\n excludeBroadcastIds\n );\n }\n\n private async _reply(id: string, response: Response) {\n return this._tryCatchChat(async () => {\n if (!response.body) {\n // Send empty response if no body\n this._broadcastChatMessage({\n body: \"\",\n done: true,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n return;\n }\n\n const reader = response.body.getReader();\n let fullResponseText = \"\"; // Accumulate the assistant's response text\n let fullReasoningText = \"\"; // Accumulate the assistant's reasoning\n // Track tool calls by toolCallid, so we can persist them as parts later\n const toolCalls = new Map<\n string,\n {\n type: string;\n state: string;\n toolCallId: string;\n toolName: string;\n input?: unknown;\n output?: unknown;\n isError?: boolean;\n errorText?: string;\n }\n >();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n // Send final completion signal\n this._broadcastChatMessage({\n body: \"\",\n done: true,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n break;\n }\n\n const chunk = decoder.decode(value);\n\n // Determine response format based on content-type\n const contentType = response.headers.get(\"content-type\") || \"\";\n const isSSE = contentType.includes(\"text/event-stream\");\n\n if (isSSE) {\n // Parse AI SDK v5 SSE format and extract text deltas\n const lines = chunk.split(\"\\n\");\n for (const line of lines) {\n if (line.startsWith(\"data: \") && line !== \"data: [DONE]\") {\n try {\n const data = JSON.parse(line.slice(6)); // Remove 'data: ' prefix\n\n switch (data.type) {\n // SSE event signaling the tool input is ready. We track by\n // `toolCallId` so we can persist it as a tool part in the message.\n case \"tool-input-available\": {\n const { toolCallId, toolName, input } = data;\n toolCalls.set(toolCallId, {\n toolCallId,\n toolName,\n input,\n type: toolName ? `tool-${toolName}` : \"dynamic-tool\",\n state: \"input-available\"\n });\n break;\n }\n\n // SSE event signaling the tool output is ready. We should've\n // already received the input in a previous event so an entry\n // with `toolCallId` should already be present\n case \"tool-output-available\": {\n const { toolCallId, output, isError, errorText } = data;\n const toolPart = toolCalls.get(toolCallId);\n if (toolPart)\n toolCalls.set(toolCallId, {\n ...toolPart,\n output,\n isError,\n errorText,\n state: \"output-available\"\n });\n break;\n }\n\n case \"error\": {\n // Non-tool errors, we set `error: true` and terminate early\n this._broadcastChatMessage({\n error: true,\n body: data.errorText ?? JSON.stringify(data),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n return;\n }\n\n case \"reasoning-delta\": {\n if (data.delta) fullReasoningText += data.delta;\n break;\n }\n\n case \"text-delta\": {\n if (data.delta) fullResponseText += data.delta;\n break;\n }\n }\n\n // Always forward the raw part to the client\n this._broadcastChatMessage({\n body: JSON.stringify(data),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n } catch (_e) {\n // Skip malformed JSON lines silently\n }\n }\n }\n } else {\n // Handle plain text responses (e.g., from generateText)\n // Treat the entire chunk as a text delta to preserve exact formatting\n if (chunk.length > 0) {\n fullResponseText += chunk;\n // Synthesize a text-delta event so clients can stream-render\n this._broadcastChatMessage({\n body: JSON.stringify({ type: \"text-delta\", delta: chunk }),\n done: false,\n id,\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE\n });\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n // After streaming is complete, persist the complete assistant's response\n const messageParts: ChatMessage[\"parts\"] = [];\n\n Array.from(toolCalls.values()).forEach((t) => {\n messageParts.push(t as ChatMessage[\"parts\"][number]);\n });\n\n if (fullReasoningText.trim()) {\n messageParts.push({ type: \"reasoning\", text: fullReasoningText });\n }\n\n if (fullResponseText.trim()) {\n messageParts.push({ type: \"text\", text: fullResponseText });\n }\n\n if (messageParts.length > 0) {\n await this.persistMessages([\n ...this.messages,\n {\n id: `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,\n role: \"assistant\",\n parts: messageParts\n }\n ]);\n }\n });\n }\n\n /**\n * For the given message id, look up its associated AbortController\n * If the AbortController does not exist, create and store one in memory\n *\n * returns the AbortSignal associated with the AbortController\n */\n private _getAbortSignal(id: string): AbortSignal | undefined {\n // Defensive check, since we're coercing message types at the moment\n if (typeof id !== \"string\") {\n return undefined;\n }\n\n if (!this._chatMessageAbortControllers.has(id)) {\n this._chatMessageAbortControllers.set(id, new AbortController());\n }\n\n return this._chatMessageAbortControllers.get(id)?.signal;\n }\n\n /**\n * Remove an abort controller from the cache of pending message responses\n */\n private _removeAbortController(id: string) {\n this._chatMessageAbortControllers.delete(id);\n }\n\n /**\n * Propagate an abort signal for any requests associated with the given message id\n */\n private _cancelChatRequest(id: string) {\n if (this._chatMessageAbortControllers.has(id)) {\n const abortController = this._chatMessageAbortControllers.get(id);\n abortController?.abort();\n }\n }\n\n /**\n * Abort all pending requests and clear the cache of AbortControllers\n */\n private _destroyAbortControllers() {\n for (const controller of this._chatMessageAbortControllers.values()) {\n controller?.abort();\n }\n this._chatMessageAbortControllers.clear();\n }\n\n /**\n * When the DO is destroyed, cancel all pending requests\n */\n async destroy() {\n this._destroyAbortControllers();\n await super.destroy();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/ai-react.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import "cloudflare:workers";
|
|
|
8
8
|
import "@modelcontextprotocol/sdk/client/index.js";
|
|
9
9
|
import "@modelcontextprotocol/sdk/types.js";
|
|
10
10
|
import "partyserver";
|
|
11
|
-
import "./client-
|
|
11
|
+
import "./client-CvaJdLQA.js";
|
|
12
12
|
import "zod";
|
|
13
13
|
import "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
14
14
|
import "@modelcontextprotocol/sdk/client/sse.js";
|
|
@@ -65,6 +65,12 @@ type UseAgentChatOptions<
|
|
|
65
65
|
* If not provided, will auto-detect from tools object.
|
|
66
66
|
*/
|
|
67
67
|
toolsRequiringConfirmation?: string[];
|
|
68
|
+
/**
|
|
69
|
+
* When true (default), automatically sends the next message only after
|
|
70
|
+
* all pending confirmation-required tool calls have been resolved.
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
autoSendAfterAllConfirmationsResolved?: boolean;
|
|
68
74
|
};
|
|
69
75
|
/**
|
|
70
76
|
* React hook for building AI chat interfaces using an Agent
|
package/dist/ai-react.js
CHANGED
|
@@ -19,6 +19,7 @@ function useAgentChat(options) {
|
|
|
19
19
|
experimental_automaticToolResolution,
|
|
20
20
|
tools,
|
|
21
21
|
toolsRequiringConfirmation: manualToolsRequiringConfirmation,
|
|
22
|
+
autoSendAfterAllConfirmationsResolved = true,
|
|
22
23
|
...rest
|
|
23
24
|
} = options;
|
|
24
25
|
const toolsRequiringConfirmation = manualToolsRequiringConfirmation ?? detectToolsRequiringConfirmation(tools);
|
|
@@ -195,15 +196,30 @@ function useAgentChat(options) {
|
|
|
195
196
|
transport: customTransport
|
|
196
197
|
});
|
|
197
198
|
const processedToolCalls = useRef(/* @__PURE__ */ new Set());
|
|
199
|
+
const lastMessage = useChatHelpers.messages[useChatHelpers.messages.length - 1];
|
|
200
|
+
const pendingConfirmations = (() => {
|
|
201
|
+
if (!lastMessage || lastMessage.role !== "assistant") {
|
|
202
|
+
return { messageId: void 0, toolCallIds: /* @__PURE__ */ new Set() };
|
|
203
|
+
}
|
|
204
|
+
const pendingIds = /* @__PURE__ */ new Set();
|
|
205
|
+
for (const part of lastMessage.parts ?? []) {
|
|
206
|
+
if (isToolUIPart(part) && part.state === "input-available" && toolsRequiringConfirmation.includes(getToolName(part))) {
|
|
207
|
+
pendingIds.add(part.toolCallId);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return { messageId: lastMessage.id, toolCallIds: pendingIds };
|
|
211
|
+
})();
|
|
212
|
+
const pendingConfirmationsRef = useRef(pendingConfirmations);
|
|
213
|
+
pendingConfirmationsRef.current = pendingConfirmations;
|
|
198
214
|
useEffect(() => {
|
|
199
215
|
if (!experimental_automaticToolResolution) {
|
|
200
216
|
return;
|
|
201
217
|
}
|
|
202
|
-
const
|
|
203
|
-
if (!
|
|
218
|
+
const lastMessage2 = useChatHelpers.messages[useChatHelpers.messages.length - 1];
|
|
219
|
+
if (!lastMessage2 || lastMessage2.role !== "assistant") {
|
|
204
220
|
return;
|
|
205
221
|
}
|
|
206
|
-
const toolCalls =
|
|
222
|
+
const toolCalls = lastMessage2.parts.filter(
|
|
207
223
|
(part) => isToolUIPart(part) && part.state === "input-available" && !processedToolCalls.current.has(part.toolCallId)
|
|
208
224
|
);
|
|
209
225
|
if (toolCalls.length > 0) {
|
|
@@ -233,7 +249,9 @@ function useAgentChat(options) {
|
|
|
233
249
|
});
|
|
234
250
|
}
|
|
235
251
|
}
|
|
236
|
-
|
|
252
|
+
if (pendingConfirmationsRef.current.toolCallIds.size === 0) {
|
|
253
|
+
useChatHelpers.sendMessage();
|
|
254
|
+
}
|
|
237
255
|
}
|
|
238
256
|
})();
|
|
239
257
|
}
|
|
@@ -276,10 +294,25 @@ function useAgentChat(options) {
|
|
|
276
294
|
agent.removeEventListener("message", onMessages);
|
|
277
295
|
};
|
|
278
296
|
}, [agent, useChatHelpers.setMessages]);
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
await addToolResult(
|
|
282
|
-
|
|
297
|
+
const addToolResultAndSendMessage = async (args) => {
|
|
298
|
+
const { toolCallId } = args;
|
|
299
|
+
await useChatHelpers.addToolResult(args);
|
|
300
|
+
if (!autoSendAfterAllConfirmationsResolved) {
|
|
301
|
+
useChatHelpers.sendMessage();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const pending = pendingConfirmationsRef.current?.toolCallIds;
|
|
305
|
+
if (!pending) {
|
|
306
|
+
useChatHelpers.sendMessage();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const wasLast = pending.size === 1 && pending.has(toolCallId);
|
|
310
|
+
if (pending.has(toolCallId)) {
|
|
311
|
+
pending.delete(toolCallId);
|
|
312
|
+
}
|
|
313
|
+
if (wasLast || pending.size === 0) {
|
|
314
|
+
useChatHelpers.sendMessage();
|
|
315
|
+
}
|
|
283
316
|
};
|
|
284
317
|
return {
|
|
285
318
|
...useChatHelpers,
|
package/dist/ai-react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat, type UseChatOptions } from \"@ai-sdk/react\";\nimport { getToolName, isToolUIPart } from \"ai\";\nimport type {\n ChatInit,\n ChatTransport,\n UIMessage as Message,\n UIMessage\n} from \"ai\";\nimport { DefaultChatTransport } from \"ai\";\nimport { nanoid } from \"nanoid\";\nimport { use, useEffect, useRef } from \"react\";\nimport type { OutgoingMessage } from \"./ai-types\";\nimport { MessageType } from \"./ai-types\";\nimport type { useAgent } from \"./react\";\n\nexport type AITool<Input = unknown, Output = unknown> = {\n description?: string;\n inputSchema?: unknown;\n execute?: (input: Input) => Output | Promise<Output>;\n};\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n// v5 useChat parameters\ntype UseChatParams<M extends UIMessage = UIMessage> = ChatInit<M> &\n UseChatOptions<M>;\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<\n State,\n ChatMessage extends UIMessage = UIMessage\n> = Omit<UseChatParams<ChatMessage>, \"fetch\"> & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n | ((options: GetInitialMessagesOptions) => Promise<ChatMessage[]>);\n /** Request credentials */\n credentials?: RequestCredentials;\n /** Request headers */\n headers?: HeadersInit;\n /**\n * @description Whether to automatically resolve tool calls that do not require human interaction.\n * @experimental\n */\n experimental_automaticToolResolution?: boolean;\n /**\n * @description Tools object for automatic detection of confirmation requirements.\n * Tools without execute function will require confirmation.\n */\n tools?: Record<string, AITool<unknown, unknown>>;\n /**\n * @description Manual override for tools requiring confirmation.\n * If not provided, will auto-detect from tools object.\n */\n toolsRequiringConfirmation?: string[];\n};\n\nconst requestCache = new Map<string, Promise<Message[]>>();\n\n/**\n * React hook for building AI chat interfaces using an Agent\n * @param options Chat options including the agent connection\n * @returns Chat interface controls and state with added clearHistory method\n */\n/**\n * Automatically detects which tools require confirmation based on their configuration.\n * Tools require confirmation if they have no execute function AND are not server-executed.\n * @param tools - Record of tool name to tool definition\n * @returns Array of tool names that require confirmation\n */\nexport function detectToolsRequiringConfirmation(\n tools?: Record<string, AITool<unknown, unknown>>\n): string[] {\n if (!tools) return [];\n\n return Object.entries(tools)\n .filter(([_name, tool]) => !tool.execute)\n .map(([name]) => name);\n}\n\nexport function useAgentChat<\n State = unknown,\n ChatMessage extends UIMessage = UIMessage\n>(\n options: UseAgentChatOptions<State, ChatMessage>\n): ReturnType<typeof useChat<ChatMessage>> & {\n clearHistory: () => void;\n} {\n const {\n agent,\n getInitialMessages,\n messages: optionsInitialMessages,\n experimental_automaticToolResolution,\n tools,\n toolsRequiringConfirmation: manualToolsRequiringConfirmation,\n ...rest\n } = options;\n\n // Auto-detect tools requiring confirmation, or use manual override\n const toolsRequiringConfirmation =\n manualToolsRequiringConfirmation ?? detectToolsRequiringConfirmation(tools);\n\n const agentUrl = new URL(\n `${// @ts-expect-error we're using a protected _url property that includes query params\n ((agent._url as string | null) || agent._pkurl)\n ?.replace(\"ws://\", \"http://\")\n .replace(\"wss://\", \"https://\")}`\n );\n\n agentUrl.searchParams.delete(\"_pk\");\n const agentUrlString = agentUrl.toString();\n\n async function defaultGetInitialMessagesFetch({\n url\n }: GetInitialMessagesOptions) {\n const getMessagesUrl = new URL(url);\n getMessagesUrl.pathname += \"/get-messages\";\n const response = await fetch(getMessagesUrl.toString(), {\n credentials: options.credentials,\n headers: options.headers\n });\n\n if (!response.ok) {\n console.warn(\n `Failed to fetch initial messages: ${response.status} ${response.statusText}`\n );\n return [];\n }\n\n const text = await response.text();\n if (!text.trim()) {\n return [];\n }\n\n try {\n return JSON.parse(text) as ChatMessage[];\n } catch (error) {\n console.warn(\"Failed to parse initial messages JSON:\", error);\n return [];\n }\n }\n\n const getInitialMessagesFetch =\n getInitialMessages || defaultGetInitialMessagesFetch;\n\n function doGetInitialMessages(\n getInitialMessagesOptions: GetInitialMessagesOptions\n ) {\n if (requestCache.has(agentUrlString)) {\n return requestCache.get(agentUrlString)! as Promise<ChatMessage[]>;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n requestCache.set(agentUrlString, promise);\n return promise;\n }\n\n const initialMessagesPromise =\n getInitialMessages === null\n ? null\n : doGetInitialMessages({\n agent: agent.agent,\n name: agent.name,\n url: agentUrlString\n });\n const initialMessages = initialMessagesPromise\n ? use(initialMessagesPromise)\n : (optionsInitialMessages ?? []);\n\n useEffect(() => {\n if (!initialMessagesPromise) {\n return;\n }\n requestCache.set(agentUrlString, initialMessagesPromise!);\n return () => {\n if (requestCache.get(agentUrlString) === initialMessagesPromise) {\n requestCache.delete(agentUrlString);\n }\n };\n }, [agentUrlString, initialMessagesPromise]);\n\n async function aiFetch(\n request: RequestInfo | URL,\n options: RequestInit = {}\n ) {\n const {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n signal,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window\n } = options;\n const id = nanoid(8);\n const abortController = new AbortController();\n let controller: ReadableStreamDefaultController;\n let isToolCallInProgress = false;\n\n signal?.addEventListener(\"abort\", () => {\n agent.send(\n JSON.stringify({\n id,\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL\n })\n );\n\n // NOTE - If we wanted to, we could preserve the \"interrupted\" message here, with the code below\n // However, I think it might be the responsibility of the library user to implement that behavior manually?\n // Reasoning: This code could be subject to collisions, as it \"force saves\" the messages we have locally\n //\n // agent.send(JSON.stringify({\n // type: MessageType.CF_AGENT_CHAT_MESSAGES,\n // messages: ... /* some way of getting current messages ref? */\n // }))\n\n abortController.abort();\n // Make sure to also close the stream (cf. https://github.com/cloudflare/agents-starter/issues/69)\n if (!isToolCallInProgress) {\n controller.close();\n }\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage<ChatMessage>;\n try {\n data = JSON.parse(event.data) as OutgoingMessage<ChatMessage>;\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === MessageType.CF_AGENT_USE_CHAT_RESPONSE) {\n if (data.id === id) {\n if (data.error) {\n controller.error(new Error(data.body));\n abortController.abort();\n } else {\n // Only enqueue non-empty data to prevent JSON parsing errors\n if (data.body?.trim()) {\n if (data.body.includes('\"tool_calls\"')) {\n isToolCallInProgress = true;\n }\n controller.enqueue(\n new TextEncoder().encode(`data: ${data.body}\\n\\n`)\n );\n }\n if (data.done && !isToolCallInProgress) {\n controller.close();\n abortController.abort();\n }\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n const stream = new ReadableStream({\n start(c) {\n controller = c;\n }\n });\n\n agent.send(\n JSON.stringify({\n id,\n init: {\n body,\n credentials,\n headers,\n integrity,\n keepalive,\n method,\n mode,\n redirect,\n referrer,\n referrerPolicy,\n window\n },\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST,\n url: request.toString()\n })\n );\n\n return new Response(stream);\n }\n\n const customTransport: ChatTransport<ChatMessage> = {\n sendMessages: async (\n options: Parameters<typeof DefaultChatTransport.prototype.sendMessages>[0]\n ) => {\n const transport = new DefaultChatTransport<ChatMessage>({\n api: agentUrlString,\n fetch: aiFetch\n });\n return transport.sendMessages(options);\n },\n reconnectToStream: async (\n options: Parameters<\n typeof DefaultChatTransport.prototype.reconnectToStream\n >[0]\n ) => {\n const transport = new DefaultChatTransport<ChatMessage>({\n api: agentUrlString,\n fetch: aiFetch\n });\n return transport.reconnectToStream(options);\n }\n };\n\n const useChatHelpers = useChat<ChatMessage>({\n ...rest,\n messages: initialMessages,\n transport: customTransport\n });\n\n const processedToolCalls = useRef(new Set<string>());\n\n // tools can be a different object everytime it's called,\n // which might lead to this effect being called multiple times with different tools objects.\n // we need to fix this, but that's a bigger refactor.\n // biome-ignore lint/correctness/useExhaustiveDependencies: we need to fix this\n useEffect(() => {\n if (!experimental_automaticToolResolution) {\n return;\n }\n\n const lastMessage =\n useChatHelpers.messages[useChatHelpers.messages.length - 1];\n if (!lastMessage || lastMessage.role !== \"assistant\") {\n return;\n }\n\n const toolCalls = lastMessage.parts.filter(\n (part) =>\n isToolUIPart(part) &&\n part.state === \"input-available\" &&\n !processedToolCalls.current.has(part.toolCallId)\n );\n\n if (toolCalls.length > 0) {\n (async () => {\n const toolCallsToResolve = toolCalls.filter(\n (part) =>\n isToolUIPart(part) &&\n !toolsRequiringConfirmation.includes(getToolName(part)) &&\n tools?.[getToolName(part)]?.execute // Only execute if client has execute function\n );\n\n if (toolCallsToResolve.length > 0) {\n for (const part of toolCallsToResolve) {\n if (isToolUIPart(part)) {\n processedToolCalls.current.add(part.toolCallId);\n let toolOutput = null;\n const toolName = getToolName(part);\n const tool = tools?.[toolName];\n\n if (tool?.execute && part.input) {\n try {\n toolOutput = await tool.execute(part.input);\n } catch (error) {\n toolOutput = `Error executing tool: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n await useChatHelpers.addToolResult({\n toolCallId: part.toolCallId,\n tool: toolName,\n output: toolOutput\n });\n }\n }\n useChatHelpers.sendMessage();\n }\n })();\n }\n }, [\n useChatHelpers.messages,\n experimental_automaticToolResolution,\n useChatHelpers.addToolResult,\n useChatHelpers.sendMessage,\n toolsRequiringConfirmation\n ]);\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") return;\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (_error) {\n return;\n }\n if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") return;\n let data: OutgoingMessage<ChatMessage>;\n try {\n data = JSON.parse(event.data) as OutgoingMessage<ChatMessage>;\n } catch (_error) {\n return;\n }\n if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) {\n useChatHelpers.setMessages(data.messages);\n }\n }\n\n agent.addEventListener(\"message\", onClearHistory);\n agent.addEventListener(\"message\", onMessages);\n\n return () => {\n agent.removeEventListener(\"message\", onClearHistory);\n agent.removeEventListener(\"message\", onMessages);\n };\n }, [agent, useChatHelpers.setMessages]);\n\n const { addToolResult } = useChatHelpers;\n\n const addToolResultAndSendMessage: typeof addToolResult = async (...args) => {\n await addToolResult(...args);\n useChatHelpers.sendMessage();\n };\n\n return {\n ...useChatHelpers,\n addToolResult: addToolResultAndSendMessage,\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_CHAT_CLEAR\n })\n );\n },\n setMessages: (\n messages: Parameters<typeof useChatHelpers.setMessages>[0]\n ) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n messages: Array.isArray(messages) ? messages : [],\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n })\n );\n }\n };\n}\n"],"mappings":"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","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat, type UseChatOptions } from \"@ai-sdk/react\";\nimport { getToolName, isToolUIPart } from \"ai\";\nimport type {\n ChatInit,\n ChatTransport,\n UIMessage as Message,\n UIMessage\n} from \"ai\";\nimport { DefaultChatTransport } from \"ai\";\nimport { nanoid } from \"nanoid\";\nimport { use, useEffect, useRef } from \"react\";\nimport type { OutgoingMessage } from \"./ai-types\";\nimport { MessageType } from \"./ai-types\";\nimport type { useAgent } from \"./react\";\n\nexport type AITool<Input = unknown, Output = unknown> = {\n description?: string;\n inputSchema?: unknown;\n execute?: (input: Input) => Output | Promise<Output>;\n};\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n// v5 useChat parameters\ntype UseChatParams<M extends UIMessage = UIMessage> = ChatInit<M> &\n UseChatOptions<M>;\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<\n State,\n ChatMessage extends UIMessage = UIMessage\n> = Omit<UseChatParams<ChatMessage>, \"fetch\"> & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n | ((options: GetInitialMessagesOptions) => Promise<ChatMessage[]>);\n /** Request credentials */\n credentials?: RequestCredentials;\n /** Request headers */\n headers?: HeadersInit;\n /**\n * @description Whether to automatically resolve tool calls that do not require human interaction.\n * @experimental\n */\n experimental_automaticToolResolution?: boolean;\n /**\n * @description Tools object for automatic detection of confirmation requirements.\n * Tools without execute function will require confirmation.\n */\n tools?: Record<string, AITool<unknown, unknown>>;\n /**\n * @description Manual override for tools requiring confirmation.\n * If not provided, will auto-detect from tools object.\n */\n toolsRequiringConfirmation?: string[];\n /**\n * When true (default), automatically sends the next message only after\n * all pending confirmation-required tool calls have been resolved.\n * @default true\n */\n autoSendAfterAllConfirmationsResolved?: boolean;\n};\n\nconst requestCache = new Map<string, Promise<Message[]>>();\n\n/**\n * React hook for building AI chat interfaces using an Agent\n * @param options Chat options including the agent connection\n * @returns Chat interface controls and state with added clearHistory method\n */\n/**\n * Automatically detects which tools require confirmation based on their configuration.\n * Tools require confirmation if they have no execute function AND are not server-executed.\n * @param tools - Record of tool name to tool definition\n * @returns Array of tool names that require confirmation\n */\nexport function detectToolsRequiringConfirmation(\n tools?: Record<string, AITool<unknown, unknown>>\n): string[] {\n if (!tools) return [];\n\n return Object.entries(tools)\n .filter(([_name, tool]) => !tool.execute)\n .map(([name]) => name);\n}\n\nexport function useAgentChat<\n State = unknown,\n ChatMessage extends UIMessage = UIMessage\n>(\n options: UseAgentChatOptions<State, ChatMessage>\n): ReturnType<typeof useChat<ChatMessage>> & {\n clearHistory: () => void;\n} {\n const {\n agent,\n getInitialMessages,\n messages: optionsInitialMessages,\n experimental_automaticToolResolution,\n tools,\n toolsRequiringConfirmation: manualToolsRequiringConfirmation,\n autoSendAfterAllConfirmationsResolved = true,\n ...rest\n } = options;\n\n // Auto-detect tools requiring confirmation, or use manual override\n const toolsRequiringConfirmation =\n manualToolsRequiringConfirmation ?? detectToolsRequiringConfirmation(tools);\n\n const agentUrl = new URL(\n `${// @ts-expect-error we're using a protected _url property that includes query params\n ((agent._url as string | null) || agent._pkurl)\n ?.replace(\"ws://\", \"http://\")\n .replace(\"wss://\", \"https://\")}`\n );\n\n agentUrl.searchParams.delete(\"_pk\");\n const agentUrlString = agentUrl.toString();\n\n async function defaultGetInitialMessagesFetch({\n url\n }: GetInitialMessagesOptions) {\n const getMessagesUrl = new URL(url);\n getMessagesUrl.pathname += \"/get-messages\";\n const response = await fetch(getMessagesUrl.toString(), {\n credentials: options.credentials,\n headers: options.headers\n });\n\n if (!response.ok) {\n console.warn(\n `Failed to fetch initial messages: ${response.status} ${response.statusText}`\n );\n return [];\n }\n\n const text = await response.text();\n if (!text.trim()) {\n return [];\n }\n\n try {\n return JSON.parse(text) as ChatMessage[];\n } catch (error) {\n console.warn(\"Failed to parse initial messages JSON:\", error);\n return [];\n }\n }\n\n const getInitialMessagesFetch =\n getInitialMessages || defaultGetInitialMessagesFetch;\n\n function doGetInitialMessages(\n getInitialMessagesOptions: GetInitialMessagesOptions\n ) {\n if (requestCache.has(agentUrlString)) {\n return requestCache.get(agentUrlString)! as Promise<ChatMessage[]>;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n requestCache.set(agentUrlString, promise);\n return promise;\n }\n\n const initialMessagesPromise =\n getInitialMessages === null\n ? null\n : doGetInitialMessages({\n agent: agent.agent,\n name: agent.name,\n url: agentUrlString\n });\n const initialMessages = initialMessagesPromise\n ? use(initialMessagesPromise)\n : (optionsInitialMessages ?? []);\n\n useEffect(() => {\n if (!initialMessagesPromise) {\n return;\n }\n requestCache.set(agentUrlString, initialMessagesPromise!);\n return () => {\n if (requestCache.get(agentUrlString) === initialMessagesPromise) {\n requestCache.delete(agentUrlString);\n }\n };\n }, [agentUrlString, initialMessagesPromise]);\n\n async function aiFetch(\n request: RequestInfo | URL,\n options: RequestInit = {}\n ) {\n const {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n signal,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window\n } = options;\n const id = nanoid(8);\n const abortController = new AbortController();\n let controller: ReadableStreamDefaultController;\n let isToolCallInProgress = false;\n\n signal?.addEventListener(\"abort\", () => {\n agent.send(\n JSON.stringify({\n id,\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL\n })\n );\n\n // NOTE - If we wanted to, we could preserve the \"interrupted\" message here, with the code below\n // However, I think it might be the responsibility of the library user to implement that behavior manually?\n // Reasoning: This code could be subject to collisions, as it \"force saves\" the messages we have locally\n //\n // agent.send(JSON.stringify({\n // type: MessageType.CF_AGENT_CHAT_MESSAGES,\n // messages: ... /* some way of getting current messages ref? */\n // }))\n\n abortController.abort();\n // Make sure to also close the stream (cf. https://github.com/cloudflare/agents-starter/issues/69)\n if (!isToolCallInProgress) {\n controller.close();\n }\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage<ChatMessage>;\n try {\n data = JSON.parse(event.data) as OutgoingMessage<ChatMessage>;\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === MessageType.CF_AGENT_USE_CHAT_RESPONSE) {\n if (data.id === id) {\n if (data.error) {\n controller.error(new Error(data.body));\n abortController.abort();\n } else {\n // Only enqueue non-empty data to prevent JSON parsing errors\n if (data.body?.trim()) {\n if (data.body.includes('\"tool_calls\"')) {\n isToolCallInProgress = true;\n }\n controller.enqueue(\n new TextEncoder().encode(`data: ${data.body}\\n\\n`)\n );\n }\n if (data.done && !isToolCallInProgress) {\n controller.close();\n abortController.abort();\n }\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n const stream = new ReadableStream({\n start(c) {\n controller = c;\n }\n });\n\n agent.send(\n JSON.stringify({\n id,\n init: {\n body,\n credentials,\n headers,\n integrity,\n keepalive,\n method,\n mode,\n redirect,\n referrer,\n referrerPolicy,\n window\n },\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST,\n url: request.toString()\n })\n );\n\n return new Response(stream);\n }\n\n const customTransport: ChatTransport<ChatMessage> = {\n sendMessages: async (\n options: Parameters<typeof DefaultChatTransport.prototype.sendMessages>[0]\n ) => {\n const transport = new DefaultChatTransport<ChatMessage>({\n api: agentUrlString,\n fetch: aiFetch\n });\n return transport.sendMessages(options);\n },\n reconnectToStream: async (\n options: Parameters<\n typeof DefaultChatTransport.prototype.reconnectToStream\n >[0]\n ) => {\n const transport = new DefaultChatTransport<ChatMessage>({\n api: agentUrlString,\n fetch: aiFetch\n });\n return transport.reconnectToStream(options);\n }\n };\n\n const useChatHelpers = useChat<ChatMessage>({\n ...rest,\n messages: initialMessages,\n transport: customTransport\n });\n\n const processedToolCalls = useRef(new Set<string>());\n\n // Calculate pending confirmations for the latest assistant message\n const lastMessage =\n useChatHelpers.messages[useChatHelpers.messages.length - 1];\n\n const pendingConfirmations = (() => {\n if (!lastMessage || lastMessage.role !== \"assistant\") {\n return { messageId: undefined, toolCallIds: new Set<string>() };\n }\n\n const pendingIds = new Set<string>();\n for (const part of lastMessage.parts ?? []) {\n if (\n isToolUIPart(part) &&\n part.state === \"input-available\" &&\n toolsRequiringConfirmation.includes(getToolName(part))\n ) {\n pendingIds.add(part.toolCallId);\n }\n }\n return { messageId: lastMessage.id, toolCallIds: pendingIds };\n })();\n\n const pendingConfirmationsRef = useRef(pendingConfirmations);\n pendingConfirmationsRef.current = pendingConfirmations;\n\n // tools can be a different object everytime it's called,\n // which might lead to this effect being called multiple times with different tools objects.\n // we need to fix this, but that's a bigger refactor.\n // biome-ignore lint/correctness/useExhaustiveDependencies: we need to fix this\n useEffect(() => {\n if (!experimental_automaticToolResolution) {\n return;\n }\n\n const lastMessage =\n useChatHelpers.messages[useChatHelpers.messages.length - 1];\n if (!lastMessage || lastMessage.role !== \"assistant\") {\n return;\n }\n\n const toolCalls = lastMessage.parts.filter(\n (part) =>\n isToolUIPart(part) &&\n part.state === \"input-available\" &&\n !processedToolCalls.current.has(part.toolCallId)\n );\n\n if (toolCalls.length > 0) {\n (async () => {\n const toolCallsToResolve = toolCalls.filter(\n (part) =>\n isToolUIPart(part) &&\n !toolsRequiringConfirmation.includes(getToolName(part)) &&\n tools?.[getToolName(part)]?.execute // Only execute if client has execute function\n );\n\n if (toolCallsToResolve.length > 0) {\n for (const part of toolCallsToResolve) {\n if (isToolUIPart(part)) {\n processedToolCalls.current.add(part.toolCallId);\n let toolOutput = null;\n const toolName = getToolName(part);\n const tool = tools?.[toolName];\n\n if (tool?.execute && part.input) {\n try {\n toolOutput = await tool.execute(part.input);\n } catch (error) {\n toolOutput = `Error executing tool: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n await useChatHelpers.addToolResult({\n toolCallId: part.toolCallId,\n tool: toolName,\n output: toolOutput\n });\n }\n }\n // If there are NO pending confirmations for the latest assistant message,\n // we can continue the conversation. Otherwise, wait for the UI to resolve\n // those confirmations; the addToolResult wrapper will send when the last\n // pending confirmation is resolved.\n if (pendingConfirmationsRef.current.toolCallIds.size === 0) {\n useChatHelpers.sendMessage();\n }\n }\n })();\n }\n }, [\n useChatHelpers.messages,\n experimental_automaticToolResolution,\n useChatHelpers.addToolResult,\n useChatHelpers.sendMessage,\n toolsRequiringConfirmation\n ]);\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") return;\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (_error) {\n return;\n }\n if (data.type === MessageType.CF_AGENT_CHAT_CLEAR) {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") return;\n let data: OutgoingMessage<ChatMessage>;\n try {\n data = JSON.parse(event.data) as OutgoingMessage<ChatMessage>;\n } catch (_error) {\n return;\n }\n if (data.type === MessageType.CF_AGENT_CHAT_MESSAGES) {\n useChatHelpers.setMessages(data.messages);\n }\n }\n\n agent.addEventListener(\"message\", onClearHistory);\n agent.addEventListener(\"message\", onMessages);\n\n return () => {\n agent.removeEventListener(\"message\", onClearHistory);\n agent.removeEventListener(\"message\", onMessages);\n };\n }, [agent, useChatHelpers.setMessages]);\n\n // Wrapper that sends only when the last pending confirmation is resolved\n const addToolResultAndSendMessage: typeof useChatHelpers.addToolResult =\n async (args) => {\n const { toolCallId } = args;\n\n await useChatHelpers.addToolResult(args);\n\n if (!autoSendAfterAllConfirmationsResolved) {\n // always send immediately\n useChatHelpers.sendMessage();\n return;\n }\n\n // wait for all confirmations\n const pending = pendingConfirmationsRef.current?.toolCallIds;\n if (!pending) {\n useChatHelpers.sendMessage();\n return;\n }\n\n const wasLast = pending.size === 1 && pending.has(toolCallId);\n if (pending.has(toolCallId)) {\n pending.delete(toolCallId);\n }\n\n if (wasLast || pending.size === 0) {\n useChatHelpers.sendMessage();\n }\n };\n\n return {\n ...useChatHelpers,\n addToolResult: addToolResultAndSendMessage,\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_CHAT_CLEAR\n })\n );\n },\n setMessages: (\n messages: Parameters<typeof useChatHelpers.setMessages>[0]\n ) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n messages: Array.isArray(messages) ? messages : [],\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n })\n );\n }\n };\n}\n"],"mappings":"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","names":["options","lastMessage"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/client.ts","../src/mcp/client-connection.ts","../src/mcp/sse-edge.ts","../src/mcp/streamable-http-edge.ts"],"sourcesContent":["import type { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport type {\n CallToolRequest,\n CallToolResultSchema,\n CompatibilityCallToolResultSchema,\n GetPromptRequest,\n Prompt,\n ReadResourceRequest,\n Resource,\n ResourceTemplate,\n Tool\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { type ToolSet, jsonSchema } from \"ai\";\nimport { nanoid } from \"nanoid\";\nimport {\n MCPClientConnection,\n type MCPTransportOptions\n} from \"./client-connection\";\n\n/**\n * Utility class that aggregates multiple MCP clients into one\n */\nexport class MCPClientManager {\n public mcpConnections: Record<string, MCPClientConnection> = {};\n private _callbackUrls: string[] = [];\n private _didWarnAboutUnstableGetAITools = false;\n /**\n * @param _name Name of the MCP client\n * @param _version Version of the MCP Client\n * @param auth Auth paramters if being used to create a DurableObjectOAuthClientProvider\n */\n constructor(\n private _name: string,\n private _version: string\n ) {}\n\n /**\n * Connect to and register an MCP server\n *\n * @param transportConfig Transport config\n * @param clientConfig Client config\n * @param capabilities Client capabilities (i.e. if the client supports roots/sampling)\n */\n async connect(\n url: string,\n options: {\n // Allows you to reconnect to a server (in the case of an auth reconnect)\n reconnect?: {\n // server id\n id: string;\n oauthClientId?: string;\n oauthCode?: string;\n };\n // we're overriding authProvider here because we want to be able to access the auth URL\n transport?: MCPTransportOptions;\n client?: ConstructorParameters<typeof Client>[1];\n } = {}\n ): Promise<{\n id: string;\n authUrl?: string;\n clientId?: string;\n }> {\n const id = options.reconnect?.id ?? nanoid(8);\n\n if (!options.transport?.authProvider) {\n console.warn(\n \"No authProvider provided in the transport options. This client will only support unauthenticated remote MCP Servers\"\n );\n } else {\n options.transport.authProvider.serverId = id;\n // reconnect with auth\n if (options.reconnect?.oauthClientId) {\n options.transport.authProvider.clientId =\n options.reconnect?.oauthClientId;\n }\n }\n\n this.mcpConnections[id] = new MCPClientConnection(\n new URL(url),\n {\n name: this._name,\n version: this._version\n },\n {\n client: options.client ?? {},\n transport: options.transport ?? {}\n }\n );\n\n await this.mcpConnections[id].init(options.reconnect?.oauthCode);\n\n const authUrl = options.transport?.authProvider?.authUrl;\n if (authUrl && options.transport?.authProvider?.redirectUrl) {\n this._callbackUrls.push(\n options.transport.authProvider.redirectUrl.toString()\n );\n return {\n authUrl,\n clientId: options.transport?.authProvider?.clientId,\n id\n };\n }\n\n return {\n id\n };\n }\n\n isCallbackRequest(req: Request): boolean {\n return (\n req.method === \"GET\" &&\n !!this._callbackUrls.find((url) => {\n return req.url.startsWith(url);\n })\n );\n }\n\n async handleCallbackRequest(req: Request) {\n const url = new URL(req.url);\n const urlMatch = this._callbackUrls.find((url) => {\n return req.url.startsWith(url);\n });\n if (!urlMatch) {\n throw new Error(\n `No callback URI match found for the request url: ${req.url}. Was the request matched with \\`isCallbackRequest()\\`?`\n );\n }\n const code = url.searchParams.get(\"code\");\n const clientId = url.searchParams.get(\"state\");\n const urlParams = urlMatch.split(\"/\");\n const serverId = urlParams[urlParams.length - 1];\n if (!code) {\n throw new Error(\"Unauthorized: no code provided\");\n }\n if (!clientId) {\n throw new Error(\"Unauthorized: no state provided\");\n }\n\n if (this.mcpConnections[serverId] === undefined) {\n throw new Error(`Could not find serverId: ${serverId}`);\n }\n\n if (this.mcpConnections[serverId].connectionState !== \"authenticating\") {\n throw new Error(\n \"Failed to authenticate: the client isn't in the `authenticating` state\"\n );\n }\n\n const conn = this.mcpConnections[serverId];\n if (!conn.options.transport.authProvider) {\n throw new Error(\n \"Trying to finalize authentication for a server connection without an authProvider\"\n );\n }\n\n conn.options.transport.authProvider.clientId = clientId;\n conn.options.transport.authProvider.serverId = serverId;\n\n // reconnect to server with authorization\n const serverUrl = conn.url.toString();\n await this.connect(serverUrl, {\n reconnect: {\n id: serverId,\n oauthClientId: clientId,\n oauthCode: code\n },\n ...conn.options\n });\n\n if (this.mcpConnections[serverId].connectionState === \"authenticating\") {\n throw new Error(\"Failed to authenticate: client failed to initialize\");\n }\n\n return { serverId };\n }\n\n /**\n * @returns namespaced list of tools\n */\n listTools(): NamespacedData[\"tools\"] {\n return getNamespacedData(this.mcpConnections, \"tools\");\n }\n\n /**\n * @returns a set of tools that you can use with the AI SDK\n */\n getAITools(): ToolSet {\n return Object.fromEntries(\n getNamespacedData(this.mcpConnections, \"tools\").map((tool) => {\n return [\n `tool_${tool.serverId}_${tool.name}`,\n {\n description: tool.description,\n execute: async (args) => {\n const result = await this.callTool({\n arguments: args,\n name: tool.name,\n serverId: tool.serverId\n });\n if (result.isError) {\n // @ts-expect-error TODO we should fix this\n throw new Error(result.content[0].text);\n }\n return result;\n },\n inputSchema: jsonSchema(tool.inputSchema)\n }\n ];\n })\n );\n }\n\n /**\n * @deprecated this has been renamed to getAITools(), and unstable_getAITools will be removed in the next major version\n * @returns a set of tools that you can use with the AI SDK\n */\n unstable_getAITools(): ToolSet {\n if (!this._didWarnAboutUnstableGetAITools) {\n this._didWarnAboutUnstableGetAITools = true;\n console.warn(\n \"unstable_getAITools is deprecated, use getAITools instead. unstable_getAITools will be removed in the next major version.\"\n );\n }\n return this.getAITools();\n }\n\n /**\n * Closes all connections to MCP servers\n */\n async closeAllConnections() {\n return Promise.all(\n Object.values(this.mcpConnections).map(async (connection) => {\n await connection.client.close();\n })\n );\n }\n\n /**\n * Closes a connection to an MCP server\n * @param id The id of the connection to close\n */\n async closeConnection(id: string) {\n if (!this.mcpConnections[id]) {\n throw new Error(`Connection with id \"${id}\" does not exist.`);\n }\n await this.mcpConnections[id].client.close();\n delete this.mcpConnections[id];\n }\n\n /**\n * @returns namespaced list of prompts\n */\n listPrompts(): NamespacedData[\"prompts\"] {\n return getNamespacedData(this.mcpConnections, \"prompts\");\n }\n\n /**\n * @returns namespaced list of tools\n */\n listResources(): NamespacedData[\"resources\"] {\n return getNamespacedData(this.mcpConnections, \"resources\");\n }\n\n /**\n * @returns namespaced list of resource templates\n */\n listResourceTemplates(): NamespacedData[\"resourceTemplates\"] {\n return getNamespacedData(this.mcpConnections, \"resourceTemplates\");\n }\n\n /**\n * Namespaced version of callTool\n */\n callTool(\n params: CallToolRequest[\"params\"] & { serverId: string },\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ) {\n const unqualifiedName = params.name.replace(`${params.serverId}.`, \"\");\n return this.mcpConnections[params.serverId].client.callTool(\n {\n ...params,\n name: unqualifiedName\n },\n resultSchema,\n options\n );\n }\n\n /**\n * Namespaced version of readResource\n */\n readResource(\n params: ReadResourceRequest[\"params\"] & { serverId: string },\n options: RequestOptions\n ) {\n return this.mcpConnections[params.serverId].client.readResource(\n params,\n options\n );\n }\n\n /**\n * Namespaced version of getPrompt\n */\n getPrompt(\n params: GetPromptRequest[\"params\"] & { serverId: string },\n options: RequestOptions\n ) {\n return this.mcpConnections[params.serverId].client.getPrompt(\n params,\n options\n );\n }\n}\n\ntype NamespacedData = {\n tools: (Tool & { serverId: string })[];\n prompts: (Prompt & { serverId: string })[];\n resources: (Resource & { serverId: string })[];\n resourceTemplates: (ResourceTemplate & { serverId: string })[];\n};\n\nexport function getNamespacedData<T extends keyof NamespacedData>(\n mcpClients: Record<string, MCPClientConnection>,\n type: T\n): NamespacedData[T] {\n const sets = Object.entries(mcpClients).map(([name, conn]) => {\n return { data: conn[type], name };\n });\n\n const namespacedData = sets.flatMap(({ name: serverId, data }) => {\n return data.map((item) => {\n return {\n ...item,\n // we add a serverId so we can easily pull it out and send the tool call to the right server\n serverId\n };\n });\n });\n\n return namespacedData as NamespacedData[T]; // Type assertion needed due to TS limitations with conditional return types\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StreamableHTTPClientTransportOptions } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport {\n type ClientCapabilities,\n type ListPromptsResult,\n type ListResourceTemplatesResult,\n type ListResourcesResult,\n type ListToolsResult,\n PromptListChangedNotificationSchema,\n ResourceListChangedNotificationSchema,\n type ResourceTemplate,\n type ServerCapabilities,\n ToolListChangedNotificationSchema,\n ElicitRequestSchema,\n type ElicitRequest,\n type ElicitResult\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { AgentsOAuthProvider } from \"./do-oauth-client-provider\";\nimport { SSEEdgeClientTransport } from \"./sse-edge\";\nimport { StreamableHTTPEdgeClientTransport } from \"./streamable-http-edge\";\n// Import types directly from MCP SDK\nimport type {\n Tool,\n Resource,\n Prompt\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nexport type MCPTransportOptions = (\n | SSEClientTransportOptions\n | StreamableHTTPClientTransportOptions\n) & {\n authProvider?: AgentsOAuthProvider;\n type?: \"sse\" | \"streamable-http\" | \"auto\";\n};\n\ntype TransportType = Exclude<MCPTransportOptions[\"type\"], \"auto\">;\n\nexport class MCPClientConnection {\n client: Client;\n connectionState:\n | \"authenticating\"\n | \"connecting\"\n | \"ready\"\n | \"discovering\"\n | \"failed\" = \"connecting\";\n instructions?: string;\n tools: Tool[] = [];\n prompts: Prompt[] = [];\n resources: Resource[] = [];\n resourceTemplates: ResourceTemplate[] = [];\n serverCapabilities: ServerCapabilities | undefined;\n\n constructor(\n public url: URL,\n info: ConstructorParameters<typeof Client>[0],\n public options: {\n transport: MCPTransportOptions;\n client: ConstructorParameters<typeof Client>[1];\n } = { client: {}, transport: {} }\n ) {\n const clientOptions = {\n ...options.client,\n capabilities: {\n ...options.client?.capabilities,\n elicitation: {}\n } as ClientCapabilities\n };\n\n this.client = new Client(info, clientOptions);\n }\n\n /**\n * Initialize a client connection\n *\n * @param code Optional OAuth code to initialize the connection with if auth hasn't been initialized\n * @returns\n */\n async init(code?: string) {\n try {\n const transportType = this.options.transport.type || \"streamable-http\";\n await this.tryConnect(transportType, code);\n // biome-ignore lint/suspicious/noExplicitAny: allow for the error check here\n } catch (e: any) {\n if (e.toString().includes(\"Unauthorized\")) {\n // unauthorized, we should wait for the user to authenticate\n this.connectionState = \"authenticating\";\n return;\n }\n this.connectionState = \"failed\";\n throw e;\n }\n\n this.connectionState = \"discovering\";\n\n this.serverCapabilities = await this.client.getServerCapabilities();\n if (!this.serverCapabilities) {\n throw new Error(\"The MCP Server failed to return server capabilities\");\n }\n\n const [\n instructionsResult,\n toolsResult,\n resourcesResult,\n promptsResult,\n resourceTemplatesResult\n ] = await Promise.allSettled([\n this.client.getInstructions(),\n this.registerTools(),\n this.registerResources(),\n this.registerPrompts(),\n this.registerResourceTemplates()\n ]);\n\n const operations = [\n { name: \"instructions\", result: instructionsResult },\n { name: \"tools\", result: toolsResult },\n { name: \"resources\", result: resourcesResult },\n { name: \"prompts\", result: promptsResult },\n { name: \"resource templates\", result: resourceTemplatesResult }\n ];\n\n for (const { name, result } of operations) {\n if (result.status === \"rejected\") {\n console.error(`Failed to initialize ${name}:`, result.reason);\n }\n }\n\n this.instructions =\n instructionsResult.status === \"fulfilled\"\n ? instructionsResult.value\n : undefined;\n this.tools = toolsResult.status === \"fulfilled\" ? toolsResult.value : [];\n this.resources =\n resourcesResult.status === \"fulfilled\" ? resourcesResult.value : [];\n this.prompts =\n promptsResult.status === \"fulfilled\" ? promptsResult.value : [];\n this.resourceTemplates =\n resourceTemplatesResult.status === \"fulfilled\"\n ? resourceTemplatesResult.value\n : [];\n\n this.connectionState = \"ready\";\n }\n\n /**\n * Notification handler registration\n */\n async registerTools(): Promise<Tool[]> {\n if (!this.serverCapabilities || !this.serverCapabilities.tools) {\n return [];\n }\n\n if (this.serverCapabilities.tools.listChanged) {\n this.client.setNotificationHandler(\n ToolListChangedNotificationSchema,\n async (_notification) => {\n this.tools = await this.fetchTools();\n }\n );\n }\n\n return this.fetchTools();\n }\n\n async registerResources(): Promise<Resource[]> {\n if (!this.serverCapabilities || !this.serverCapabilities.resources) {\n return [];\n }\n\n if (this.serverCapabilities.resources.listChanged) {\n this.client.setNotificationHandler(\n ResourceListChangedNotificationSchema,\n async (_notification) => {\n this.resources = await this.fetchResources();\n }\n );\n }\n\n return this.fetchResources();\n }\n\n async registerPrompts(): Promise<Prompt[]> {\n if (!this.serverCapabilities || !this.serverCapabilities.prompts) {\n return [];\n }\n\n if (this.serverCapabilities.prompts.listChanged) {\n this.client.setNotificationHandler(\n PromptListChangedNotificationSchema,\n async (_notification) => {\n this.prompts = await this.fetchPrompts();\n }\n );\n }\n\n return this.fetchPrompts();\n }\n\n async registerResourceTemplates(): Promise<ResourceTemplate[]> {\n if (!this.serverCapabilities || !this.serverCapabilities.resources) {\n return [];\n }\n\n return this.fetchResourceTemplates();\n }\n\n async fetchTools() {\n let toolsAgg: Tool[] = [];\n let toolsResult: ListToolsResult = { tools: [] };\n do {\n toolsResult = await this.client\n .listTools({\n cursor: toolsResult.nextCursor\n })\n .catch(capabilityErrorHandler({ tools: [] }, \"tools/list\"));\n toolsAgg = toolsAgg.concat(toolsResult.tools);\n } while (toolsResult.nextCursor);\n return toolsAgg;\n }\n\n async fetchResources() {\n let resourcesAgg: Resource[] = [];\n let resourcesResult: ListResourcesResult = { resources: [] };\n do {\n resourcesResult = await this.client\n .listResources({\n cursor: resourcesResult.nextCursor\n })\n .catch(capabilityErrorHandler({ resources: [] }, \"resources/list\"));\n resourcesAgg = resourcesAgg.concat(resourcesResult.resources);\n } while (resourcesResult.nextCursor);\n return resourcesAgg;\n }\n\n async fetchPrompts() {\n let promptsAgg: Prompt[] = [];\n let promptsResult: ListPromptsResult = { prompts: [] };\n do {\n promptsResult = await this.client\n .listPrompts({\n cursor: promptsResult.nextCursor\n })\n .catch(capabilityErrorHandler({ prompts: [] }, \"prompts/list\"));\n promptsAgg = promptsAgg.concat(promptsResult.prompts);\n } while (promptsResult.nextCursor);\n return promptsAgg;\n }\n\n async fetchResourceTemplates() {\n let templatesAgg: ResourceTemplate[] = [];\n let templatesResult: ListResourceTemplatesResult = {\n resourceTemplates: []\n };\n do {\n templatesResult = await this.client\n .listResourceTemplates({\n cursor: templatesResult.nextCursor\n })\n .catch(\n capabilityErrorHandler(\n { resourceTemplates: [] },\n \"resources/templates/list\"\n )\n );\n templatesAgg = templatesAgg.concat(templatesResult.resourceTemplates);\n } while (templatesResult.nextCursor);\n return templatesAgg;\n }\n\n /**\n * Handle elicitation request from server\n * Automatically uses the Agent's built-in elicitation handling if available\n */\n async handleElicitationRequest(\n _request: ElicitRequest\n ): Promise<ElicitResult> {\n // Elicitation handling must be implemented by the platform\n // For MCP servers, this should be handled by McpAgent.elicitInput()\n throw new Error(\n \"Elicitation handler must be implemented for your platform. Override handleElicitationRequest method.\"\n );\n }\n /**\n * Get the transport for the client\n * @param transportType - The transport type to get\n * @returns The transport for the client\n */\n getTransport(transportType: TransportType) {\n switch (transportType) {\n case \"streamable-http\":\n return new StreamableHTTPEdgeClientTransport(\n this.url,\n this.options.transport as StreamableHTTPClientTransportOptions\n );\n case \"sse\":\n return new SSEEdgeClientTransport(\n this.url,\n this.options.transport as SSEClientTransportOptions\n );\n default:\n throw new Error(`Unsupported transport type: ${transportType}`);\n }\n }\n\n async tryConnect(transportType: MCPTransportOptions[\"type\"], code?: string) {\n const transports: TransportType[] =\n transportType === \"auto\" ? [\"streamable-http\", \"sse\"] : [transportType];\n\n for (const currentTransportType of transports) {\n const isLastTransport =\n currentTransportType === transports[transports.length - 1];\n const hasFallback =\n transportType === \"auto\" &&\n currentTransportType === \"streamable-http\" &&\n !isLastTransport;\n\n const transport = await this.getTransport(currentTransportType);\n\n if (code) {\n await transport.finishAuth(code);\n }\n\n try {\n await this.client.connect(transport);\n break;\n } catch (e) {\n const error = e instanceof Error ? e : new Error(String(e));\n\n if (\n hasFallback &&\n (error.message.includes(\"404\") || error.message.includes(\"405\"))\n ) {\n // try the next transport if we have a fallback\n continue;\n }\n\n throw e;\n }\n }\n\n // Set up elicitation request handler\n this.client.setRequestHandler(\n ElicitRequestSchema,\n async (request: ElicitRequest) => {\n return await this.handleElicitationRequest(request);\n }\n );\n }\n}\n\nfunction capabilityErrorHandler<T>(empty: T, method: string) {\n return (e: { code: number }) => {\n // server is badly behaved and returning invalid capabilities. This commonly occurs for resource templates\n if (e.code === -32601) {\n console.error(\n `The server advertised support for the capability ${method.split(\"/\")[0]}, but returned \"Method not found\" for '${method}'.`\n );\n return empty;\n }\n throw e;\n };\n}\n","import type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport {\n SSEClientTransport,\n type SSEClientTransportOptions\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\n\nexport class SSEEdgeClientTransport extends SSEClientTransport {\n private authProvider: OAuthClientProvider | undefined;\n /**\n * Creates a new EdgeSSEClientTransport, which overrides fetch to be compatible with the CF workers environment\n */\n constructor(url: URL, options: SSEClientTransportOptions) {\n const fetchOverride: typeof fetch = async (\n fetchUrl: RequestInfo | URL,\n fetchInit: RequestInit = {}\n ) => {\n // add auth headers\n const headers = await this.authHeaders();\n const workerOptions = {\n ...fetchInit,\n headers: {\n ...options.requestInit?.headers,\n ...fetchInit?.headers,\n ...headers\n }\n };\n\n // Remove unsupported properties\n delete workerOptions.mode;\n\n // Call the original fetch with fixed options\n return (\n (options.eventSourceInit?.fetch?.(\n fetchUrl as URL | string,\n // @ts-expect-error Expects FetchLikeInit from EventSource but is compatible with RequestInit\n workerOptions\n ) as Promise<Response>) || fetch(fetchUrl, workerOptions)\n );\n };\n\n super(url, {\n ...options,\n eventSourceInit: {\n ...options.eventSourceInit,\n fetch: fetchOverride\n }\n });\n this.authProvider = options.authProvider;\n }\n\n async authHeaders() {\n if (this.authProvider) {\n const tokens = await this.authProvider.tokens();\n if (tokens) {\n return {\n Authorization: `Bearer ${tokens.access_token}`\n };\n }\n }\n }\n}\n","import type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\n\nexport class StreamableHTTPEdgeClientTransport extends StreamableHTTPClientTransport {\n private authProvider: OAuthClientProvider | undefined;\n\n /**\n * Creates a new StreamableHTTPEdgeClientTransport, which overrides fetch to be compatible with the CF workers environment\n */\n constructor(url: URL, options: StreamableHTTPClientTransportOptions) {\n const fetchOverride: typeof fetch = async (\n fetchUrl: RequestInfo | URL,\n fetchInit: RequestInit = {}\n ) => {\n // add auth headers\n const headers = await this.authHeaders();\n const workerOptions = {\n ...fetchInit,\n headers: {\n ...options.requestInit?.headers,\n ...fetchInit?.headers,\n ...headers\n }\n };\n\n // Remove unsupported properties\n delete workerOptions.mode;\n\n // Call the original fetch with fixed options\n return (\n // @ts-expect-error Custom fetch function for Cloudflare Workers compatibility\n (options.requestInit?.fetch?.(\n fetchUrl as URL | string,\n workerOptions\n ) as Promise<Response>) || fetch(fetchUrl, workerOptions)\n );\n };\n\n super(url, {\n ...options,\n requestInit: {\n ...options.requestInit,\n // @ts-expect-error Custom fetch override for Cloudflare Workers\n fetch: fetchOverride\n }\n });\n this.authProvider = options.authProvider;\n }\n\n async authHeaders() {\n if (this.authProvider) {\n const tokens = await this.authProvider.tokens();\n if (tokens) {\n return {\n Authorization: `Bearer ${tokens.access_token}`\n };\n }\n }\n }\n}\n"],"mappings":"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","names":["url"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCPClientManager
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MH46VMM4.js";
|
|
4
4
|
import {
|
|
5
5
|
DurableObjectOAuthClientProvider
|
|
6
6
|
} from "./chunk-LL2AFX7V.js";
|
|
@@ -326,7 +326,7 @@ var _Agent = class _Agent extends Server {
|
|
|
326
326
|
);
|
|
327
327
|
};
|
|
328
328
|
const _onStart = this.onStart.bind(this);
|
|
329
|
-
this.onStart = async () => {
|
|
329
|
+
this.onStart = async (props) => {
|
|
330
330
|
return agentContext.run(
|
|
331
331
|
{
|
|
332
332
|
agent: this,
|
|
@@ -377,7 +377,7 @@ var _Agent = class _Agent extends Server {
|
|
|
377
377
|
});
|
|
378
378
|
});
|
|
379
379
|
}
|
|
380
|
-
return _onStart();
|
|
380
|
+
return _onStart(props);
|
|
381
381
|
});
|
|
382
382
|
}
|
|
383
383
|
);
|
|
@@ -1293,4 +1293,4 @@ export {
|
|
|
1293
1293
|
getAgentByName,
|
|
1294
1294
|
StreamingResponse
|
|
1295
1295
|
};
|
|
1296
|
-
//# sourceMappingURL=chunk-
|
|
1296
|
+
//# sourceMappingURL=chunk-YDUDMOL6.js.map
|