agents 0.0.0-f913299 → 0.0.0-fbaa8f7
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 +4 -1
- package/dist/ai-chat-agent.js +75 -76
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/{chunk-X6BBKLSC.js → chunk-PDF5WEP4.js} +43 -69
- package/dist/chunk-PDF5WEP4.js.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/index.ts +23 -59
- package/dist/chunk-X6BBKLSC.js.map +0 -1
package/dist/ai-chat-agent.d.ts
CHANGED
|
@@ -11,10 +11,11 @@ declare class AIChatAgent<Env = unknown, State = unknown> extends Agent<
|
|
|
11
11
|
Env,
|
|
12
12
|
State
|
|
13
13
|
> {
|
|
14
|
-
#private;
|
|
15
14
|
/** Array of chat messages for the current conversation */
|
|
16
15
|
messages: Message[];
|
|
17
16
|
constructor(ctx: AgentContext, env: Env);
|
|
17
|
+
private sendChatMessage;
|
|
18
|
+
private broadcastChatMessage;
|
|
18
19
|
onMessage(connection: Connection, message: WSMessage): Promise<void>;
|
|
19
20
|
onRequest(request: Request): Promise<Response>;
|
|
20
21
|
/**
|
|
@@ -30,6 +31,8 @@ declare class AIChatAgent<Env = unknown, State = unknown> extends Agent<
|
|
|
30
31
|
* @param messages Chat messages to save
|
|
31
32
|
*/
|
|
32
33
|
saveMessages(messages: Message[]): Promise<void>;
|
|
34
|
+
private persistMessages;
|
|
35
|
+
private reply;
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
export { AIChatAgent };
|
package/dist/ai-chat-agent.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import
|
|
5
|
-
__privateAdd,
|
|
6
|
-
__privateMethod
|
|
7
|
-
} from "./chunk-HMLY7DHA.js";
|
|
3
|
+
} from "./chunk-PDF5WEP4.js";
|
|
4
|
+
import "./chunk-HMLY7DHA.js";
|
|
8
5
|
|
|
9
6
|
// src/ai-chat-agent.ts
|
|
10
7
|
import { appendResponseMessages } from "ai";
|
|
11
8
|
var decoder = new TextDecoder();
|
|
12
|
-
var _AIChatAgent_instances, sendChatMessage_fn, broadcastChatMessage_fn, tryCatch_fn, persistMessages_fn, reply_fn;
|
|
13
9
|
var AIChatAgent = class extends Agent {
|
|
14
10
|
constructor(ctx, env) {
|
|
15
11
|
super(ctx, env);
|
|
16
|
-
__privateAdd(this, _AIChatAgent_instances);
|
|
17
12
|
this.sql`create table if not exists cf_ai_chat_agent_messages (
|
|
18
13
|
id text primary key,
|
|
19
14
|
message text not null,
|
|
@@ -23,6 +18,18 @@ var AIChatAgent = class extends Agent {
|
|
|
23
18
|
return JSON.parse(row.message);
|
|
24
19
|
});
|
|
25
20
|
}
|
|
21
|
+
sendChatMessage(connection, message) {
|
|
22
|
+
try {
|
|
23
|
+
connection.send(JSON.stringify(message));
|
|
24
|
+
} catch (e) {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
broadcastChatMessage(message, exclude) {
|
|
28
|
+
try {
|
|
29
|
+
this.broadcast(JSON.stringify(message), exclude);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
26
33
|
async onMessage(connection, message) {
|
|
27
34
|
if (typeof message === "string") {
|
|
28
35
|
let data;
|
|
@@ -49,45 +56,46 @@ var AIChatAgent = class extends Agent {
|
|
|
49
56
|
// duplex
|
|
50
57
|
} = data.init;
|
|
51
58
|
const { messages } = JSON.parse(body);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
this.broadcastChatMessage(
|
|
60
|
+
{
|
|
61
|
+
type: "cf_agent_chat_messages",
|
|
62
|
+
messages
|
|
63
|
+
},
|
|
64
|
+
[connection.id]
|
|
65
|
+
);
|
|
66
|
+
await this.persistMessages(messages, [connection.id]);
|
|
67
|
+
const response = await this.onChatMessage(async ({ response: response2 }) => {
|
|
68
|
+
const finalMessages = appendResponseMessages({
|
|
69
|
+
messages,
|
|
70
|
+
responseMessages: response2.messages
|
|
64
71
|
});
|
|
65
|
-
|
|
66
|
-
await __privateMethod(this, _AIChatAgent_instances, reply_fn).call(this, data.id, response);
|
|
67
|
-
}
|
|
72
|
+
await this.persistMessages(finalMessages, [connection.id]);
|
|
68
73
|
});
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
if (response) {
|
|
75
|
+
await this.reply(data.id, response);
|
|
76
|
+
}
|
|
77
|
+
} else if (data.type === "cf_agent_chat_clear") {
|
|
71
78
|
this.sql`delete from cf_ai_chat_agent_messages`;
|
|
72
79
|
this.messages = [];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
this.broadcastChatMessage(
|
|
81
|
+
{
|
|
82
|
+
type: "cf_agent_chat_clear"
|
|
83
|
+
},
|
|
84
|
+
[connection.id]
|
|
85
|
+
);
|
|
76
86
|
} else if (data.type === "cf_agent_chat_messages") {
|
|
77
|
-
await
|
|
87
|
+
await this.persistMessages(data.messages, [connection.id]);
|
|
78
88
|
}
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
async onRequest(request) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return super.onRequest(request);
|
|
90
|
-
});
|
|
92
|
+
if (request.url.endsWith("/get-messages")) {
|
|
93
|
+
const messages = (this.sql`select * from cf_ai_chat_agent_messages` || []).map((row) => {
|
|
94
|
+
return JSON.parse(row.message);
|
|
95
|
+
});
|
|
96
|
+
return new Response(JSON.stringify(messages));
|
|
97
|
+
}
|
|
98
|
+
return super.onRequest(request);
|
|
91
99
|
}
|
|
92
100
|
/**
|
|
93
101
|
* Handle incoming chat messages and generate a response
|
|
@@ -104,13 +112,13 @@ var AIChatAgent = class extends Agent {
|
|
|
104
112
|
* @param messages Chat messages to save
|
|
105
113
|
*/
|
|
106
114
|
async saveMessages(messages) {
|
|
107
|
-
await
|
|
115
|
+
await this.persistMessages(messages);
|
|
108
116
|
const response = await this.onChatMessage(async ({ response: response2 }) => {
|
|
109
117
|
const finalMessages = appendResponseMessages({
|
|
110
118
|
messages,
|
|
111
119
|
responseMessages: response2.messages
|
|
112
120
|
});
|
|
113
|
-
await
|
|
121
|
+
await this.persistMessages(finalMessages, []);
|
|
114
122
|
});
|
|
115
123
|
if (response) {
|
|
116
124
|
for await (const chunk of response.body) {
|
|
@@ -119,50 +127,41 @@ var AIChatAgent = class extends Agent {
|
|
|
119
127
|
response.body?.cancel();
|
|
120
128
|
}
|
|
121
129
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
persistMessages_fn = async function(messages, excludeBroadcastIds = []) {
|
|
138
|
-
this.sql`delete from cf_ai_chat_agent_messages`;
|
|
139
|
-
for (const message of messages) {
|
|
140
|
-
this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${message.id},${JSON.stringify(message)})`;
|
|
130
|
+
async persistMessages(messages, excludeBroadcastIds = []) {
|
|
131
|
+
this.sql`delete from cf_ai_chat_agent_messages`;
|
|
132
|
+
for (const message of messages) {
|
|
133
|
+
this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${message.id},${JSON.stringify(message)})`;
|
|
134
|
+
}
|
|
135
|
+
this.messages = messages;
|
|
136
|
+
this.broadcastChatMessage(
|
|
137
|
+
{
|
|
138
|
+
type: "cf_agent_chat_messages",
|
|
139
|
+
messages
|
|
140
|
+
},
|
|
141
|
+
excludeBroadcastIds
|
|
142
|
+
);
|
|
141
143
|
}
|
|
142
|
-
|
|
143
|
-
__privateMethod(this, _AIChatAgent_instances, broadcastChatMessage_fn).call(this, {
|
|
144
|
-
type: "cf_agent_chat_messages",
|
|
145
|
-
messages
|
|
146
|
-
}, excludeBroadcastIds);
|
|
147
|
-
};
|
|
148
|
-
reply_fn = async function(id, response) {
|
|
149
|
-
return __privateMethod(this, _AIChatAgent_instances, tryCatch_fn).call(this, async () => {
|
|
144
|
+
async reply(id, response) {
|
|
150
145
|
for await (const chunk of response.body) {
|
|
151
146
|
const body = decoder.decode(chunk);
|
|
152
|
-
|
|
147
|
+
for (const conn of this.getConnections()) {
|
|
148
|
+
this.sendChatMessage(conn, {
|
|
149
|
+
id,
|
|
150
|
+
type: "cf_agent_use_chat_response",
|
|
151
|
+
body,
|
|
152
|
+
done: false
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const conn of this.getConnections()) {
|
|
157
|
+
this.sendChatMessage(conn, {
|
|
153
158
|
id,
|
|
154
159
|
type: "cf_agent_use_chat_response",
|
|
155
|
-
body,
|
|
156
|
-
done:
|
|
160
|
+
body: "",
|
|
161
|
+
done: true
|
|
157
162
|
});
|
|
158
163
|
}
|
|
159
|
-
|
|
160
|
-
id,
|
|
161
|
-
type: "cf_agent_use_chat_response",
|
|
162
|
-
body: "",
|
|
163
|
-
done: true
|
|
164
|
-
});
|
|
165
|
-
});
|
|
164
|
+
}
|
|
166
165
|
};
|
|
167
166
|
export {
|
|
168
167
|
AIChatAgent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport type {\n Message as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet,\n} from \"ai\";\nimport { appendResponseMessages } from \"ai\";\nimport type { OutgoingMessage, IncomingMessage } from \"./ai-types\";\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n this.messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n }\n\n
|
|
1
|
+
{"version":3,"sources":["../src/ai-chat-agent.ts"],"sourcesContent":["import { Agent, type AgentContext, type Connection, type WSMessage } from \"./\";\nimport type {\n Message as ChatMessage,\n StreamTextOnFinishCallback,\n ToolSet,\n} from \"ai\";\nimport { appendResponseMessages } from \"ai\";\nimport type { OutgoingMessage, IncomingMessage } from \"./ai-types\";\nconst decoder = new TextDecoder();\n\n/**\n * Extension of Agent with built-in chat capabilities\n * @template Env Environment type containing bindings\n */\nexport class AIChatAgent<Env = unknown, State = unknown> extends Agent<\n Env,\n State\n> {\n /** Array of chat messages for the current conversation */\n messages: ChatMessage[];\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n this.sql`create table if not exists cf_ai_chat_agent_messages (\n id text primary key,\n message text not null,\n created_at datetime default current_timestamp\n )`;\n this.messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n }\n\n private sendChatMessage(connection: Connection, message: OutgoingMessage) {\n try {\n connection.send(JSON.stringify(message));\n } catch (e) {\n // silently ignore\n }\n }\n\n private broadcastChatMessage(message: OutgoingMessage, exclude?: string[]) {\n try {\n this.broadcast(JSON.stringify(message), exclude);\n } catch (e) {\n // silently ignore\n }\n }\n\n override async onMessage(connection: Connection, message: WSMessage) {\n if (typeof message === \"string\") {\n let data: IncomingMessage;\n try {\n data = JSON.parse(message) as IncomingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (\n data.type === \"cf_agent_use_chat_request\" &&\n data.init.method === \"POST\"\n ) {\n const {\n method,\n keepalive,\n headers,\n body, // we're reading this\n redirect,\n integrity,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher,\n // duplex\n } = data.init;\n const { messages } = JSON.parse(body as string);\n this.broadcastChatMessage(\n {\n type: \"cf_agent_chat_messages\",\n messages,\n },\n [connection.id]\n );\n await this.persistMessages(messages, [connection.id]);\n const response = await this.onChatMessage(async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages,\n });\n\n await this.persistMessages(finalMessages, [connection.id]);\n });\n if (response) {\n await this.reply(data.id, response);\n }\n } else if (data.type === \"cf_agent_chat_clear\") {\n this.sql`delete from cf_ai_chat_agent_messages`;\n this.messages = [];\n this.broadcastChatMessage(\n {\n type: \"cf_agent_chat_clear\",\n },\n [connection.id]\n );\n } else if (data.type === \"cf_agent_chat_messages\") {\n // replace the messages with the new ones\n await this.persistMessages(data.messages, [connection.id]);\n }\n }\n }\n\n override async onRequest(request: Request): Promise<Response> {\n if (request.url.endsWith(\"/get-messages\")) {\n const messages = (\n this.sql`select * from cf_ai_chat_agent_messages` || []\n ).map((row) => {\n return JSON.parse(row.message as string);\n });\n return new Response(JSON.stringify(messages));\n }\n return super.onRequest(request);\n }\n\n /**\n * Handle incoming chat messages and generate a response\n * @param onFinish Callback to be called when the response is finished\n * @returns Response to send to the client or undefined\n */\n async onChatMessage(\n onFinish: StreamTextOnFinishCallback<ToolSet>\n ): Promise<Response | undefined> {\n throw new Error(\n \"recieved a chat message, override onChatMessage and return a Response to send to the client\"\n );\n }\n\n /**\n * Save messages on the server side and trigger AI response\n * @param messages Chat messages to save\n */\n async saveMessages(messages: ChatMessage[]) {\n await this.persistMessages(messages);\n const response = await this.onChatMessage(async ({ response }) => {\n const finalMessages = appendResponseMessages({\n messages,\n responseMessages: response.messages,\n });\n\n await this.persistMessages(finalMessages, []);\n });\n if (response) {\n // we're just going to drain the body\n // @ts-ignore TODO: fix this type error\n for await (const chunk of response.body!) {\n decoder.decode(chunk);\n }\n response.body?.cancel();\n }\n }\n\n private async persistMessages(\n messages: ChatMessage[],\n excludeBroadcastIds: string[] = []\n ) {\n this.sql`delete from cf_ai_chat_agent_messages`;\n for (const message of messages) {\n this.sql`insert into cf_ai_chat_agent_messages (id, message) values (${\n message.id\n },${JSON.stringify(message)})`;\n }\n this.messages = messages;\n this.broadcastChatMessage(\n {\n type: \"cf_agent_chat_messages\",\n messages: messages,\n },\n excludeBroadcastIds\n );\n }\n\n private async reply(id: string, response: Response) {\n // now take chunks out from dataStreamResponse and send them to the client\n\n // @ts-expect-error TODO: fix this type error\n for await (const chunk of response.body!) {\n const body = decoder.decode(chunk);\n\n for (const conn of this.getConnections()) {\n this.sendChatMessage(conn, {\n id,\n type: \"cf_agent_use_chat_response\",\n body,\n done: false,\n });\n }\n }\n\n for (const conn of this.getConnections()) {\n this.sendChatMessage(conn, {\n id,\n type: \"cf_agent_use_chat_response\",\n body: \"\",\n done: true,\n });\n }\n }\n}\n"],"mappings":"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","names":["response"]}
|
|
@@ -38,7 +38,7 @@ function getNextCronTime(cron) {
|
|
|
38
38
|
var STATE_ROW_ID = "cf_state_row_id";
|
|
39
39
|
var STATE_WAS_CHANGED = "cf_state_was_changed";
|
|
40
40
|
var DEFAULT_STATE = {};
|
|
41
|
-
var _state, _Agent_instances, setStateInternal_fn
|
|
41
|
+
var _state, _Agent_instances, setStateInternal_fn;
|
|
42
42
|
var Agent = class extends Server {
|
|
43
43
|
constructor(ctx, env) {
|
|
44
44
|
super(ctx, env);
|
|
@@ -56,7 +56,7 @@ var Agent = class extends Server {
|
|
|
56
56
|
)
|
|
57
57
|
`;
|
|
58
58
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
59
|
-
|
|
59
|
+
try {
|
|
60
60
|
this.sql`
|
|
61
61
|
CREATE TABLE IF NOT EXISTS cf_agents_schedules (
|
|
62
62
|
id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
|
|
@@ -70,18 +70,21 @@ var Agent = class extends Server {
|
|
|
70
70
|
)
|
|
71
71
|
`;
|
|
72
72
|
await this.alarm();
|
|
73
|
-
})
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.error(e);
|
|
75
|
+
throw e;
|
|
76
|
+
}
|
|
74
77
|
});
|
|
75
78
|
const _onMessage = this.onMessage.bind(this);
|
|
76
79
|
this.onMessage = async (connection, message) => {
|
|
77
80
|
if (typeof message !== "string") {
|
|
78
|
-
return
|
|
81
|
+
return _onMessage(connection, message);
|
|
79
82
|
}
|
|
80
83
|
let parsed;
|
|
81
84
|
try {
|
|
82
85
|
parsed = JSON.parse(message);
|
|
83
86
|
} catch (e) {
|
|
84
|
-
return
|
|
87
|
+
return _onMessage(connection, message);
|
|
85
88
|
}
|
|
86
89
|
if (isStateUpdateMessage(parsed)) {
|
|
87
90
|
__privateMethod(this, _Agent_instances, setStateInternal_fn).call(this, parsed.state, connection);
|
|
@@ -94,7 +97,7 @@ var Agent = class extends Server {
|
|
|
94
97
|
if (typeof methodFn !== "function") {
|
|
95
98
|
throw new Error(`Method ${method} does not exist`);
|
|
96
99
|
}
|
|
97
|
-
if (!
|
|
100
|
+
if (!this.isCallable(method)) {
|
|
98
101
|
throw new Error(`Method ${method} is not callable`);
|
|
99
102
|
}
|
|
100
103
|
const metadata = callableMetadata.get(methodFn);
|
|
@@ -124,7 +127,7 @@ var Agent = class extends Server {
|
|
|
124
127
|
}
|
|
125
128
|
return;
|
|
126
129
|
}
|
|
127
|
-
return
|
|
130
|
+
return _onMessage(connection, message);
|
|
128
131
|
};
|
|
129
132
|
const _onConnect = this.onConnect.bind(this);
|
|
130
133
|
this.onConnect = (connection, ctx2) => {
|
|
@@ -137,7 +140,7 @@ var Agent = class extends Server {
|
|
|
137
140
|
})
|
|
138
141
|
);
|
|
139
142
|
}
|
|
140
|
-
|
|
143
|
+
_onConnect(connection, ctx2);
|
|
141
144
|
}, 20);
|
|
142
145
|
};
|
|
143
146
|
}
|
|
@@ -183,7 +186,7 @@ var Agent = class extends Server {
|
|
|
183
186
|
return [...this.ctx.storage.sql.exec(query, ...values)];
|
|
184
187
|
} catch (e) {
|
|
185
188
|
console.error(`failed to execute sql query: ${query}`, e);
|
|
186
|
-
throw
|
|
189
|
+
throw e;
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
/**
|
|
@@ -207,25 +210,6 @@ var Agent = class extends Server {
|
|
|
207
210
|
onEmail(email) {
|
|
208
211
|
throw new Error("Not implemented");
|
|
209
212
|
}
|
|
210
|
-
onError(connectionOrError, error) {
|
|
211
|
-
let theError;
|
|
212
|
-
if (connectionOrError && error) {
|
|
213
|
-
theError = error;
|
|
214
|
-
console.error(
|
|
215
|
-
"Error on websocket connection:",
|
|
216
|
-
connectionOrError.id,
|
|
217
|
-
theError
|
|
218
|
-
);
|
|
219
|
-
console.error(
|
|
220
|
-
"Override onError(connection, error) to handle websocket connection errors"
|
|
221
|
-
);
|
|
222
|
-
} else {
|
|
223
|
-
theError = connectionOrError;
|
|
224
|
-
console.error("Error on server:", theError);
|
|
225
|
-
console.error("Override onError(error) to handle server errors");
|
|
226
|
-
}
|
|
227
|
-
throw theError;
|
|
228
|
-
}
|
|
229
213
|
/**
|
|
230
214
|
* Render content (not implemented in base class)
|
|
231
215
|
*/
|
|
@@ -256,7 +240,7 @@ var Agent = class extends Server {
|
|
|
256
240
|
payload
|
|
257
241
|
)}, 'scheduled', ${timestamp})
|
|
258
242
|
`;
|
|
259
|
-
await
|
|
243
|
+
await this.scheduleNextAlarm();
|
|
260
244
|
return {
|
|
261
245
|
id,
|
|
262
246
|
callback,
|
|
@@ -274,7 +258,7 @@ var Agent = class extends Server {
|
|
|
274
258
|
payload
|
|
275
259
|
)}, 'delayed', ${when}, ${timestamp})
|
|
276
260
|
`;
|
|
277
|
-
await
|
|
261
|
+
await this.scheduleNextAlarm();
|
|
278
262
|
return {
|
|
279
263
|
id,
|
|
280
264
|
callback,
|
|
@@ -293,7 +277,7 @@ var Agent = class extends Server {
|
|
|
293
277
|
payload
|
|
294
278
|
)}, 'cron', ${when}, ${timestamp})
|
|
295
279
|
`;
|
|
296
|
-
await
|
|
280
|
+
await this.scheduleNextAlarm();
|
|
297
281
|
return {
|
|
298
282
|
id,
|
|
299
283
|
callback,
|
|
@@ -315,10 +299,7 @@ var Agent = class extends Server {
|
|
|
315
299
|
const result = this.sql`
|
|
316
300
|
SELECT * FROM cf_agents_schedules WHERE id = ${id}
|
|
317
301
|
`;
|
|
318
|
-
if (!result)
|
|
319
|
-
console.error(`schedule ${id} not found`);
|
|
320
|
-
return void 0;
|
|
321
|
-
}
|
|
302
|
+
if (!result) return void 0;
|
|
322
303
|
return { ...result[0], payload: JSON.parse(result[0].payload) };
|
|
323
304
|
}
|
|
324
305
|
/**
|
|
@@ -364,9 +345,22 @@ var Agent = class extends Server {
|
|
|
364
345
|
*/
|
|
365
346
|
async cancelSchedule(id) {
|
|
366
347
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
367
|
-
await
|
|
348
|
+
await this.scheduleNextAlarm();
|
|
368
349
|
return true;
|
|
369
350
|
}
|
|
351
|
+
async scheduleNextAlarm() {
|
|
352
|
+
const result = this.sql`
|
|
353
|
+
SELECT time FROM cf_agents_schedules
|
|
354
|
+
WHERE time > ${Math.floor(Date.now() / 1e3)}
|
|
355
|
+
ORDER BY time ASC
|
|
356
|
+
LIMIT 1
|
|
357
|
+
`;
|
|
358
|
+
if (!result) return;
|
|
359
|
+
if (result.length > 0 && "time" in result[0]) {
|
|
360
|
+
const nextTime = result[0].time * 1e3;
|
|
361
|
+
await this.ctx.storage.setAlarm(nextTime);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
370
364
|
/**
|
|
371
365
|
* Method called when an alarm fires
|
|
372
366
|
* Executes any scheduled tasks that are due
|
|
@@ -383,9 +377,9 @@ var Agent = class extends Server {
|
|
|
383
377
|
continue;
|
|
384
378
|
}
|
|
385
379
|
try {
|
|
386
|
-
|
|
380
|
+
callback.bind(this)(JSON.parse(row.payload), row);
|
|
387
381
|
} catch (e) {
|
|
388
|
-
console.error(`error executing callback
|
|
382
|
+
console.error(`error executing callback ${row.callback}`, e);
|
|
389
383
|
}
|
|
390
384
|
if (row.type === "cron") {
|
|
391
385
|
const nextExecutionTime = getNextCronTime(row.cron);
|
|
@@ -399,7 +393,7 @@ var Agent = class extends Server {
|
|
|
399
393
|
`;
|
|
400
394
|
}
|
|
401
395
|
}
|
|
402
|
-
await
|
|
396
|
+
await this.scheduleNextAlarm();
|
|
403
397
|
}
|
|
404
398
|
/**
|
|
405
399
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
@@ -410,6 +404,13 @@ var Agent = class extends Server {
|
|
|
410
404
|
await this.ctx.storage.deleteAlarm();
|
|
411
405
|
await this.ctx.storage.deleteAll();
|
|
412
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Get all methods marked as callable on this Agent
|
|
409
|
+
* @returns A map of method names to their metadata
|
|
410
|
+
*/
|
|
411
|
+
isCallable(method) {
|
|
412
|
+
return callableMetadata.has(this[method]);
|
|
413
|
+
}
|
|
413
414
|
};
|
|
414
415
|
_state = new WeakMap();
|
|
415
416
|
_Agent_instances = new WeakSet();
|
|
@@ -430,34 +431,7 @@ setStateInternal_fn = function(state, source = "server") {
|
|
|
430
431
|
}),
|
|
431
432
|
source !== "server" ? [source.id] : []
|
|
432
433
|
);
|
|
433
|
-
|
|
434
|
-
};
|
|
435
|
-
tryCatch_fn = async function(fn) {
|
|
436
|
-
try {
|
|
437
|
-
return await fn();
|
|
438
|
-
} catch (e) {
|
|
439
|
-
throw this.onError(e);
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
scheduleNextAlarm_fn = async function() {
|
|
443
|
-
const result = this.sql`
|
|
444
|
-
SELECT time FROM cf_agents_schedules
|
|
445
|
-
WHERE time > ${Math.floor(Date.now() / 1e3)}
|
|
446
|
-
ORDER BY time ASC
|
|
447
|
-
LIMIT 1
|
|
448
|
-
`;
|
|
449
|
-
if (!result) return;
|
|
450
|
-
if (result.length > 0 && "time" in result[0]) {
|
|
451
|
-
const nextTime = result[0].time * 1e3;
|
|
452
|
-
await this.ctx.storage.setAlarm(nextTime);
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
/**
|
|
456
|
-
* Get all methods marked as callable on this Agent
|
|
457
|
-
* @returns A map of method names to their metadata
|
|
458
|
-
*/
|
|
459
|
-
isCallable_fn = function(method) {
|
|
460
|
-
return callableMetadata.has(this[method]);
|
|
434
|
+
this.onStateUpdate(state, source);
|
|
461
435
|
};
|
|
462
436
|
/**
|
|
463
437
|
* Agent configuration options
|
|
@@ -492,7 +466,7 @@ async function routeAgentRequest(request, env, options) {
|
|
|
492
466
|
...options
|
|
493
467
|
}
|
|
494
468
|
);
|
|
495
|
-
if (response && corsHeaders && request.headers.get("upgrade")
|
|
469
|
+
if (response && corsHeaders && request.headers.get("upgrade") !== "websocket") {
|
|
496
470
|
response = new Response(response.body, {
|
|
497
471
|
headers: {
|
|
498
472
|
...response.headers,
|
|
@@ -565,4 +539,4 @@ export {
|
|
|
565
539
|
getAgentByName,
|
|
566
540
|
StreamingResponse
|
|
567
541
|
};
|
|
568
|
-
//# sourceMappingURL=chunk-
|
|
542
|
+
//# sourceMappingURL=chunk-PDF5WEP4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n Server,\n routePartykitRequest,\n type PartyServerOptions,\n getServerByName,\n type Connection,\n type ConnectionContext,\n type WSMessage,\n} from \"partyserver\";\n\nimport { parseCronExpression } from \"cron-schedule\";\nimport { nanoid } from \"nanoid\";\n\nexport type { Connection, WSMessage, ConnectionContext } from \"partyserver\";\n\nimport { WorkflowEntrypoint as CFWorkflowEntrypoint } from \"cloudflare:workers\";\n\n/**\n * RPC request message from client\n */\nexport type RPCRequest = {\n type: \"rpc\";\n id: string;\n method: string;\n args: unknown[];\n};\n\n/**\n * State update message from client\n */\nexport type StateUpdateMessage = {\n type: \"cf_agent_state\";\n state: unknown;\n};\n\n/**\n * RPC response message to client\n */\nexport type RPCResponse = {\n type: \"rpc\";\n id: string;\n} & (\n | {\n success: true;\n result: unknown;\n done?: false;\n }\n | {\n success: true;\n result: unknown;\n done: true;\n }\n | {\n success: false;\n error: string;\n }\n);\n\n/**\n * Type guard for RPC request messages\n */\nfunction isRPCRequest(msg: unknown): msg is RPCRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === \"rpc\" &&\n \"id\" in msg &&\n typeof msg.id === \"string\" &&\n \"method\" in msg &&\n typeof msg.method === \"string\" &&\n \"args\" in msg &&\n Array.isArray((msg as RPCRequest).args)\n );\n}\n\n/**\n * Type guard for state update messages\n */\nfunction isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === \"cf_agent_state\" &&\n \"state\" in msg\n );\n}\n\n/**\n * Metadata for a callable method\n */\nexport type CallableMetadata = {\n /** Optional description of what the method does */\n description?: string;\n /** Whether the method supports streaming responses */\n streaming?: boolean;\n};\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nconst callableMetadata = new Map<Function, CallableMetadata>();\n\n/**\n * Decorator that marks a method as callable by clients\n * @param metadata Optional metadata about the callable method\n */\nexport function unstable_callable(metadata: CallableMetadata = {}) {\n return function callableDecorator<This, Args extends unknown[], Return>(\n target: (this: This, ...args: Args) => Return,\n context: ClassMethodDecoratorContext\n ) {\n if (!callableMetadata.has(target)) {\n callableMetadata.set(target, metadata);\n }\n\n return target;\n };\n}\n\n/**\n * A class for creating workflow entry points that can be used with Cloudflare Workers\n */\nexport class WorkflowEntrypoint extends CFWorkflowEntrypoint {}\n\n/**\n * Represents a scheduled task within an Agent\n * @template T Type of the payload data\n */\nexport type Schedule<T = string> = {\n /** Unique identifier for the schedule */\n id: string;\n /** Name of the method to be called */\n callback: string;\n /** Data to be passed to the callback */\n payload: T;\n} & (\n | {\n /** Type of schedule for one-time execution at a specific time */\n type: \"scheduled\";\n /** Timestamp when the task should execute */\n time: number;\n }\n | {\n /** Type of schedule for delayed execution */\n type: \"delayed\";\n /** Timestamp when the task should execute */\n time: number;\n /** Number of seconds to delay execution */\n delayInSeconds: number;\n }\n | {\n /** Type of schedule for recurring execution based on cron expression */\n type: \"cron\";\n /** Timestamp for the next execution */\n time: number;\n /** Cron expression defining the schedule */\n cron: string;\n }\n);\n\nfunction getNextCronTime(cron: string) {\n const interval = parseCronExpression(cron);\n return interval.getNextDate();\n}\n\nconst STATE_ROW_ID = \"cf_state_row_id\";\nconst STATE_WAS_CHANGED = \"cf_state_was_changed\";\n\nconst DEFAULT_STATE = {} as unknown;\n\n/**\n * Base class for creating Agent implementations\n * @template Env Environment type containing bindings\n * @template State State type to store within the Agent\n */\nexport class Agent<Env, State = unknown> extends Server<Env> {\n #state = DEFAULT_STATE as State;\n\n /**\n * Initial state for the Agent\n * Override to provide default state values\n */\n initialState: State = DEFAULT_STATE as State;\n\n /**\n * Current state of the Agent\n */\n get state(): State {\n if (this.#state !== DEFAULT_STATE) {\n // state was previously set, and populated internal state\n return this.#state;\n }\n // looks like this is the first time the state is being accessed\n // check if the state was set in a previous life\n const wasChanged = this.sql<{ state: \"true\" | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}\n `;\n\n // ok, let's pick up the actual state from the db\n const result = this.sql<{ state: State | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}\n `;\n\n if (\n wasChanged[0]?.state === \"true\" ||\n // we do this check for people who updated their code before we shipped wasChanged\n result[0]?.state\n ) {\n const state = result[0]?.state as string; // could be null?\n\n this.#state = JSON.parse(state);\n return this.#state;\n }\n\n // ok, this is the first time the state is being accessed\n // and the state was not set in a previous life\n // so we need to set the initial state (if provided)\n if (this.initialState === DEFAULT_STATE) {\n // no initial state provided, so we return undefined\n return undefined as State;\n }\n // initial state provided, so we set the state,\n // update db and return the initial state\n this.setState(this.initialState);\n return this.initialState;\n }\n\n /**\n * Agent configuration options\n */\n static options = {\n /** Whether the Agent should hibernate when inactive */\n hibernate: true, // default to hibernate\n };\n\n /**\n * Execute SQL queries against the Agent's database\n * @template T Type of the returned rows\n * @param strings SQL query template strings\n * @param values Values to be inserted into the query\n * @returns Array of query results\n */\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n let query = \"\";\n try {\n // Construct the SQL query with placeholders\n query = strings.reduce(\n (acc, str, i) => acc + str + (i < values.length ? \"?\" : \"\"),\n \"\"\n );\n\n // Execute the SQL query with the provided values\n return [...this.ctx.storage.sql.exec(query, ...values)] as T[];\n } catch (e) {\n console.error(`failed to execute sql query: ${query}`, e);\n throw e;\n }\n }\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_state (\n id TEXT PRIMARY KEY NOT NULL,\n state TEXT\n )\n `;\n\n void this.ctx.blockConcurrencyWhile(async () => {\n try {\n // Create alarms table if it doesn't exist\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_schedules (\n id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),\n callback TEXT,\n payload TEXT,\n type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron')),\n time INTEGER,\n delayInSeconds INTEGER,\n cron TEXT,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n // execute any pending alarms and schedule the next alarm\n await this.alarm();\n } catch (e) {\n console.error(e);\n throw e;\n }\n });\n\n const _onMessage = this.onMessage.bind(this);\n this.onMessage = async (connection: Connection, message: WSMessage) => {\n if (typeof message !== \"string\") {\n return _onMessage(connection, message);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(message);\n } catch (e) {\n // silently fail and let the onMessage handler handle it\n return _onMessage(connection, message);\n }\n\n if (isStateUpdateMessage(parsed)) {\n this.#setStateInternal(parsed.state as State, connection);\n return;\n }\n\n if (isRPCRequest(parsed)) {\n try {\n const { id, method, args } = parsed;\n\n // Check if method exists and is callable\n const methodFn = this[method as keyof this];\n if (typeof methodFn !== \"function\") {\n throw new Error(`Method ${method} does not exist`);\n }\n\n if (!this.isCallable(method)) {\n throw new Error(`Method ${method} is not callable`);\n }\n\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n const metadata = callableMetadata.get(methodFn as Function);\n\n // For streaming methods, pass a StreamingResponse object\n if (metadata?.streaming) {\n const stream = new StreamingResponse(connection, id);\n await methodFn.apply(this, [stream, ...args]);\n return;\n }\n\n // For regular methods, execute and send response\n const result = await methodFn.apply(this, args);\n const response: RPCResponse = {\n type: \"rpc\",\n id,\n success: true,\n result,\n done: true,\n };\n connection.send(JSON.stringify(response));\n } catch (e) {\n // Send error response\n const response: RPCResponse = {\n type: \"rpc\",\n id: parsed.id,\n success: false,\n error: e instanceof Error ? e.message : \"Unknown error occurred\",\n };\n connection.send(JSON.stringify(response));\n console.error(\"RPC error:\", e);\n }\n return;\n }\n\n return _onMessage(connection, message);\n };\n\n const _onConnect = this.onConnect.bind(this);\n this.onConnect = (connection: Connection, ctx: ConnectionContext) => {\n // TODO: This is a hack to ensure the state is sent after the connection is established\n // must fix this\n setTimeout(() => {\n if (this.state) {\n connection.send(\n JSON.stringify({\n type: \"cf_agent_state\",\n state: this.state,\n })\n );\n }\n _onConnect(connection, ctx);\n }, 20);\n };\n }\n\n #setStateInternal(state: State, source: Connection | \"server\" = \"server\") {\n this.#state = state;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_ROW_ID}, ${JSON.stringify(state)})\n `;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_WAS_CHANGED}, ${JSON.stringify(true)})\n `;\n this.broadcast(\n JSON.stringify({\n type: \"cf_agent_state\",\n state: state,\n }),\n source !== \"server\" ? [source.id] : []\n );\n this.onStateUpdate(state, source);\n }\n\n /**\n * Update the Agent's state\n * @param state New state to set\n */\n setState(state: State) {\n this.#setStateInternal(state, \"server\");\n }\n\n /**\n * Called when the Agent's state is updated\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates\n }\n\n /**\n * Called when the Agent receives an email\n * @param email Email message to process\n */\n onEmail(email: ForwardableEmailMessage) {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Render content (not implemented in base class)\n */\n render() {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Schedule a task to be executed in the future\n * @template T Type of the payload data\n * @param when When to execute the task (Date, seconds delay, or cron expression)\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async schedule<T = string>(\n when: Date | string | number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n const id = nanoid(9);\n\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n if (when instanceof Date) {\n const timestamp = Math.floor(when.getTime() / 1000);\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'scheduled', ${timestamp})\n `;\n\n await this.scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n time: timestamp,\n type: \"scheduled\",\n };\n }\n if (typeof when === \"number\") {\n const time = new Date(Date.now() + when * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, delayInSeconds, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'delayed', ${when}, ${timestamp})\n `;\n\n await this.scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n delayInSeconds: when,\n time: timestamp,\n type: \"delayed\",\n };\n }\n if (typeof when === \"string\") {\n const nextExecutionTime = getNextCronTime(when);\n const timestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, cron, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'cron', ${when}, ${timestamp})\n `;\n\n await this.scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n cron: when,\n time: timestamp,\n type: \"cron\",\n };\n }\n throw new Error(\"Invalid schedule type\");\n }\n\n /**\n * Get a scheduled task by ID\n * @template T Type of the payload data\n * @param id ID of the scheduled task\n * @returns The Schedule object or undefined if not found\n */\n async getSchedule<T = string>(id: string): Promise<Schedule<T> | undefined> {\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE id = ${id}\n `;\n if (!result) return undefined;\n\n return { ...result[0], payload: JSON.parse(result[0].payload) as T };\n }\n\n /**\n * Get scheduled tasks matching the given criteria\n * @template T Type of the payload data\n * @param criteria Criteria to filter schedules\n * @returns Array of matching Schedule objects\n */\n getSchedules<T = string>(\n criteria: {\n description?: string;\n id?: string;\n type?: \"scheduled\" | \"delayed\" | \"cron\";\n timeRange?: { start?: Date; end?: Date };\n } = {}\n ): Schedule<T>[] {\n let query = \"SELECT * FROM cf_agents_schedules WHERE 1=1\";\n const params = [];\n\n if (criteria.id) {\n query += \" AND id = ?\";\n params.push(criteria.id);\n }\n\n if (criteria.description) {\n query += \" AND description = ?\";\n params.push(criteria.description);\n }\n\n if (criteria.type) {\n query += \" AND type = ?\";\n params.push(criteria.type);\n }\n\n if (criteria.timeRange) {\n query += \" AND time >= ? AND time <= ?\";\n const start = criteria.timeRange.start || new Date(0);\n const end = criteria.timeRange.end || new Date(999999999999999);\n params.push(\n Math.floor(start.getTime() / 1000),\n Math.floor(end.getTime() / 1000)\n );\n }\n\n const result = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray()\n .map((row) => ({\n ...row,\n payload: JSON.parse(row.payload as string) as T,\n })) as Schedule<T>[];\n\n return result;\n }\n\n /**\n * Cancel a scheduled task\n * @param id ID of the task to cancel\n * @returns true if the task was cancelled, false otherwise\n */\n async cancelSchedule(id: string): Promise<boolean> {\n this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;\n\n await this.scheduleNextAlarm();\n return true;\n }\n\n private async scheduleNextAlarm() {\n // Find the next schedule that needs to be executed\n const result = this.sql`\n SELECT time FROM cf_agents_schedules \n WHERE time > ${Math.floor(Date.now() / 1000)}\n ORDER BY time ASC \n LIMIT 1\n `;\n if (!result) return;\n\n if (result.length > 0 && \"time\" in result[0]) {\n const nextTime = (result[0].time as number) * 1000;\n await this.ctx.storage.setAlarm(nextTime);\n }\n }\n\n /**\n * Method called when an alarm fires\n * Executes any scheduled tasks that are due\n */\n async alarm() {\n const now = Math.floor(Date.now() / 1000);\n\n // Get all schedules that should be executed now\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE time <= ${now}\n `;\n\n for (const row of result || []) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n continue;\n }\n try {\n (\n callback as (\n payload: unknown,\n schedule: Schedule<unknown>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n } catch (e) {\n console.error(`error executing callback ${row.callback}`, e);\n }\n if (row.type === \"cron\") {\n // Update next execution time for cron schedules\n const nextExecutionTime = getNextCronTime(row.cron);\n const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else {\n // Delete one-time schedules after execution\n this.sql`\n DELETE FROM cf_agents_schedules WHERE id = ${row.id}\n `;\n }\n }\n\n // Schedule the next alarm\n await this.scheduleNextAlarm();\n }\n\n /**\n * Destroy the Agent, removing all state and scheduled tasks\n */\n async destroy() {\n // drop all tables\n this.sql`DROP TABLE IF EXISTS cf_agents_state`;\n this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;\n\n // delete all alarms\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n }\n\n /**\n * Get all methods marked as callable on this Agent\n * @returns A map of method names to their metadata\n */\n private isCallable(method: string): boolean {\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n return callableMetadata.has(this[method as keyof this] as Function);\n }\n}\n\n/**\n * Namespace for creating Agent instances\n * @template Agentic Type of the Agent class\n */\nexport type AgentNamespace<Agentic extends Agent<unknown>> =\n DurableObjectNamespace<Agentic>;\n\n/**\n * Agent's durable context\n */\nexport type AgentContext = DurableObjectState;\n\n/**\n * Configuration options for Agent routing\n */\nexport type AgentOptions<Env> = PartyServerOptions<Env> & {\n /**\n * Whether to enable CORS for the Agent\n */\n cors?: boolean | HeadersInit | undefined;\n};\n\n/**\n * Route a request to the appropriate Agent\n * @param request Request to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n * @returns Response from the Agent or undefined if no route matched\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n) {\n const corsHeaders =\n options?.cors === true\n ? {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, HEAD, OPTIONS\",\n \"Access-Control-Allow-Credentials\": \"true\",\n \"Access-Control-Max-Age\": \"86400\",\n }\n : options?.cors;\n\n if (request.method === \"OPTIONS\") {\n if (corsHeaders) {\n return new Response(null, {\n headers: corsHeaders,\n });\n }\n console.warn(\n \"Received an OPTIONS request, but cors was not enabled. Pass `cors: true` or `cors: { ...custom cors headers }` to routeAgentRequest to enable CORS.\"\n );\n }\n\n let response = await routePartykitRequest(\n request,\n env as Record<string, unknown>,\n {\n prefix: \"agents\",\n ...(options as PartyServerOptions<Record<string, unknown>>),\n }\n );\n\n if (\n response &&\n corsHeaders &&\n request.headers.get(\"upgrade\") !== \"websocket\"\n ) {\n response = new Response(response.body, {\n headers: {\n ...response.headers,\n ...corsHeaders,\n },\n });\n }\n return response;\n}\n\n/**\n * Route an email to the appropriate Agent\n * @param email Email message to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n */\nexport async function routeAgentEmail<Env>(\n email: ForwardableEmailMessage,\n env: Env,\n options?: AgentOptions<Env>\n): Promise<void> {}\n\n/**\n * Get or create an Agent by name\n * @template Env Environment type containing bindings\n * @template T Type of the Agent class\n * @param namespace Agent namespace\n * @param name Name of the Agent instance\n * @param options Options for Agent creation\n * @returns Promise resolving to an Agent instance stub\n */\nexport function getAgentByName<Env, T extends Agent<Env>>(\n namespace: AgentNamespace<T>,\n name: string,\n options?: {\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n }\n) {\n return getServerByName<Env, T>(namespace, name, options);\n}\n\n/**\n * A wrapper for streaming responses in callable methods\n */\nexport class StreamingResponse {\n #connection: Connection;\n #id: string;\n #closed = false;\n\n constructor(connection: Connection, id: string) {\n this.#connection = connection;\n this.#id = id;\n }\n\n /**\n * Send a chunk of data to the client\n * @param chunk The data to send\n */\n send(chunk: unknown) {\n if (this.#closed) {\n throw new Error(\"StreamingResponse is already closed\");\n }\n const response: RPCResponse = {\n type: \"rpc\",\n id: this.#id,\n success: true,\n result: chunk,\n done: false,\n };\n this.#connection.send(JSON.stringify(response));\n }\n\n /**\n * End the stream and send the final chunk (if any)\n * @param finalChunk Optional final chunk of data to send\n */\n end(finalChunk?: unknown) {\n if (this.#closed) {\n throw new Error(\"StreamingResponse is already closed\");\n }\n this.#closed = true;\n const response: RPCResponse = {\n type: \"rpc\",\n id: this.#id,\n success: true,\n result: finalChunk,\n done: true,\n };\n this.#connection.send(JSON.stringify(response));\n }\n}\n"],"mappings":"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","names":["ctx"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -149,8 +149,6 @@ declare class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
149
149
|
* @param email Email message to process
|
|
150
150
|
*/
|
|
151
151
|
onEmail(email: ForwardableEmailMessage): void;
|
|
152
|
-
onError(connection: Connection, error: unknown): void | Promise<void>;
|
|
153
|
-
onError(error: unknown): void | Promise<void>;
|
|
154
152
|
/**
|
|
155
153
|
* Render content (not implemented in base class)
|
|
156
154
|
*/
|
|
@@ -196,6 +194,7 @@ declare class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
196
194
|
* @returns true if the task was cancelled, false otherwise
|
|
197
195
|
*/
|
|
198
196
|
cancelSchedule(id: string): Promise<boolean>;
|
|
197
|
+
private scheduleNextAlarm;
|
|
199
198
|
/**
|
|
200
199
|
* Method called when an alarm fires
|
|
201
200
|
* Executes any scheduled tasks that are due
|
|
@@ -205,6 +204,11 @@ declare class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
205
204
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
206
205
|
*/
|
|
207
206
|
destroy(): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Get all methods marked as callable on this Agent
|
|
209
|
+
* @returns A map of method names to their metadata
|
|
210
|
+
*/
|
|
211
|
+
private isCallable;
|
|
208
212
|
}
|
|
209
213
|
/**
|
|
210
214
|
* Namespace for creating Agent instances
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-fbaa8f7",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"description": "A home for your AI agents",
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"cron-schedule": "^5.0.4",
|
|
61
|
-
"nanoid": "^5.1.
|
|
61
|
+
"nanoid": "^5.1.3",
|
|
62
62
|
"partyserver": "^0.0.65",
|
|
63
63
|
"partysocket": "0.0.0-548c226"
|
|
64
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -256,7 +256,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
256
256
|
return [...this.ctx.storage.sql.exec(query, ...values)] as T[];
|
|
257
257
|
} catch (e) {
|
|
258
258
|
console.error(`failed to execute sql query: ${query}`, e);
|
|
259
|
-
throw
|
|
259
|
+
throw e;
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
constructor(ctx: AgentContext, env: Env) {
|
|
@@ -270,7 +270,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
270
270
|
`;
|
|
271
271
|
|
|
272
272
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
273
|
-
|
|
273
|
+
try {
|
|
274
274
|
// Create alarms table if it doesn't exist
|
|
275
275
|
this.sql`
|
|
276
276
|
CREATE TABLE IF NOT EXISTS cf_agents_schedules (
|
|
@@ -287,13 +287,16 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
287
287
|
|
|
288
288
|
// execute any pending alarms and schedule the next alarm
|
|
289
289
|
await this.alarm();
|
|
290
|
-
})
|
|
290
|
+
} catch (e) {
|
|
291
|
+
console.error(e);
|
|
292
|
+
throw e;
|
|
293
|
+
}
|
|
291
294
|
});
|
|
292
295
|
|
|
293
296
|
const _onMessage = this.onMessage.bind(this);
|
|
294
297
|
this.onMessage = async (connection: Connection, message: WSMessage) => {
|
|
295
298
|
if (typeof message !== "string") {
|
|
296
|
-
return
|
|
299
|
+
return _onMessage(connection, message);
|
|
297
300
|
}
|
|
298
301
|
|
|
299
302
|
let parsed: unknown;
|
|
@@ -301,7 +304,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
301
304
|
parsed = JSON.parse(message);
|
|
302
305
|
} catch (e) {
|
|
303
306
|
// silently fail and let the onMessage handler handle it
|
|
304
|
-
return
|
|
307
|
+
return _onMessage(connection, message);
|
|
305
308
|
}
|
|
306
309
|
|
|
307
310
|
if (isStateUpdateMessage(parsed)) {
|
|
@@ -319,7 +322,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
319
322
|
throw new Error(`Method ${method} does not exist`);
|
|
320
323
|
}
|
|
321
324
|
|
|
322
|
-
if (!this
|
|
325
|
+
if (!this.isCallable(method)) {
|
|
323
326
|
throw new Error(`Method ${method} is not callable`);
|
|
324
327
|
}
|
|
325
328
|
|
|
@@ -357,7 +360,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
357
360
|
return;
|
|
358
361
|
}
|
|
359
362
|
|
|
360
|
-
return
|
|
363
|
+
return _onMessage(connection, message);
|
|
361
364
|
};
|
|
362
365
|
|
|
363
366
|
const _onConnect = this.onConnect.bind(this);
|
|
@@ -373,7 +376,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
373
376
|
})
|
|
374
377
|
);
|
|
375
378
|
}
|
|
376
|
-
|
|
379
|
+
_onConnect(connection, ctx);
|
|
377
380
|
}, 20);
|
|
378
381
|
};
|
|
379
382
|
}
|
|
@@ -395,7 +398,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
395
398
|
}),
|
|
396
399
|
source !== "server" ? [source.id] : []
|
|
397
400
|
);
|
|
398
|
-
|
|
401
|
+
this.onStateUpdate(state, source);
|
|
399
402
|
}
|
|
400
403
|
|
|
401
404
|
/**
|
|
@@ -423,41 +426,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
423
426
|
throw new Error("Not implemented");
|
|
424
427
|
}
|
|
425
428
|
|
|
426
|
-
async #tryCatch<T>(fn: () => T | Promise<T>) {
|
|
427
|
-
try {
|
|
428
|
-
return await fn();
|
|
429
|
-
} catch (e) {
|
|
430
|
-
throw this.onError(e);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
override onError(
|
|
435
|
-
connection: Connection,
|
|
436
|
-
error: unknown
|
|
437
|
-
): void | Promise<void>;
|
|
438
|
-
override onError(error: unknown): void | Promise<void>;
|
|
439
|
-
override onError(connectionOrError: Connection | unknown, error?: unknown) {
|
|
440
|
-
let theError: unknown;
|
|
441
|
-
if (connectionOrError && error) {
|
|
442
|
-
theError = error;
|
|
443
|
-
// this is a websocket connection error
|
|
444
|
-
console.error(
|
|
445
|
-
"Error on websocket connection:",
|
|
446
|
-
(connectionOrError as Connection).id,
|
|
447
|
-
theError
|
|
448
|
-
);
|
|
449
|
-
console.error(
|
|
450
|
-
"Override onError(connection, error) to handle websocket connection errors"
|
|
451
|
-
);
|
|
452
|
-
} else {
|
|
453
|
-
theError = connectionOrError;
|
|
454
|
-
// this is a server error
|
|
455
|
-
console.error("Error on server:", theError);
|
|
456
|
-
console.error("Override onError(error) to handle server errors");
|
|
457
|
-
}
|
|
458
|
-
throw theError;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
429
|
/**
|
|
462
430
|
* Render content (not implemented in base class)
|
|
463
431
|
*/
|
|
@@ -497,7 +465,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
497
465
|
)}, 'scheduled', ${timestamp})
|
|
498
466
|
`;
|
|
499
467
|
|
|
500
|
-
await this
|
|
468
|
+
await this.scheduleNextAlarm();
|
|
501
469
|
|
|
502
470
|
return {
|
|
503
471
|
id,
|
|
@@ -518,7 +486,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
518
486
|
)}, 'delayed', ${when}, ${timestamp})
|
|
519
487
|
`;
|
|
520
488
|
|
|
521
|
-
await this
|
|
489
|
+
await this.scheduleNextAlarm();
|
|
522
490
|
|
|
523
491
|
return {
|
|
524
492
|
id,
|
|
@@ -540,7 +508,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
540
508
|
)}, 'cron', ${when}, ${timestamp})
|
|
541
509
|
`;
|
|
542
510
|
|
|
543
|
-
await this
|
|
511
|
+
await this.scheduleNextAlarm();
|
|
544
512
|
|
|
545
513
|
return {
|
|
546
514
|
id,
|
|
@@ -564,10 +532,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
564
532
|
const result = this.sql<Schedule<string>>`
|
|
565
533
|
SELECT * FROM cf_agents_schedules WHERE id = ${id}
|
|
566
534
|
`;
|
|
567
|
-
if (!result)
|
|
568
|
-
console.error(`schedule ${id} not found`);
|
|
569
|
-
return undefined;
|
|
570
|
-
}
|
|
535
|
+
if (!result) return undefined;
|
|
571
536
|
|
|
572
537
|
return { ...result[0], payload: JSON.parse(result[0].payload) as T };
|
|
573
538
|
}
|
|
@@ -633,11 +598,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
633
598
|
async cancelSchedule(id: string): Promise<boolean> {
|
|
634
599
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
635
600
|
|
|
636
|
-
await this
|
|
601
|
+
await this.scheduleNextAlarm();
|
|
637
602
|
return true;
|
|
638
603
|
}
|
|
639
604
|
|
|
640
|
-
async
|
|
605
|
+
private async scheduleNextAlarm() {
|
|
641
606
|
// Find the next schedule that needs to be executed
|
|
642
607
|
const result = this.sql`
|
|
643
608
|
SELECT time FROM cf_agents_schedules
|
|
@@ -672,14 +637,14 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
672
637
|
continue;
|
|
673
638
|
}
|
|
674
639
|
try {
|
|
675
|
-
|
|
640
|
+
(
|
|
676
641
|
callback as (
|
|
677
642
|
payload: unknown,
|
|
678
643
|
schedule: Schedule<unknown>
|
|
679
644
|
) => Promise<void>
|
|
680
645
|
).bind(this)(JSON.parse(row.payload as string), row);
|
|
681
646
|
} catch (e) {
|
|
682
|
-
console.error(`error executing callback
|
|
647
|
+
console.error(`error executing callback ${row.callback}`, e);
|
|
683
648
|
}
|
|
684
649
|
if (row.type === "cron") {
|
|
685
650
|
// Update next execution time for cron schedules
|
|
@@ -698,7 +663,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
698
663
|
}
|
|
699
664
|
|
|
700
665
|
// Schedule the next alarm
|
|
701
|
-
await this
|
|
666
|
+
await this.scheduleNextAlarm();
|
|
702
667
|
}
|
|
703
668
|
|
|
704
669
|
/**
|
|
@@ -718,7 +683,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
|
|
|
718
683
|
* Get all methods marked as callable on this Agent
|
|
719
684
|
* @returns A map of method names to their metadata
|
|
720
685
|
*/
|
|
721
|
-
|
|
686
|
+
private isCallable(method: string): boolean {
|
|
722
687
|
// biome-ignore lint/complexity/noBannedTypes: <explanation>
|
|
723
688
|
return callableMetadata.has(this[method as keyof this] as Function);
|
|
724
689
|
}
|
|
@@ -791,8 +756,7 @@ export async function routeAgentRequest<Env>(
|
|
|
791
756
|
if (
|
|
792
757
|
response &&
|
|
793
758
|
corsHeaders &&
|
|
794
|
-
request.headers.get("upgrade")
|
|
795
|
-
request.headers.get("Upgrade")?.toLowerCase() !== "websocket"
|
|
759
|
+
request.headers.get("upgrade") !== "websocket"
|
|
796
760
|
) {
|
|
797
761
|
response = new Response(response.body, {
|
|
798
762
|
headers: {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n Server,\n routePartykitRequest,\n type PartyServerOptions,\n getServerByName,\n type Connection,\n type ConnectionContext,\n type WSMessage,\n} from \"partyserver\";\n\nimport { parseCronExpression } from \"cron-schedule\";\nimport { nanoid } from \"nanoid\";\n\nexport type { Connection, WSMessage, ConnectionContext } from \"partyserver\";\n\nimport { WorkflowEntrypoint as CFWorkflowEntrypoint } from \"cloudflare:workers\";\n\n/**\n * RPC request message from client\n */\nexport type RPCRequest = {\n type: \"rpc\";\n id: string;\n method: string;\n args: unknown[];\n};\n\n/**\n * State update message from client\n */\nexport type StateUpdateMessage = {\n type: \"cf_agent_state\";\n state: unknown;\n};\n\n/**\n * RPC response message to client\n */\nexport type RPCResponse = {\n type: \"rpc\";\n id: string;\n} & (\n | {\n success: true;\n result: unknown;\n done?: false;\n }\n | {\n success: true;\n result: unknown;\n done: true;\n }\n | {\n success: false;\n error: string;\n }\n);\n\n/**\n * Type guard for RPC request messages\n */\nfunction isRPCRequest(msg: unknown): msg is RPCRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === \"rpc\" &&\n \"id\" in msg &&\n typeof msg.id === \"string\" &&\n \"method\" in msg &&\n typeof msg.method === \"string\" &&\n \"args\" in msg &&\n Array.isArray((msg as RPCRequest).args)\n );\n}\n\n/**\n * Type guard for state update messages\n */\nfunction isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === \"cf_agent_state\" &&\n \"state\" in msg\n );\n}\n\n/**\n * Metadata for a callable method\n */\nexport type CallableMetadata = {\n /** Optional description of what the method does */\n description?: string;\n /** Whether the method supports streaming responses */\n streaming?: boolean;\n};\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nconst callableMetadata = new Map<Function, CallableMetadata>();\n\n/**\n * Decorator that marks a method as callable by clients\n * @param metadata Optional metadata about the callable method\n */\nexport function unstable_callable(metadata: CallableMetadata = {}) {\n return function callableDecorator<This, Args extends unknown[], Return>(\n target: (this: This, ...args: Args) => Return,\n context: ClassMethodDecoratorContext\n ) {\n if (!callableMetadata.has(target)) {\n callableMetadata.set(target, metadata);\n }\n\n return target;\n };\n}\n\n/**\n * A class for creating workflow entry points that can be used with Cloudflare Workers\n */\nexport class WorkflowEntrypoint extends CFWorkflowEntrypoint {}\n\n/**\n * Represents a scheduled task within an Agent\n * @template T Type of the payload data\n */\nexport type Schedule<T = string> = {\n /** Unique identifier for the schedule */\n id: string;\n /** Name of the method to be called */\n callback: string;\n /** Data to be passed to the callback */\n payload: T;\n} & (\n | {\n /** Type of schedule for one-time execution at a specific time */\n type: \"scheduled\";\n /** Timestamp when the task should execute */\n time: number;\n }\n | {\n /** Type of schedule for delayed execution */\n type: \"delayed\";\n /** Timestamp when the task should execute */\n time: number;\n /** Number of seconds to delay execution */\n delayInSeconds: number;\n }\n | {\n /** Type of schedule for recurring execution based on cron expression */\n type: \"cron\";\n /** Timestamp for the next execution */\n time: number;\n /** Cron expression defining the schedule */\n cron: string;\n }\n);\n\nfunction getNextCronTime(cron: string) {\n const interval = parseCronExpression(cron);\n return interval.getNextDate();\n}\n\nconst STATE_ROW_ID = \"cf_state_row_id\";\nconst STATE_WAS_CHANGED = \"cf_state_was_changed\";\n\nconst DEFAULT_STATE = {} as unknown;\n\n/**\n * Base class for creating Agent implementations\n * @template Env Environment type containing bindings\n * @template State State type to store within the Agent\n */\nexport class Agent<Env, State = unknown> extends Server<Env> {\n #state = DEFAULT_STATE as State;\n\n /**\n * Initial state for the Agent\n * Override to provide default state values\n */\n initialState: State = DEFAULT_STATE as State;\n\n /**\n * Current state of the Agent\n */\n get state(): State {\n if (this.#state !== DEFAULT_STATE) {\n // state was previously set, and populated internal state\n return this.#state;\n }\n // looks like this is the first time the state is being accessed\n // check if the state was set in a previous life\n const wasChanged = this.sql<{ state: \"true\" | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}\n `;\n\n // ok, let's pick up the actual state from the db\n const result = this.sql<{ state: State | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}\n `;\n\n if (\n wasChanged[0]?.state === \"true\" ||\n // we do this check for people who updated their code before we shipped wasChanged\n result[0]?.state\n ) {\n const state = result[0]?.state as string; // could be null?\n\n this.#state = JSON.parse(state);\n return this.#state;\n }\n\n // ok, this is the first time the state is being accessed\n // and the state was not set in a previous life\n // so we need to set the initial state (if provided)\n if (this.initialState === DEFAULT_STATE) {\n // no initial state provided, so we return undefined\n return undefined as State;\n }\n // initial state provided, so we set the state,\n // update db and return the initial state\n this.setState(this.initialState);\n return this.initialState;\n }\n\n /**\n * Agent configuration options\n */\n static options = {\n /** Whether the Agent should hibernate when inactive */\n hibernate: true, // default to hibernate\n };\n\n /**\n * Execute SQL queries against the Agent's database\n * @template T Type of the returned rows\n * @param strings SQL query template strings\n * @param values Values to be inserted into the query\n * @returns Array of query results\n */\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n let query = \"\";\n try {\n // Construct the SQL query with placeholders\n query = strings.reduce(\n (acc, str, i) => acc + str + (i < values.length ? \"?\" : \"\"),\n \"\"\n );\n\n // Execute the SQL query with the provided values\n return [...this.ctx.storage.sql.exec(query, ...values)] as T[];\n } catch (e) {\n console.error(`failed to execute sql query: ${query}`, e);\n throw this.onError(e);\n }\n }\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_state (\n id TEXT PRIMARY KEY NOT NULL,\n state TEXT\n )\n `;\n\n void this.ctx.blockConcurrencyWhile(async () => {\n return this.#tryCatch(async () => {\n // Create alarms table if it doesn't exist\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_schedules (\n id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),\n callback TEXT,\n payload TEXT,\n type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron')),\n time INTEGER,\n delayInSeconds INTEGER,\n cron TEXT,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n // execute any pending alarms and schedule the next alarm\n await this.alarm();\n });\n });\n\n const _onMessage = this.onMessage.bind(this);\n this.onMessage = async (connection: Connection, message: WSMessage) => {\n if (typeof message !== \"string\") {\n return this.#tryCatch(() => _onMessage(connection, message));\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(message);\n } catch (e) {\n // silently fail and let the onMessage handler handle it\n return this.#tryCatch(() => _onMessage(connection, message));\n }\n\n if (isStateUpdateMessage(parsed)) {\n this.#setStateInternal(parsed.state as State, connection);\n return;\n }\n\n if (isRPCRequest(parsed)) {\n try {\n const { id, method, args } = parsed;\n\n // Check if method exists and is callable\n const methodFn = this[method as keyof this];\n if (typeof methodFn !== \"function\") {\n throw new Error(`Method ${method} does not exist`);\n }\n\n if (!this.#isCallable(method)) {\n throw new Error(`Method ${method} is not callable`);\n }\n\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n const metadata = callableMetadata.get(methodFn as Function);\n\n // For streaming methods, pass a StreamingResponse object\n if (metadata?.streaming) {\n const stream = new StreamingResponse(connection, id);\n await methodFn.apply(this, [stream, ...args]);\n return;\n }\n\n // For regular methods, execute and send response\n const result = await methodFn.apply(this, args);\n const response: RPCResponse = {\n type: \"rpc\",\n id,\n success: true,\n result,\n done: true,\n };\n connection.send(JSON.stringify(response));\n } catch (e) {\n // Send error response\n const response: RPCResponse = {\n type: \"rpc\",\n id: parsed.id,\n success: false,\n error: e instanceof Error ? e.message : \"Unknown error occurred\",\n };\n connection.send(JSON.stringify(response));\n console.error(\"RPC error:\", e);\n }\n return;\n }\n\n return this.#tryCatch(() => _onMessage(connection, message));\n };\n\n const _onConnect = this.onConnect.bind(this);\n this.onConnect = (connection: Connection, ctx: ConnectionContext) => {\n // TODO: This is a hack to ensure the state is sent after the connection is established\n // must fix this\n setTimeout(() => {\n if (this.state) {\n connection.send(\n JSON.stringify({\n type: \"cf_agent_state\",\n state: this.state,\n })\n );\n }\n return this.#tryCatch(() => _onConnect(connection, ctx));\n }, 20);\n };\n }\n\n #setStateInternal(state: State, source: Connection | \"server\" = \"server\") {\n this.#state = state;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_ROW_ID}, ${JSON.stringify(state)})\n `;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_WAS_CHANGED}, ${JSON.stringify(true)})\n `;\n this.broadcast(\n JSON.stringify({\n type: \"cf_agent_state\",\n state: state,\n }),\n source !== \"server\" ? [source.id] : []\n );\n return this.#tryCatch(() => this.onStateUpdate(state, source));\n }\n\n /**\n * Update the Agent's state\n * @param state New state to set\n */\n setState(state: State) {\n this.#setStateInternal(state, \"server\");\n }\n\n /**\n * Called when the Agent's state is updated\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates\n }\n\n /**\n * Called when the Agent receives an email\n * @param email Email message to process\n */\n onEmail(email: ForwardableEmailMessage) {\n throw new Error(\"Not implemented\");\n }\n\n async #tryCatch<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n override onError(\n connection: Connection,\n error: unknown\n ): void | Promise<void>;\n override onError(error: unknown): void | Promise<void>;\n override onError(connectionOrError: Connection | unknown, error?: unknown) {\n let theError: unknown;\n if (connectionOrError && error) {\n theError = error;\n // this is a websocket connection error\n console.error(\n \"Error on websocket connection:\",\n (connectionOrError as Connection).id,\n theError\n );\n console.error(\n \"Override onError(connection, error) to handle websocket connection errors\"\n );\n } else {\n theError = connectionOrError;\n // this is a server error\n console.error(\"Error on server:\", theError);\n console.error(\"Override onError(error) to handle server errors\");\n }\n throw theError;\n }\n\n /**\n * Render content (not implemented in base class)\n */\n render() {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Schedule a task to be executed in the future\n * @template T Type of the payload data\n * @param when When to execute the task (Date, seconds delay, or cron expression)\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async schedule<T = string>(\n when: Date | string | number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n const id = nanoid(9);\n\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n if (when instanceof Date) {\n const timestamp = Math.floor(when.getTime() / 1000);\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'scheduled', ${timestamp})\n `;\n\n await this.#scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n time: timestamp,\n type: \"scheduled\",\n };\n }\n if (typeof when === \"number\") {\n const time = new Date(Date.now() + when * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, delayInSeconds, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'delayed', ${when}, ${timestamp})\n `;\n\n await this.#scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n delayInSeconds: when,\n time: timestamp,\n type: \"delayed\",\n };\n }\n if (typeof when === \"string\") {\n const nextExecutionTime = getNextCronTime(when);\n const timestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, cron, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'cron', ${when}, ${timestamp})\n `;\n\n await this.#scheduleNextAlarm();\n\n return {\n id,\n callback: callback,\n payload: payload as T,\n cron: when,\n time: timestamp,\n type: \"cron\",\n };\n }\n throw new Error(\"Invalid schedule type\");\n }\n\n /**\n * Get a scheduled task by ID\n * @template T Type of the payload data\n * @param id ID of the scheduled task\n * @returns The Schedule object or undefined if not found\n */\n async getSchedule<T = string>(id: string): Promise<Schedule<T> | undefined> {\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE id = ${id}\n `;\n if (!result) {\n console.error(`schedule ${id} not found`);\n return undefined;\n }\n\n return { ...result[0], payload: JSON.parse(result[0].payload) as T };\n }\n\n /**\n * Get scheduled tasks matching the given criteria\n * @template T Type of the payload data\n * @param criteria Criteria to filter schedules\n * @returns Array of matching Schedule objects\n */\n getSchedules<T = string>(\n criteria: {\n description?: string;\n id?: string;\n type?: \"scheduled\" | \"delayed\" | \"cron\";\n timeRange?: { start?: Date; end?: Date };\n } = {}\n ): Schedule<T>[] {\n let query = \"SELECT * FROM cf_agents_schedules WHERE 1=1\";\n const params = [];\n\n if (criteria.id) {\n query += \" AND id = ?\";\n params.push(criteria.id);\n }\n\n if (criteria.description) {\n query += \" AND description = ?\";\n params.push(criteria.description);\n }\n\n if (criteria.type) {\n query += \" AND type = ?\";\n params.push(criteria.type);\n }\n\n if (criteria.timeRange) {\n query += \" AND time >= ? AND time <= ?\";\n const start = criteria.timeRange.start || new Date(0);\n const end = criteria.timeRange.end || new Date(999999999999999);\n params.push(\n Math.floor(start.getTime() / 1000),\n Math.floor(end.getTime() / 1000)\n );\n }\n\n const result = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray()\n .map((row) => ({\n ...row,\n payload: JSON.parse(row.payload as string) as T,\n })) as Schedule<T>[];\n\n return result;\n }\n\n /**\n * Cancel a scheduled task\n * @param id ID of the task to cancel\n * @returns true if the task was cancelled, false otherwise\n */\n async cancelSchedule(id: string): Promise<boolean> {\n this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;\n\n await this.#scheduleNextAlarm();\n return true;\n }\n\n async #scheduleNextAlarm() {\n // Find the next schedule that needs to be executed\n const result = this.sql`\n SELECT time FROM cf_agents_schedules \n WHERE time > ${Math.floor(Date.now() / 1000)}\n ORDER BY time ASC \n LIMIT 1\n `;\n if (!result) return;\n\n if (result.length > 0 && \"time\" in result[0]) {\n const nextTime = (result[0].time as number) * 1000;\n await this.ctx.storage.setAlarm(nextTime);\n }\n }\n\n /**\n * Method called when an alarm fires\n * Executes any scheduled tasks that are due\n */\n async alarm() {\n const now = Math.floor(Date.now() / 1000);\n\n // Get all schedules that should be executed now\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE time <= ${now}\n `;\n\n for (const row of result || []) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n continue;\n }\n try {\n await (\n callback as (\n payload: unknown,\n schedule: Schedule<unknown>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n } catch (e) {\n console.error(`error executing callback \"${row.callback}\"`, e);\n }\n if (row.type === \"cron\") {\n // Update next execution time for cron schedules\n const nextExecutionTime = getNextCronTime(row.cron);\n const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else {\n // Delete one-time schedules after execution\n this.sql`\n DELETE FROM cf_agents_schedules WHERE id = ${row.id}\n `;\n }\n }\n\n // Schedule the next alarm\n await this.#scheduleNextAlarm();\n }\n\n /**\n * Destroy the Agent, removing all state and scheduled tasks\n */\n async destroy() {\n // drop all tables\n this.sql`DROP TABLE IF EXISTS cf_agents_state`;\n this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;\n\n // delete all alarms\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n }\n\n /**\n * Get all methods marked as callable on this Agent\n * @returns A map of method names to their metadata\n */\n #isCallable(method: string): boolean {\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n return callableMetadata.has(this[method as keyof this] as Function);\n }\n}\n\n/**\n * Namespace for creating Agent instances\n * @template Agentic Type of the Agent class\n */\nexport type AgentNamespace<Agentic extends Agent<unknown>> =\n DurableObjectNamespace<Agentic>;\n\n/**\n * Agent's durable context\n */\nexport type AgentContext = DurableObjectState;\n\n/**\n * Configuration options for Agent routing\n */\nexport type AgentOptions<Env> = PartyServerOptions<Env> & {\n /**\n * Whether to enable CORS for the Agent\n */\n cors?: boolean | HeadersInit | undefined;\n};\n\n/**\n * Route a request to the appropriate Agent\n * @param request Request to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n * @returns Response from the Agent or undefined if no route matched\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n) {\n const corsHeaders =\n options?.cors === true\n ? {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, HEAD, OPTIONS\",\n \"Access-Control-Allow-Credentials\": \"true\",\n \"Access-Control-Max-Age\": \"86400\",\n }\n : options?.cors;\n\n if (request.method === \"OPTIONS\") {\n if (corsHeaders) {\n return new Response(null, {\n headers: corsHeaders,\n });\n }\n console.warn(\n \"Received an OPTIONS request, but cors was not enabled. Pass `cors: true` or `cors: { ...custom cors headers }` to routeAgentRequest to enable CORS.\"\n );\n }\n\n let response = await routePartykitRequest(\n request,\n env as Record<string, unknown>,\n {\n prefix: \"agents\",\n ...(options as PartyServerOptions<Record<string, unknown>>),\n }\n );\n\n if (\n response &&\n corsHeaders &&\n request.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\" &&\n request.headers.get(\"Upgrade\")?.toLowerCase() !== \"websocket\"\n ) {\n response = new Response(response.body, {\n headers: {\n ...response.headers,\n ...corsHeaders,\n },\n });\n }\n return response;\n}\n\n/**\n * Route an email to the appropriate Agent\n * @param email Email message to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n */\nexport async function routeAgentEmail<Env>(\n email: ForwardableEmailMessage,\n env: Env,\n options?: AgentOptions<Env>\n): Promise<void> {}\n\n/**\n * Get or create an Agent by name\n * @template Env Environment type containing bindings\n * @template T Type of the Agent class\n * @param namespace Agent namespace\n * @param name Name of the Agent instance\n * @param options Options for Agent creation\n * @returns Promise resolving to an Agent instance stub\n */\nexport function getAgentByName<Env, T extends Agent<Env>>(\n namespace: AgentNamespace<T>,\n name: string,\n options?: {\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n }\n) {\n return getServerByName<Env, T>(namespace, name, options);\n}\n\n/**\n * A wrapper for streaming responses in callable methods\n */\nexport class StreamingResponse {\n #connection: Connection;\n #id: string;\n #closed = false;\n\n constructor(connection: Connection, id: string) {\n this.#connection = connection;\n this.#id = id;\n }\n\n /**\n * Send a chunk of data to the client\n * @param chunk The data to send\n */\n send(chunk: unknown) {\n if (this.#closed) {\n throw new Error(\"StreamingResponse is already closed\");\n }\n const response: RPCResponse = {\n type: \"rpc\",\n id: this.#id,\n success: true,\n result: chunk,\n done: false,\n };\n this.#connection.send(JSON.stringify(response));\n }\n\n /**\n * End the stream and send the final chunk (if any)\n * @param finalChunk Optional final chunk of data to send\n */\n end(finalChunk?: unknown) {\n if (this.#closed) {\n throw new Error(\"StreamingResponse is already closed\");\n }\n this.#closed = true;\n const response: RPCResponse = {\n type: \"rpc\",\n id: this.#id,\n success: true,\n result: finalChunk,\n done: true,\n };\n this.#connection.send(JSON.stringify(response));\n }\n}\n"],"mappings":"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","names":["ctx"]}
|