agents 0.0.0-dd6a9e3 → 0.0.0-de168a2
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/dist/ai-chat-agent.d.ts +5 -1
- package/dist/ai-chat-agent.js +20 -19
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.js +16 -9
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-X6BBKLSC.js → chunk-XG52S6YY.js} +95 -72
- package/dist/chunk-XG52S6YY.js.map +1 -0
- package/dist/client.js +16 -23
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +5 -5
- package/dist/mcp/client.d.ts +763 -0
- package/dist/mcp/client.js +408 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/do-oauth-client-provider.d.ts +41 -0
- package/dist/mcp/do-oauth-client-provider.js +107 -0
- package/dist/mcp/do-oauth-client-provider.js.map +1 -0
- package/dist/mcp/index.d.ts +45 -0
- package/dist/mcp/index.js +349 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/react.js +34 -27
- package/dist/react.js.map +1 -1
- package/package.json +21 -8
- package/src/index.ts +116 -92
- package/dist/chunk-X6BBKLSC.js.map +0 -1
- package/dist/mcp.d.ts +0 -58
- package/dist/mcp.js +0 -945
- package/dist/mcp.js.map +0 -1
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Agent
|
|
3
|
+
} from "../chunk-XG52S6YY.js";
|
|
4
|
+
import {
|
|
5
|
+
__privateAdd,
|
|
6
|
+
__privateGet,
|
|
7
|
+
__privateMethod,
|
|
8
|
+
__privateSet
|
|
9
|
+
} from "../chunk-HMLY7DHA.js";
|
|
10
|
+
|
|
11
|
+
// src/mcp/index.ts
|
|
12
|
+
import { DurableObject } from "cloudflare:workers";
|
|
13
|
+
import { JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
|
|
15
|
+
function handleCORS(request, corsOptions) {
|
|
16
|
+
const origin = request.headers.get("Origin") || "*";
|
|
17
|
+
const corsHeaders = {
|
|
18
|
+
"Access-Control-Allow-Origin": corsOptions?.origin || origin,
|
|
19
|
+
"Access-Control-Allow-Methods": corsOptions?.methods || "GET, POST, OPTIONS",
|
|
20
|
+
"Access-Control-Allow-Headers": corsOptions?.headers || "Content-Type",
|
|
21
|
+
"Access-Control-Max-Age": (corsOptions?.maxAge || 86400).toString()
|
|
22
|
+
};
|
|
23
|
+
if (request.method === "OPTIONS") {
|
|
24
|
+
return new Response(null, { headers: corsHeaders });
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
var _getWebSocket, _started;
|
|
29
|
+
var McpTransport = class {
|
|
30
|
+
constructor(getWebSocket) {
|
|
31
|
+
__privateAdd(this, _getWebSocket);
|
|
32
|
+
__privateAdd(this, _started, false);
|
|
33
|
+
__privateSet(this, _getWebSocket, getWebSocket);
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
if (__privateGet(this, _started)) {
|
|
37
|
+
throw new Error("Transport already started");
|
|
38
|
+
}
|
|
39
|
+
__privateSet(this, _started, true);
|
|
40
|
+
}
|
|
41
|
+
async send(message) {
|
|
42
|
+
if (!__privateGet(this, _started)) {
|
|
43
|
+
throw new Error("Transport not started");
|
|
44
|
+
}
|
|
45
|
+
const websocket = __privateGet(this, _getWebSocket).call(this);
|
|
46
|
+
if (!websocket) {
|
|
47
|
+
throw new Error("WebSocket not connected");
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
websocket.send(JSON.stringify(message));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
this.onerror?.(error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async close() {
|
|
57
|
+
this.onclose?.();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
_getWebSocket = new WeakMap();
|
|
61
|
+
_started = new WeakMap();
|
|
62
|
+
var _status, _transport, _connected, _agent, _McpAgent_instances, initialize_fn;
|
|
63
|
+
var McpAgent = class extends DurableObject {
|
|
64
|
+
constructor(ctx, env) {
|
|
65
|
+
var _a;
|
|
66
|
+
super(ctx, env);
|
|
67
|
+
__privateAdd(this, _McpAgent_instances);
|
|
68
|
+
__privateAdd(this, _status, "zero");
|
|
69
|
+
__privateAdd(this, _transport);
|
|
70
|
+
__privateAdd(this, _connected, false);
|
|
71
|
+
/**
|
|
72
|
+
* Since McpAgent's _aren't_ yet real "Agents" (they route differently, don't support
|
|
73
|
+
* websockets, don't support hibernation), let's only expose a couple of the methods
|
|
74
|
+
* to the outer class: initialState/state/setState/onStateUpdate/sql
|
|
75
|
+
*/
|
|
76
|
+
__privateAdd(this, _agent);
|
|
77
|
+
this.initRun = false;
|
|
78
|
+
const self = this;
|
|
79
|
+
__privateSet(this, _agent, new (_a = class extends Agent {
|
|
80
|
+
onStateUpdate(state, source) {
|
|
81
|
+
return self.onStateUpdate(state, source);
|
|
82
|
+
}
|
|
83
|
+
}, _a.options = {
|
|
84
|
+
hibernate: true
|
|
85
|
+
}, _a)(ctx, env));
|
|
86
|
+
}
|
|
87
|
+
get state() {
|
|
88
|
+
return __privateGet(this, _agent).state;
|
|
89
|
+
}
|
|
90
|
+
sql(strings, ...values) {
|
|
91
|
+
return __privateGet(this, _agent).sql(strings, ...values);
|
|
92
|
+
}
|
|
93
|
+
setState(state) {
|
|
94
|
+
return __privateGet(this, _agent).setState(state);
|
|
95
|
+
}
|
|
96
|
+
onStateUpdate(state, source) {
|
|
97
|
+
}
|
|
98
|
+
async onStart() {
|
|
99
|
+
var _a;
|
|
100
|
+
const self = this;
|
|
101
|
+
__privateSet(this, _agent, new (_a = class extends Agent {
|
|
102
|
+
constructor() {
|
|
103
|
+
super(...arguments);
|
|
104
|
+
this.initialState = self.initialState;
|
|
105
|
+
}
|
|
106
|
+
onStateUpdate(state, source) {
|
|
107
|
+
return self.onStateUpdate(state, source);
|
|
108
|
+
}
|
|
109
|
+
}, _a.options = {
|
|
110
|
+
hibernate: true
|
|
111
|
+
}, _a)(this.ctx, this.env));
|
|
112
|
+
this.props = await this.ctx.storage.get("props");
|
|
113
|
+
this.init?.();
|
|
114
|
+
__privateSet(this, _transport, new McpTransport(() => this.getWebSocket()));
|
|
115
|
+
await this.server.connect(__privateGet(this, _transport));
|
|
116
|
+
}
|
|
117
|
+
async _init(props) {
|
|
118
|
+
await this.ctx.storage.put("props", props);
|
|
119
|
+
this.props = props;
|
|
120
|
+
if (!this.initRun) {
|
|
121
|
+
this.initRun = true;
|
|
122
|
+
await this.init();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Allow the worker to fetch a websocket connection to the agent
|
|
126
|
+
async fetch(request) {
|
|
127
|
+
if (__privateGet(this, _status) !== "started") {
|
|
128
|
+
await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
|
|
129
|
+
}
|
|
130
|
+
if (request.headers.get("Upgrade") !== "websocket") {
|
|
131
|
+
return new Response("Expected WebSocket Upgrade request", {
|
|
132
|
+
status: 400
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const url = new URL(request.url);
|
|
136
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
137
|
+
if (!sessionId) {
|
|
138
|
+
return new Response("Missing sessionId", { status: 400 });
|
|
139
|
+
}
|
|
140
|
+
if (__privateGet(this, _connected)) {
|
|
141
|
+
return new Response("WebSocket already connected", { status: 400 });
|
|
142
|
+
}
|
|
143
|
+
const response = await __privateGet(this, _agent).fetch(request);
|
|
144
|
+
__privateSet(this, _connected, true);
|
|
145
|
+
__privateSet(this, _transport, new McpTransport(() => this.getWebSocket()));
|
|
146
|
+
await this.server.connect(__privateGet(this, _transport));
|
|
147
|
+
return response;
|
|
148
|
+
}
|
|
149
|
+
getWebSocket() {
|
|
150
|
+
const websockets = this.ctx.getWebSockets();
|
|
151
|
+
if (websockets.length === 0) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
return websockets[0];
|
|
155
|
+
}
|
|
156
|
+
async onMCPMessage(sessionId, request) {
|
|
157
|
+
if (__privateGet(this, _status) !== "started") {
|
|
158
|
+
await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const contentType = request.headers.get("content-type") || "";
|
|
162
|
+
if (!contentType.includes("application/json")) {
|
|
163
|
+
return new Response(`Unsupported content-type: ${contentType}`, {
|
|
164
|
+
status: 400
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const contentLength = Number.parseInt(
|
|
168
|
+
request.headers.get("content-length") || "0",
|
|
169
|
+
10
|
|
170
|
+
);
|
|
171
|
+
if (contentLength > MAXIMUM_MESSAGE_SIZE) {
|
|
172
|
+
return new Response(`Request body too large: ${contentLength} bytes`, {
|
|
173
|
+
status: 400
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const message = await request.json();
|
|
177
|
+
let parsedMessage;
|
|
178
|
+
try {
|
|
179
|
+
parsedMessage = JSONRPCMessageSchema.parse(message);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
__privateGet(this, _transport)?.onerror?.(error);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
__privateGet(this, _transport)?.onmessage?.(parsedMessage);
|
|
185
|
+
return new Response("Accepted", { status: 202 });
|
|
186
|
+
} catch (error) {
|
|
187
|
+
__privateGet(this, _transport)?.onerror?.(error);
|
|
188
|
+
return new Response(String(error), { status: 400 });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// This is unused since there are no incoming websocket messages
|
|
192
|
+
async webSocketMessage(ws, event) {
|
|
193
|
+
let message;
|
|
194
|
+
try {
|
|
195
|
+
const data = typeof event === "string" ? event : new TextDecoder().decode(event);
|
|
196
|
+
message = JSONRPCMessageSchema.parse(JSON.parse(data));
|
|
197
|
+
} catch (error) {
|
|
198
|
+
__privateGet(this, _transport)?.onerror?.(error);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (__privateGet(this, _status) !== "started") {
|
|
202
|
+
await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
|
|
203
|
+
}
|
|
204
|
+
__privateGet(this, _transport)?.onmessage?.(message);
|
|
205
|
+
}
|
|
206
|
+
// WebSocket event handlers for hibernation support
|
|
207
|
+
async webSocketError(ws, error) {
|
|
208
|
+
if (__privateGet(this, _status) !== "started") {
|
|
209
|
+
await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
|
|
210
|
+
}
|
|
211
|
+
__privateGet(this, _transport)?.onerror?.(error);
|
|
212
|
+
}
|
|
213
|
+
async webSocketClose(ws, code, reason, wasClean) {
|
|
214
|
+
if (__privateGet(this, _status) !== "started") {
|
|
215
|
+
await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
|
|
216
|
+
}
|
|
217
|
+
__privateGet(this, _transport)?.onclose?.();
|
|
218
|
+
__privateSet(this, _connected, false);
|
|
219
|
+
}
|
|
220
|
+
static mount(path, {
|
|
221
|
+
binding = "MCP_OBJECT",
|
|
222
|
+
corsOptions
|
|
223
|
+
} = {}) {
|
|
224
|
+
let pathname = path;
|
|
225
|
+
if (path === "/") {
|
|
226
|
+
pathname = "/*";
|
|
227
|
+
}
|
|
228
|
+
const basePattern = new URLPattern({ pathname });
|
|
229
|
+
const messagePattern = new URLPattern({ pathname: `${pathname}/message` });
|
|
230
|
+
return {
|
|
231
|
+
fetch: async (request, env, ctx) => {
|
|
232
|
+
const corsResponse = handleCORS(request, corsOptions);
|
|
233
|
+
if (corsResponse) return corsResponse;
|
|
234
|
+
const url = new URL(request.url);
|
|
235
|
+
const namespace = env[binding];
|
|
236
|
+
if (request.method === "GET" && basePattern.test(url)) {
|
|
237
|
+
const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString();
|
|
238
|
+
const { readable, writable } = new TransformStream();
|
|
239
|
+
const writer = writable.getWriter();
|
|
240
|
+
const encoder = new TextEncoder();
|
|
241
|
+
const endpointMessage = `event: endpoint
|
|
242
|
+
data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
|
|
243
|
+
|
|
244
|
+
`;
|
|
245
|
+
writer.write(encoder.encode(endpointMessage));
|
|
246
|
+
const id = namespace.idFromString(sessionId);
|
|
247
|
+
const doStub = namespace.get(id);
|
|
248
|
+
await doStub._init(ctx.props);
|
|
249
|
+
const upgradeUrl = new URL(request.url);
|
|
250
|
+
upgradeUrl.searchParams.set("sessionId", sessionId);
|
|
251
|
+
const response = await doStub.fetch(
|
|
252
|
+
new Request(upgradeUrl, {
|
|
253
|
+
headers: {
|
|
254
|
+
Upgrade: "websocket",
|
|
255
|
+
// Required by PartyServer
|
|
256
|
+
"x-partykit-room": sessionId
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
const ws = response.webSocket;
|
|
261
|
+
if (!ws) {
|
|
262
|
+
console.error("Failed to establish WebSocket connection");
|
|
263
|
+
await writer.close();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
ws.accept();
|
|
267
|
+
ws.addEventListener("message", async (event) => {
|
|
268
|
+
try {
|
|
269
|
+
const message = JSON.parse(event.data);
|
|
270
|
+
const result = JSONRPCMessageSchema.safeParse(message);
|
|
271
|
+
if (!result.success) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const messageText = `event: message
|
|
275
|
+
data: ${JSON.stringify(result.data)}
|
|
276
|
+
|
|
277
|
+
`;
|
|
278
|
+
await writer.write(encoder.encode(messageText));
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error("Error forwarding message to SSE:", error);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
ws.addEventListener("error", async (error) => {
|
|
284
|
+
try {
|
|
285
|
+
await writer.close();
|
|
286
|
+
} catch (e) {
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
ws.addEventListener("close", async () => {
|
|
290
|
+
try {
|
|
291
|
+
await writer.close();
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error("Error closing SSE connection:", error);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
return new Response(readable, {
|
|
297
|
+
headers: {
|
|
298
|
+
"Content-Type": "text/event-stream",
|
|
299
|
+
"Cache-Control": "no-cache",
|
|
300
|
+
Connection: "keep-alive",
|
|
301
|
+
"Access-Control-Allow-Origin": corsOptions?.origin || "*"
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (request.method === "POST" && messagePattern.test(url)) {
|
|
306
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
307
|
+
if (!sessionId) {
|
|
308
|
+
return new Response(
|
|
309
|
+
`Missing sessionId. Expected POST to ${pathname} to initiate new one`,
|
|
310
|
+
{ status: 400 }
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const object = namespace.get(namespace.idFromString(sessionId));
|
|
314
|
+
const response = await object.onMCPMessage(sessionId, request);
|
|
315
|
+
const headers = new Headers();
|
|
316
|
+
response.headers.forEach?.((value, key) => {
|
|
317
|
+
headers.set(key, value);
|
|
318
|
+
});
|
|
319
|
+
headers.set(
|
|
320
|
+
"Access-Control-Allow-Origin",
|
|
321
|
+
corsOptions?.origin || "*"
|
|
322
|
+
);
|
|
323
|
+
return new Response(response.body, {
|
|
324
|
+
status: response.status,
|
|
325
|
+
statusText: response.statusText,
|
|
326
|
+
headers
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return new Response("Not Found", { status: 404 });
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
_status = new WeakMap();
|
|
335
|
+
_transport = new WeakMap();
|
|
336
|
+
_connected = new WeakMap();
|
|
337
|
+
_agent = new WeakMap();
|
|
338
|
+
_McpAgent_instances = new WeakSet();
|
|
339
|
+
initialize_fn = async function() {
|
|
340
|
+
await this.ctx.blockConcurrencyWhile(async () => {
|
|
341
|
+
__privateSet(this, _status, "starting");
|
|
342
|
+
await this.onStart();
|
|
343
|
+
__privateSet(this, _status, "started");
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
export {
|
|
347
|
+
McpAgent
|
|
348
|
+
};
|
|
349
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport { Agent } from \"../\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Connection } from \"../\";\nimport type { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\nimport { JSONRPCMessageSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\nconst MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; // 4MB\n\n// CORS helper function\nfunction handleCORS(\n request: Request,\n corsOptions?: CORSOptions\n): Response | null {\n const origin = request.headers.get(\"Origin\") || \"*\";\n const corsHeaders = {\n \"Access-Control-Allow-Origin\": corsOptions?.origin || origin,\n \"Access-Control-Allow-Methods\":\n corsOptions?.methods || \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": corsOptions?.headers || \"Content-Type\",\n \"Access-Control-Max-Age\": (corsOptions?.maxAge || 86400).toString(),\n };\n\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n return null;\n}\n\ninterface CORSOptions {\n origin?: string;\n methods?: string;\n headers?: string;\n maxAge?: number;\n}\n\nclass McpTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n #getWebSocket: () => WebSocket | null;\n #started = false;\n constructor(getWebSocket: () => WebSocket | null) {\n this.#getWebSocket = getWebSocket;\n }\n\n async start() {\n // The transport does not manage the WebSocket connection since it's terminated\n // by the Durable Object in order to allow hibernation. There's nothing to initialize.\n if (this.#started) {\n throw new Error(\"Transport already started\");\n }\n this.#started = true;\n }\n\n async send(message: JSONRPCMessage) {\n if (!this.#started) {\n throw new Error(\"Transport not started\");\n }\n const websocket = this.#getWebSocket();\n if (!websocket) {\n throw new Error(\"WebSocket not connected\");\n }\n try {\n websocket.send(JSON.stringify(message));\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n async close() {\n // Similar to start, the only thing to do is to pass the event on to the server\n this.onclose?.();\n }\n}\n\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>,\n> extends DurableObject<Env> {\n #status: \"zero\" | \"starting\" | \"started\" = \"zero\";\n #transport?: McpTransport;\n #connected = false;\n\n /**\n * Since McpAgent's _aren't_ yet real \"Agents\" (they route differently, don't support\n * websockets, don't support hibernation), let's only expose a couple of the methods\n * to the outer class: initialState/state/setState/onStateUpdate/sql\n */\n #agent: Agent<Env, State>;\n\n protected constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n const self = this;\n\n this.#agent = new (class extends Agent<Env, State> {\n static options = {\n hibernate: true,\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n })(ctx, env);\n }\n\n /**\n * Agents API allowlist\n */\n initialState!: State;\n get state() {\n return this.#agent.state;\n }\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n return this.#agent.sql<T>(strings, ...values);\n }\n\n setState(state: State) {\n return this.#agent.setState(state);\n }\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates\n }\n async onStart() {\n const self = this;\n\n this.#agent = new (class extends Agent<Env, State> {\n initialState: State = self.initialState;\n static options = {\n hibernate: true,\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n })(this.ctx, this.env);\n\n this.props = (await this.ctx.storage.get(\"props\")) as Props;\n this.init?.();\n\n // Connect to the MCP server\n this.#transport = new McpTransport(() => this.getWebSocket());\n await this.server.connect(this.#transport);\n }\n\n /**\n * McpAgent API\n */\n abstract server: McpServer;\n props!: Props;\n initRun = false;\n\n abstract init(): Promise<void>;\n\n async _init(props: Props) {\n await this.ctx.storage.put(\"props\", props);\n this.props = props;\n if (!this.initRun) {\n this.initRun = true;\n await this.init();\n }\n }\n\n async #initialize(): Promise<void> {\n await this.ctx.blockConcurrencyWhile(async () => {\n this.#status = \"starting\";\n await this.onStart();\n this.#status = \"started\";\n });\n }\n\n // Allow the worker to fetch a websocket connection to the agent\n async fetch(request: Request): Promise<Response> {\n if (this.#status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this.#initialize();\n }\n\n // Only handle WebSocket upgrade requests\n if (request.headers.get(\"Upgrade\") !== \"websocket\") {\n return new Response(\"Expected WebSocket Upgrade request\", {\n status: 400,\n });\n }\n\n const url = new URL(request.url);\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId) {\n return new Response(\"Missing sessionId\", { status: 400 });\n }\n\n // For now, each agent can only have one connection\n // If we get an upgrade while already connected, we should error\n if (this.#connected) {\n return new Response(\"WebSocket already connected\", { status: 400 });\n }\n\n // Defer to the Agent's fetch method to handle the WebSocket connection\n // PartyServer does a lot to manage the connections under the hood\n const response = await this.#agent.fetch(request);\n\n this.#connected = true;\n\n // Connect to the MCP server\n this.#transport = new McpTransport(() => this.getWebSocket());\n await this.server.connect(this.#transport);\n\n return response;\n }\n\n getWebSocket() {\n const websockets = this.ctx.getWebSockets();\n if (websockets.length === 0) {\n return null;\n }\n return websockets[0];\n }\n\n async onMCPMessage(sessionId: string, request: Request): Promise<Response> {\n if (this.#status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this.#initialize();\n }\n try {\n const contentType = request.headers.get(\"content-type\") || \"\";\n if (!contentType.includes(\"application/json\")) {\n return new Response(`Unsupported content-type: ${contentType}`, {\n status: 400,\n });\n }\n\n // check if the request body is too large\n const contentLength = Number.parseInt(\n request.headers.get(\"content-length\") || \"0\",\n 10\n );\n if (contentLength > MAXIMUM_MESSAGE_SIZE) {\n return new Response(`Request body too large: ${contentLength} bytes`, {\n status: 400,\n });\n }\n\n // Clone the request before reading the body to avoid stream issues\n const message = await request.json();\n let parsedMessage: JSONRPCMessage;\n try {\n parsedMessage = JSONRPCMessageSchema.parse(message);\n } catch (error) {\n this.#transport?.onerror?.(error as Error);\n throw error;\n }\n\n this.#transport?.onmessage?.(parsedMessage);\n return new Response(\"Accepted\", { status: 202 });\n } catch (error) {\n this.#transport?.onerror?.(error as Error);\n return new Response(String(error), { status: 400 });\n }\n }\n\n // This is unused since there are no incoming websocket messages\n async webSocketMessage(ws: WebSocket, event: ArrayBuffer | string) {\n let message: JSONRPCMessage;\n try {\n // Ensure event is a string\n const data =\n typeof event === \"string\" ? event : new TextDecoder().decode(event);\n message = JSONRPCMessageSchema.parse(JSON.parse(data));\n } catch (error) {\n this.#transport?.onerror?.(error as Error);\n return;\n }\n\n if (this.#status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this.#initialize();\n }\n\n this.#transport?.onmessage?.(message);\n }\n\n // WebSocket event handlers for hibernation support\n async webSocketError(ws: WebSocket, error: unknown): Promise<void> {\n if (this.#status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this.#initialize();\n }\n this.#transport?.onerror?.(error as Error);\n }\n\n async webSocketClose(\n ws: WebSocket,\n code: number,\n reason: string,\n wasClean: boolean\n ): Promise<void> {\n if (this.#status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this.#initialize();\n }\n this.#transport?.onclose?.();\n this.#connected = false;\n }\n\n static mount(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions,\n }: {\n binding?: string;\n corsOptions?: CORSOptions;\n } = {}\n ) {\n let pathname = path;\n if (path === \"/\") {\n pathname = \"/*\";\n }\n const basePattern = new URLPattern({ pathname });\n const messagePattern = new URLPattern({ pathname: `${pathname}/message` });\n\n return {\n fetch: async (\n request: Request,\n env: Record<string, DurableObjectNamespace<McpAgent>>,\n ctx: ExecutionContext\n ) => {\n // Handle CORS preflight\n const corsResponse = handleCORS(request, corsOptions);\n if (corsResponse) return corsResponse;\n\n const url = new URL(request.url);\n const namespace = env[binding];\n\n // Handle SSE connections\n if (request.method === \"GET\" && basePattern.test(url)) {\n // Use a session ID if one is passed in, or create a unique\n // session ID for this connection\n const sessionId =\n url.searchParams.get(\"sessionId\") ||\n namespace.newUniqueId().toString();\n\n // Create a Transform Stream for SSE\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n\n // Send the endpoint event\n const endpointMessage = `event: endpoint\\ndata: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}\\n\\n`;\n writer.write(encoder.encode(endpointMessage));\n\n // Get the Durable Object\n const id = namespace.idFromString(sessionId);\n const doStub = namespace.get(id);\n\n // Initialize the object\n await doStub._init(ctx.props);\n\n // Connect to the Durable Object via WebSocket\n const upgradeUrl = new URL(request.url);\n upgradeUrl.searchParams.set(\"sessionId\", sessionId);\n const response = await doStub.fetch(\n new Request(upgradeUrl, {\n headers: {\n Upgrade: \"websocket\",\n // Required by PartyServer\n \"x-partykit-room\": sessionId,\n },\n })\n );\n\n // Get the WebSocket\n const ws = response.webSocket;\n if (!ws) {\n console.error(\"Failed to establish WebSocket connection\");\n await writer.close();\n return;\n }\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", async (event) => {\n try {\n const message = JSON.parse(event.data);\n\n // validate that the message is a valid JSONRPC message\n const result = JSONRPCMessageSchema.safeParse(message);\n if (!result.success) {\n // The message was not a valid JSONRPC message, so we will drop it\n // PartyKit will broadcast state change messages to all connected clients\n // and we need to filter those out so they are not passed to MCP clients\n return;\n }\n\n // Send the message as an SSE event\n const messageText = `event: message\\ndata: ${JSON.stringify(result.data)}\\n\\n`;\n await writer.write(encoder.encode(messageText));\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n }\n });\n\n // Handle WebSocket errors\n ws.addEventListener(\"error\", async (error) => {\n try {\n await writer.close();\n } catch (e) {\n // Ignore errors when closing\n }\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", async () => {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n });\n\n // Return the SSE response\n return new Response(readable, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\n },\n });\n }\n\n // Handle MCP messages\n if (request.method === \"POST\" && messagePattern.test(url)) {\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId) {\n return new Response(\n `Missing sessionId. Expected POST to ${pathname} to initiate new one`,\n { status: 400 }\n );\n }\n\n // Get the Durable Object\n const object = namespace.get(namespace.idFromString(sessionId));\n\n // Forward the request to the Durable Object\n const response = await object.onMCPMessage(sessionId, request);\n\n // Add CORS headers\n const headers = new Headers();\n response.headers.forEach?.((value, key) => {\n headers.set(key, value);\n });\n headers.set(\n \"Access-Control-Allow-Origin\",\n corsOptions?.origin || \"*\"\n );\n\n return new Response(response.body as unknown as BodyInit, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return new Response(\"Not Found\", { status: 404 });\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/react.js
CHANGED
|
@@ -3,33 +3,25 @@ import "./chunk-HMLY7DHA.js";
|
|
|
3
3
|
// src/react.tsx
|
|
4
4
|
import { usePartySocket } from "partysocket/react";
|
|
5
5
|
import { useCallback, useRef } from "react";
|
|
6
|
+
function camelCaseToKebabCase(str) {
|
|
7
|
+
if (str === str.toUpperCase() && str !== str.toLowerCase()) {
|
|
8
|
+
return str.toLowerCase().replace(/_/g, "-");
|
|
9
|
+
}
|
|
10
|
+
let kebabified = str.replace(
|
|
11
|
+
/[A-Z]/g,
|
|
12
|
+
(letter) => `-${letter.toLowerCase()}`
|
|
13
|
+
);
|
|
14
|
+
kebabified = kebabified.startsWith("-") ? kebabified.slice(1) : kebabified;
|
|
15
|
+
return kebabified.replace(/_/g, "-").replace(/-$/, "");
|
|
16
|
+
}
|
|
6
17
|
function useAgent(options) {
|
|
18
|
+
const agentNamespace = camelCaseToKebabCase(options.agent);
|
|
7
19
|
const pendingCallsRef = useRef(
|
|
8
20
|
/* @__PURE__ */ new Map()
|
|
9
21
|
);
|
|
10
|
-
const call = useCallback(
|
|
11
|
-
(method, args = [], streamOptions) => {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
const id = Math.random().toString(36).slice(2);
|
|
14
|
-
pendingCallsRef.current.set(id, {
|
|
15
|
-
resolve,
|
|
16
|
-
reject,
|
|
17
|
-
stream: streamOptions
|
|
18
|
-
});
|
|
19
|
-
const request = {
|
|
20
|
-
type: "rpc",
|
|
21
|
-
id,
|
|
22
|
-
method,
|
|
23
|
-
args
|
|
24
|
-
};
|
|
25
|
-
agent.send(JSON.stringify(request));
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
[]
|
|
29
|
-
);
|
|
30
22
|
const agent = usePartySocket({
|
|
31
23
|
prefix: "agents",
|
|
32
|
-
party:
|
|
24
|
+
party: agentNamespace,
|
|
33
25
|
room: options.name || "default",
|
|
34
26
|
...options,
|
|
35
27
|
onMessage: (message) => {
|
|
@@ -72,23 +64,38 @@ function useAgent(options) {
|
|
|
72
64
|
options.onMessage?.(message);
|
|
73
65
|
}
|
|
74
66
|
});
|
|
67
|
+
const call = useCallback(
|
|
68
|
+
(method, args = [], streamOptions) => {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
const id = Math.random().toString(36).slice(2);
|
|
71
|
+
pendingCallsRef.current.set(id, {
|
|
72
|
+
resolve,
|
|
73
|
+
reject,
|
|
74
|
+
stream: streamOptions
|
|
75
|
+
});
|
|
76
|
+
const request = {
|
|
77
|
+
type: "rpc",
|
|
78
|
+
id,
|
|
79
|
+
method,
|
|
80
|
+
args
|
|
81
|
+
};
|
|
82
|
+
agent.send(JSON.stringify(request));
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
[agent]
|
|
86
|
+
);
|
|
75
87
|
agent.setState = (state) => {
|
|
76
88
|
agent.send(JSON.stringify({ type: "cf_agent_state", state }));
|
|
77
89
|
options.onStateUpdate?.(state, "client");
|
|
78
90
|
};
|
|
79
91
|
agent.call = call;
|
|
80
|
-
agent.agent =
|
|
92
|
+
agent.agent = agentNamespace;
|
|
81
93
|
agent.name = options.name || "default";
|
|
82
94
|
if (agent.agent !== agent.agent.toLowerCase()) {
|
|
83
95
|
console.warn(
|
|
84
96
|
`Agent name: ${agent.agent} should probably be in lowercase. Received: ${agent.agent}`
|
|
85
97
|
);
|
|
86
98
|
}
|
|
87
|
-
if (agent.name !== agent.name.toLowerCase()) {
|
|
88
|
-
console.warn(
|
|
89
|
-
`Agent instance name: ${agent.name} should probably be in lowercase. Received: ${agent.name}`
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
99
|
return agent;
|
|
93
100
|
}
|
|
94
101
|
export {
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef } from \"react\";\nimport type { RPCRequest, RPCResponse } from \"./\";\nimport type { StreamOptions } from \"./client\";\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n};\n\n/**\n * React hook for connecting to an Agent\n * @template State Type of the Agent's state\n * @param options Connection options\n * @returns WebSocket connection with setState and call methods\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n ) => Promise<T>;\n} {\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >()\n );\n\n //
|
|
1
|
+
{"version":3,"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef } from \"react\";\nimport type { RPCRequest, RPCResponse } from \"./\";\nimport type { StreamOptions } from \"./client\";\n\n/**\n * Convert a camelCase string to a kebab-case string\n * @param str The string to convert\n * @returns The kebab-case string\n */\nfunction camelCaseToKebabCase(str: string): string {\n // If string is all uppercase, convert to lowercase\n if (str === str.toUpperCase() && str !== str.toLowerCase()) {\n return str.toLowerCase().replace(/_/g, \"-\");\n }\n\n // Otherwise handle camelCase to kebab-case\n let kebabified = str.replace(\n /[A-Z]/g,\n (letter) => `-${letter.toLowerCase()}`\n );\n kebabified = kebabified.startsWith(\"-\") ? kebabified.slice(1) : kebabified;\n // Convert any remaining underscores to hyphens and remove trailing -'s\n return kebabified.replace(/_/g, \"-\").replace(/-$/, \"\");\n}\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n};\n\n/**\n * React hook for connecting to an Agent\n * @template State Type of the Agent's state\n * @param options Connection options\n * @returns WebSocket connection with setState and call methods\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n ) => Promise<T>;\n} {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >()\n );\n\n // TODO: if options.query is a function, then use\n // \"use()\" to get the value and pass it\n // as a query parameter to usePartySocket\n const agent = usePartySocket({\n prefix: \"agents\",\n party: agentNamespace,\n room: options.name || \"default\",\n ...options,\n onMessage: (message) => {\n if (typeof message.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(message.data);\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return options.onMessage?.(message);\n }\n if (parsedMessage.type === \"cf_agent_state\") {\n options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === \"rpc\") {\n const response = parsedMessage as RPCResponse;\n const pending = pendingCallsRef.current.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n }\n return;\n }\n }\n options.onMessage?.(message);\n },\n }) as PartySocket & {\n agent: string;\n name: string;\n setState: (state: State) => void;\n call: <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n ) => Promise<T>;\n };\n // Create the call method\n const call = useCallback(\n <T = unknown,>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> => {\n return new Promise((resolve, reject) => {\n const id = Math.random().toString(36).slice(2);\n pendingCallsRef.current.set(id, {\n resolve: resolve as (value: unknown) => void,\n reject,\n stream: streamOptions,\n });\n\n const request: RPCRequest = {\n type: \"rpc\",\n id,\n method,\n args,\n };\n\n agent.send(JSON.stringify(request));\n });\n },\n [agent]\n );\n\n agent.setState = (state: State) => {\n agent.send(JSON.stringify({ type: \"cf_agent_state\", state }));\n options.onStateUpdate?.(state, \"client\");\n };\n\n agent.call = call;\n agent.agent = agentNamespace;\n agent.name = options.name || \"default\";\n\n // warn if agent isn't in lowercase\n if (agent.agent !== agent.agent.toLowerCase()) {\n console.warn(\n `Agent name: ${agent.agent} should probably be in lowercase. Received: ${agent.agent}`\n );\n }\n\n return agent;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-de168a2",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -38,15 +38,30 @@
|
|
|
38
38
|
"require": "./dist/ai-chat-agent.js",
|
|
39
39
|
"import": "./dist/ai-chat-agent.js"
|
|
40
40
|
},
|
|
41
|
+
"./ai-types": {
|
|
42
|
+
"types": "./dist/ai-types.d.ts",
|
|
43
|
+
"require": "./dist/ai-types.js",
|
|
44
|
+
"import": "./dist/ai-types.js"
|
|
45
|
+
},
|
|
41
46
|
"./schedule": {
|
|
42
47
|
"types": "./dist/schedule.d.ts",
|
|
43
48
|
"require": "./dist/schedule.js",
|
|
44
49
|
"import": "./dist/schedule.js"
|
|
45
50
|
},
|
|
46
51
|
"./mcp": {
|
|
47
|
-
"types": "./dist/mcp.d.ts",
|
|
48
|
-
"require": "./dist/mcp.js",
|
|
49
|
-
"import": "./dist/mcp.js"
|
|
52
|
+
"types": "./dist/mcp/index.d.ts",
|
|
53
|
+
"require": "./dist/mcp/index.js",
|
|
54
|
+
"import": "./dist/mcp/index.js"
|
|
55
|
+
},
|
|
56
|
+
"./mcp/client": {
|
|
57
|
+
"types": "./dist/mcp/client.d.ts",
|
|
58
|
+
"require": "./dist/mcp/client.js",
|
|
59
|
+
"import": "./dist/mcp/client.js"
|
|
60
|
+
},
|
|
61
|
+
"./mcp/do-oauth-client-provider": {
|
|
62
|
+
"types": "./dist/mcp/do-oauth-client-provider.d.ts",
|
|
63
|
+
"require": "./dist/mcp/do-oauth-client-provider.js",
|
|
64
|
+
"import": "./dist/mcp/do-oauth-client-provider.js"
|
|
50
65
|
}
|
|
51
66
|
},
|
|
52
67
|
"keywords": [],
|
|
@@ -62,12 +77,10 @@
|
|
|
62
77
|
"license": "MIT",
|
|
63
78
|
"description": "A home for your AI agents",
|
|
64
79
|
"dependencies": {
|
|
80
|
+
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
65
81
|
"cron-schedule": "^5.0.4",
|
|
66
82
|
"nanoid": "^5.1.5",
|
|
67
83
|
"partyserver": "^0.0.66",
|
|
68
|
-
"partysocket": "
|
|
69
|
-
},
|
|
70
|
-
"devDependencies": {
|
|
71
|
-
"@modelcontextprotocol/sdk": "^1.7.0"
|
|
84
|
+
"partysocket": "1.1.3"
|
|
72
85
|
}
|
|
73
86
|
}
|