agents 0.0.0-74a8c74 → 0.0.0-75614c2
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 +50 -5
- package/dist/ai-chat-agent.js +118 -51
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +17 -4
- package/dist/ai-react.js +62 -46
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.d.ts +5 -0
- package/dist/chunk-767EASBA.js +106 -0
- package/dist/chunk-767EASBA.js.map +1 -0
- package/dist/{chunk-SZEXGW6W.js → chunk-CGWTDCBQ.js} +381 -170
- package/dist/chunk-CGWTDCBQ.js.map +1 -0
- package/dist/chunk-E3LCYPCB.js +469 -0
- package/dist/chunk-E3LCYPCB.js.map +1 -0
- package/dist/chunk-NKZZ66QY.js +116 -0
- package/dist/chunk-NKZZ66QY.js.map +1 -0
- package/dist/client.d.ts +15 -1
- package/dist/client.js +6 -126
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +124 -20
- package/dist/index.js +8 -7
- package/dist/mcp/client.d.ts +142 -34
- package/dist/mcp/client.js +3 -780
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +41 -0
- package/dist/mcp/do-oauth-client-provider.js +7 -0
- package/dist/mcp/do-oauth-client-provider.js.map +1 -0
- package/dist/mcp/index.d.ts +50 -7
- package/dist/mcp/index.js +719 -71
- package/dist/mcp/index.js.map +1 -1
- package/dist/react.d.ts +85 -5
- package/dist/react.js +50 -29
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +2 -2
- package/dist/schedule.js +4 -4
- package/dist/schedule.js.map +1 -1
- package/dist/serializable.d.ts +32 -0
- package/dist/serializable.js +1 -0
- package/dist/serializable.js.map +1 -0
- package/package.json +76 -53
- package/src/index.ts +431 -93
- package/dist/chunk-EZ76ZGDB.js +0 -1721
- package/dist/chunk-EZ76ZGDB.js.map +0 -1
- package/dist/chunk-SZEXGW6W.js.map +0 -1
|
@@ -1,13 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MCPClientManager
|
|
3
|
+
} from "./chunk-E3LCYPCB.js";
|
|
4
|
+
import {
|
|
5
|
+
DurableObjectOAuthClientProvider
|
|
6
|
+
} from "./chunk-767EASBA.js";
|
|
7
|
+
import {
|
|
8
|
+
camelCaseToKebabCase
|
|
9
|
+
} from "./chunk-NKZZ66QY.js";
|
|
10
|
+
|
|
1
11
|
// src/index.ts
|
|
12
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
13
|
+
import { parseCronExpression } from "cron-schedule";
|
|
14
|
+
import { nanoid } from "nanoid";
|
|
2
15
|
import {
|
|
3
|
-
|
|
16
|
+
getServerByName,
|
|
4
17
|
routePartykitRequest,
|
|
5
|
-
|
|
18
|
+
Server
|
|
6
19
|
} from "partyserver";
|
|
7
|
-
import { parseCronExpression } from "cron-schedule";
|
|
8
|
-
import { nanoid } from "nanoid";
|
|
9
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
-
import { WorkflowEntrypoint as CFWorkflowEntrypoint } from "cloudflare:workers";
|
|
11
20
|
function isRPCRequest(msg) {
|
|
12
21
|
return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "rpc" && "id" in msg && typeof msg.id === "string" && "method" in msg && typeof msg.method === "string" && "args" in msg && Array.isArray(msg.args);
|
|
13
22
|
}
|
|
@@ -23,8 +32,6 @@ function unstable_callable(metadata = {}) {
|
|
|
23
32
|
return target;
|
|
24
33
|
};
|
|
25
34
|
}
|
|
26
|
-
var WorkflowEntrypoint = class extends CFWorkflowEntrypoint {
|
|
27
|
-
};
|
|
28
35
|
function getNextCronTime(cron) {
|
|
29
36
|
const interval = parseCronExpression(cron);
|
|
30
37
|
return interval.getNextDate();
|
|
@@ -32,69 +39,72 @@ function getNextCronTime(cron) {
|
|
|
32
39
|
var STATE_ROW_ID = "cf_state_row_id";
|
|
33
40
|
var STATE_WAS_CHANGED = "cf_state_was_changed";
|
|
34
41
|
var DEFAULT_STATE = {};
|
|
35
|
-
var
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
* Current state of the Agent
|
|
45
|
-
*/
|
|
46
|
-
get state() {
|
|
47
|
-
if (this.#state !== DEFAULT_STATE) {
|
|
48
|
-
return this.#state;
|
|
49
|
-
}
|
|
50
|
-
const wasChanged = this.sql`
|
|
51
|
-
SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}
|
|
52
|
-
`;
|
|
53
|
-
const result = this.sql`
|
|
54
|
-
SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
|
|
55
|
-
`;
|
|
56
|
-
if (wasChanged[0]?.state === "true" || // we do this check for people who updated their code before we shipped wasChanged
|
|
57
|
-
result[0]?.state) {
|
|
58
|
-
const state = result[0]?.state;
|
|
59
|
-
this.#state = JSON.parse(state);
|
|
60
|
-
return this.#state;
|
|
61
|
-
}
|
|
62
|
-
if (this.initialState === DEFAULT_STATE) {
|
|
63
|
-
return void 0;
|
|
64
|
-
}
|
|
65
|
-
this.setState(this.initialState);
|
|
66
|
-
return this.initialState;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Agent configuration options
|
|
70
|
-
*/
|
|
71
|
-
static options = {
|
|
72
|
-
/** Whether the Agent should hibernate when inactive */
|
|
73
|
-
hibernate: true
|
|
74
|
-
// default to hibernate
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Execute SQL queries against the Agent's database
|
|
78
|
-
* @template T Type of the returned rows
|
|
79
|
-
* @param strings SQL query template strings
|
|
80
|
-
* @param values Values to be inserted into the query
|
|
81
|
-
* @returns Array of query results
|
|
82
|
-
*/
|
|
83
|
-
sql(strings, ...values) {
|
|
84
|
-
let query = "";
|
|
85
|
-
try {
|
|
86
|
-
query = strings.reduce(
|
|
87
|
-
(acc, str, i) => acc + str + (i < values.length ? "?" : ""),
|
|
88
|
-
""
|
|
89
|
-
);
|
|
90
|
-
return [...this.ctx.storage.sql.exec(query, ...values)];
|
|
91
|
-
} catch (e) {
|
|
92
|
-
console.error(`failed to execute sql query: ${query}`, e);
|
|
93
|
-
throw this.onError(e);
|
|
94
|
-
}
|
|
42
|
+
var agentContext = new AsyncLocalStorage();
|
|
43
|
+
function getCurrentAgent() {
|
|
44
|
+
const store = agentContext.getStore();
|
|
45
|
+
if (!store) {
|
|
46
|
+
return {
|
|
47
|
+
agent: void 0,
|
|
48
|
+
connection: void 0,
|
|
49
|
+
request: void 0
|
|
50
|
+
};
|
|
95
51
|
}
|
|
52
|
+
return store;
|
|
53
|
+
}
|
|
54
|
+
var Agent = class extends Server {
|
|
96
55
|
constructor(ctx, env) {
|
|
97
56
|
super(ctx, env);
|
|
57
|
+
this._state = DEFAULT_STATE;
|
|
58
|
+
this._ParentClass = Object.getPrototypeOf(this).constructor;
|
|
59
|
+
this.mcp = new MCPClientManager(this._ParentClass.name, "0.0.1");
|
|
60
|
+
/**
|
|
61
|
+
* Initial state for the Agent
|
|
62
|
+
* Override to provide default state values
|
|
63
|
+
*/
|
|
64
|
+
this.initialState = DEFAULT_STATE;
|
|
65
|
+
/**
|
|
66
|
+
* Method called when an alarm fires.
|
|
67
|
+
* Executes any scheduled tasks that are due.
|
|
68
|
+
*
|
|
69
|
+
* @remarks
|
|
70
|
+
* To schedule a task, please use the `this.schedule` method instead.
|
|
71
|
+
* See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
|
|
72
|
+
*/
|
|
73
|
+
this.alarm = async () => {
|
|
74
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
75
|
+
const result = this.sql`
|
|
76
|
+
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
77
|
+
`;
|
|
78
|
+
for (const row of result || []) {
|
|
79
|
+
const callback = this[row.callback];
|
|
80
|
+
if (!callback) {
|
|
81
|
+
console.error(`callback ${row.callback} not found`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
await agentContext.run(
|
|
85
|
+
{ agent: this, connection: void 0, request: void 0 },
|
|
86
|
+
async () => {
|
|
87
|
+
try {
|
|
88
|
+
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
console.error(`error executing callback "${row.callback}"`, e);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
if (row.type === "cron") {
|
|
95
|
+
const nextExecutionTime = getNextCronTime(row.cron);
|
|
96
|
+
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
97
|
+
this.sql`
|
|
98
|
+
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
99
|
+
`;
|
|
100
|
+
} else {
|
|
101
|
+
this.sql`
|
|
102
|
+
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
await this._scheduleNextAlarm();
|
|
107
|
+
};
|
|
98
108
|
this.sql`
|
|
99
109
|
CREATE TABLE IF NOT EXISTS cf_agents_state (
|
|
100
110
|
id TEXT PRIMARY KEY NOT NULL,
|
|
@@ -102,7 +112,7 @@ var Agent = class extends Server {
|
|
|
102
112
|
)
|
|
103
113
|
`;
|
|
104
114
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
105
|
-
return this
|
|
115
|
+
return this._tryCatch(async () => {
|
|
106
116
|
this.sql`
|
|
107
117
|
CREATE TABLE IF NOT EXISTS cf_agents_schedules (
|
|
108
118
|
id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
|
|
@@ -118,22 +128,55 @@ var Agent = class extends Server {
|
|
|
118
128
|
await this.alarm();
|
|
119
129
|
});
|
|
120
130
|
});
|
|
131
|
+
this.sql`
|
|
132
|
+
CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (
|
|
133
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
134
|
+
name TEXT NOT NULL,
|
|
135
|
+
server_url TEXT NOT NULL,
|
|
136
|
+
callback_url TEXT NOT NULL,
|
|
137
|
+
client_id TEXT,
|
|
138
|
+
auth_url TEXT,
|
|
139
|
+
server_options TEXT
|
|
140
|
+
)
|
|
141
|
+
`;
|
|
142
|
+
const _onRequest = this.onRequest.bind(this);
|
|
143
|
+
this.onRequest = (request) => {
|
|
144
|
+
return agentContext.run(
|
|
145
|
+
{ agent: this, connection: void 0, request },
|
|
146
|
+
async () => {
|
|
147
|
+
if (this.mcp.isCallbackRequest(request)) {
|
|
148
|
+
await this.mcp.handleCallbackRequest(request);
|
|
149
|
+
this.broadcast(
|
|
150
|
+
JSON.stringify({
|
|
151
|
+
mcp: this.getMcpServers(),
|
|
152
|
+
type: "cf_agent_mcp_servers"
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
return new Response("<script>window.close();</script>", {
|
|
156
|
+
headers: { "content-type": "text/html" },
|
|
157
|
+
status: 200
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return this._tryCatch(() => _onRequest(request));
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
};
|
|
121
164
|
const _onMessage = this.onMessage.bind(this);
|
|
122
165
|
this.onMessage = async (connection, message) => {
|
|
123
|
-
return
|
|
166
|
+
return agentContext.run(
|
|
124
167
|
{ agent: this, connection, request: void 0 },
|
|
125
168
|
async () => {
|
|
126
169
|
if (typeof message !== "string") {
|
|
127
|
-
return this
|
|
170
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
128
171
|
}
|
|
129
172
|
let parsed;
|
|
130
173
|
try {
|
|
131
174
|
parsed = JSON.parse(message);
|
|
132
|
-
} catch (
|
|
133
|
-
return this
|
|
175
|
+
} catch (_e) {
|
|
176
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
134
177
|
}
|
|
135
178
|
if (isStateUpdateMessage(parsed)) {
|
|
136
|
-
this
|
|
179
|
+
this._setStateInternal(parsed.state, connection);
|
|
137
180
|
return;
|
|
138
181
|
}
|
|
139
182
|
if (isRPCRequest(parsed)) {
|
|
@@ -143,7 +186,7 @@ var Agent = class extends Server {
|
|
|
143
186
|
if (typeof methodFn !== "function") {
|
|
144
187
|
throw new Error(`Method ${method} does not exist`);
|
|
145
188
|
}
|
|
146
|
-
if (!this
|
|
189
|
+
if (!this._isCallable(method)) {
|
|
147
190
|
throw new Error(`Method ${method} is not callable`);
|
|
148
191
|
}
|
|
149
192
|
const metadata = callableMetadata.get(methodFn);
|
|
@@ -154,51 +197,135 @@ var Agent = class extends Server {
|
|
|
154
197
|
}
|
|
155
198
|
const result = await methodFn.apply(this, args);
|
|
156
199
|
const response = {
|
|
157
|
-
|
|
200
|
+
done: true,
|
|
158
201
|
id,
|
|
159
|
-
success: true,
|
|
160
202
|
result,
|
|
161
|
-
|
|
203
|
+
success: true,
|
|
204
|
+
type: "rpc"
|
|
162
205
|
};
|
|
163
206
|
connection.send(JSON.stringify(response));
|
|
164
207
|
} catch (e) {
|
|
165
208
|
const response = {
|
|
166
|
-
|
|
209
|
+
error: e instanceof Error ? e.message : "Unknown error occurred",
|
|
167
210
|
id: parsed.id,
|
|
168
211
|
success: false,
|
|
169
|
-
|
|
212
|
+
type: "rpc"
|
|
170
213
|
};
|
|
171
214
|
connection.send(JSON.stringify(response));
|
|
172
215
|
console.error("RPC error:", e);
|
|
173
216
|
}
|
|
174
217
|
return;
|
|
175
218
|
}
|
|
176
|
-
return this
|
|
219
|
+
return this._tryCatch(() => _onMessage(connection, message));
|
|
177
220
|
}
|
|
178
221
|
);
|
|
179
222
|
};
|
|
180
223
|
const _onConnect = this.onConnect.bind(this);
|
|
181
224
|
this.onConnect = (connection, ctx2) => {
|
|
182
|
-
return
|
|
225
|
+
return agentContext.run(
|
|
183
226
|
{ agent: this, connection, request: ctx2.request },
|
|
184
227
|
async () => {
|
|
185
228
|
setTimeout(() => {
|
|
186
229
|
if (this.state) {
|
|
187
230
|
connection.send(
|
|
188
231
|
JSON.stringify({
|
|
189
|
-
|
|
190
|
-
|
|
232
|
+
state: this.state,
|
|
233
|
+
type: "cf_agent_state"
|
|
191
234
|
})
|
|
192
235
|
);
|
|
193
236
|
}
|
|
194
|
-
|
|
237
|
+
connection.send(
|
|
238
|
+
JSON.stringify({
|
|
239
|
+
mcp: this.getMcpServers(),
|
|
240
|
+
type: "cf_agent_mcp_servers"
|
|
241
|
+
})
|
|
242
|
+
);
|
|
243
|
+
return this._tryCatch(() => _onConnect(connection, ctx2));
|
|
195
244
|
}, 20);
|
|
196
245
|
}
|
|
197
246
|
);
|
|
198
247
|
};
|
|
248
|
+
const _onStart = this.onStart.bind(this);
|
|
249
|
+
this.onStart = async () => {
|
|
250
|
+
return agentContext.run(
|
|
251
|
+
{ agent: this, connection: void 0, request: void 0 },
|
|
252
|
+
async () => {
|
|
253
|
+
const servers = this.sql`
|
|
254
|
+
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
255
|
+
`;
|
|
256
|
+
Promise.allSettled(
|
|
257
|
+
servers.map((server) => {
|
|
258
|
+
return this._connectToMcpServerInternal(
|
|
259
|
+
server.name,
|
|
260
|
+
server.server_url,
|
|
261
|
+
server.callback_url,
|
|
262
|
+
server.server_options ? JSON.parse(server.server_options) : void 0,
|
|
263
|
+
{
|
|
264
|
+
id: server.id,
|
|
265
|
+
oauthClientId: server.client_id ?? void 0
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
})
|
|
269
|
+
).then((_results) => {
|
|
270
|
+
this.broadcast(
|
|
271
|
+
JSON.stringify({
|
|
272
|
+
type: "cf_agent_mcp_servers",
|
|
273
|
+
mcp: this.getMcpServers()
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
await this._tryCatch(() => _onStart());
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
};
|
|
199
281
|
}
|
|
200
|
-
|
|
201
|
-
|
|
282
|
+
/**
|
|
283
|
+
* Current state of the Agent
|
|
284
|
+
*/
|
|
285
|
+
get state() {
|
|
286
|
+
if (this._state !== DEFAULT_STATE) {
|
|
287
|
+
return this._state;
|
|
288
|
+
}
|
|
289
|
+
const wasChanged = this.sql`
|
|
290
|
+
SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}
|
|
291
|
+
`;
|
|
292
|
+
const result = this.sql`
|
|
293
|
+
SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
|
|
294
|
+
`;
|
|
295
|
+
if (wasChanged[0]?.state === "true" || // we do this check for people who updated their code before we shipped wasChanged
|
|
296
|
+
result[0]?.state) {
|
|
297
|
+
const state = result[0]?.state;
|
|
298
|
+
this._state = JSON.parse(state);
|
|
299
|
+
return this._state;
|
|
300
|
+
}
|
|
301
|
+
if (this.initialState === DEFAULT_STATE) {
|
|
302
|
+
return void 0;
|
|
303
|
+
}
|
|
304
|
+
this.setState(this.initialState);
|
|
305
|
+
return this.initialState;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Execute SQL queries against the Agent's database
|
|
309
|
+
* @template T Type of the returned rows
|
|
310
|
+
* @param strings SQL query template strings
|
|
311
|
+
* @param values Values to be inserted into the query
|
|
312
|
+
* @returns Array of query results
|
|
313
|
+
*/
|
|
314
|
+
sql(strings, ...values) {
|
|
315
|
+
let query = "";
|
|
316
|
+
try {
|
|
317
|
+
query = strings.reduce(
|
|
318
|
+
(acc, str, i) => acc + str + (i < values.length ? "?" : ""),
|
|
319
|
+
""
|
|
320
|
+
);
|
|
321
|
+
return [...this.ctx.storage.sql.exec(query, ...values)];
|
|
322
|
+
} catch (e) {
|
|
323
|
+
console.error(`failed to execute sql query: ${query}`, e);
|
|
324
|
+
throw this.onError(e);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
_setStateInternal(state, source = "server") {
|
|
328
|
+
this._state = state;
|
|
202
329
|
this.sql`
|
|
203
330
|
INSERT OR REPLACE INTO cf_agents_state (id, state)
|
|
204
331
|
VALUES (${STATE_ROW_ID}, ${JSON.stringify(state)})
|
|
@@ -209,14 +336,14 @@ var Agent = class extends Server {
|
|
|
209
336
|
`;
|
|
210
337
|
this.broadcast(
|
|
211
338
|
JSON.stringify({
|
|
212
|
-
|
|
213
|
-
|
|
339
|
+
state,
|
|
340
|
+
type: "cf_agent_state"
|
|
214
341
|
}),
|
|
215
342
|
source !== "server" ? [source.id] : []
|
|
216
343
|
);
|
|
217
|
-
return this
|
|
218
|
-
const { connection, request } =
|
|
219
|
-
return
|
|
344
|
+
return this._tryCatch(() => {
|
|
345
|
+
const { connection, request } = agentContext.getStore() || {};
|
|
346
|
+
return agentContext.run(
|
|
220
347
|
{ agent: this, connection, request },
|
|
221
348
|
async () => {
|
|
222
349
|
return this.onStateUpdate(state, source);
|
|
@@ -229,28 +356,30 @@ var Agent = class extends Server {
|
|
|
229
356
|
* @param state New state to set
|
|
230
357
|
*/
|
|
231
358
|
setState(state) {
|
|
232
|
-
this
|
|
359
|
+
this._setStateInternal(state, "server");
|
|
233
360
|
}
|
|
234
361
|
/**
|
|
235
362
|
* Called when the Agent's state is updated
|
|
236
363
|
* @param state Updated state
|
|
237
364
|
* @param source Source of the state update ("server" or a client connection)
|
|
238
365
|
*/
|
|
366
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
239
367
|
onStateUpdate(state, source) {
|
|
240
368
|
}
|
|
241
369
|
/**
|
|
242
370
|
* Called when the Agent receives an email
|
|
243
371
|
* @param email Email message to process
|
|
244
372
|
*/
|
|
373
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
|
|
245
374
|
onEmail(email) {
|
|
246
|
-
return
|
|
375
|
+
return agentContext.run(
|
|
247
376
|
{ agent: this, connection: void 0, request: void 0 },
|
|
248
377
|
async () => {
|
|
249
378
|
console.error("onEmail not implemented");
|
|
250
379
|
}
|
|
251
380
|
);
|
|
252
381
|
}
|
|
253
|
-
async
|
|
382
|
+
async _tryCatch(fn) {
|
|
254
383
|
try {
|
|
255
384
|
return await fn();
|
|
256
385
|
} catch (e) {
|
|
@@ -306,10 +435,10 @@ var Agent = class extends Server {
|
|
|
306
435
|
payload
|
|
307
436
|
)}, 'scheduled', ${timestamp})
|
|
308
437
|
`;
|
|
309
|
-
await this
|
|
438
|
+
await this._scheduleNextAlarm();
|
|
310
439
|
return {
|
|
311
|
-
id,
|
|
312
440
|
callback,
|
|
441
|
+
id,
|
|
313
442
|
payload,
|
|
314
443
|
time: timestamp,
|
|
315
444
|
type: "scheduled"
|
|
@@ -324,12 +453,12 @@ var Agent = class extends Server {
|
|
|
324
453
|
payload
|
|
325
454
|
)}, 'delayed', ${when}, ${timestamp})
|
|
326
455
|
`;
|
|
327
|
-
await this
|
|
456
|
+
await this._scheduleNextAlarm();
|
|
328
457
|
return {
|
|
329
|
-
id,
|
|
330
458
|
callback,
|
|
331
|
-
payload,
|
|
332
459
|
delayInSeconds: when,
|
|
460
|
+
id,
|
|
461
|
+
payload,
|
|
333
462
|
time: timestamp,
|
|
334
463
|
type: "delayed"
|
|
335
464
|
};
|
|
@@ -343,12 +472,12 @@ var Agent = class extends Server {
|
|
|
343
472
|
payload
|
|
344
473
|
)}, 'cron', ${when}, ${timestamp})
|
|
345
474
|
`;
|
|
346
|
-
await this
|
|
475
|
+
await this._scheduleNextAlarm();
|
|
347
476
|
return {
|
|
348
|
-
id,
|
|
349
477
|
callback,
|
|
350
|
-
payload,
|
|
351
478
|
cron: when,
|
|
479
|
+
id,
|
|
480
|
+
payload,
|
|
352
481
|
time: timestamp,
|
|
353
482
|
type: "cron"
|
|
354
483
|
};
|
|
@@ -410,10 +539,10 @@ var Agent = class extends Server {
|
|
|
410
539
|
*/
|
|
411
540
|
async cancelSchedule(id) {
|
|
412
541
|
this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
|
|
413
|
-
await this
|
|
542
|
+
await this._scheduleNextAlarm();
|
|
414
543
|
return true;
|
|
415
544
|
}
|
|
416
|
-
async
|
|
545
|
+
async _scheduleNextAlarm() {
|
|
417
546
|
const result = this.sql`
|
|
418
547
|
SELECT time FROM cf_agents_schedules
|
|
419
548
|
WHERE time > ${Math.floor(Date.now() / 1e3)}
|
|
@@ -426,67 +555,152 @@ var Agent = class extends Server {
|
|
|
426
555
|
await this.ctx.storage.setAlarm(nextTime);
|
|
427
556
|
}
|
|
428
557
|
}
|
|
429
|
-
/**
|
|
430
|
-
* Method called when an alarm fires
|
|
431
|
-
* Executes any scheduled tasks that are due
|
|
432
|
-
*/
|
|
433
|
-
async alarm() {
|
|
434
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
435
|
-
const result = this.sql`
|
|
436
|
-
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
437
|
-
`;
|
|
438
|
-
for (const row of result || []) {
|
|
439
|
-
const callback = this[row.callback];
|
|
440
|
-
if (!callback) {
|
|
441
|
-
console.error(`callback ${row.callback} not found`);
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
await unstable_context.run(
|
|
445
|
-
{ agent: this, connection: void 0, request: void 0 },
|
|
446
|
-
async () => {
|
|
447
|
-
try {
|
|
448
|
-
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
449
|
-
} catch (e) {
|
|
450
|
-
console.error(`error executing callback "${row.callback}"`, e);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
);
|
|
454
|
-
if (row.type === "cron") {
|
|
455
|
-
const nextExecutionTime = getNextCronTime(row.cron);
|
|
456
|
-
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
457
|
-
this.sql`
|
|
458
|
-
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
459
|
-
`;
|
|
460
|
-
} else {
|
|
461
|
-
this.sql`
|
|
462
|
-
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
463
|
-
`;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
await this.#scheduleNextAlarm();
|
|
467
|
-
}
|
|
468
558
|
/**
|
|
469
559
|
* Destroy the Agent, removing all state and scheduled tasks
|
|
470
560
|
*/
|
|
471
561
|
async destroy() {
|
|
472
562
|
this.sql`DROP TABLE IF EXISTS cf_agents_state`;
|
|
473
563
|
this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
|
|
564
|
+
this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;
|
|
474
565
|
await this.ctx.storage.deleteAlarm();
|
|
475
566
|
await this.ctx.storage.deleteAll();
|
|
567
|
+
this.ctx.abort("destroyed");
|
|
476
568
|
}
|
|
477
569
|
/**
|
|
478
570
|
* Get all methods marked as callable on this Agent
|
|
479
571
|
* @returns A map of method names to their metadata
|
|
480
572
|
*/
|
|
481
|
-
|
|
573
|
+
_isCallable(method) {
|
|
482
574
|
return callableMetadata.has(this[method]);
|
|
483
575
|
}
|
|
576
|
+
/**
|
|
577
|
+
* Connect to a new MCP Server
|
|
578
|
+
*
|
|
579
|
+
* @param url MCP Server SSE URL
|
|
580
|
+
* @param callbackHost Base host for the agent, used for the redirect URI.
|
|
581
|
+
* @param agentsPrefix agents routing prefix if not using `agents`
|
|
582
|
+
* @param options MCP client and transport (header) options
|
|
583
|
+
* @returns authUrl
|
|
584
|
+
*/
|
|
585
|
+
async addMcpServer(serverName, url, callbackHost, agentsPrefix = "agents", options) {
|
|
586
|
+
const callbackUrl = `${callbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
|
|
587
|
+
const result = await this._connectToMcpServerInternal(
|
|
588
|
+
serverName,
|
|
589
|
+
url,
|
|
590
|
+
callbackUrl,
|
|
591
|
+
options
|
|
592
|
+
);
|
|
593
|
+
this.sql`
|
|
594
|
+
INSERT
|
|
595
|
+
OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
|
|
596
|
+
VALUES (
|
|
597
|
+
${result.id},
|
|
598
|
+
${serverName},
|
|
599
|
+
${url},
|
|
600
|
+
${result.clientId ?? null},
|
|
601
|
+
${result.authUrl ?? null},
|
|
602
|
+
${callbackUrl},
|
|
603
|
+
${options ? JSON.stringify(options) : null}
|
|
604
|
+
);
|
|
605
|
+
`;
|
|
606
|
+
this.broadcast(
|
|
607
|
+
JSON.stringify({
|
|
608
|
+
mcp: this.getMcpServers(),
|
|
609
|
+
type: "cf_agent_mcp_servers"
|
|
610
|
+
})
|
|
611
|
+
);
|
|
612
|
+
return result;
|
|
613
|
+
}
|
|
614
|
+
async _connectToMcpServerInternal(_serverName, url, callbackUrl, options, reconnect) {
|
|
615
|
+
const authProvider = new DurableObjectOAuthClientProvider(
|
|
616
|
+
this.ctx.storage,
|
|
617
|
+
this.name,
|
|
618
|
+
callbackUrl
|
|
619
|
+
);
|
|
620
|
+
if (reconnect) {
|
|
621
|
+
authProvider.serverId = reconnect.id;
|
|
622
|
+
if (reconnect.oauthClientId) {
|
|
623
|
+
authProvider.clientId = reconnect.oauthClientId;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
let headerTransportOpts = {};
|
|
627
|
+
if (options?.transport?.headers) {
|
|
628
|
+
headerTransportOpts = {
|
|
629
|
+
eventSourceInit: {
|
|
630
|
+
fetch: (url2, init) => fetch(url2, {
|
|
631
|
+
...init,
|
|
632
|
+
headers: options?.transport?.headers
|
|
633
|
+
})
|
|
634
|
+
},
|
|
635
|
+
requestInit: {
|
|
636
|
+
headers: options?.transport?.headers
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
const { id, authUrl, clientId } = await this.mcp.connect(url, {
|
|
641
|
+
client: options?.client,
|
|
642
|
+
reconnect,
|
|
643
|
+
transport: {
|
|
644
|
+
...headerTransportOpts,
|
|
645
|
+
authProvider
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
return {
|
|
649
|
+
authUrl,
|
|
650
|
+
clientId,
|
|
651
|
+
id
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
async removeMcpServer(id) {
|
|
655
|
+
this.mcp.closeConnection(id);
|
|
656
|
+
this.sql`
|
|
657
|
+
DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
|
|
658
|
+
`;
|
|
659
|
+
this.broadcast(
|
|
660
|
+
JSON.stringify({
|
|
661
|
+
mcp: this.getMcpServers(),
|
|
662
|
+
type: "cf_agent_mcp_servers"
|
|
663
|
+
})
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
getMcpServers() {
|
|
667
|
+
const mcpState = {
|
|
668
|
+
prompts: this.mcp.listPrompts(),
|
|
669
|
+
resources: this.mcp.listResources(),
|
|
670
|
+
servers: {},
|
|
671
|
+
tools: this.mcp.listTools()
|
|
672
|
+
};
|
|
673
|
+
const servers = this.sql`
|
|
674
|
+
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
675
|
+
`;
|
|
676
|
+
for (const server of servers) {
|
|
677
|
+
const serverConn = this.mcp.mcpConnections[server.id];
|
|
678
|
+
mcpState.servers[server.id] = {
|
|
679
|
+
auth_url: server.auth_url,
|
|
680
|
+
capabilities: serverConn?.serverCapabilities ?? null,
|
|
681
|
+
instructions: serverConn?.instructions ?? null,
|
|
682
|
+
name: server.name,
|
|
683
|
+
server_url: server.server_url,
|
|
684
|
+
// mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
|
|
685
|
+
state: serverConn?.connectionState ?? "authenticating"
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
return mcpState;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
/**
|
|
692
|
+
* Agent configuration options
|
|
693
|
+
*/
|
|
694
|
+
Agent.options = {
|
|
695
|
+
/** Whether the Agent should hibernate when inactive */
|
|
696
|
+
hibernate: true
|
|
697
|
+
// default to hibernate
|
|
484
698
|
};
|
|
485
699
|
async function routeAgentRequest(request, env, options) {
|
|
486
700
|
const corsHeaders = options?.cors === true ? {
|
|
487
|
-
"Access-Control-Allow-Origin": "*",
|
|
488
|
-
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
489
701
|
"Access-Control-Allow-Credentials": "true",
|
|
702
|
+
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
|
|
703
|
+
"Access-Control-Allow-Origin": "*",
|
|
490
704
|
"Access-Control-Max-Age": "86400"
|
|
491
705
|
} : options?.cors;
|
|
492
706
|
if (request.method === "OPTIONS") {
|
|
@@ -517,64 +731,61 @@ async function routeAgentRequest(request, env, options) {
|
|
|
517
731
|
}
|
|
518
732
|
return response;
|
|
519
733
|
}
|
|
520
|
-
async function routeAgentEmail(
|
|
734
|
+
async function routeAgentEmail(_email, _env, _options) {
|
|
521
735
|
}
|
|
522
|
-
function getAgentByName(namespace, name, options) {
|
|
736
|
+
async function getAgentByName(namespace, name, options) {
|
|
523
737
|
return getServerByName(namespace, name, options);
|
|
524
738
|
}
|
|
525
739
|
var StreamingResponse = class {
|
|
526
|
-
#connection;
|
|
527
|
-
#id;
|
|
528
|
-
#closed = false;
|
|
529
740
|
constructor(connection, id) {
|
|
530
|
-
this
|
|
531
|
-
this
|
|
741
|
+
this._closed = false;
|
|
742
|
+
this._connection = connection;
|
|
743
|
+
this._id = id;
|
|
532
744
|
}
|
|
533
745
|
/**
|
|
534
746
|
* Send a chunk of data to the client
|
|
535
747
|
* @param chunk The data to send
|
|
536
748
|
*/
|
|
537
749
|
send(chunk) {
|
|
538
|
-
if (this
|
|
750
|
+
if (this._closed) {
|
|
539
751
|
throw new Error("StreamingResponse is already closed");
|
|
540
752
|
}
|
|
541
753
|
const response = {
|
|
542
|
-
|
|
543
|
-
id: this
|
|
544
|
-
success: true,
|
|
754
|
+
done: false,
|
|
755
|
+
id: this._id,
|
|
545
756
|
result: chunk,
|
|
546
|
-
|
|
757
|
+
success: true,
|
|
758
|
+
type: "rpc"
|
|
547
759
|
};
|
|
548
|
-
this
|
|
760
|
+
this._connection.send(JSON.stringify(response));
|
|
549
761
|
}
|
|
550
762
|
/**
|
|
551
763
|
* End the stream and send the final chunk (if any)
|
|
552
764
|
* @param finalChunk Optional final chunk of data to send
|
|
553
765
|
*/
|
|
554
766
|
end(finalChunk) {
|
|
555
|
-
if (this
|
|
767
|
+
if (this._closed) {
|
|
556
768
|
throw new Error("StreamingResponse is already closed");
|
|
557
769
|
}
|
|
558
|
-
this
|
|
770
|
+
this._closed = true;
|
|
559
771
|
const response = {
|
|
560
|
-
|
|
561
|
-
id: this
|
|
562
|
-
success: true,
|
|
772
|
+
done: true,
|
|
773
|
+
id: this._id,
|
|
563
774
|
result: finalChunk,
|
|
564
|
-
|
|
775
|
+
success: true,
|
|
776
|
+
type: "rpc"
|
|
565
777
|
};
|
|
566
|
-
this
|
|
778
|
+
this._connection.send(JSON.stringify(response));
|
|
567
779
|
}
|
|
568
780
|
};
|
|
569
781
|
|
|
570
782
|
export {
|
|
571
783
|
unstable_callable,
|
|
572
|
-
|
|
573
|
-
unstable_context,
|
|
784
|
+
getCurrentAgent,
|
|
574
785
|
Agent,
|
|
575
786
|
routeAgentRequest,
|
|
576
787
|
routeAgentEmail,
|
|
577
788
|
getAgentByName,
|
|
578
789
|
StreamingResponse
|
|
579
790
|
};
|
|
580
|
-
//# sourceMappingURL=chunk-
|
|
791
|
+
//# sourceMappingURL=chunk-CGWTDCBQ.js.map
|