agents 0.0.0-bcae0ba → 0.0.0-c3e8618
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 +2 -6
- package/dist/ai-chat-agent.d.ts +23 -30
- package/dist/ai-react.d.ts +45 -71
- package/dist/ai-types.d.ts +40 -60
- package/dist/client.d.ts +37 -57
- package/dist/index.d.ts +176 -223
- package/dist/mcp/client.d.ts +675 -0
- package/dist/mcp/index.d.ts +41 -0
- package/dist/react.d.ts +15 -24
- package/dist/schedule.d.ts +20 -30
- package/package.json +17 -4
- package/src/index.ts +167 -100
- package/dist/ai-chat-agent.js +0 -169
- package/dist/ai-chat-agent.js.map +0 -1
- package/dist/ai-react.js +0 -189
- package/dist/ai-react.js.map +0 -1
- package/dist/ai-types.js +0 -1
- package/dist/ai-types.js.map +0 -1
- package/dist/chunk-HMLY7DHA.js +0 -16
- package/dist/chunk-HMLY7DHA.js.map +0 -1
- package/dist/chunk-PDF5WEP4.js +0 -542
- package/dist/chunk-PDF5WEP4.js.map +0 -1
- package/dist/client.js +0 -138
- package/dist/client.js.map +0 -1
- package/dist/index.js +0 -20
- package/dist/index.js.map +0 -1
- package/dist/react.js +0 -97
- package/dist/react.js.map +0 -1
- package/dist/schedule.js +0 -73
- package/dist/schedule.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DurableObject } from 'cloudflare:workers';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { Connection } from 'partyserver';
|
|
4
|
+
|
|
5
|
+
interface CORSOptions {
|
|
6
|
+
origin?: string;
|
|
7
|
+
methods?: string;
|
|
8
|
+
headers?: string;
|
|
9
|
+
maxAge?: number;
|
|
10
|
+
}
|
|
11
|
+
declare abstract class McpAgent<Env = unknown, State = unknown, Props extends Record<string, unknown> = Record<string, unknown>> extends DurableObject<Env> {
|
|
12
|
+
#private;
|
|
13
|
+
protected constructor(ctx: DurableObjectState, env: Env);
|
|
14
|
+
/**
|
|
15
|
+
* Agents API allowlist
|
|
16
|
+
*/
|
|
17
|
+
initialState: State;
|
|
18
|
+
get state(): State;
|
|
19
|
+
sql<T = Record<string, string | number | boolean | null>>(strings: TemplateStringsArray, ...values: (string | number | boolean | null)[]): T[];
|
|
20
|
+
setState(state: State): void;
|
|
21
|
+
onStateUpdate(state: State | undefined, source: Connection | "server"): void;
|
|
22
|
+
/**
|
|
23
|
+
* McpAgent API
|
|
24
|
+
*/
|
|
25
|
+
abstract server: McpServer;
|
|
26
|
+
private transport;
|
|
27
|
+
props: Props;
|
|
28
|
+
initRun: boolean;
|
|
29
|
+
abstract init(): Promise<void>;
|
|
30
|
+
_init(props: Props): Promise<void>;
|
|
31
|
+
onSSE(path: string): Promise<Response>;
|
|
32
|
+
onMCPMessage(request: Request): Promise<Response>;
|
|
33
|
+
static mount(path: string, { binding, corsOptions, }?: {
|
|
34
|
+
binding?: string;
|
|
35
|
+
corsOptions?: CORSOptions;
|
|
36
|
+
}): {
|
|
37
|
+
fetch: (request: Request, env: Record<string, DurableObjectNamespace<McpAgent>>, ctx: ExecutionContext) => Promise<Response>;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { McpAgent };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
import { PartySocket } from
|
|
2
|
-
import { usePartySocket } from
|
|
3
|
-
import { StreamOptions } from
|
|
1
|
+
import { PartySocket } from 'partysocket';
|
|
2
|
+
import { usePartySocket } from 'partysocket/react';
|
|
3
|
+
import { StreamOptions } from './client.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Options for the useAgent hook
|
|
7
7
|
* @template State Type of the Agent's state
|
|
8
8
|
*/
|
|
9
|
-
type UseAgentOptions<State = unknown> = Omit<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
name?: string;
|
|
17
|
-
/** Called when the Agent's state is updated */
|
|
18
|
-
onStateUpdate?: (state: State, source: "server" | "client") => void;
|
|
9
|
+
type UseAgentOptions<State = unknown> = Omit<Parameters<typeof usePartySocket>[0], "party" | "room"> & {
|
|
10
|
+
/** Name of the agent to connect to */
|
|
11
|
+
agent: string;
|
|
12
|
+
/** Name of the specific Agent instance */
|
|
13
|
+
name?: string;
|
|
14
|
+
/** Called when the Agent's state is updated */
|
|
15
|
+
onStateUpdate?: (state: State, source: "server" | "client") => void;
|
|
19
16
|
};
|
|
20
17
|
/**
|
|
21
18
|
* React hook for connecting to an Agent
|
|
@@ -23,17 +20,11 @@ type UseAgentOptions<State = unknown> = Omit<
|
|
|
23
20
|
* @param options Connection options
|
|
24
21
|
* @returns WebSocket connection with setState and call methods
|
|
25
22
|
*/
|
|
26
|
-
declare function useAgent<State = unknown>(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
setState: (state: State) => void;
|
|
32
|
-
call: <T = unknown>(
|
|
33
|
-
method: string,
|
|
34
|
-
args?: unknown[],
|
|
35
|
-
streamOptions?: StreamOptions
|
|
36
|
-
) => Promise<T>;
|
|
23
|
+
declare function useAgent<State = unknown>(options: UseAgentOptions<State>): PartySocket & {
|
|
24
|
+
agent: string;
|
|
25
|
+
name: string;
|
|
26
|
+
setState: (state: State) => void;
|
|
27
|
+
call: <T = unknown>(method: string, args?: unknown[], streamOptions?: StreamOptions) => Promise<T>;
|
|
37
28
|
};
|
|
38
29
|
|
|
39
30
|
export { type UseAgentOptions, useAgent };
|
package/dist/schedule.d.ts
CHANGED
|
@@ -1,53 +1,43 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
type Schedule = z.infer<typeof unstable_scheduleSchema>;
|
|
4
|
-
declare function unstable_getSchedulePrompt(event: {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
declare function unstable_getSchedulePrompt(event: {
|
|
5
|
+
date: Date;
|
|
6
|
+
}): string;
|
|
7
|
+
declare const unstable_scheduleSchema: z.ZodObject<{
|
|
7
8
|
description: z.ZodString;
|
|
8
|
-
when: z.ZodObject<
|
|
9
|
-
{
|
|
9
|
+
when: z.ZodObject<{
|
|
10
10
|
type: z.ZodEnum<["scheduled", "delayed", "cron", "no-schedule"]>;
|
|
11
11
|
date: z.ZodOptional<z.ZodDate>;
|
|
12
12
|
delayInSeconds: z.ZodOptional<z.ZodNumber>;
|
|
13
13
|
cron: z.ZodOptional<z.ZodString>;
|
|
14
|
-
|
|
15
|
-
"strip",
|
|
16
|
-
z.ZodTypeAny,
|
|
17
|
-
{
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
15
|
type: "scheduled" | "delayed" | "cron" | "no-schedule";
|
|
19
16
|
cron?: string | undefined;
|
|
20
17
|
delayInSeconds?: number | undefined;
|
|
21
18
|
date?: Date | undefined;
|
|
22
|
-
|
|
23
|
-
{
|
|
19
|
+
}, {
|
|
24
20
|
type: "scheduled" | "delayed" | "cron" | "no-schedule";
|
|
25
21
|
cron?: string | undefined;
|
|
26
22
|
delayInSeconds?: number | undefined;
|
|
27
23
|
date?: Date | undefined;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
"strip",
|
|
32
|
-
z.ZodTypeAny,
|
|
33
|
-
{
|
|
24
|
+
}>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
26
|
description: string;
|
|
35
27
|
when: {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
type: "scheduled" | "delayed" | "cron" | "no-schedule";
|
|
29
|
+
cron?: string | undefined;
|
|
30
|
+
delayInSeconds?: number | undefined;
|
|
31
|
+
date?: Date | undefined;
|
|
40
32
|
};
|
|
41
|
-
|
|
42
|
-
{
|
|
33
|
+
}, {
|
|
43
34
|
description: string;
|
|
44
35
|
when: {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
type: "scheduled" | "delayed" | "cron" | "no-schedule";
|
|
37
|
+
cron?: string | undefined;
|
|
38
|
+
delayInSeconds?: number | undefined;
|
|
39
|
+
date?: Date | undefined;
|
|
49
40
|
};
|
|
50
|
-
|
|
51
|
-
>;
|
|
41
|
+
}>;
|
|
52
42
|
|
|
53
43
|
export { type Schedule, unstable_getSchedulePrompt, unstable_scheduleSchema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-c3e8618",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -42,6 +42,16 @@
|
|
|
42
42
|
"types": "./dist/schedule.d.ts",
|
|
43
43
|
"require": "./dist/schedule.js",
|
|
44
44
|
"import": "./dist/schedule.js"
|
|
45
|
+
},
|
|
46
|
+
"./mcp": {
|
|
47
|
+
"types": "./dist/mcp/index.d.ts",
|
|
48
|
+
"require": "./dist/mcp/index.js",
|
|
49
|
+
"import": "./dist/mcp/index.js"
|
|
50
|
+
},
|
|
51
|
+
"./mcp/client": {
|
|
52
|
+
"types": "./dist/mcp/client.d.ts",
|
|
53
|
+
"require": "./dist/mcp/client.js",
|
|
54
|
+
"import": "./dist/mcp/client.js"
|
|
45
55
|
}
|
|
46
56
|
},
|
|
47
57
|
"keywords": [],
|
|
@@ -58,8 +68,11 @@
|
|
|
58
68
|
"description": "A home for your AI agents",
|
|
59
69
|
"dependencies": {
|
|
60
70
|
"cron-schedule": "^5.0.4",
|
|
61
|
-
"nanoid": "^5.1.
|
|
62
|
-
"partyserver": "^0.0.
|
|
63
|
-
"partysocket": "
|
|
71
|
+
"nanoid": "^5.1.5",
|
|
72
|
+
"partyserver": "^0.0.66",
|
|
73
|
+
"partysocket": "1.1.3"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@modelcontextprotocol/sdk": "^1.8.0"
|
|
64
77
|
}
|
|
65
78
|
}
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
import { parseCronExpression } from "cron-schedule";
|
|
12
12
|
import { nanoid } from "nanoid";
|
|
13
13
|
|
|
14
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15
|
+
|
|
14
16
|
export type { Connection, WSMessage, ConnectionContext } from "partyserver";
|
|
15
17
|
|
|
16
18
|
import { WorkflowEntrypoint as CFWorkflowEntrypoint } from "cloudflare:workers";
|
|
@@ -168,6 +170,12 @@ const STATE_WAS_CHANGED = "cf_state_was_changed";
|
|
|
168
170
|
|
|
169
171
|
const DEFAULT_STATE = {} as unknown;
|
|
170
172
|
|
|
173
|
+
export const unstable_context = new AsyncLocalStorage<{
|
|
174
|
+
agent: Agent<unknown>;
|
|
175
|
+
connection: Connection | undefined;
|
|
176
|
+
request: Request | undefined;
|
|
177
|
+
}>();
|
|
178
|
+
|
|
171
179
|
/**
|
|
172
180
|
* Base class for creating Agent implementations
|
|
173
181
|
* @template Env Environment type containing bindings
|
|
@@ -256,7 +264,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
256
264
|
return [...this.ctx.storage.sql.exec(query, ...values)] as T[];
|
|
257
265
|
} catch (e) {
|
|
258
266
|
console.error(`failed to execute sql query: ${query}`, e);
|
|
259
|
-
throw e;
|
|
267
|
+
throw this.onError(e);
|
|
260
268
|
}
|
|
261
269
|
}
|
|
262
270
|
constructor(ctx: AgentContext, env: Env) {
|
|
@@ -270,7 +278,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
270
278
|
`;
|
|
271
279
|
|
|
272
280
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
273
|
-
|
|
281
|
+
return this.#tryCatch(async () => {
|
|
274
282
|
// Create alarms table if it doesn't exist
|
|
275
283
|
this.sql`
|
|
276
284
|
CREATE TABLE IF NOT EXISTS cf_agents_schedules (
|
|
@@ -287,97 +295,105 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
287
295
|
|
|
288
296
|
// execute any pending alarms and schedule the next alarm
|
|
289
297
|
await this.alarm();
|
|
290
|
-
}
|
|
291
|
-
console.error(e);
|
|
292
|
-
throw e;
|
|
293
|
-
}
|
|
298
|
+
});
|
|
294
299
|
});
|
|
295
300
|
|
|
296
301
|
const _onMessage = this.onMessage.bind(this);
|
|
297
302
|
this.onMessage = async (connection: Connection, message: WSMessage) => {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
parsed = JSON.parse(message);
|
|
305
|
-
} catch (e) {
|
|
306
|
-
// silently fail and let the onMessage handler handle it
|
|
307
|
-
return _onMessage(connection, message);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (isStateUpdateMessage(parsed)) {
|
|
311
|
-
this.#setStateInternal(parsed.state as State, connection);
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (isRPCRequest(parsed)) {
|
|
316
|
-
try {
|
|
317
|
-
const { id, method, args } = parsed;
|
|
318
|
-
|
|
319
|
-
// Check if method exists and is callable
|
|
320
|
-
const methodFn = this[method as keyof this];
|
|
321
|
-
if (typeof methodFn !== "function") {
|
|
322
|
-
throw new Error(`Method ${method} does not exist`);
|
|
303
|
+
return unstable_context.run(
|
|
304
|
+
{ agent: this, connection, request: undefined },
|
|
305
|
+
async () => {
|
|
306
|
+
if (typeof message !== "string") {
|
|
307
|
+
return this.#tryCatch(() => _onMessage(connection, message));
|
|
323
308
|
}
|
|
324
309
|
|
|
325
|
-
|
|
326
|
-
|
|
310
|
+
let parsed: unknown;
|
|
311
|
+
try {
|
|
312
|
+
parsed = JSON.parse(message);
|
|
313
|
+
} catch (e) {
|
|
314
|
+
// silently fail and let the onMessage handler handle it
|
|
315
|
+
return this.#tryCatch(() => _onMessage(connection, message));
|
|
327
316
|
}
|
|
328
317
|
|
|
329
|
-
|
|
330
|
-
|
|
318
|
+
if (isStateUpdateMessage(parsed)) {
|
|
319
|
+
this.#setStateInternal(parsed.state as State, connection);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
331
322
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
323
|
+
if (isRPCRequest(parsed)) {
|
|
324
|
+
try {
|
|
325
|
+
const { id, method, args } = parsed;
|
|
326
|
+
|
|
327
|
+
// Check if method exists and is callable
|
|
328
|
+
const methodFn = this[method as keyof this];
|
|
329
|
+
if (typeof methodFn !== "function") {
|
|
330
|
+
throw new Error(`Method ${method} does not exist`);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!this.#isCallable(method)) {
|
|
334
|
+
throw new Error(`Method ${method} is not callable`);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
338
|
+
const metadata = callableMetadata.get(methodFn as Function);
|
|
339
|
+
|
|
340
|
+
// For streaming methods, pass a StreamingResponse object
|
|
341
|
+
if (metadata?.streaming) {
|
|
342
|
+
const stream = new StreamingResponse(connection, id);
|
|
343
|
+
await methodFn.apply(this, [stream, ...args]);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// For regular methods, execute and send response
|
|
348
|
+
const result = await methodFn.apply(this, args);
|
|
349
|
+
const response: RPCResponse = {
|
|
350
|
+
type: "rpc",
|
|
351
|
+
id,
|
|
352
|
+
success: true,
|
|
353
|
+
result,
|
|
354
|
+
done: true,
|
|
355
|
+
};
|
|
356
|
+
connection.send(JSON.stringify(response));
|
|
357
|
+
} catch (e) {
|
|
358
|
+
// Send error response
|
|
359
|
+
const response: RPCResponse = {
|
|
360
|
+
type: "rpc",
|
|
361
|
+
id: parsed.id,
|
|
362
|
+
success: false,
|
|
363
|
+
error:
|
|
364
|
+
e instanceof Error ? e.message : "Unknown error occurred",
|
|
365
|
+
};
|
|
366
|
+
connection.send(JSON.stringify(response));
|
|
367
|
+
console.error("RPC error:", e);
|
|
368
|
+
}
|
|
336
369
|
return;
|
|
337
370
|
}
|
|
338
371
|
|
|
339
|
-
|
|
340
|
-
const result = await methodFn.apply(this, args);
|
|
341
|
-
const response: RPCResponse = {
|
|
342
|
-
type: "rpc",
|
|
343
|
-
id,
|
|
344
|
-
success: true,
|
|
345
|
-
result,
|
|
346
|
-
done: true,
|
|
347
|
-
};
|
|
348
|
-
connection.send(JSON.stringify(response));
|
|
349
|
-
} catch (e) {
|
|
350
|
-
// Send error response
|
|
351
|
-
const response: RPCResponse = {
|
|
352
|
-
type: "rpc",
|
|
353
|
-
id: parsed.id,
|
|
354
|
-
success: false,
|
|
355
|
-
error: e instanceof Error ? e.message : "Unknown error occurred",
|
|
356
|
-
};
|
|
357
|
-
connection.send(JSON.stringify(response));
|
|
358
|
-
console.error("RPC error:", e);
|
|
372
|
+
return this.#tryCatch(() => _onMessage(connection, message));
|
|
359
373
|
}
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return _onMessage(connection, message);
|
|
374
|
+
);
|
|
364
375
|
};
|
|
365
376
|
|
|
366
377
|
const _onConnect = this.onConnect.bind(this);
|
|
367
378
|
this.onConnect = (connection: Connection, ctx: ConnectionContext) => {
|
|
368
379
|
// TODO: This is a hack to ensure the state is sent after the connection is established
|
|
369
380
|
// must fix this
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
381
|
+
return unstable_context.run(
|
|
382
|
+
{ agent: this, connection, request: ctx.request },
|
|
383
|
+
async () => {
|
|
384
|
+
setTimeout(() => {
|
|
385
|
+
if (this.state) {
|
|
386
|
+
connection.send(
|
|
387
|
+
JSON.stringify({
|
|
388
|
+
type: "cf_agent_state",
|
|
389
|
+
state: this.state,
|
|
390
|
+
})
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return this.#tryCatch(() => _onConnect(connection, ctx));
|
|
394
|
+
}, 20);
|
|
378
395
|
}
|
|
379
|
-
|
|
380
|
-
}, 20);
|
|
396
|
+
);
|
|
381
397
|
};
|
|
382
398
|
}
|
|
383
399
|
|
|
@@ -398,7 +414,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
398
414
|
}),
|
|
399
415
|
source !== "server" ? [source.id] : []
|
|
400
416
|
);
|
|
401
|
-
this
|
|
417
|
+
return this.#tryCatch(() => {
|
|
418
|
+
const { connection, request } = unstable_context.getStore() || {};
|
|
419
|
+
return unstable_context.run(
|
|
420
|
+
{ agent: this, connection, request },
|
|
421
|
+
async () => {
|
|
422
|
+
return this.onStateUpdate(state, source);
|
|
423
|
+
}
|
|
424
|
+
);
|
|
425
|
+
});
|
|
402
426
|
}
|
|
403
427
|
|
|
404
428
|
/**
|
|
@@ -423,7 +447,47 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
423
447
|
* @param email Email message to process
|
|
424
448
|
*/
|
|
425
449
|
onEmail(email: ForwardableEmailMessage) {
|
|
426
|
-
|
|
450
|
+
return unstable_context.run(
|
|
451
|
+
{ agent: this, connection: undefined, request: undefined },
|
|
452
|
+
async () => {
|
|
453
|
+
console.error("onEmail not implemented");
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async #tryCatch<T>(fn: () => T | Promise<T>) {
|
|
459
|
+
try {
|
|
460
|
+
return await fn();
|
|
461
|
+
} catch (e) {
|
|
462
|
+
throw this.onError(e);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
override onError(
|
|
467
|
+
connection: Connection,
|
|
468
|
+
error: unknown
|
|
469
|
+
): void | Promise<void>;
|
|
470
|
+
override onError(error: unknown): void | Promise<void>;
|
|
471
|
+
override onError(connectionOrError: Connection | unknown, error?: unknown) {
|
|
472
|
+
let theError: unknown;
|
|
473
|
+
if (connectionOrError && error) {
|
|
474
|
+
theError = error;
|
|
475
|
+
// this is a websocket connection error
|
|
476
|
+
console.error(
|
|
477
|
+
"Error on websocket connection:",
|
|
478
|
+
(connectionOrError as Connection).id,
|
|
479
|
+
theError
|
|
480
|
+
);
|
|
481
|
+
console.error(
|
|
482
|
+
"Override onError(connection, error) to handle websocket connection errors"
|
|
483
|
+
);
|
|
484
|
+
} else {
|
|
485
|
+
theError = connectionOrError;
|
|
486
|
+
// this is a server error
|
|
487
|
+
console.error("Error on server:", theError);
|
|
488
|
+
console.error("Override onError(error) to handle server errors");
|
|
489
|
+
}
|
|
490
|
+
throw theError;
|
|
427
491
|
}
|
|
428
492
|
|
|
429
493
|
/**
|
|
@@ -465,7 +529,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
465
529
|
)}, 'scheduled', ${timestamp})
|
|
466
530
|
`;
|
|
467
531
|
|
|
468
|
-
await this
|
|
532
|
+
await this.#scheduleNextAlarm();
|
|
469
533
|
|
|
470
534
|
return {
|
|
471
535
|
id,
|
|
@@ -486,7 +550,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
486
550
|
)}, 'delayed', ${when}, ${timestamp})
|
|
487
551
|
`;
|
|
488
552
|
|
|
489
|
-
await this
|
|
553
|
+
await this.#scheduleNextAlarm();
|
|
490
554
|
|
|
491
555
|
return {
|
|
492
556
|
id,
|
|
@@ -508,7 +572,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
508
572
|
)}, 'cron', ${when}, ${timestamp})
|
|
509
573
|
`;
|
|
510
574
|
|
|
511
|
-
await this
|
|
575
|
+
await this.#scheduleNextAlarm();
|
|
512
576
|
|
|
513
577
|
return {
|
|
514
578
|
id,
|
|
@@ -532,7 +596,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
532
596
|
const result = this.sql<Schedule<string>>`
|
|
533
597
|
SELECT * FROM cf_agents_schedules WHERE id = ${id}
|
|
534
598
|
`;
|
|
535
|
-
if (!result)
|
|
599
|
+
if (!result) {
|
|
600
|
+
console.error(`schedule ${id} not found`);
|
|
601
|
+
return undefined;
|
|
602
|
+
}
|
|
536
603
|
|
|
537
604
|
return { ...result[0], payload: JSON.parse(result[0].payload) as T };
|
|
538
605
|
}
|
|
@@ -545,7 +612,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
545
612
|
*/
|
|
546
613
|
getSchedules<T = string>(
|
|
547
614
|
criteria: {
|
|
548
|
-
description?: string;
|
|
549
615
|
id?: string;
|
|
550
616
|
type?: "scheduled" | "delayed" | "cron";
|
|
551
617
|
timeRange?: { start?: Date; end?: Date };
|
|
@@ -559,11 +625,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
559
625
|
params.push(criteria.id);
|
|
560
626
|
}
|
|
561
627
|
|
|
562
|
-
if (criteria.description) {
|
|
563
|
-
query += " AND description = ?";
|
|
564
|
-
params.push(criteria.description);
|
|
565
|
-
}
|
|
566
|
-
|
|
567
628
|
if (criteria.type) {
|
|
568
629
|
query += " AND type = ?";
|
|
569
630
|
params.push(criteria.type);
|
|
@@ -598,11 +659,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
598
659
|
async cancelSchedule(id: string): Promise<boolean> {
|
|
599
660
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
600
661
|
|
|
601
|
-
await this
|
|
662
|
+
await this.#scheduleNextAlarm();
|
|
602
663
|
return true;
|
|
603
664
|
}
|
|
604
665
|
|
|
605
|
-
|
|
666
|
+
async #scheduleNextAlarm() {
|
|
606
667
|
// Find the next schedule that needs to be executed
|
|
607
668
|
const result = this.sql`
|
|
608
669
|
SELECT time FROM cf_agents_schedules
|
|
@@ -636,16 +697,21 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
636
697
|
console.error(`callback ${row.callback} not found`);
|
|
637
698
|
continue;
|
|
638
699
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
700
|
+
await unstable_context.run(
|
|
701
|
+
{ agent: this, connection: undefined, request: undefined },
|
|
702
|
+
async () => {
|
|
703
|
+
try {
|
|
704
|
+
await (
|
|
705
|
+
callback as (
|
|
706
|
+
payload: unknown,
|
|
707
|
+
schedule: Schedule<unknown>
|
|
708
|
+
) => Promise<void>
|
|
709
|
+
).bind(this)(JSON.parse(row.payload as string), row);
|
|
710
|
+
} catch (e) {
|
|
711
|
+
console.error(`error executing callback "${row.callback}"`, e);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
);
|
|
649
715
|
if (row.type === "cron") {
|
|
650
716
|
// Update next execution time for cron schedules
|
|
651
717
|
const nextExecutionTime = getNextCronTime(row.cron);
|
|
@@ -663,7 +729,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
663
729
|
}
|
|
664
730
|
|
|
665
731
|
// Schedule the next alarm
|
|
666
|
-
await this
|
|
732
|
+
await this.#scheduleNextAlarm();
|
|
667
733
|
}
|
|
668
734
|
|
|
669
735
|
/**
|
|
@@ -683,7 +749,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
683
749
|
* Get all methods marked as callable on this Agent
|
|
684
750
|
* @returns A map of method names to their metadata
|
|
685
751
|
*/
|
|
686
|
-
|
|
752
|
+
#isCallable(method: string): boolean {
|
|
687
753
|
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
688
754
|
return callableMetadata.has(this[method as keyof this] as Function);
|
|
689
755
|
}
|
|
@@ -756,7 +822,8 @@ export async function routeAgentRequest<Env>(
|
|
|
756
822
|
if (
|
|
757
823
|
response &&
|
|
758
824
|
corsHeaders &&
|
|
759
|
-
request.headers.get("upgrade") !== "websocket"
|
|
825
|
+
request.headers.get("upgrade")?.toLowerCase() !== "websocket" &&
|
|
826
|
+
request.headers.get("Upgrade")?.toLowerCase() !== "websocket"
|
|
760
827
|
) {
|
|
761
828
|
response = new Response(response.body, {
|
|
762
829
|
headers: {
|