agents 0.0.103 → 0.0.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/dist/ai-chat-agent.d.ts +1 -1
- package/dist/ai-chat-agent.js +4 -4
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +2 -2
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-JFRK72K3.js → chunk-5YIRLLUX.js} +437 -83
- package/dist/chunk-5YIRLLUX.js.map +1 -0
- package/dist/{chunk-NKZZ66QY.js → chunk-KUH345EY.js} +1 -1
- package/dist/chunk-KUH345EY.js.map +1 -0
- package/dist/{chunk-E3LCYPCB.js → chunk-MW5BQ2FW.js} +1 -1
- package/dist/chunk-MW5BQ2FW.js.map +1 -0
- package/dist/{chunk-767EASBA.js → chunk-PVQZBKN7.js} +1 -1
- package/dist/chunk-PVQZBKN7.js.map +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/{index-CITGJflw.d.ts → index-BIJvkfYt.d.ts} +144 -16
- package/dist/index.d.ts +13 -5
- package/dist/index.js +10 -4
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/do-oauth-client-provider.js +1 -1
- package/dist/mcp/index.d.ts +3 -3
- package/dist/mcp/index.js +6 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js.map +1 -1
- package/dist/schedule.js.map +1 -1
- package/package.json +2 -1
- package/src/index.ts +647 -134
- package/dist/chunk-767EASBA.js.map +0 -1
- package/dist/chunk-E3LCYPCB.js.map +0 -1
- package/dist/chunk-JFRK72K3.js.map +0 -1
- package/dist/chunk-NKZZ66QY.js.map +0 -1
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCPClientManager
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MW5BQ2FW.js";
|
|
4
4
|
import {
|
|
5
5
|
DurableObjectOAuthClientProvider
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PVQZBKN7.js";
|
|
7
7
|
import {
|
|
8
8
|
camelCaseToKebabCase
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KUH345EY.js";
|
|
10
10
|
|
|
11
11
|
// src/index.ts
|
|
12
12
|
import { AsyncLocalStorage } from "async_hooks";
|
|
13
13
|
import { parseCronExpression } from "cron-schedule";
|
|
14
14
|
import { nanoid } from "nanoid";
|
|
15
|
+
import { EmailMessage } from "cloudflare:email";
|
|
15
16
|
import {
|
|
17
|
+
Server,
|
|
16
18
|
getServerByName,
|
|
17
|
-
routePartykitRequest
|
|
18
|
-
Server
|
|
19
|
+
routePartykitRequest
|
|
19
20
|
} from "partyserver";
|
|
20
21
|
function isRPCRequest(msg) {
|
|
21
22
|
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);
|
|
@@ -46,12 +47,21 @@ function getCurrentAgent() {
|
|
|
46
47
|
return {
|
|
47
48
|
agent: void 0,
|
|
48
49
|
connection: void 0,
|
|
49
|
-
request: void 0
|
|
50
|
+
request: void 0,
|
|
51
|
+
email: void 0
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
return store;
|
|
53
55
|
}
|
|
54
|
-
|
|
56
|
+
function withAgentContext(method) {
|
|
57
|
+
return function(...args) {
|
|
58
|
+
const { connection, request, email } = getCurrentAgent();
|
|
59
|
+
return agentContext.run({ agent: this, connection, request, email }, () => {
|
|
60
|
+
return method.apply(this, args);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
var _Agent = class _Agent extends Server {
|
|
55
65
|
constructor(ctx, env) {
|
|
56
66
|
super(ctx, env);
|
|
57
67
|
this._state = DEFAULT_STATE;
|
|
@@ -66,6 +76,7 @@ var Agent = class extends Server {
|
|
|
66
76
|
* The observability implementation to use for the Agent
|
|
67
77
|
*/
|
|
68
78
|
this.observability = genericObservability;
|
|
79
|
+
this._flushingQueue = false;
|
|
69
80
|
/**
|
|
70
81
|
* Method called when an alarm fires.
|
|
71
82
|
* Executes any scheduled tasks that are due.
|
|
@@ -79,52 +90,68 @@ var Agent = class extends Server {
|
|
|
79
90
|
const result = this.sql`
|
|
80
91
|
SELECT * FROM cf_agents_schedules WHERE time <= ${now}
|
|
81
92
|
`;
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
await agentContext.run(
|
|
89
|
-
{ agent: this, connection: void 0, request: void 0 },
|
|
90
|
-
async () => {
|
|
91
|
-
try {
|
|
92
|
-
this.observability?.emit(
|
|
93
|
-
{
|
|
94
|
-
displayMessage: `Schedule ${row.id} executed`,
|
|
95
|
-
id: nanoid(),
|
|
96
|
-
payload: row,
|
|
97
|
-
timestamp: Date.now(),
|
|
98
|
-
type: "schedule:execute"
|
|
99
|
-
},
|
|
100
|
-
this.ctx
|
|
101
|
-
);
|
|
102
|
-
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
103
|
-
} catch (e) {
|
|
104
|
-
console.error(`error executing callback "${row.callback}"`, e);
|
|
105
|
-
}
|
|
93
|
+
if (result && Array.isArray(result)) {
|
|
94
|
+
for (const row of result) {
|
|
95
|
+
const callback = this[row.callback];
|
|
96
|
+
if (!callback) {
|
|
97
|
+
console.error(`callback ${row.callback} not found`);
|
|
98
|
+
continue;
|
|
106
99
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
100
|
+
await agentContext.run(
|
|
101
|
+
{
|
|
102
|
+
agent: this,
|
|
103
|
+
connection: void 0,
|
|
104
|
+
request: void 0,
|
|
105
|
+
email: void 0
|
|
106
|
+
},
|
|
107
|
+
async () => {
|
|
108
|
+
try {
|
|
109
|
+
this.observability?.emit(
|
|
110
|
+
{
|
|
111
|
+
displayMessage: `Schedule ${row.id} executed`,
|
|
112
|
+
id: nanoid(),
|
|
113
|
+
payload: row,
|
|
114
|
+
timestamp: Date.now(),
|
|
115
|
+
type: "schedule:execute"
|
|
116
|
+
},
|
|
117
|
+
this.ctx
|
|
118
|
+
);
|
|
119
|
+
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.error(`error executing callback "${row.callback}"`, e);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
if (row.type === "cron") {
|
|
126
|
+
const nextExecutionTime = getNextCronTime(row.cron);
|
|
127
|
+
const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
|
|
128
|
+
this.sql`
|
|
112
129
|
UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
|
|
113
130
|
`;
|
|
114
|
-
|
|
115
|
-
|
|
131
|
+
} else {
|
|
132
|
+
this.sql`
|
|
116
133
|
DELETE FROM cf_agents_schedules WHERE id = ${row.id}
|
|
117
134
|
`;
|
|
135
|
+
}
|
|
118
136
|
}
|
|
119
137
|
}
|
|
120
138
|
await this._scheduleNextAlarm();
|
|
121
139
|
};
|
|
140
|
+
this._autoWrapCustomMethods();
|
|
122
141
|
this.sql`
|
|
123
142
|
CREATE TABLE IF NOT EXISTS cf_agents_state (
|
|
124
143
|
id TEXT PRIMARY KEY NOT NULL,
|
|
125
144
|
state TEXT
|
|
126
145
|
)
|
|
127
146
|
`;
|
|
147
|
+
this.sql`
|
|
148
|
+
CREATE TABLE IF NOT EXISTS cf_agents_queues (
|
|
149
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
150
|
+
payload TEXT,
|
|
151
|
+
callback TEXT,
|
|
152
|
+
created_at INTEGER DEFAULT (unixepoch())
|
|
153
|
+
)
|
|
154
|
+
`;
|
|
128
155
|
void this.ctx.blockConcurrencyWhile(async () => {
|
|
129
156
|
return this._tryCatch(async () => {
|
|
130
157
|
this.sql`
|
|
@@ -156,7 +183,7 @@ var Agent = class extends Server {
|
|
|
156
183
|
const _onRequest = this.onRequest.bind(this);
|
|
157
184
|
this.onRequest = (request) => {
|
|
158
185
|
return agentContext.run(
|
|
159
|
-
{ agent: this, connection: void 0, request },
|
|
186
|
+
{ agent: this, connection: void 0, request, email: void 0 },
|
|
160
187
|
async () => {
|
|
161
188
|
if (this.mcp.isCallbackRequest(request)) {
|
|
162
189
|
await this.mcp.handleCallbackRequest(request);
|
|
@@ -178,7 +205,7 @@ var Agent = class extends Server {
|
|
|
178
205
|
const _onMessage = this.onMessage.bind(this);
|
|
179
206
|
this.onMessage = async (connection, message) => {
|
|
180
207
|
return agentContext.run(
|
|
181
|
-
{ agent: this, connection, request: void 0 },
|
|
208
|
+
{ agent: this, connection, request: void 0, email: void 0 },
|
|
182
209
|
async () => {
|
|
183
210
|
if (typeof message !== "string") {
|
|
184
211
|
return this._tryCatch(() => _onMessage(connection, message));
|
|
@@ -252,7 +279,7 @@ var Agent = class extends Server {
|
|
|
252
279
|
const _onConnect = this.onConnect.bind(this);
|
|
253
280
|
this.onConnect = (connection, ctx2) => {
|
|
254
281
|
return agentContext.run(
|
|
255
|
-
{ agent: this, connection, request: ctx2.request },
|
|
282
|
+
{ agent: this, connection, request: ctx2.request, email: void 0 },
|
|
256
283
|
async () => {
|
|
257
284
|
setTimeout(() => {
|
|
258
285
|
if (this.state) {
|
|
@@ -289,32 +316,39 @@ var Agent = class extends Server {
|
|
|
289
316
|
const _onStart = this.onStart.bind(this);
|
|
290
317
|
this.onStart = async () => {
|
|
291
318
|
return agentContext.run(
|
|
292
|
-
{
|
|
319
|
+
{
|
|
320
|
+
agent: this,
|
|
321
|
+
connection: void 0,
|
|
322
|
+
request: void 0,
|
|
323
|
+
email: void 0
|
|
324
|
+
},
|
|
293
325
|
async () => {
|
|
294
326
|
const servers = this.sql`
|
|
295
327
|
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
296
328
|
`;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
).then((_results) => {
|
|
311
|
-
this.broadcast(
|
|
312
|
-
JSON.stringify({
|
|
313
|
-
mcp: this.getMcpServers(),
|
|
314
|
-
type: "cf_agent_mcp_servers"
|
|
329
|
+
if (servers && Array.isArray(servers) && servers.length > 0) {
|
|
330
|
+
Promise.allSettled(
|
|
331
|
+
servers.map((server) => {
|
|
332
|
+
return this._connectToMcpServerInternal(
|
|
333
|
+
server.name,
|
|
334
|
+
server.server_url,
|
|
335
|
+
server.callback_url,
|
|
336
|
+
server.server_options ? JSON.parse(server.server_options) : void 0,
|
|
337
|
+
{
|
|
338
|
+
id: server.id,
|
|
339
|
+
oauthClientId: server.client_id ?? void 0
|
|
340
|
+
}
|
|
341
|
+
);
|
|
315
342
|
})
|
|
316
|
-
)
|
|
317
|
-
|
|
343
|
+
).then((_results) => {
|
|
344
|
+
this.broadcast(
|
|
345
|
+
JSON.stringify({
|
|
346
|
+
mcp: this.getMcpServers(),
|
|
347
|
+
type: "cf_agent_mcp_servers"
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
318
352
|
await this._tryCatch(() => _onStart());
|
|
319
353
|
}
|
|
320
354
|
);
|
|
@@ -384,9 +418,9 @@ var Agent = class extends Server {
|
|
|
384
418
|
source !== "server" ? [source.id] : []
|
|
385
419
|
);
|
|
386
420
|
return this._tryCatch(() => {
|
|
387
|
-
const { connection, request } = agentContext.getStore() || {};
|
|
421
|
+
const { connection, request, email } = agentContext.getStore() || {};
|
|
388
422
|
return agentContext.run(
|
|
389
|
-
{ agent: this, connection, request },
|
|
423
|
+
{ agent: this, connection, request, email },
|
|
390
424
|
async () => {
|
|
391
425
|
this.observability?.emit(
|
|
392
426
|
{
|
|
@@ -422,18 +456,67 @@ var Agent = class extends Server {
|
|
|
422
456
|
onStateUpdate(state, source) {
|
|
423
457
|
}
|
|
424
458
|
/**
|
|
425
|
-
* Called when the Agent receives an email
|
|
459
|
+
* Called when the Agent receives an email via routeAgentEmail()
|
|
460
|
+
* Override this method to handle incoming emails
|
|
426
461
|
* @param email Email message to process
|
|
427
462
|
*/
|
|
428
|
-
|
|
429
|
-
onEmail(email) {
|
|
463
|
+
async _onEmail(email) {
|
|
430
464
|
return agentContext.run(
|
|
431
|
-
{ agent: this, connection: void 0, request: void 0 },
|
|
465
|
+
{ agent: this, connection: void 0, request: void 0, email },
|
|
432
466
|
async () => {
|
|
433
|
-
|
|
467
|
+
if ("onEmail" in this && typeof this.onEmail === "function") {
|
|
468
|
+
return this._tryCatch(
|
|
469
|
+
() => this.onEmail(email)
|
|
470
|
+
);
|
|
471
|
+
} else {
|
|
472
|
+
console.log("Received email from:", email.from, "to:", email.to);
|
|
473
|
+
console.log("Subject:", email.headers.get("subject"));
|
|
474
|
+
console.log(
|
|
475
|
+
"Implement onEmail(email: AgentEmail): Promise<void> in your agent to process emails"
|
|
476
|
+
);
|
|
477
|
+
}
|
|
434
478
|
}
|
|
435
479
|
);
|
|
436
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* Reply to an email
|
|
483
|
+
* @param email The email to reply to
|
|
484
|
+
* @param options Options for the reply
|
|
485
|
+
* @returns void
|
|
486
|
+
*/
|
|
487
|
+
async replyToEmail(email, options) {
|
|
488
|
+
return this._tryCatch(async () => {
|
|
489
|
+
const agentName = camelCaseToKebabCase(this._ParentClass.name);
|
|
490
|
+
const agentId = this.name;
|
|
491
|
+
const { createMimeMessage } = await import("mimetext");
|
|
492
|
+
const msg = createMimeMessage();
|
|
493
|
+
msg.setSender({ addr: email.to, name: options.fromName });
|
|
494
|
+
msg.setRecipient(email.from);
|
|
495
|
+
msg.setSubject(
|
|
496
|
+
options.subject || `Re: ${email.headers.get("subject")}` || "No subject"
|
|
497
|
+
);
|
|
498
|
+
msg.addMessage({
|
|
499
|
+
contentType: options.contentType || "text/plain",
|
|
500
|
+
data: options.body
|
|
501
|
+
});
|
|
502
|
+
const domain = email.from.split("@")[1];
|
|
503
|
+
const messageId = `<${agentId}@${domain}>`;
|
|
504
|
+
msg.setHeader("In-Reply-To", email.headers.get("Message-ID"));
|
|
505
|
+
msg.setHeader("Message-ID", messageId);
|
|
506
|
+
msg.setHeader("X-Agent-Name", agentName);
|
|
507
|
+
msg.setHeader("X-Agent-ID", agentId);
|
|
508
|
+
if (options.headers) {
|
|
509
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
510
|
+
msg.setHeader(key, value);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
await email.reply({
|
|
514
|
+
from: email.to,
|
|
515
|
+
raw: msg.asRaw(),
|
|
516
|
+
to: email.from
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
}
|
|
437
520
|
async _tryCatch(fn) {
|
|
438
521
|
try {
|
|
439
522
|
return await fn();
|
|
@@ -441,6 +524,55 @@ var Agent = class extends Server {
|
|
|
441
524
|
throw this.onError(e);
|
|
442
525
|
}
|
|
443
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Automatically wrap custom methods with agent context
|
|
529
|
+
* This ensures getCurrentAgent() works in all custom methods without decorators
|
|
530
|
+
*/
|
|
531
|
+
_autoWrapCustomMethods() {
|
|
532
|
+
const basePrototypes = [_Agent.prototype, Server.prototype];
|
|
533
|
+
const baseMethods = /* @__PURE__ */ new Set();
|
|
534
|
+
for (const baseProto of basePrototypes) {
|
|
535
|
+
let proto2 = baseProto;
|
|
536
|
+
while (proto2 && proto2 !== Object.prototype) {
|
|
537
|
+
const methodNames = Object.getOwnPropertyNames(proto2);
|
|
538
|
+
for (const methodName of methodNames) {
|
|
539
|
+
baseMethods.add(methodName);
|
|
540
|
+
}
|
|
541
|
+
proto2 = Object.getPrototypeOf(proto2);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
let proto = Object.getPrototypeOf(this);
|
|
545
|
+
let depth = 0;
|
|
546
|
+
while (proto && proto !== Object.prototype && depth < 10) {
|
|
547
|
+
const methodNames = Object.getOwnPropertyNames(proto);
|
|
548
|
+
for (const methodName of methodNames) {
|
|
549
|
+
if (baseMethods.has(methodName) || methodName.startsWith("_") || typeof this[methodName] !== "function") {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
if (!baseMethods.has(methodName)) {
|
|
553
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
|
|
554
|
+
if (descriptor && typeof descriptor.value === "function") {
|
|
555
|
+
const wrappedFunction = withAgentContext(
|
|
556
|
+
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
557
|
+
this[methodName]
|
|
558
|
+
// biome-ignore lint/suspicious/noExplicitAny: I can't typescript
|
|
559
|
+
);
|
|
560
|
+
if (this._isCallable(methodName)) {
|
|
561
|
+
callableMetadata.set(
|
|
562
|
+
wrappedFunction,
|
|
563
|
+
callableMetadata.get(
|
|
564
|
+
this[methodName]
|
|
565
|
+
)
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
this.constructor.prototype[methodName] = wrappedFunction;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
proto = Object.getPrototypeOf(proto);
|
|
573
|
+
depth++;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
444
576
|
onError(connectionOrError, error) {
|
|
445
577
|
let theError;
|
|
446
578
|
if (connectionOrError && error) {
|
|
@@ -466,6 +598,112 @@ var Agent = class extends Server {
|
|
|
466
598
|
render() {
|
|
467
599
|
throw new Error("Not implemented");
|
|
468
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Queue a task to be executed in the future
|
|
603
|
+
* @param payload Payload to pass to the callback
|
|
604
|
+
* @param callback Name of the method to call
|
|
605
|
+
* @returns The ID of the queued task
|
|
606
|
+
*/
|
|
607
|
+
async queue(callback, payload) {
|
|
608
|
+
const id = nanoid(9);
|
|
609
|
+
if (typeof callback !== "string") {
|
|
610
|
+
throw new Error("Callback must be a string");
|
|
611
|
+
}
|
|
612
|
+
if (typeof this[callback] !== "function") {
|
|
613
|
+
throw new Error(`this.${callback} is not a function`);
|
|
614
|
+
}
|
|
615
|
+
this.sql`
|
|
616
|
+
INSERT OR REPLACE INTO cf_agents_queues (id, payload, callback)
|
|
617
|
+
VALUES (${id}, ${JSON.stringify(payload)}, ${callback})
|
|
618
|
+
`;
|
|
619
|
+
void this._flushQueue().catch((e) => {
|
|
620
|
+
console.error("Error flushing queue:", e);
|
|
621
|
+
});
|
|
622
|
+
return id;
|
|
623
|
+
}
|
|
624
|
+
async _flushQueue() {
|
|
625
|
+
if (this._flushingQueue) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
this._flushingQueue = true;
|
|
629
|
+
while (true) {
|
|
630
|
+
const executed = [];
|
|
631
|
+
const result = this.sql`
|
|
632
|
+
SELECT * FROM cf_agents_queues
|
|
633
|
+
ORDER BY created_at ASC
|
|
634
|
+
`;
|
|
635
|
+
if (!result || result.length === 0) {
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
for (const row of result || []) {
|
|
639
|
+
const callback = this[row.callback];
|
|
640
|
+
if (!callback) {
|
|
641
|
+
console.error(`callback ${row.callback} not found`);
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const { connection, request, email } = agentContext.getStore() || {};
|
|
645
|
+
await agentContext.run(
|
|
646
|
+
{
|
|
647
|
+
agent: this,
|
|
648
|
+
connection,
|
|
649
|
+
request,
|
|
650
|
+
email
|
|
651
|
+
},
|
|
652
|
+
async () => {
|
|
653
|
+
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
654
|
+
executed.push(row.id);
|
|
655
|
+
}
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
for (const id of executed) {
|
|
659
|
+
await this.dequeue(id);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
this._flushingQueue = false;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Dequeue a task by ID
|
|
666
|
+
* @param id ID of the task to dequeue
|
|
667
|
+
*/
|
|
668
|
+
async dequeue(id) {
|
|
669
|
+
this.sql`DELETE FROM cf_agents_queues WHERE id = ${id}`;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Dequeue all tasks
|
|
673
|
+
*/
|
|
674
|
+
async dequeueAll() {
|
|
675
|
+
this.sql`DELETE FROM cf_agents_queues`;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Dequeue all tasks by callback
|
|
679
|
+
* @param callback Name of the callback to dequeue
|
|
680
|
+
*/
|
|
681
|
+
async dequeueAllByCallback(callback) {
|
|
682
|
+
this.sql`DELETE FROM cf_agents_queues WHERE callback = ${callback}`;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Get a queued task by ID
|
|
686
|
+
* @param id ID of the task to get
|
|
687
|
+
* @returns The task or undefined if not found
|
|
688
|
+
*/
|
|
689
|
+
async getQueue(id) {
|
|
690
|
+
const result = this.sql`
|
|
691
|
+
SELECT * FROM cf_agents_queues WHERE id = ${id}
|
|
692
|
+
`;
|
|
693
|
+
return result ? { ...result[0], payload: JSON.parse(result[0].payload) } : void 0;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Get all queues by key and value
|
|
697
|
+
* @param key Key to filter by
|
|
698
|
+
* @param value Value to filter by
|
|
699
|
+
* @returns Array of matching QueueItem objects
|
|
700
|
+
*/
|
|
701
|
+
async getQueues(key, value) {
|
|
702
|
+
const result = this.sql`
|
|
703
|
+
SELECT * FROM cf_agents_queues
|
|
704
|
+
`;
|
|
705
|
+
return result.filter((row) => JSON.parse(row.payload)[key] === value);
|
|
706
|
+
}
|
|
469
707
|
/**
|
|
470
708
|
* Schedule a task to be executed in the future
|
|
471
709
|
* @template T Type of the payload data
|
|
@@ -646,6 +884,7 @@ var Agent = class extends Server {
|
|
|
646
884
|
this.sql`DROP TABLE IF EXISTS cf_agents_state`;
|
|
647
885
|
this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
|
|
648
886
|
this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;
|
|
887
|
+
this.sql`DROP TABLE IF EXISTS cf_agents_queues`;
|
|
649
888
|
await this.ctx.storage.deleteAlarm();
|
|
650
889
|
await this.ctx.storage.deleteAll();
|
|
651
890
|
this.ctx.abort("destroyed");
|
|
@@ -767,17 +1006,19 @@ var Agent = class extends Server {
|
|
|
767
1006
|
const servers = this.sql`
|
|
768
1007
|
SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
|
|
769
1008
|
`;
|
|
770
|
-
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1009
|
+
if (servers && Array.isArray(servers) && servers.length > 0) {
|
|
1010
|
+
for (const server of servers) {
|
|
1011
|
+
const serverConn = this.mcp.mcpConnections[server.id];
|
|
1012
|
+
mcpState.servers[server.id] = {
|
|
1013
|
+
auth_url: server.auth_url,
|
|
1014
|
+
capabilities: serverConn?.serverCapabilities ?? null,
|
|
1015
|
+
instructions: serverConn?.instructions ?? null,
|
|
1016
|
+
name: server.name,
|
|
1017
|
+
server_url: server.server_url,
|
|
1018
|
+
// mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
|
|
1019
|
+
state: serverConn?.connectionState ?? "authenticating"
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
781
1022
|
}
|
|
782
1023
|
return mcpState;
|
|
783
1024
|
}
|
|
@@ -785,11 +1026,12 @@ var Agent = class extends Server {
|
|
|
785
1026
|
/**
|
|
786
1027
|
* Agent configuration options
|
|
787
1028
|
*/
|
|
788
|
-
|
|
1029
|
+
_Agent.options = {
|
|
789
1030
|
/** Whether the Agent should hibernate when inactive */
|
|
790
1031
|
hibernate: true
|
|
791
1032
|
// default to hibernate
|
|
792
1033
|
};
|
|
1034
|
+
var Agent = _Agent;
|
|
793
1035
|
async function routeAgentRequest(request, env, options) {
|
|
794
1036
|
const corsHeaders = options?.cors === true ? {
|
|
795
1037
|
"Access-Control-Allow-Credentials": "true",
|
|
@@ -825,7 +1067,116 @@ async function routeAgentRequest(request, env, options) {
|
|
|
825
1067
|
}
|
|
826
1068
|
return response;
|
|
827
1069
|
}
|
|
828
|
-
|
|
1070
|
+
function createHeaderBasedEmailResolver() {
|
|
1071
|
+
return async (email, _env) => {
|
|
1072
|
+
const messageId = email.headers.get("message-id");
|
|
1073
|
+
if (messageId) {
|
|
1074
|
+
const messageIdMatch = messageId.match(/<([^@]+)@([^>]+)>/);
|
|
1075
|
+
if (messageIdMatch) {
|
|
1076
|
+
const [, agentId2, domain] = messageIdMatch;
|
|
1077
|
+
const agentName2 = domain.split(".")[0];
|
|
1078
|
+
return { agentName: agentName2, agentId: agentId2 };
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
const references = email.headers.get("references");
|
|
1082
|
+
if (references) {
|
|
1083
|
+
const referencesMatch = references.match(
|
|
1084
|
+
/<([A-Za-z0-9+/]{43}=)@([^>]+)>/
|
|
1085
|
+
);
|
|
1086
|
+
if (referencesMatch) {
|
|
1087
|
+
const [, base64Id, domain] = referencesMatch;
|
|
1088
|
+
const agentId2 = Buffer.from(base64Id, "base64").toString("hex");
|
|
1089
|
+
const agentName2 = domain.split(".")[0];
|
|
1090
|
+
return { agentName: agentName2, agentId: agentId2 };
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
const agentName = email.headers.get("x-agent-name");
|
|
1094
|
+
const agentId = email.headers.get("x-agent-id");
|
|
1095
|
+
if (agentName && agentId) {
|
|
1096
|
+
return { agentName, agentId };
|
|
1097
|
+
}
|
|
1098
|
+
return null;
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
function createAddressBasedEmailResolver(defaultAgentName) {
|
|
1102
|
+
return async (email, _env) => {
|
|
1103
|
+
const emailMatch = email.to.match(/^([^+@]+)(?:\+([^@]+))?@(.+)$/);
|
|
1104
|
+
if (!emailMatch) {
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
const [, localPart, subAddress] = emailMatch;
|
|
1108
|
+
if (subAddress) {
|
|
1109
|
+
return {
|
|
1110
|
+
agentName: localPart,
|
|
1111
|
+
agentId: subAddress
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
return {
|
|
1115
|
+
agentName: defaultAgentName,
|
|
1116
|
+
agentId: localPart
|
|
1117
|
+
};
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
function createCatchAllEmailResolver(agentName, agentId) {
|
|
1121
|
+
return async () => ({ agentName, agentId });
|
|
1122
|
+
}
|
|
1123
|
+
async function routeAgentEmail(email, env, options) {
|
|
1124
|
+
const routingInfo = await options.resolver(email, env);
|
|
1125
|
+
if (!routingInfo) {
|
|
1126
|
+
console.warn("No routing information found for email, dropping message");
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
const namespaceBinding = env[routingInfo.agentName];
|
|
1130
|
+
if (!namespaceBinding) {
|
|
1131
|
+
throw new Error(
|
|
1132
|
+
`Agent namespace '${routingInfo.agentName}' not found in environment`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
if (typeof namespaceBinding !== "object" || !("idFromName" in namespaceBinding) || typeof namespaceBinding.idFromName !== "function") {
|
|
1136
|
+
throw new Error(
|
|
1137
|
+
`Environment binding '${routingInfo.agentName}' is not an AgentNamespace (found: ${typeof namespaceBinding})`
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
const namespace = namespaceBinding;
|
|
1141
|
+
const agent = await getAgentByName(namespace, routingInfo.agentId);
|
|
1142
|
+
const serialisableEmail = {
|
|
1143
|
+
getRaw: async () => {
|
|
1144
|
+
const reader = email.raw.getReader();
|
|
1145
|
+
const chunks = [];
|
|
1146
|
+
let done = false;
|
|
1147
|
+
while (!done) {
|
|
1148
|
+
const { value, done: readerDone } = await reader.read();
|
|
1149
|
+
done = readerDone;
|
|
1150
|
+
if (value) {
|
|
1151
|
+
chunks.push(value);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
1155
|
+
const combined = new Uint8Array(totalLength);
|
|
1156
|
+
let offset = 0;
|
|
1157
|
+
for (const chunk of chunks) {
|
|
1158
|
+
combined.set(chunk, offset);
|
|
1159
|
+
offset += chunk.length;
|
|
1160
|
+
}
|
|
1161
|
+
return combined;
|
|
1162
|
+
},
|
|
1163
|
+
headers: email.headers,
|
|
1164
|
+
rawSize: email.rawSize,
|
|
1165
|
+
setReject: (reason) => {
|
|
1166
|
+
email.setReject(reason);
|
|
1167
|
+
},
|
|
1168
|
+
forward: (rcptTo, headers) => {
|
|
1169
|
+
return email.forward(rcptTo, headers);
|
|
1170
|
+
},
|
|
1171
|
+
reply: (options2) => {
|
|
1172
|
+
return email.reply(
|
|
1173
|
+
new EmailMessage(options2.from, options2.to, options2.raw)
|
|
1174
|
+
);
|
|
1175
|
+
},
|
|
1176
|
+
from: email.from,
|
|
1177
|
+
to: email.to
|
|
1178
|
+
};
|
|
1179
|
+
await agent._onEmail(serialisableEmail);
|
|
829
1180
|
}
|
|
830
1181
|
async function getAgentByName(namespace, name, options) {
|
|
831
1182
|
return getServerByName(namespace, name, options);
|
|
@@ -903,8 +1254,11 @@ export {
|
|
|
903
1254
|
getCurrentAgent,
|
|
904
1255
|
Agent,
|
|
905
1256
|
routeAgentRequest,
|
|
1257
|
+
createHeaderBasedEmailResolver,
|
|
1258
|
+
createAddressBasedEmailResolver,
|
|
1259
|
+
createCatchAllEmailResolver,
|
|
906
1260
|
routeAgentEmail,
|
|
907
1261
|
getAgentByName,
|
|
908
1262
|
StreamingResponse
|
|
909
1263
|
};
|
|
910
|
-
//# sourceMappingURL=chunk-
|
|
1264
|
+
//# sourceMappingURL=chunk-5YIRLLUX.js.map
|