agents 0.0.0-33ff003 → 0.0.0-352d62c
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 +131 -25
- package/dist/ai-chat-agent.d.ts +10 -5
- package/dist/ai-chat-agent.js +75 -42
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +14 -9
- package/dist/ai-react.js +31 -31
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.d.ts +27 -9
- package/dist/ai-types.js +6 -0
- package/dist/chunk-EEKLJYON.js +17 -0
- package/dist/chunk-EEKLJYON.js.map +1 -0
- package/dist/{chunk-Y67CHZBI.js → chunk-EM3J4KV7.js} +168 -34
- package/dist/chunk-EM3J4KV7.js.map +1 -0
- package/dist/chunk-ID62XSAS.js +1290 -0
- package/dist/chunk-ID62XSAS.js.map +1 -0
- package/dist/{chunk-BZXOAZUX.js → chunk-PVQZBKN7.js} +5 -5
- package/dist/chunk-PVQZBKN7.js.map +1 -0
- package/dist/{chunk-QSGN3REV.js → chunk-QEVM4BVL.js} +10 -17
- package/dist/chunk-QEVM4BVL.js.map +1 -0
- package/dist/client-DgyzBU_8.d.ts +4601 -0
- package/dist/client.d.ts +8 -2
- package/dist/client.js +2 -2
- package/dist/index.d.ts +192 -19
- package/dist/index.js +11 -5
- package/dist/mcp/client.d.ts +9 -781
- package/dist/mcp/client.js +1 -2
- package/dist/mcp/do-oauth-client-provider.js +1 -2
- package/dist/mcp/index.d.ts +38 -10
- package/dist/mcp/index.js +238 -62
- package/dist/mcp/index.js.map +1 -1
- package/dist/observability/index.d.ts +46 -0
- package/dist/observability/index.js +11 -0
- package/dist/react.d.ts +81 -11
- package/dist/react.js +20 -10
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +6 -6
- package/dist/schedule.js +4 -6
- package/dist/schedule.js.map +1 -1
- package/dist/serializable.d.ts +32 -0
- package/dist/serializable.js +1 -0
- package/dist/serializable.js.map +1 -0
- package/package.json +79 -71
- package/src/index.ts +865 -187
- package/dist/chunk-BZXOAZUX.js.map +0 -1
- package/dist/chunk-NOUFNU2O.js +0 -12
- package/dist/chunk-NPGUKHFR.js +0 -773
- package/dist/chunk-NPGUKHFR.js.map +0 -1
- package/dist/chunk-QSGN3REV.js.map +0 -1
- package/dist/chunk-Y67CHZBI.js.map +0 -1
- /package/dist/{chunk-NOUFNU2O.js.map → observability/index.js.map} +0 -0
package/dist/ai-react.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-EEKLJYON.js";
|
|
2
2
|
|
|
3
3
|
// src/ai-react.tsx
|
|
4
4
|
import { useChat } from "@ai-sdk/react";
|
|
5
|
-
import { use, useEffect } from "react";
|
|
6
5
|
import { nanoid } from "nanoid";
|
|
6
|
+
import { use, useEffect } from "react";
|
|
7
7
|
var requestCache = /* @__PURE__ */ new Map();
|
|
8
8
|
function useAgentChat(options) {
|
|
9
9
|
const { agent, getInitialMessages, ...rest } = options;
|
|
@@ -19,8 +19,8 @@ function useAgentChat(options) {
|
|
|
19
19
|
const getMessagesUrl = new URL(url);
|
|
20
20
|
getMessagesUrl.pathname += "/get-messages";
|
|
21
21
|
const response = await fetch(getMessagesUrl.toString(), {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
credentials: options.credentials,
|
|
23
|
+
headers: options.headers
|
|
24
24
|
});
|
|
25
25
|
return response.json();
|
|
26
26
|
}
|
|
@@ -71,8 +71,8 @@ function useAgentChat(options) {
|
|
|
71
71
|
signal?.addEventListener("abort", () => {
|
|
72
72
|
agent.send(
|
|
73
73
|
JSON.stringify({
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
id,
|
|
75
|
+
type: "cf_agent_chat_request_cancel" /* CF_AGENT_CHAT_REQUEST_CANCEL */
|
|
76
76
|
})
|
|
77
77
|
);
|
|
78
78
|
abortController.abort();
|
|
@@ -84,10 +84,10 @@ function useAgentChat(options) {
|
|
|
84
84
|
let data;
|
|
85
85
|
try {
|
|
86
86
|
data = JSON.parse(event.data);
|
|
87
|
-
} catch (
|
|
87
|
+
} catch (_error) {
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
if (data.type === "cf_agent_use_chat_response") {
|
|
90
|
+
if (data.type === "cf_agent_use_chat_response" /* CF_AGENT_USE_CHAT_RESPONSE */) {
|
|
91
91
|
if (data.id === id) {
|
|
92
92
|
controller.enqueue(new TextEncoder().encode(data.body));
|
|
93
93
|
if (data.done) {
|
|
@@ -107,32 +107,32 @@ function useAgentChat(options) {
|
|
|
107
107
|
});
|
|
108
108
|
agent.send(
|
|
109
109
|
JSON.stringify({
|
|
110
|
-
type: "cf_agent_use_chat_request",
|
|
111
110
|
id,
|
|
112
|
-
url: request.toString(),
|
|
113
111
|
init: {
|
|
114
|
-
method,
|
|
115
|
-
keepalive,
|
|
116
|
-
headers,
|
|
117
112
|
body,
|
|
118
|
-
redirect,
|
|
119
|
-
integrity,
|
|
120
113
|
credentials,
|
|
114
|
+
headers,
|
|
115
|
+
integrity,
|
|
116
|
+
keepalive,
|
|
117
|
+
method,
|
|
121
118
|
mode,
|
|
119
|
+
redirect,
|
|
122
120
|
referrer,
|
|
123
121
|
referrerPolicy,
|
|
124
122
|
window
|
|
125
123
|
// dispatcher,
|
|
126
124
|
// duplex
|
|
127
|
-
}
|
|
125
|
+
},
|
|
126
|
+
type: "cf_agent_use_chat_request" /* CF_AGENT_USE_CHAT_REQUEST */,
|
|
127
|
+
url: request.toString()
|
|
128
128
|
})
|
|
129
129
|
);
|
|
130
130
|
return new Response(stream);
|
|
131
131
|
}
|
|
132
132
|
const useChatHelpers = useChat({
|
|
133
|
+
fetch: aiFetch,
|
|
133
134
|
initialMessages,
|
|
134
135
|
sendExtraMessageFields: true,
|
|
135
|
-
fetch: aiFetch,
|
|
136
136
|
...rest
|
|
137
137
|
});
|
|
138
138
|
useEffect(() => {
|
|
@@ -143,10 +143,10 @@ function useAgentChat(options) {
|
|
|
143
143
|
let data;
|
|
144
144
|
try {
|
|
145
145
|
data = JSON.parse(event.data);
|
|
146
|
-
} catch (
|
|
146
|
+
} catch (_error) {
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
|
-
if (data.type === "cf_agent_chat_clear") {
|
|
149
|
+
if (data.type === "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */) {
|
|
150
150
|
useChatHelpers.setMessages([]);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -157,10 +157,10 @@ function useAgentChat(options) {
|
|
|
157
157
|
let data;
|
|
158
158
|
try {
|
|
159
159
|
data = JSON.parse(event.data);
|
|
160
|
-
} catch (
|
|
160
|
+
} catch (_error) {
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
-
if (data.type === "cf_agent_chat_messages") {
|
|
163
|
+
if (data.type === "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */) {
|
|
164
164
|
useChatHelpers.setMessages(data.messages);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -174,26 +174,26 @@ function useAgentChat(options) {
|
|
|
174
174
|
return {
|
|
175
175
|
...useChatHelpers,
|
|
176
176
|
/**
|
|
177
|
-
*
|
|
178
|
-
* @param messages New messages to set
|
|
177
|
+
* Clear chat history on both client and Agent
|
|
179
178
|
*/
|
|
180
|
-
|
|
181
|
-
useChatHelpers.setMessages(
|
|
179
|
+
clearHistory: () => {
|
|
180
|
+
useChatHelpers.setMessages([]);
|
|
182
181
|
agent.send(
|
|
183
182
|
JSON.stringify({
|
|
184
|
-
type: "
|
|
185
|
-
messages
|
|
183
|
+
type: "cf_agent_chat_clear" /* CF_AGENT_CHAT_CLEAR */
|
|
186
184
|
})
|
|
187
185
|
);
|
|
188
186
|
},
|
|
189
187
|
/**
|
|
190
|
-
*
|
|
188
|
+
* Set the chat messages and synchronize with the Agent
|
|
189
|
+
* @param messages New messages to set
|
|
191
190
|
*/
|
|
192
|
-
|
|
193
|
-
useChatHelpers.setMessages(
|
|
191
|
+
setMessages: (messages) => {
|
|
192
|
+
useChatHelpers.setMessages(messages);
|
|
194
193
|
agent.send(
|
|
195
194
|
JSON.stringify({
|
|
196
|
-
|
|
195
|
+
messages,
|
|
196
|
+
type: "cf_agent_chat_messages" /* CF_AGENT_CHAT_MESSAGES */
|
|
197
197
|
})
|
|
198
198
|
);
|
|
199
199
|
}
|
package/dist/ai-react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat } from \"@ai-sdk/react\";\nimport type { Message } from \"ai\";\nimport { use, useEffect } from \"react\";\nimport type { OutgoingMessage } from \"./ai-types\";\nimport type { useAgent } from \"./react\";\nimport { nanoid } from \"nanoid\";\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<State> = Omit<\n Parameters<typeof useChat>[0] & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n // | (() => Message[])\n | ((options: GetInitialMessagesOptions) => Promise<Message[]>);\n },\n \"fetch\"\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 */\nexport function useAgentChat<State = unknown>(\n options: UseAgentChatOptions<State>\n) {\n const { agent, getInitialMessages, ...rest } = options;\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 // delete the _pk query param\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 headers: options.headers,\n credentials: options.credentials,\n });\n return response.json<Message[]>();\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)!;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n // immediately cache the promise so that we don't\n // create multiple requests for the same agent during multiple\n // concurrent renders\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 : (rest.initialMessages ?? []);\n\n // manages adding and removing the promise from the cache\n useEffect(() => {\n if (!initialMessagesPromise) {\n return;\n }\n // this effect is responsible for removing the promise from the cache\n // when the component unmounts or the promise changes,\n // but that means it also must add the promise to the cache\n // so that multiple arbitrary effect runs produce the expected state\n // when resolved.\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 // we're going to use a websocket to do the actual \"fetching\"\n // but still satisfy the type signature of the fetch function\n // so we'll return a promise that resolves to a response\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 // dispatcher, duplex\n } = options;\n const id = nanoid(8);\n const abortController = new AbortController();\n\n signal?.addEventListener(\"abort\", () => {\n // Propagate request cancellation to the Agent\n // We need to communciate cancellation as a websocket message, instead of a request signal\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_request_cancel\",\n id,\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: \"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 controller.close();\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_use_chat_response\") {\n if (data.id === id) {\n controller.enqueue(new TextEncoder().encode(data.body));\n if (data.done) {\n controller.close();\n abortController.abort();\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n let controller: ReadableStreamDefaultController;\n\n const stream = new ReadableStream({\n start(c) {\n controller = c;\n },\n });\n\n agent.send(\n JSON.stringify({\n type: \"cf_agent_use_chat_request\",\n id,\n url: request.toString(),\n init: {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher,\n // duplex\n },\n })\n );\n\n return new Response(stream);\n }\n const useChatHelpers = useChat({\n initialMessages,\n sendExtraMessageFields: true,\n fetch: aiFetch,\n ...rest,\n });\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_chat_clear\") {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"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 return {\n ...useChatHelpers,\n /**\n * Set the chat messages and synchronize with the Agent\n * @param messages New messages to set\n */\n setMessages: (messages: Message[]) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_messages\",\n messages,\n })\n );\n },\n /**\n * Clear chat history on both client and Agent\n */\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_clear\",\n })\n );\n },\n };\n}\n"],"mappings":"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","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat } from \"@ai-sdk/react\";\nimport type { Message } from \"ai\";\nimport { nanoid } from \"nanoid\";\nimport { use, useEffect } from \"react\";\nimport { MessageType, type OutgoingMessage } from \"./ai-types\";\nimport type { useAgent } from \"./react\";\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<State> = Omit<\n Parameters<typeof useChat>[0] & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n // | (() => Message[])\n | ((options: GetInitialMessagesOptions) => Promise<Message[]>);\n },\n \"fetch\"\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 */\nexport function useAgentChat<State = unknown>(\n options: UseAgentChatOptions<State>\n) {\n const { agent, getInitialMessages, ...rest } = options;\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 // delete the _pk query param\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 return response.json<Message[]>();\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)!;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n // immediately cache the promise so that we don't\n // create multiple requests for the same agent during multiple\n // concurrent renders\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 : (rest.initialMessages ?? []);\n\n // manages adding and removing the promise from the cache\n useEffect(() => {\n if (!initialMessagesPromise) {\n return;\n }\n // this effect is responsible for removing the promise from the cache\n // when the component unmounts or the promise changes,\n // but that means it also must add the promise to the cache\n // so that multiple arbitrary effect runs produce the expected state\n // when resolved.\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 // we're going to use a websocket to do the actual \"fetching\"\n // but still satisfy the type signature of the fetch function\n // so we'll return a promise that resolves to a response\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 // dispatcher, duplex\n } = options;\n const id = nanoid(8);\n const abortController = new AbortController();\n\n signal?.addEventListener(\"abort\", () => {\n // Propagate request cancellation to the Agent\n // We need to communciate cancellation as a websocket message, instead of a request signal\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: \"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 controller.close();\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\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 controller.enqueue(new TextEncoder().encode(data.body));\n if (data.done) {\n controller.close();\n abortController.abort();\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n let controller: ReadableStreamDefaultController;\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 // dispatcher,\n // duplex\n },\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST,\n url: request.toString()\n })\n );\n\n return new Response(stream);\n }\n const useChatHelpers = useChat({\n fetch: aiFetch,\n initialMessages,\n sendExtraMessageFields: true,\n ...rest\n });\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\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_CHAT_CLEAR) {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\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_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 return {\n ...useChatHelpers,\n /**\n * Clear chat history on both client and Agent\n */\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_CHAT_CLEAR\n })\n );\n },\n /**\n * Set the chat messages and synchronize with the Agent\n * @param messages New messages to set\n */\n setMessages: (messages: Message[]) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n messages,\n type: MessageType.CF_AGENT_CHAT_MESSAGES\n })\n );\n }\n };\n}\n"],"mappings":"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","names":["options"]}
|
package/dist/ai-types.d.ts
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
import { Message } from "ai";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Enum for message types used in Agent communication
|
|
5
|
+
*/
|
|
6
|
+
declare enum MessageType {
|
|
7
|
+
/** Indicates this message contains updated chat messages */
|
|
8
|
+
CF_AGENT_CHAT_MESSAGES = "cf_agent_chat_messages",
|
|
9
|
+
/** Indicates this message is a response to a chat request */
|
|
10
|
+
CF_AGENT_USE_CHAT_RESPONSE = "cf_agent_use_chat_response",
|
|
11
|
+
/** Indicates this message is a command to clear chat history */
|
|
12
|
+
CF_AGENT_CHAT_CLEAR = "cf_agent_chat_clear",
|
|
13
|
+
/** Indicates this message is a request to the chat API */
|
|
14
|
+
CF_AGENT_USE_CHAT_REQUEST = "cf_agent_use_chat_request",
|
|
15
|
+
/** Indicates the user wants to stop generation of this message */
|
|
16
|
+
CF_AGENT_CHAT_REQUEST_CANCEL = "cf_agent_chat_request_cancel",
|
|
17
|
+
CF_AGENT_MCP_SERVERS = "cf_agent_mcp_servers",
|
|
18
|
+
CF_AGENT_STATE = "cf_agent_state",
|
|
19
|
+
RPC = "rpc"
|
|
20
|
+
}
|
|
3
21
|
/**
|
|
4
22
|
* Types of messages sent from the Agent to clients
|
|
5
23
|
*/
|
|
6
24
|
type OutgoingMessage =
|
|
7
25
|
| {
|
|
8
26
|
/** Indicates this message contains updated chat messages */
|
|
9
|
-
type:
|
|
27
|
+
type: MessageType.CF_AGENT_CHAT_MESSAGES;
|
|
10
28
|
/** Array of chat messages */
|
|
11
29
|
messages: Message[];
|
|
12
30
|
}
|
|
13
31
|
| {
|
|
14
32
|
/** Indicates this message is a response to a chat request */
|
|
15
|
-
type:
|
|
33
|
+
type: MessageType.CF_AGENT_USE_CHAT_RESPONSE;
|
|
16
34
|
/** Unique ID of the request this response corresponds to */
|
|
17
35
|
id: string;
|
|
18
36
|
/** Content body of the response */
|
|
@@ -22,13 +40,13 @@ type OutgoingMessage =
|
|
|
22
40
|
}
|
|
23
41
|
| {
|
|
24
42
|
/** Indicates this message contains updated chat messages */
|
|
25
|
-
type:
|
|
43
|
+
type: MessageType.CF_AGENT_CHAT_MESSAGES;
|
|
26
44
|
/** Array of chat messages */
|
|
27
45
|
messages: Message[];
|
|
28
46
|
}
|
|
29
47
|
| {
|
|
30
48
|
/** Indicates this message is a command to clear chat history */
|
|
31
|
-
type:
|
|
49
|
+
type: MessageType.CF_AGENT_CHAT_CLEAR;
|
|
32
50
|
};
|
|
33
51
|
/**
|
|
34
52
|
* Types of messages sent from clients to the Agent
|
|
@@ -36,7 +54,7 @@ type OutgoingMessage =
|
|
|
36
54
|
type IncomingMessage =
|
|
37
55
|
| {
|
|
38
56
|
/** Indicates this message is a request to the chat API */
|
|
39
|
-
type:
|
|
57
|
+
type: MessageType.CF_AGENT_USE_CHAT_REQUEST;
|
|
40
58
|
/** Unique ID for this request */
|
|
41
59
|
id: string;
|
|
42
60
|
/** Request initialization options */
|
|
@@ -57,18 +75,18 @@ type IncomingMessage =
|
|
|
57
75
|
}
|
|
58
76
|
| {
|
|
59
77
|
/** Indicates this message is a command to clear chat history */
|
|
60
|
-
type:
|
|
78
|
+
type: MessageType.CF_AGENT_CHAT_CLEAR;
|
|
61
79
|
}
|
|
62
80
|
| {
|
|
63
81
|
/** Indicates this message contains updated chat messages */
|
|
64
|
-
type:
|
|
82
|
+
type: MessageType.CF_AGENT_CHAT_MESSAGES;
|
|
65
83
|
/** Array of chat messages */
|
|
66
84
|
messages: Message[];
|
|
67
85
|
}
|
|
68
86
|
| {
|
|
69
87
|
/** Indicates the user wants to stop generation of this message */
|
|
70
|
-
type:
|
|
88
|
+
type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL;
|
|
71
89
|
id: string;
|
|
72
90
|
};
|
|
73
91
|
|
|
74
|
-
export type
|
|
92
|
+
export { type IncomingMessage, MessageType, type OutgoingMessage };
|
package/dist/ai-types.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/ai-types.ts
|
|
2
|
+
var MessageType = /* @__PURE__ */ ((MessageType2) => {
|
|
3
|
+
MessageType2["CF_AGENT_CHAT_MESSAGES"] = "cf_agent_chat_messages";
|
|
4
|
+
MessageType2["CF_AGENT_USE_CHAT_RESPONSE"] = "cf_agent_use_chat_response";
|
|
5
|
+
MessageType2["CF_AGENT_CHAT_CLEAR"] = "cf_agent_chat_clear";
|
|
6
|
+
MessageType2["CF_AGENT_USE_CHAT_REQUEST"] = "cf_agent_use_chat_request";
|
|
7
|
+
MessageType2["CF_AGENT_CHAT_REQUEST_CANCEL"] = "cf_agent_chat_request_cancel";
|
|
8
|
+
MessageType2["CF_AGENT_MCP_SERVERS"] = "cf_agent_mcp_servers";
|
|
9
|
+
MessageType2["CF_AGENT_STATE"] = "cf_agent_state";
|
|
10
|
+
MessageType2["RPC"] = "rpc";
|
|
11
|
+
return MessageType2;
|
|
12
|
+
})(MessageType || {});
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
MessageType
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-EEKLJYON.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai-types.ts"],"sourcesContent":["import type { Message as ChatMessage } from \"ai\";\n\n/**\n * Enum for message types used in Agent communication\n */\nexport enum MessageType {\n /** Indicates this message contains updated chat messages */\n CF_AGENT_CHAT_MESSAGES = \"cf_agent_chat_messages\",\n /** Indicates this message is a response to a chat request */\n CF_AGENT_USE_CHAT_RESPONSE = \"cf_agent_use_chat_response\",\n /** Indicates this message is a command to clear chat history */\n CF_AGENT_CHAT_CLEAR = \"cf_agent_chat_clear\",\n /** Indicates this message is a request to the chat API */\n CF_AGENT_USE_CHAT_REQUEST = \"cf_agent_use_chat_request\",\n /** Indicates the user wants to stop generation of this message */\n CF_AGENT_CHAT_REQUEST_CANCEL = \"cf_agent_chat_request_cancel\",\n\n CF_AGENT_MCP_SERVERS = \"cf_agent_mcp_servers\",\n CF_AGENT_STATE = \"cf_agent_state\",\n RPC = \"rpc\"\n}\n\n/**\n * Types of messages sent from the Agent to clients\n */\nexport type OutgoingMessage =\n | {\n /** Indicates this message contains updated chat messages */\n type: MessageType.CF_AGENT_CHAT_MESSAGES;\n /** Array of chat messages */\n messages: ChatMessage[];\n }\n | {\n /** Indicates this message is a response to a chat request */\n type: MessageType.CF_AGENT_USE_CHAT_RESPONSE;\n /** Unique ID of the request this response corresponds to */\n id: string;\n /** Content body of the response */\n body: string;\n /** Whether this is the final chunk of the response */\n done: boolean;\n }\n | {\n /** Indicates this message contains updated chat messages */\n type: MessageType.CF_AGENT_CHAT_MESSAGES;\n /** Array of chat messages */\n messages: ChatMessage[];\n }\n | {\n /** Indicates this message is a command to clear chat history */\n type: MessageType.CF_AGENT_CHAT_CLEAR;\n };\n\n/**\n * Types of messages sent from clients to the Agent\n */\nexport type IncomingMessage =\n | {\n /** Indicates this message is a request to the chat API */\n type: MessageType.CF_AGENT_USE_CHAT_REQUEST;\n /** Unique ID for this request */\n id: string;\n /** Request initialization options */\n init: Pick<\n RequestInit,\n | \"method\"\n | \"keepalive\"\n | \"headers\"\n | \"body\"\n | \"redirect\"\n | \"integrity\"\n | \"credentials\"\n | \"mode\"\n | \"referrer\"\n | \"referrerPolicy\"\n | \"window\"\n >;\n }\n | {\n /** Indicates this message is a command to clear chat history */\n type: MessageType.CF_AGENT_CHAT_CLEAR;\n }\n | {\n /** Indicates this message contains updated chat messages */\n type: MessageType.CF_AGENT_CHAT_MESSAGES;\n /** Array of chat messages */\n messages: ChatMessage[];\n }\n | {\n /** Indicates the user wants to stop generation of this message */\n type: MessageType.CF_AGENT_CHAT_REQUEST_CANCEL;\n id: string;\n };\n"],"mappings":";AAKO,IAAK,cAAL,kBAAKA,iBAAL;AAEL,EAAAA,aAAA,4BAAyB;AAEzB,EAAAA,aAAA,gCAA6B;AAE7B,EAAAA,aAAA,yBAAsB;AAEtB,EAAAA,aAAA,+BAA4B;AAE5B,EAAAA,aAAA,kCAA+B;AAE/B,EAAAA,aAAA,0BAAuB;AACvB,EAAAA,aAAA,oBAAiB;AACjB,EAAAA,aAAA,SAAM;AAdI,SAAAA;AAAA,GAAA;","names":["MessageType"]}
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
// src/mcp/client.ts
|
|
2
|
+
import { jsonSchema } from "ai";
|
|
3
|
+
import { nanoid } from "nanoid";
|
|
4
|
+
|
|
5
|
+
// src/mcp/client-connection.ts
|
|
6
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
7
|
+
import {
|
|
8
|
+
PromptListChangedNotificationSchema,
|
|
9
|
+
ResourceListChangedNotificationSchema,
|
|
10
|
+
ToolListChangedNotificationSchema,
|
|
11
|
+
ElicitRequestSchema
|
|
12
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
|
|
1
14
|
// src/mcp/sse-edge.ts
|
|
2
15
|
import {
|
|
3
16
|
SSEClientTransport
|
|
@@ -45,15 +58,59 @@ var SSEEdgeClientTransport = class extends SSEClientTransport {
|
|
|
45
58
|
}
|
|
46
59
|
};
|
|
47
60
|
|
|
48
|
-
// src/mcp/
|
|
61
|
+
// src/mcp/streamable-http-edge.ts
|
|
49
62
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
StreamableHTTPClientTransport
|
|
64
|
+
} from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
65
|
+
var StreamableHTTPEdgeClientTransport = class extends StreamableHTTPClientTransport {
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new StreamableHTTPEdgeClientTransport, which overrides fetch to be compatible with the CF workers environment
|
|
68
|
+
*/
|
|
69
|
+
constructor(url, options) {
|
|
70
|
+
const fetchOverride = async (fetchUrl, fetchInit = {}) => {
|
|
71
|
+
const headers = await this.authHeaders();
|
|
72
|
+
const workerOptions = {
|
|
73
|
+
...fetchInit,
|
|
74
|
+
headers: {
|
|
75
|
+
...options.requestInit?.headers,
|
|
76
|
+
...fetchInit?.headers,
|
|
77
|
+
...headers
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
delete workerOptions.mode;
|
|
81
|
+
return (
|
|
82
|
+
// @ts-expect-error Custom fetch function for Cloudflare Workers compatibility
|
|
83
|
+
options.requestInit?.fetch?.(
|
|
84
|
+
fetchUrl,
|
|
85
|
+
workerOptions
|
|
86
|
+
) || fetch(fetchUrl, workerOptions)
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
super(url, {
|
|
90
|
+
...options,
|
|
91
|
+
requestInit: {
|
|
92
|
+
...options.requestInit,
|
|
93
|
+
// @ts-expect-error Custom fetch override for Cloudflare Workers
|
|
94
|
+
fetch: fetchOverride
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
this.authProvider = options.authProvider;
|
|
98
|
+
}
|
|
99
|
+
async authHeaders() {
|
|
100
|
+
if (this.authProvider) {
|
|
101
|
+
const tokens = await this.authProvider.tokens();
|
|
102
|
+
if (tokens) {
|
|
103
|
+
return {
|
|
104
|
+
Authorization: `Bearer ${tokens.access_token}`
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/mcp/client-connection.ts
|
|
55
112
|
var MCPClientConnection = class {
|
|
56
|
-
constructor(url, info, options = {
|
|
113
|
+
constructor(url, info, options = { client: {}, transport: {} }) {
|
|
57
114
|
this.url = url;
|
|
58
115
|
this.options = options;
|
|
59
116
|
this.connectionState = "connecting";
|
|
@@ -61,7 +118,14 @@ var MCPClientConnection = class {
|
|
|
61
118
|
this.prompts = [];
|
|
62
119
|
this.resources = [];
|
|
63
120
|
this.resourceTemplates = [];
|
|
64
|
-
|
|
121
|
+
const clientOptions = {
|
|
122
|
+
...options.client,
|
|
123
|
+
capabilities: {
|
|
124
|
+
...options.client?.capabilities,
|
|
125
|
+
elicitation: {}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
this.client = new Client(info, clientOptions);
|
|
65
129
|
}
|
|
66
130
|
/**
|
|
67
131
|
* Initialize a client connection
|
|
@@ -71,14 +135,8 @@ var MCPClientConnection = class {
|
|
|
71
135
|
*/
|
|
72
136
|
async init(code) {
|
|
73
137
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
this.options.transport
|
|
77
|
-
);
|
|
78
|
-
if (code) {
|
|
79
|
-
await transport.finishAuth(code);
|
|
80
|
-
}
|
|
81
|
-
await this.client.connect(transport);
|
|
138
|
+
const transportType = this.options.transport.type || "streamable-http";
|
|
139
|
+
await this.tryConnect(transportType, code);
|
|
82
140
|
} catch (e) {
|
|
83
141
|
if (e.toString().includes("Unauthorized")) {
|
|
84
142
|
this.connectionState = "authenticating";
|
|
@@ -92,18 +150,36 @@ var MCPClientConnection = class {
|
|
|
92
150
|
if (!this.serverCapabilities) {
|
|
93
151
|
throw new Error("The MCP Server failed to return server capabilities");
|
|
94
152
|
}
|
|
95
|
-
const [
|
|
153
|
+
const [
|
|
154
|
+
instructionsResult,
|
|
155
|
+
toolsResult,
|
|
156
|
+
resourcesResult,
|
|
157
|
+
promptsResult,
|
|
158
|
+
resourceTemplatesResult
|
|
159
|
+
] = await Promise.allSettled([
|
|
96
160
|
this.client.getInstructions(),
|
|
97
161
|
this.registerTools(),
|
|
98
162
|
this.registerResources(),
|
|
99
163
|
this.registerPrompts(),
|
|
100
164
|
this.registerResourceTemplates()
|
|
101
165
|
]);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
166
|
+
const operations = [
|
|
167
|
+
{ name: "instructions", result: instructionsResult },
|
|
168
|
+
{ name: "tools", result: toolsResult },
|
|
169
|
+
{ name: "resources", result: resourcesResult },
|
|
170
|
+
{ name: "prompts", result: promptsResult },
|
|
171
|
+
{ name: "resource templates", result: resourceTemplatesResult }
|
|
172
|
+
];
|
|
173
|
+
for (const { name, result } of operations) {
|
|
174
|
+
if (result.status === "rejected") {
|
|
175
|
+
console.error(`Failed to initialize ${name}:`, result.reason);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
this.instructions = instructionsResult.status === "fulfilled" ? instructionsResult.value : void 0;
|
|
179
|
+
this.tools = toolsResult.status === "fulfilled" ? toolsResult.value : [];
|
|
180
|
+
this.resources = resourcesResult.status === "fulfilled" ? resourcesResult.value : [];
|
|
181
|
+
this.prompts = promptsResult.status === "fulfilled" ? promptsResult.value : [];
|
|
182
|
+
this.resourceTemplates = resourceTemplatesResult.status === "fulfilled" ? resourceTemplatesResult.value : [];
|
|
107
183
|
this.connectionState = "ready";
|
|
108
184
|
}
|
|
109
185
|
/**
|
|
@@ -208,6 +284,63 @@ var MCPClientConnection = class {
|
|
|
208
284
|
} while (templatesResult.nextCursor);
|
|
209
285
|
return templatesAgg;
|
|
210
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Handle elicitation request from server
|
|
289
|
+
* Automatically uses the Agent's built-in elicitation handling if available
|
|
290
|
+
*/
|
|
291
|
+
async handleElicitationRequest(_request) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
"Elicitation handler must be implemented for your platform. Override handleElicitationRequest method."
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Get the transport for the client
|
|
298
|
+
* @param transportType - The transport type to get
|
|
299
|
+
* @returns The transport for the client
|
|
300
|
+
*/
|
|
301
|
+
getTransport(transportType) {
|
|
302
|
+
switch (transportType) {
|
|
303
|
+
case "streamable-http":
|
|
304
|
+
return new StreamableHTTPEdgeClientTransport(
|
|
305
|
+
this.url,
|
|
306
|
+
this.options.transport
|
|
307
|
+
);
|
|
308
|
+
case "sse":
|
|
309
|
+
return new SSEEdgeClientTransport(
|
|
310
|
+
this.url,
|
|
311
|
+
this.options.transport
|
|
312
|
+
);
|
|
313
|
+
default:
|
|
314
|
+
throw new Error(`Unsupported transport type: ${transportType}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async tryConnect(transportType, code) {
|
|
318
|
+
const transports = transportType === "auto" ? ["streamable-http", "sse"] : [transportType];
|
|
319
|
+
for (const currentTransportType of transports) {
|
|
320
|
+
const isLastTransport = currentTransportType === transports[transports.length - 1];
|
|
321
|
+
const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
|
|
322
|
+
const transport = await this.getTransport(currentTransportType);
|
|
323
|
+
if (code) {
|
|
324
|
+
await transport.finishAuth(code);
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
await this.client.connect(transport);
|
|
328
|
+
break;
|
|
329
|
+
} catch (e) {
|
|
330
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
331
|
+
if (hasFallback && (error.message.includes("404") || error.message.includes("405"))) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
throw e;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
this.client.setRequestHandler(
|
|
338
|
+
ElicitRequestSchema,
|
|
339
|
+
async (request) => {
|
|
340
|
+
return await this.handleElicitationRequest(request);
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
}
|
|
211
344
|
};
|
|
212
345
|
function capabilityErrorHandler(empty, method) {
|
|
213
346
|
return (e) => {
|
|
@@ -222,8 +355,6 @@ function capabilityErrorHandler(empty, method) {
|
|
|
222
355
|
}
|
|
223
356
|
|
|
224
357
|
// src/mcp/client.ts
|
|
225
|
-
import { jsonSchema } from "ai";
|
|
226
|
-
import { nanoid } from "nanoid";
|
|
227
358
|
var MCPClientManager = class {
|
|
228
359
|
/**
|
|
229
360
|
* @param _name Name of the MCP client
|
|
@@ -262,8 +393,8 @@ var MCPClientManager = class {
|
|
|
262
393
|
version: this._version
|
|
263
394
|
},
|
|
264
395
|
{
|
|
265
|
-
|
|
266
|
-
|
|
396
|
+
client: options.client ?? {},
|
|
397
|
+
transport: options.transport ?? {}
|
|
267
398
|
}
|
|
268
399
|
);
|
|
269
400
|
await this.mcpConnections[id].init(options.reconnect?.oauthCode);
|
|
@@ -273,9 +404,9 @@ var MCPClientManager = class {
|
|
|
273
404
|
options.transport.authProvider.redirectUrl.toString()
|
|
274
405
|
);
|
|
275
406
|
return {
|
|
276
|
-
id,
|
|
277
407
|
authUrl,
|
|
278
|
-
clientId: options.transport?.authProvider?.clientId
|
|
408
|
+
clientId: options.transport?.authProvider?.clientId,
|
|
409
|
+
id
|
|
279
410
|
};
|
|
280
411
|
}
|
|
281
412
|
return {
|
|
@@ -350,21 +481,21 @@ var MCPClientManager = class {
|
|
|
350
481
|
return Object.fromEntries(
|
|
351
482
|
getNamespacedData(this.mcpConnections, "tools").map((tool) => {
|
|
352
483
|
return [
|
|
353
|
-
|
|
484
|
+
`tool_${tool.serverId}_${tool.name}`,
|
|
354
485
|
{
|
|
355
|
-
parameters: jsonSchema(tool.inputSchema),
|
|
356
486
|
description: tool.description,
|
|
357
487
|
execute: async (args) => {
|
|
358
488
|
const result = await this.callTool({
|
|
359
|
-
name: tool.name,
|
|
360
489
|
arguments: args,
|
|
490
|
+
name: tool.name,
|
|
361
491
|
serverId: tool.serverId
|
|
362
492
|
});
|
|
363
493
|
if (result.isError) {
|
|
364
494
|
throw new Error(result.content[0].text);
|
|
365
495
|
}
|
|
366
496
|
return result;
|
|
367
|
-
}
|
|
497
|
+
},
|
|
498
|
+
parameters: jsonSchema(tool.inputSchema)
|
|
368
499
|
}
|
|
369
500
|
];
|
|
370
501
|
})
|
|
@@ -389,6 +520,7 @@ var MCPClientManager = class {
|
|
|
389
520
|
throw new Error(`Connection with id "${id}" does not exist.`);
|
|
390
521
|
}
|
|
391
522
|
await this.mcpConnections[id].client.close();
|
|
523
|
+
delete this.mcpConnections[id];
|
|
392
524
|
}
|
|
393
525
|
/**
|
|
394
526
|
* @returns namespaced list of prompts
|
|
@@ -443,7 +575,7 @@ var MCPClientManager = class {
|
|
|
443
575
|
};
|
|
444
576
|
function getNamespacedData(mcpClients, type) {
|
|
445
577
|
const sets = Object.entries(mcpClients).map(([name, conn]) => {
|
|
446
|
-
return {
|
|
578
|
+
return { data: conn[type], name };
|
|
447
579
|
});
|
|
448
580
|
const namespacedData = sets.flatMap(({ name: serverId, data }) => {
|
|
449
581
|
return data.map((item) => {
|
|
@@ -458,7 +590,9 @@ function getNamespacedData(mcpClients, type) {
|
|
|
458
590
|
}
|
|
459
591
|
|
|
460
592
|
export {
|
|
593
|
+
SSEEdgeClientTransport,
|
|
594
|
+
StreamableHTTPEdgeClientTransport,
|
|
461
595
|
MCPClientManager,
|
|
462
596
|
getNamespacedData
|
|
463
597
|
};
|
|
464
|
-
//# sourceMappingURL=chunk-
|
|
598
|
+
//# sourceMappingURL=chunk-EM3J4KV7.js.map
|