agents 0.0.0-74a8c74 → 0.0.0-7b22285
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 +0 -1
- package/dist/ai-chat-agent.js +60 -63
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.js +18 -9
- package/dist/ai-react.js.map +1 -1
- package/dist/chunk-HMLY7DHA.js +16 -0
- package/dist/chunk-HMLY7DHA.js.map +1 -0
- package/dist/{chunk-SZEXGW6W.js → chunk-XG52S6YY.js} +151 -140
- package/dist/chunk-XG52S6YY.js.map +1 -0
- package/dist/client.js +43 -43
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +2 -3
- package/dist/mcp/client.d.ts +110 -22
- package/dist/mcp/client.js +193 -571
- package/dist/mcp/client.js.map +1 -1
- 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 +8 -4
- package/dist/mcp/index.js +268 -54
- package/dist/mcp/index.js.map +1 -1
- package/dist/react.js +36 -27
- package/dist/react.js.map +1 -1
- package/dist/schedule.js +2 -0
- package/dist/schedule.js.map +1 -1
- package/package.json +7 -4
- package/src/index.ts +0 -7
- package/dist/chunk-EZ76ZGDB.js +0 -1721
- package/dist/chunk-EZ76ZGDB.js.map +0 -1
- package/dist/chunk-SZEXGW6W.js.map +0 -1
package/dist/mcp/index.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-XG52S6YY.js";
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
__privateAdd,
|
|
6
|
+
__privateGet,
|
|
7
|
+
__privateMethod,
|
|
8
|
+
__privateSet
|
|
9
|
+
} from "../chunk-HMLY7DHA.js";
|
|
7
10
|
|
|
8
11
|
// src/mcp/index.ts
|
|
9
12
|
import { DurableObject } from "cloudflare:workers";
|
|
13
|
+
import { JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
|
|
10
15
|
function handleCORS(request, corsOptions) {
|
|
11
16
|
const origin = request.headers.get("Origin") || "*";
|
|
12
17
|
const corsHeaders = {
|
|
@@ -20,68 +25,208 @@ function handleCORS(request, corsOptions) {
|
|
|
20
25
|
}
|
|
21
26
|
return null;
|
|
22
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;
|
|
23
63
|
var McpAgent = class extends DurableObject {
|
|
24
|
-
/**
|
|
25
|
-
* Since McpAgent's _aren't_ yet real "Agents" (they route differently, don't support
|
|
26
|
-
* websockets, don't support hibernation), let's only expose a couple of the methods
|
|
27
|
-
* to the outer class: initialState/state/setState/onStateUpdate/sql
|
|
28
|
-
*/
|
|
29
|
-
#agent;
|
|
30
64
|
constructor(ctx, env) {
|
|
65
|
+
var _a;
|
|
31
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;
|
|
32
78
|
const self = this;
|
|
33
|
-
this
|
|
34
|
-
static options = {
|
|
35
|
-
hibernate: false
|
|
36
|
-
};
|
|
79
|
+
__privateSet(this, _agent, new (_a = class extends Agent {
|
|
37
80
|
onStateUpdate(state, source) {
|
|
38
81
|
return self.onStateUpdate(state, source);
|
|
39
82
|
}
|
|
40
|
-
}
|
|
83
|
+
}, _a.options = {
|
|
84
|
+
hibernate: true
|
|
85
|
+
}, _a)(ctx, env));
|
|
41
86
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Agents API allowlist
|
|
44
|
-
*/
|
|
45
|
-
initialState;
|
|
46
87
|
get state() {
|
|
47
|
-
|
|
48
|
-
return this.#agent.state;
|
|
88
|
+
return __privateGet(this, _agent).state;
|
|
49
89
|
}
|
|
50
90
|
sql(strings, ...values) {
|
|
51
|
-
return this
|
|
91
|
+
return __privateGet(this, _agent).sql(strings, ...values);
|
|
52
92
|
}
|
|
53
93
|
setState(state) {
|
|
54
|
-
return this
|
|
94
|
+
return __privateGet(this, _agent).setState(state);
|
|
55
95
|
}
|
|
56
96
|
onStateUpdate(state, source) {
|
|
57
97
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
+
}
|
|
61
117
|
async _init(props) {
|
|
118
|
+
await this.ctx.storage.put("props", props);
|
|
62
119
|
this.props = props;
|
|
63
120
|
if (!this.initRun) {
|
|
64
121
|
this.initRun = true;
|
|
65
122
|
await this.init();
|
|
66
123
|
}
|
|
67
124
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
this.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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;
|
|
75
148
|
}
|
|
76
|
-
|
|
77
|
-
|
|
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);
|
|
78
219
|
}
|
|
79
220
|
static mount(path, {
|
|
80
221
|
binding = "MCP_OBJECT",
|
|
81
222
|
corsOptions
|
|
82
223
|
} = {}) {
|
|
83
|
-
|
|
84
|
-
|
|
224
|
+
let pathname = path;
|
|
225
|
+
if (path === "/") {
|
|
226
|
+
pathname = "/*";
|
|
227
|
+
}
|
|
228
|
+
const basePattern = new URLPattern({ pathname });
|
|
229
|
+
const messagePattern = new URLPattern({ pathname: `${pathname}/message` });
|
|
85
230
|
return {
|
|
86
231
|
fetch: async (request, env, ctx) => {
|
|
87
232
|
const corsResponse = handleCORS(request, corsOptions);
|
|
@@ -89,39 +234,96 @@ var McpAgent = class extends DurableObject {
|
|
|
89
234
|
const url = new URL(request.url);
|
|
90
235
|
const namespace = env[binding];
|
|
91
236
|
if (request.method === "GET" && basePattern.test(url)) {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
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
|
+
}
|
|
98
282
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
+
}
|
|
104
303
|
});
|
|
105
304
|
}
|
|
106
305
|
if (request.method === "POST" && messagePattern.test(url)) {
|
|
107
306
|
const sessionId = url.searchParams.get("sessionId");
|
|
108
307
|
if (!sessionId) {
|
|
109
308
|
return new Response(
|
|
110
|
-
`Missing sessionId. Expected POST to ${
|
|
309
|
+
`Missing sessionId. Expected POST to ${pathname} to initiate new one`,
|
|
111
310
|
{ status: 400 }
|
|
112
311
|
);
|
|
113
312
|
}
|
|
114
313
|
const object = namespace.get(namespace.idFromString(sessionId));
|
|
115
|
-
const response = await object.onMCPMessage(request);
|
|
116
|
-
const
|
|
117
|
-
response.headers.forEach((value, key) => {
|
|
118
|
-
|
|
314
|
+
const response = await object.onMCPMessage(sessionId, request);
|
|
315
|
+
const headers = new Headers();
|
|
316
|
+
response.headers.forEach?.((value, key) => {
|
|
317
|
+
headers.set(key, value);
|
|
119
318
|
});
|
|
120
|
-
|
|
319
|
+
headers.set(
|
|
320
|
+
"Access-Control-Allow-Origin",
|
|
321
|
+
corsOptions?.origin || "*"
|
|
322
|
+
);
|
|
121
323
|
return new Response(response.body, {
|
|
122
324
|
status: response.status,
|
|
123
325
|
statusText: response.statusText,
|
|
124
|
-
headers
|
|
326
|
+
headers
|
|
125
327
|
});
|
|
126
328
|
}
|
|
127
329
|
return new Response("Not Found", { status: 404 });
|
|
@@ -129,6 +331,18 @@ var McpAgent = class extends DurableObject {
|
|
|
129
331
|
};
|
|
130
332
|
}
|
|
131
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
|
+
};
|
|
132
346
|
export {
|
|
133
347
|
McpAgent
|
|
134
348
|
};
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +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 { SSEEdgeServerTransport } from \"./sse-edge\";\nimport type { Connection } from \"../\";\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\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>,\n> extends DurableObject<Env> {\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 readonly #agent: Agent<Env, State>;\n protected constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n const self = this;\n\n // Since McpAgent's _aren't_ yet real \"Agents\" (they route differently, they don't support\n // websockets, hibernation, scheduling etc), let's only expose a couple of the methods\n // to the outer class for now.\n this.#agent = new (class extends Agent<Env, State> {\n static options = {\n hibernate: false,\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 if (this.initialState) this.#agent.initialState = this.initialState;\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\n /**\n * McpAgent API\n */\n abstract server: McpServer;\n private transport!: SSEEdgeServerTransport;\n props!: Props;\n initRun = false;\n\n abstract init(): Promise<void>;\n\n async _init(props: Props) {\n this.props = props;\n if (!this.initRun) {\n this.initRun = true;\n await this.init();\n }\n }\n\n async onSSE(path: string): Promise<Response> {\n this.transport = new SSEEdgeServerTransport(\n `${path}/message`,\n this.ctx.id.toString()\n );\n await this.server.connect(this.transport);\n return this.transport.sseResponse;\n }\n\n async onMCPMessage(request: Request): Promise<Response> {\n return this.transport.handlePostMessage(request);\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 const basePattern = new URLPattern({ pathname: path });\n const messagePattern = new URLPattern({ pathname: `${path}/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 if (request.method === \"GET\" && basePattern.test(url)) {\n const object = namespace.get(namespace.newUniqueId());\n // @ts-ignore\n await object._init(ctx.props);\n const response = await object.onSSE(path);\n\n // Convert headers to a plain object\n const headerObj: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headerObj[key] = value;\n });\n headerObj[\"Access-Control-Allow-Origin\"] = corsOptions?.origin || \"*\";\n\n // Clone the response to get a new body stream\n // const clonedResponse = response.clone();\n return new Response(response.body as unknown as BodyInit, {\n status: response.status,\n statusText: response.statusText,\n headers: headerObj,\n });\n }\n\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 ${path} to initiate new one`,\n { status: 400 }\n );\n }\n const object = namespace.get(namespace.idFromString(sessionId));\n const response = await object.onMCPMessage(request);\n\n // Convert headers to a plain object\n const headerObj: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headerObj[key] = value;\n });\n headerObj[\"Access-Control-Allow-Origin\"] = corsOptions?.origin || \"*\";\n\n return new Response(response.body as unknown as BodyInit, {\n status: response.status,\n statusText: response.statusText,\n headers: headerObj,\n });\n }\n\n return new Response(\"Not Found\", { status: 404 });\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
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
|
@@ -1,33 +1,27 @@
|
|
|
1
|
+
import "./chunk-HMLY7DHA.js";
|
|
2
|
+
|
|
1
3
|
// src/react.tsx
|
|
2
4
|
import { usePartySocket } from "partysocket/react";
|
|
3
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
|
+
}
|
|
4
17
|
function useAgent(options) {
|
|
18
|
+
const agentNamespace = camelCaseToKebabCase(options.agent);
|
|
5
19
|
const pendingCallsRef = useRef(
|
|
6
20
|
/* @__PURE__ */ new Map()
|
|
7
21
|
);
|
|
8
|
-
const call = useCallback(
|
|
9
|
-
(method, args = [], streamOptions) => {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
const id = Math.random().toString(36).slice(2);
|
|
12
|
-
pendingCallsRef.current.set(id, {
|
|
13
|
-
resolve,
|
|
14
|
-
reject,
|
|
15
|
-
stream: streamOptions
|
|
16
|
-
});
|
|
17
|
-
const request = {
|
|
18
|
-
type: "rpc",
|
|
19
|
-
id,
|
|
20
|
-
method,
|
|
21
|
-
args
|
|
22
|
-
};
|
|
23
|
-
agent.send(JSON.stringify(request));
|
|
24
|
-
});
|
|
25
|
-
},
|
|
26
|
-
[]
|
|
27
|
-
);
|
|
28
22
|
const agent = usePartySocket({
|
|
29
23
|
prefix: "agents",
|
|
30
|
-
party:
|
|
24
|
+
party: agentNamespace,
|
|
31
25
|
room: options.name || "default",
|
|
32
26
|
...options,
|
|
33
27
|
onMessage: (message) => {
|
|
@@ -70,23 +64,38 @@ function useAgent(options) {
|
|
|
70
64
|
options.onMessage?.(message);
|
|
71
65
|
}
|
|
72
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
|
+
);
|
|
73
87
|
agent.setState = (state) => {
|
|
74
88
|
agent.send(JSON.stringify({ type: "cf_agent_state", state }));
|
|
75
89
|
options.onStateUpdate?.(state, "client");
|
|
76
90
|
};
|
|
77
91
|
agent.call = call;
|
|
78
|
-
agent.agent =
|
|
92
|
+
agent.agent = agentNamespace;
|
|
79
93
|
agent.name = options.name || "default";
|
|
80
94
|
if (agent.agent !== agent.agent.toLowerCase()) {
|
|
81
95
|
console.warn(
|
|
82
96
|
`Agent name: ${agent.agent} should probably be in lowercase. Received: ${agent.agent}`
|
|
83
97
|
);
|
|
84
98
|
}
|
|
85
|
-
if (agent.name !== agent.name.toLowerCase()) {
|
|
86
|
-
console.warn(
|
|
87
|
-
`Agent instance name: ${agent.name} should probably be in lowercase. Received: ${agent.name}`
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
99
|
return agent;
|
|
91
100
|
}
|
|
92
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/dist/schedule.js
CHANGED
package/dist/schedule.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schedule.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport type Schedule = z.infer<typeof unstable_scheduleSchema>;\n\nexport function unstable_getSchedulePrompt(event: { date: Date }) {\n return `\n[Schedule Parser Component]\n\nCurrent time: ${event.date.toUTCString()}\n\nThis component parses natural language scheduling requests into a structured format. It extracts:\n1. A clean task description (without timing information)\n2. Scheduling details in one of these formats:\n - scheduled: Specific date/time events\n - delayed: Relative time delays (in seconds)\n - cron: Recurring patterns\n - no-schedule: Tasks without timing\n\nRules:\n- Task descriptions should be clean and focused on the action\n- Use numbers (0-6) for days in cron patterns (0=Sunday)\n- For recurring tasks, use standard cron syntax\n- For relative times, convert to seconds\n- For specific dates, use the current time as reference\n\nExample outputs:\n{\n \"description\": \"meeting with team\",\n \"when\": {\n \"type\": \"scheduled\",\n \"date\": \"tomorrow at 14:00\"\n }\n}\n\n{\n \"description\": \"backup database\",\n \"when\": {\n \"type\": \"cron\",\n \"cron\": \"0 0 * * *\"\n }\n}\n\n{\n \"description\": \"send report\",\n \"when\": {\n \"type\": \"delayed\",\n \"delayInSeconds\": 1800\n }\n}\n\n[End Schedule Parser Component]\n`;\n}\n\nexport const unstable_scheduleSchema = z.object({\n description: z.string().describe(\"A description of the task\"),\n when: z.object({\n type: z\n .enum([\"scheduled\", \"delayed\", \"cron\", \"no-schedule\"])\n .describe(\"The type of scheduling details\"),\n date: z.coerce\n .date()\n .optional()\n .describe(\n \"execute task at the specified date and time (only use if the type is scheduled)\"\n ),\n delayInSeconds: z\n .number()\n .optional()\n .describe(\n \"execute task after a delay in seconds (only use if the type is delayed)\"\n ),\n cron: z\n .string()\n .optional()\n .describe(\n \"execute task on a recurring interval specified as cron syntax (only use if the type is cron)\"\n ),\n }),\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/schedule.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport type Schedule = z.infer<typeof unstable_scheduleSchema>;\n\nexport function unstable_getSchedulePrompt(event: { date: Date }) {\n return `\n[Schedule Parser Component]\n\nCurrent time: ${event.date.toUTCString()}\n\nThis component parses natural language scheduling requests into a structured format. It extracts:\n1. A clean task description (without timing information)\n2. Scheduling details in one of these formats:\n - scheduled: Specific date/time events\n - delayed: Relative time delays (in seconds)\n - cron: Recurring patterns\n - no-schedule: Tasks without timing\n\nRules:\n- Task descriptions should be clean and focused on the action\n- Use numbers (0-6) for days in cron patterns (0=Sunday)\n- For recurring tasks, use standard cron syntax\n- For relative times, convert to seconds\n- For specific dates, use the current time as reference\n\nExample outputs:\n{\n \"description\": \"meeting with team\",\n \"when\": {\n \"type\": \"scheduled\",\n \"date\": \"tomorrow at 14:00\"\n }\n}\n\n{\n \"description\": \"backup database\",\n \"when\": {\n \"type\": \"cron\",\n \"cron\": \"0 0 * * *\"\n }\n}\n\n{\n \"description\": \"send report\",\n \"when\": {\n \"type\": \"delayed\",\n \"delayInSeconds\": 1800\n }\n}\n\n[End Schedule Parser Component]\n`;\n}\n\nexport const unstable_scheduleSchema = z.object({\n description: z.string().describe(\"A description of the task\"),\n when: z.object({\n type: z\n .enum([\"scheduled\", \"delayed\", \"cron\", \"no-schedule\"])\n .describe(\"The type of scheduling details\"),\n date: z.coerce\n .date()\n .optional()\n .describe(\n \"execute task at the specified date and time (only use if the type is scheduled)\"\n ),\n delayInSeconds: z\n .number()\n .optional()\n .describe(\n \"execute task after a delay in seconds (only use if the type is delayed)\"\n ),\n cron: z\n .string()\n .optional()\n .describe(\n \"execute task on a recurring interval specified as cron syntax (only use if the type is cron)\"\n ),\n }),\n});\n"],"mappings":";;;AAAA,SAAS,SAAS;AAIX,SAAS,2BAA2B,OAAuB;AAChE,SAAO;AAAA;AAAA;AAAA,gBAGO,MAAM,KAAK,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4CxC;AAEO,IAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,aAAa,EAAE,OAAO,EAAE,SAAS,2BAA2B;AAAA,EAC5D,MAAM,EAAE,OAAO;AAAA,IACb,MAAM,EACH,KAAK,CAAC,aAAa,WAAW,QAAQ,aAAa,CAAC,EACpD,SAAS,gCAAgC;AAAA,IAC5C,MAAM,EAAE,OACL,KAAK,EACL,SAAS,EACT;AAAA,MACC;AAAA,IACF;AAAA,IACF,gBAAgB,EACb,OAAO,EACP,SAAS,EACT;AAAA,MACC;AAAA,IACF;AAAA,IACF,MAAM,EACH,OAAO,EACP,SAAS,EACT;AAAA,MACC;AAAA,IACF;AAAA,EACJ,CAAC;AACH,CAAC;","names":[]}
|