agents 0.0.0-ac74811 → 0.0.0-afd9efd

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.
Files changed (73) hide show
  1. package/README.md +255 -27
  2. package/dist/_esm-LV5FJ3HK.js +3922 -0
  3. package/dist/_esm-LV5FJ3HK.js.map +1 -0
  4. package/dist/ai-chat-agent.d.ts +14 -9
  5. package/dist/ai-chat-agent.js +485 -66
  6. package/dist/ai-chat-agent.js.map +1 -1
  7. package/dist/ai-chat-v5-migration.d.ts +152 -0
  8. package/dist/ai-chat-v5-migration.js +20 -0
  9. package/dist/ai-chat-v5-migration.js.map +1 -0
  10. package/dist/ai-react.d.ts +69 -71
  11. package/dist/ai-react.js +246 -99
  12. package/dist/ai-react.js.map +1 -1
  13. package/dist/ai-types.d.ts +37 -19
  14. package/dist/ai-types.js +7 -0
  15. package/dist/ccip-CMBYN64O.js +15 -0
  16. package/dist/ccip-CMBYN64O.js.map +1 -0
  17. package/dist/{chunk-JFRK72K3.js → chunk-2Y6KNRNP.js} +591 -158
  18. package/dist/chunk-2Y6KNRNP.js.map +1 -0
  19. package/dist/chunk-5Y6BEZDY.js +276 -0
  20. package/dist/chunk-5Y6BEZDY.js.map +1 -0
  21. package/dist/chunk-BER7KXUJ.js +18 -0
  22. package/dist/chunk-BER7KXUJ.js.map +1 -0
  23. package/dist/{chunk-767EASBA.js → chunk-C2OEBJZ2.js} +14 -7
  24. package/dist/chunk-C2OEBJZ2.js.map +1 -0
  25. package/dist/chunk-JJBFIGUC.js +5202 -0
  26. package/dist/chunk-JJBFIGUC.js.map +1 -0
  27. package/dist/chunk-PR4QN5HX.js +43 -0
  28. package/dist/chunk-PR4QN5HX.js.map +1 -0
  29. package/dist/{chunk-NKZZ66QY.js → chunk-QEVM4BVL.js} +5 -5
  30. package/dist/chunk-QEVM4BVL.js.map +1 -0
  31. package/dist/chunk-QUOGV3WN.js +949 -0
  32. package/dist/chunk-QUOGV3WN.js.map +1 -0
  33. package/dist/chunk-TYAY6AU6.js +159 -0
  34. package/dist/chunk-TYAY6AU6.js.map +1 -0
  35. package/dist/chunk-UJVEAURM.js +150 -0
  36. package/dist/chunk-UJVEAURM.js.map +1 -0
  37. package/dist/client-C8tswVoM.d.ts +5248 -0
  38. package/dist/client.d.ts +2 -2
  39. package/dist/client.js +3 -1
  40. package/dist/codemode/ai.d.ts +25 -0
  41. package/dist/codemode/ai.js +5200 -0
  42. package/dist/codemode/ai.js.map +1 -0
  43. package/dist/index.d.ts +550 -24
  44. package/dist/index.js +14 -4
  45. package/dist/mcp/client.d.ts +10 -1053
  46. package/dist/mcp/client.js +2 -1
  47. package/dist/mcp/do-oauth-client-provider.d.ts +1 -0
  48. package/dist/mcp/do-oauth-client-provider.js +2 -1
  49. package/dist/mcp/index.d.ts +58 -63
  50. package/dist/mcp/index.js +969 -637
  51. package/dist/mcp/index.js.map +1 -1
  52. package/dist/mcp/x402.d.ts +39 -0
  53. package/dist/mcp/x402.js +3195 -0
  54. package/dist/mcp/x402.js.map +1 -0
  55. package/dist/mcp-BH1fJeiU.d.ts +58 -0
  56. package/dist/observability/index.d.ts +34 -12
  57. package/dist/observability/index.js +6 -4
  58. package/dist/react.d.ts +19 -11
  59. package/dist/react.js +107 -7
  60. package/dist/react.js.map +1 -1
  61. package/dist/schedule.d.ts +83 -9
  62. package/dist/schedule.js +17 -2
  63. package/dist/schedule.js.map +1 -1
  64. package/dist/secp256k1-M22GZP2U.js +2193 -0
  65. package/dist/secp256k1-M22GZP2U.js.map +1 -0
  66. package/package.json +41 -12
  67. package/src/index.ts +874 -208
  68. package/dist/chunk-767EASBA.js.map +0 -1
  69. package/dist/chunk-E3LCYPCB.js +0 -469
  70. package/dist/chunk-E3LCYPCB.js.map +0 -1
  71. package/dist/chunk-JFRK72K3.js.map +0 -1
  72. package/dist/chunk-NKZZ66QY.js.map +0 -1
  73. package/dist/index-CITGJflw.d.ts +0 -486
@@ -1,30 +1,32 @@
1
1
  import {
2
+ DisposableStore,
2
3
  MCPClientManager
3
- } from "./chunk-E3LCYPCB.js";
4
+ } from "./chunk-QUOGV3WN.js";
4
5
  import {
5
6
  DurableObjectOAuthClientProvider
6
- } from "./chunk-767EASBA.js";
7
+ } from "./chunk-C2OEBJZ2.js";
7
8
  import {
8
9
  camelCaseToKebabCase
9
- } from "./chunk-NKZZ66QY.js";
10
+ } from "./chunk-QEVM4BVL.js";
10
11
 
11
12
  // src/index.ts
12
13
  import { AsyncLocalStorage } from "async_hooks";
13
14
  import { parseCronExpression } from "cron-schedule";
14
15
  import { nanoid } from "nanoid";
16
+ import { EmailMessage } from "cloudflare:email";
15
17
  import {
18
+ Server,
16
19
  getServerByName,
17
- routePartykitRequest,
18
- Server
20
+ routePartykitRequest
19
21
  } from "partyserver";
20
22
  function isRPCRequest(msg) {
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);
23
+ return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "rpc" /* RPC */ && "id" in msg && typeof msg.id === "string" && "method" in msg && typeof msg.method === "string" && "args" in msg && Array.isArray(msg.args);
22
24
  }
23
25
  function isStateUpdateMessage(msg) {
24
- return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "cf_agent_state" && "state" in msg;
26
+ return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "cf_agent_state" /* CF_AGENT_STATE */ && "state" in msg;
25
27
  }
26
28
  var callableMetadata = /* @__PURE__ */ new Map();
27
- function unstable_callable(metadata = {}) {
29
+ function callable(metadata = {}) {
28
30
  return function callableDecorator(target, context) {
29
31
  if (!callableMetadata.has(target)) {
30
32
  callableMetadata.set(target, metadata);
@@ -32,6 +34,16 @@ function unstable_callable(metadata = {}) {
32
34
  return target;
33
35
  };
34
36
  }
37
+ var didWarnAboutUnstableCallable = false;
38
+ var unstable_callable = (metadata = {}) => {
39
+ if (!didWarnAboutUnstableCallable) {
40
+ didWarnAboutUnstableCallable = true;
41
+ console.warn(
42
+ "unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version."
43
+ );
44
+ }
45
+ callable(metadata);
46
+ };
35
47
  function getNextCronTime(cron) {
36
48
  const interval = parseCronExpression(cron);
37
49
  return interval.getNextDate();
@@ -46,17 +58,33 @@ function getCurrentAgent() {
46
58
  return {
47
59
  agent: void 0,
48
60
  connection: void 0,
49
- request: void 0
61
+ request: void 0,
62
+ email: void 0
50
63
  };
51
64
  }
52
65
  return store;
53
66
  }
54
- var Agent = class extends Server {
67
+ function withAgentContext(method) {
68
+ return function(...args) {
69
+ const { connection, request, email, agent } = getCurrentAgent();
70
+ if (agent === this) {
71
+ return method.apply(this, args);
72
+ }
73
+ return agentContext.run({ agent: this, connection, request, email }, () => {
74
+ return method.apply(this, args);
75
+ });
76
+ };
77
+ }
78
+ var _Agent = class _Agent extends Server {
55
79
  constructor(ctx, env) {
56
80
  super(ctx, env);
57
81
  this._state = DEFAULT_STATE;
82
+ this._disposables = new DisposableStore();
58
83
  this._ParentClass = Object.getPrototypeOf(this).constructor;
59
- this.mcp = new MCPClientManager(this._ParentClass.name, "0.0.1");
84
+ this.mcp = new MCPClientManager(
85
+ this._ParentClass.name,
86
+ "0.0.1"
87
+ );
60
88
  /**
61
89
  * Initial state for the Agent
62
90
  * Override to provide default state values
@@ -66,6 +94,7 @@ var Agent = class extends Server {
66
94
  * The observability implementation to use for the Agent
67
95
  */
68
96
  this.observability = genericObservability;
97
+ this._flushingQueue = false;
69
98
  /**
70
99
  * Method called when an alarm fires.
71
100
  * Executes any scheduled tasks that are due.
@@ -79,52 +108,84 @@ var Agent = class extends Server {
79
108
  const result = this.sql`
80
109
  SELECT * FROM cf_agents_schedules WHERE time <= ${now}
81
110
  `;
82
- for (const row of result || []) {
83
- const callback = this[row.callback];
84
- if (!callback) {
85
- console.error(`callback ${row.callback} not found`);
86
- continue;
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
- }
111
+ if (result && Array.isArray(result)) {
112
+ for (const row of result) {
113
+ const callback = this[row.callback];
114
+ if (!callback) {
115
+ console.error(`callback ${row.callback} not found`);
116
+ continue;
106
117
  }
107
- );
108
- if (row.type === "cron") {
109
- const nextExecutionTime = getNextCronTime(row.cron);
110
- const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
111
- this.sql`
118
+ await agentContext.run(
119
+ {
120
+ agent: this,
121
+ connection: void 0,
122
+ request: void 0,
123
+ email: void 0
124
+ },
125
+ async () => {
126
+ try {
127
+ this.observability?.emit(
128
+ {
129
+ displayMessage: `Schedule ${row.id} executed`,
130
+ id: nanoid(),
131
+ payload: {
132
+ callback: row.callback,
133
+ id: row.id
134
+ },
135
+ timestamp: Date.now(),
136
+ type: "schedule:execute"
137
+ },
138
+ this.ctx
139
+ );
140
+ await callback.bind(this)(JSON.parse(row.payload), row);
141
+ } catch (e) {
142
+ console.error(`error executing callback "${row.callback}"`, e);
143
+ }
144
+ }
145
+ );
146
+ if (row.type === "cron") {
147
+ const nextExecutionTime = getNextCronTime(row.cron);
148
+ const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
149
+ this.sql`
112
150
  UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
113
151
  `;
114
- } else {
115
- this.sql`
152
+ } else {
153
+ this.sql`
116
154
  DELETE FROM cf_agents_schedules WHERE id = ${row.id}
117
155
  `;
156
+ }
118
157
  }
119
158
  }
120
159
  await this._scheduleNextAlarm();
121
160
  };
161
+ if (!wrappedClasses.has(this.constructor)) {
162
+ this._autoWrapCustomMethods();
163
+ wrappedClasses.add(this.constructor);
164
+ }
165
+ this._disposables.add(
166
+ this.mcp.onConnected(async () => {
167
+ this.broadcastMcpServers();
168
+ })
169
+ );
170
+ this._disposables.add(
171
+ this.mcp.onObservabilityEvent((event) => {
172
+ this.observability?.emit(event);
173
+ })
174
+ );
122
175
  this.sql`
123
176
  CREATE TABLE IF NOT EXISTS cf_agents_state (
124
177
  id TEXT PRIMARY KEY NOT NULL,
125
178
  state TEXT
126
179
  )
127
180
  `;
181
+ this.sql`
182
+ CREATE TABLE IF NOT EXISTS cf_agents_queues (
183
+ id TEXT PRIMARY KEY NOT NULL,
184
+ payload TEXT,
185
+ callback TEXT,
186
+ created_at INTEGER DEFAULT (unixepoch())
187
+ )
188
+ `;
128
189
  void this.ctx.blockConcurrencyWhile(async () => {
129
190
  return this._tryCatch(async () => {
130
191
  this.sql`
@@ -156,20 +217,19 @@ var Agent = class extends Server {
156
217
  const _onRequest = this.onRequest.bind(this);
157
218
  this.onRequest = (request) => {
158
219
  return agentContext.run(
159
- { agent: this, connection: void 0, request },
220
+ { agent: this, connection: void 0, request, email: void 0 },
160
221
  async () => {
161
222
  if (this.mcp.isCallbackRequest(request)) {
162
- await this.mcp.handleCallbackRequest(request);
163
- this.broadcast(
164
- JSON.stringify({
165
- mcp: this.getMcpServers(),
166
- type: "cf_agent_mcp_servers"
167
- })
168
- );
169
- return new Response("<script>window.close();</script>", {
170
- headers: { "content-type": "text/html" },
171
- status: 200
172
- });
223
+ const result = await this.mcp.handleCallbackRequest(request);
224
+ this.broadcastMcpServers();
225
+ if (result.authSuccess) {
226
+ this.mcp.establishConnection(result.serverId).catch((error) => {
227
+ console.error("Background connection failed:", error);
228
+ }).finally(() => {
229
+ this.broadcastMcpServers();
230
+ });
231
+ }
232
+ return this.handleOAuthCallbackResponse(result, request);
173
233
  }
174
234
  return this._tryCatch(() => _onRequest(request));
175
235
  }
@@ -178,7 +238,7 @@ var Agent = class extends Server {
178
238
  const _onMessage = this.onMessage.bind(this);
179
239
  this.onMessage = async (connection, message) => {
180
240
  return agentContext.run(
181
- { agent: this, connection, request: void 0 },
241
+ { agent: this, connection, request: void 0, email: void 0 },
182
242
  async () => {
183
243
  if (typeof message !== "string") {
184
244
  return this._tryCatch(() => _onMessage(connection, message));
@@ -215,10 +275,8 @@ var Agent = class extends Server {
215
275
  displayMessage: `RPC call to ${method}`,
216
276
  id: nanoid(),
217
277
  payload: {
218
- args,
219
278
  method,
220
- streaming: metadata?.streaming,
221
- success: true
279
+ streaming: metadata?.streaming
222
280
  },
223
281
  timestamp: Date.now(),
224
282
  type: "rpc"
@@ -230,7 +288,7 @@ var Agent = class extends Server {
230
288
  id,
231
289
  result,
232
290
  success: true,
233
- type: "rpc"
291
+ type: "rpc" /* RPC */
234
292
  };
235
293
  connection.send(JSON.stringify(response));
236
294
  } catch (e) {
@@ -238,7 +296,7 @@ var Agent = class extends Server {
238
296
  error: e instanceof Error ? e.message : "Unknown error occurred",
239
297
  id: parsed.id,
240
298
  success: false,
241
- type: "rpc"
299
+ type: "rpc" /* RPC */
242
300
  };
243
301
  connection.send(JSON.stringify(response));
244
302
  console.error("RPC error:", e);
@@ -252,70 +310,84 @@ var Agent = class extends Server {
252
310
  const _onConnect = this.onConnect.bind(this);
253
311
  this.onConnect = (connection, ctx2) => {
254
312
  return agentContext.run(
255
- { agent: this, connection, request: ctx2.request },
256
- async () => {
257
- setTimeout(() => {
258
- if (this.state) {
259
- connection.send(
260
- JSON.stringify({
261
- state: this.state,
262
- type: "cf_agent_state"
263
- })
264
- );
265
- }
313
+ { agent: this, connection, request: ctx2.request, email: void 0 },
314
+ () => {
315
+ if (this.state) {
266
316
  connection.send(
267
317
  JSON.stringify({
268
- mcp: this.getMcpServers(),
269
- type: "cf_agent_mcp_servers"
318
+ state: this.state,
319
+ type: "cf_agent_state" /* CF_AGENT_STATE */
270
320
  })
271
321
  );
272
- this.observability?.emit(
273
- {
274
- displayMessage: "Connection established",
275
- id: nanoid(),
276
- payload: {
277
- connectionId: connection.id
278
- },
279
- timestamp: Date.now(),
280
- type: "connect"
322
+ }
323
+ connection.send(
324
+ JSON.stringify({
325
+ mcp: this.getMcpServers(),
326
+ type: "cf_agent_mcp_servers" /* CF_AGENT_MCP_SERVERS */
327
+ })
328
+ );
329
+ this.observability?.emit(
330
+ {
331
+ displayMessage: "Connection established",
332
+ id: nanoid(),
333
+ payload: {
334
+ connectionId: connection.id
281
335
  },
282
- this.ctx
283
- );
284
- return this._tryCatch(() => _onConnect(connection, ctx2));
285
- }, 20);
336
+ timestamp: Date.now(),
337
+ type: "connect"
338
+ },
339
+ this.ctx
340
+ );
341
+ return this._tryCatch(() => _onConnect(connection, ctx2));
286
342
  }
287
343
  );
288
344
  };
289
345
  const _onStart = this.onStart.bind(this);
290
- this.onStart = async () => {
346
+ this.onStart = async (props) => {
291
347
  return agentContext.run(
292
- { agent: this, connection: void 0, request: void 0 },
348
+ {
349
+ agent: this,
350
+ connection: void 0,
351
+ request: void 0,
352
+ email: void 0
353
+ },
293
354
  async () => {
294
- const servers = this.sql`
355
+ await this._tryCatch(() => {
356
+ const servers = this.sql`
295
357
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
296
358
  `;
297
- Promise.allSettled(
298
- servers.map((server) => {
299
- return this._connectToMcpServerInternal(
300
- server.name,
301
- server.server_url,
302
- server.callback_url,
303
- server.server_options ? JSON.parse(server.server_options) : void 0,
304
- {
305
- id: server.id,
306
- oauthClientId: server.client_id ?? void 0
359
+ this.broadcastMcpServers();
360
+ if (servers && Array.isArray(servers) && servers.length > 0) {
361
+ servers.forEach((server) => {
362
+ if (server.callback_url) {
363
+ this.mcp.registerCallbackUrl(
364
+ `${server.callback_url}/${server.id}`
365
+ );
307
366
  }
308
- );
309
- })
310
- ).then((_results) => {
311
- this.broadcast(
312
- JSON.stringify({
313
- mcp: this.getMcpServers(),
314
- type: "cf_agent_mcp_servers"
315
- })
316
- );
367
+ });
368
+ servers.forEach((server) => {
369
+ this._connectToMcpServerInternal(
370
+ server.name,
371
+ server.server_url,
372
+ server.callback_url,
373
+ server.server_options ? JSON.parse(server.server_options) : void 0,
374
+ {
375
+ id: server.id,
376
+ oauthClientId: server.client_id ?? void 0
377
+ }
378
+ ).then(() => {
379
+ this.broadcastMcpServers();
380
+ }).catch((error) => {
381
+ console.error(
382
+ `Error connecting to MCP server: ${server.name} (${server.server_url})`,
383
+ error
384
+ );
385
+ this.broadcastMcpServers();
386
+ });
387
+ });
388
+ }
389
+ return _onStart(props);
317
390
  });
318
- await this._tryCatch(() => _onStart());
319
391
  }
320
392
  );
321
393
  };
@@ -366,7 +438,6 @@ var Agent = class extends Server {
366
438
  }
367
439
  }
368
440
  _setStateInternal(state, source = "server") {
369
- const previousState = this._state;
370
441
  this._state = state;
371
442
  this.sql`
372
443
  INSERT OR REPLACE INTO cf_agents_state (id, state)
@@ -379,23 +450,20 @@ var Agent = class extends Server {
379
450
  this.broadcast(
380
451
  JSON.stringify({
381
452
  state,
382
- type: "cf_agent_state"
453
+ type: "cf_agent_state" /* CF_AGENT_STATE */
383
454
  }),
384
455
  source !== "server" ? [source.id] : []
385
456
  );
386
457
  return this._tryCatch(() => {
387
- const { connection, request } = agentContext.getStore() || {};
458
+ const { connection, request, email } = agentContext.getStore() || {};
388
459
  return agentContext.run(
389
- { agent: this, connection, request },
460
+ { agent: this, connection, request, email },
390
461
  async () => {
391
462
  this.observability?.emit(
392
463
  {
393
464
  displayMessage: "State updated",
394
465
  id: nanoid(),
395
- payload: {
396
- previousState,
397
- state
398
- },
466
+ payload: {},
399
467
  timestamp: Date.now(),
400
468
  type: "state:update"
401
469
  },
@@ -422,18 +490,67 @@ var Agent = class extends Server {
422
490
  onStateUpdate(state, source) {
423
491
  }
424
492
  /**
425
- * Called when the Agent receives an email
493
+ * Called when the Agent receives an email via routeAgentEmail()
494
+ * Override this method to handle incoming emails
426
495
  * @param email Email message to process
427
496
  */
428
- // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
429
- onEmail(email) {
497
+ async _onEmail(email) {
430
498
  return agentContext.run(
431
- { agent: this, connection: void 0, request: void 0 },
499
+ { agent: this, connection: void 0, request: void 0, email },
432
500
  async () => {
433
- console.error("onEmail not implemented");
501
+ if ("onEmail" in this && typeof this.onEmail === "function") {
502
+ return this._tryCatch(
503
+ () => this.onEmail(email)
504
+ );
505
+ } else {
506
+ console.log("Received email from:", email.from, "to:", email.to);
507
+ console.log("Subject:", email.headers.get("subject"));
508
+ console.log(
509
+ "Implement onEmail(email: AgentEmail): Promise<void> in your agent to process emails"
510
+ );
511
+ }
434
512
  }
435
513
  );
436
514
  }
515
+ /**
516
+ * Reply to an email
517
+ * @param email The email to reply to
518
+ * @param options Options for the reply
519
+ * @returns void
520
+ */
521
+ async replyToEmail(email, options) {
522
+ return this._tryCatch(async () => {
523
+ const agentName = camelCaseToKebabCase(this._ParentClass.name);
524
+ const agentId = this.name;
525
+ const { createMimeMessage } = await import("mimetext");
526
+ const msg = createMimeMessage();
527
+ msg.setSender({ addr: email.to, name: options.fromName });
528
+ msg.setRecipient(email.from);
529
+ msg.setSubject(
530
+ options.subject || `Re: ${email.headers.get("subject")}` || "No subject"
531
+ );
532
+ msg.addMessage({
533
+ contentType: options.contentType || "text/plain",
534
+ data: options.body
535
+ });
536
+ const domain = email.from.split("@")[1];
537
+ const messageId = `<${agentId}@${domain}>`;
538
+ msg.setHeader("In-Reply-To", email.headers.get("Message-ID"));
539
+ msg.setHeader("Message-ID", messageId);
540
+ msg.setHeader("X-Agent-Name", agentName);
541
+ msg.setHeader("X-Agent-ID", agentId);
542
+ if (options.headers) {
543
+ for (const [key, value] of Object.entries(options.headers)) {
544
+ msg.setHeader(key, value);
545
+ }
546
+ }
547
+ await email.reply({
548
+ from: email.to,
549
+ raw: msg.asRaw(),
550
+ to: email.from
551
+ });
552
+ });
553
+ }
437
554
  async _tryCatch(fn) {
438
555
  try {
439
556
  return await fn();
@@ -441,6 +558,49 @@ var Agent = class extends Server {
441
558
  throw this.onError(e);
442
559
  }
443
560
  }
561
+ /**
562
+ * Automatically wrap custom methods with agent context
563
+ * This ensures getCurrentAgent() works in all custom methods without decorators
564
+ */
565
+ _autoWrapCustomMethods() {
566
+ const basePrototypes = [_Agent.prototype, Server.prototype];
567
+ const baseMethods = /* @__PURE__ */ new Set();
568
+ for (const baseProto of basePrototypes) {
569
+ let proto2 = baseProto;
570
+ while (proto2 && proto2 !== Object.prototype) {
571
+ const methodNames = Object.getOwnPropertyNames(proto2);
572
+ for (const methodName of methodNames) {
573
+ baseMethods.add(methodName);
574
+ }
575
+ proto2 = Object.getPrototypeOf(proto2);
576
+ }
577
+ }
578
+ let proto = Object.getPrototypeOf(this);
579
+ let depth = 0;
580
+ while (proto && proto !== Object.prototype && depth < 10) {
581
+ const methodNames = Object.getOwnPropertyNames(proto);
582
+ for (const methodName of methodNames) {
583
+ const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
584
+ if (baseMethods.has(methodName) || methodName.startsWith("_") || !descriptor || !!descriptor.get || typeof descriptor.value !== "function") {
585
+ continue;
586
+ }
587
+ const wrappedFunction = withAgentContext(
588
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
589
+ this[methodName]
590
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
591
+ );
592
+ if (this._isCallable(methodName)) {
593
+ callableMetadata.set(
594
+ wrappedFunction,
595
+ callableMetadata.get(this[methodName])
596
+ );
597
+ }
598
+ this.constructor.prototype[methodName] = wrappedFunction;
599
+ }
600
+ proto = Object.getPrototypeOf(proto);
601
+ depth++;
602
+ }
603
+ }
444
604
  onError(connectionOrError, error) {
445
605
  let theError;
446
606
  if (connectionOrError && error) {
@@ -466,6 +626,108 @@ var Agent = class extends Server {
466
626
  render() {
467
627
  throw new Error("Not implemented");
468
628
  }
629
+ /**
630
+ * Queue a task to be executed in the future
631
+ * @param payload Payload to pass to the callback
632
+ * @param callback Name of the method to call
633
+ * @returns The ID of the queued task
634
+ */
635
+ async queue(callback, payload) {
636
+ const id = nanoid(9);
637
+ if (typeof callback !== "string") {
638
+ throw new Error("Callback must be a string");
639
+ }
640
+ if (typeof this[callback] !== "function") {
641
+ throw new Error(`this.${callback} is not a function`);
642
+ }
643
+ this.sql`
644
+ INSERT OR REPLACE INTO cf_agents_queues (id, payload, callback)
645
+ VALUES (${id}, ${JSON.stringify(payload)}, ${callback})
646
+ `;
647
+ void this._flushQueue().catch((e) => {
648
+ console.error("Error flushing queue:", e);
649
+ });
650
+ return id;
651
+ }
652
+ async _flushQueue() {
653
+ if (this._flushingQueue) {
654
+ return;
655
+ }
656
+ this._flushingQueue = true;
657
+ while (true) {
658
+ const result = this.sql`
659
+ SELECT * FROM cf_agents_queues
660
+ ORDER BY created_at ASC
661
+ `;
662
+ if (!result || result.length === 0) {
663
+ break;
664
+ }
665
+ for (const row of result || []) {
666
+ const callback = this[row.callback];
667
+ if (!callback) {
668
+ console.error(`callback ${row.callback} not found`);
669
+ continue;
670
+ }
671
+ const { connection, request, email } = agentContext.getStore() || {};
672
+ await agentContext.run(
673
+ {
674
+ agent: this,
675
+ connection,
676
+ request,
677
+ email
678
+ },
679
+ async () => {
680
+ await callback.bind(this)(JSON.parse(row.payload), row);
681
+ await this.dequeue(row.id);
682
+ }
683
+ );
684
+ }
685
+ }
686
+ this._flushingQueue = false;
687
+ }
688
+ /**
689
+ * Dequeue a task by ID
690
+ * @param id ID of the task to dequeue
691
+ */
692
+ async dequeue(id) {
693
+ this.sql`DELETE FROM cf_agents_queues WHERE id = ${id}`;
694
+ }
695
+ /**
696
+ * Dequeue all tasks
697
+ */
698
+ async dequeueAll() {
699
+ this.sql`DELETE FROM cf_agents_queues`;
700
+ }
701
+ /**
702
+ * Dequeue all tasks by callback
703
+ * @param callback Name of the callback to dequeue
704
+ */
705
+ async dequeueAllByCallback(callback) {
706
+ this.sql`DELETE FROM cf_agents_queues WHERE callback = ${callback}`;
707
+ }
708
+ /**
709
+ * Get a queued task by ID
710
+ * @param id ID of the task to get
711
+ * @returns The task or undefined if not found
712
+ */
713
+ async getQueue(id) {
714
+ const result = this.sql`
715
+ SELECT * FROM cf_agents_queues WHERE id = ${id}
716
+ `;
717
+ return result ? { ...result[0], payload: JSON.parse(result[0].payload) } : void 0;
718
+ }
719
+ /**
720
+ * Get all queues by key and value
721
+ * @param key Key to filter by
722
+ * @param value Value to filter by
723
+ * @returns Array of matching QueueItem objects
724
+ */
725
+ async getQueues(key, value) {
726
+ const result = this.sql`
727
+ SELECT * FROM cf_agents_queues
728
+ `;
729
+ return result.filter((row) => JSON.parse(row.payload)[key] === value);
730
+ }
469
731
  /**
470
732
  * Schedule a task to be executed in the future
471
733
  * @template T Type of the payload data
@@ -480,7 +742,10 @@ var Agent = class extends Server {
480
742
  {
481
743
  displayMessage: `Schedule ${schedule.id} created`,
482
744
  id: nanoid(),
483
- payload: schedule,
745
+ payload: {
746
+ callback,
747
+ id
748
+ },
484
749
  timestamp: Date.now(),
485
750
  type: "schedule:create"
486
751
  },
@@ -615,7 +880,10 @@ var Agent = class extends Server {
615
880
  {
616
881
  displayMessage: `Schedule ${id} cancelled`,
617
882
  id: nanoid(),
618
- payload: schedule,
883
+ payload: {
884
+ callback: schedule.callback,
885
+ id: schedule.id
886
+ },
619
887
  timestamp: Date.now(),
620
888
  type: "schedule:cancel"
621
889
  },
@@ -628,9 +896,9 @@ var Agent = class extends Server {
628
896
  }
629
897
  async _scheduleNextAlarm() {
630
898
  const result = this.sql`
631
- SELECT time FROM cf_agents_schedules
899
+ SELECT time FROM cf_agents_schedules
632
900
  WHERE time > ${Math.floor(Date.now() / 1e3)}
633
- ORDER BY time ASC
901
+ ORDER BY time ASC
634
902
  LIMIT 1
635
903
  `;
636
904
  if (!result) return;
@@ -646,8 +914,11 @@ var Agent = class extends Server {
646
914
  this.sql`DROP TABLE IF EXISTS cf_agents_state`;
647
915
  this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
648
916
  this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;
917
+ this.sql`DROP TABLE IF EXISTS cf_agents_queues`;
649
918
  await this.ctx.storage.deleteAlarm();
650
919
  await this.ctx.storage.deleteAll();
920
+ this._disposables.dispose();
921
+ await this.mcp.dispose?.();
651
922
  this.ctx.abort("destroyed");
652
923
  this.observability?.emit(
653
924
  {
@@ -670,14 +941,26 @@ var Agent = class extends Server {
670
941
  /**
671
942
  * Connect to a new MCP Server
672
943
  *
944
+ * @param serverName Name of the MCP server
673
945
  * @param url MCP Server SSE URL
674
- * @param callbackHost Base host for the agent, used for the redirect URI.
946
+ * @param callbackHost Base host for the agent, used for the redirect URI. If not provided, will be derived from the current request.
675
947
  * @param agentsPrefix agents routing prefix if not using `agents`
676
- * @param options MCP client and transport (header) options
948
+ * @param options MCP client and transport options
677
949
  * @returns authUrl
678
950
  */
679
951
  async addMcpServer(serverName, url, callbackHost, agentsPrefix = "agents", options) {
680
- const callbackUrl = `${callbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
952
+ let resolvedCallbackHost = callbackHost;
953
+ if (!resolvedCallbackHost) {
954
+ const { request } = getCurrentAgent();
955
+ if (!request) {
956
+ throw new Error(
957
+ "callbackHost is required when not called within a request context"
958
+ );
959
+ }
960
+ const requestUrl = new URL(request.url);
961
+ resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;
962
+ }
963
+ const callbackUrl = `${resolvedCallbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
681
964
  const result = await this._connectToMcpServerInternal(
682
965
  serverName,
683
966
  url,
@@ -697,12 +980,7 @@ var Agent = class extends Server {
697
980
  ${options ? JSON.stringify(options) : null}
698
981
  );
699
982
  `;
700
- this.broadcast(
701
- JSON.stringify({
702
- mcp: this.getMcpServers(),
703
- type: "cf_agent_mcp_servers"
704
- })
705
- );
983
+ this.broadcastMcpServers();
706
984
  return result;
707
985
  }
708
986
  async _connectToMcpServerInternal(_serverName, url, callbackUrl, options, reconnect) {
@@ -717,6 +995,7 @@ var Agent = class extends Server {
717
995
  authProvider.clientId = reconnect.oauthClientId;
718
996
  }
719
997
  }
998
+ const transportType = options?.transport?.type ?? "auto";
720
999
  let headerTransportOpts = {};
721
1000
  if (options?.transport?.headers) {
722
1001
  headerTransportOpts = {
@@ -736,7 +1015,8 @@ var Agent = class extends Server {
736
1015
  reconnect,
737
1016
  transport: {
738
1017
  ...headerTransportOpts,
739
- authProvider
1018
+ authProvider,
1019
+ type: transportType
740
1020
  }
741
1021
  });
742
1022
  return {
@@ -747,15 +1027,11 @@ var Agent = class extends Server {
747
1027
  }
748
1028
  async removeMcpServer(id) {
749
1029
  this.mcp.closeConnection(id);
1030
+ this.mcp.unregisterCallbackUrl(id);
750
1031
  this.sql`
751
1032
  DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
752
1033
  `;
753
- this.broadcast(
754
- JSON.stringify({
755
- mcp: this.getMcpServers(),
756
- type: "cf_agent_mcp_servers"
757
- })
758
- );
1034
+ this.broadcastMcpServers();
759
1035
  }
760
1036
  getMcpServers() {
761
1037
  const mcpState = {
@@ -767,29 +1043,63 @@ var Agent = class extends Server {
767
1043
  const servers = this.sql`
768
1044
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
769
1045
  `;
770
- for (const server of servers) {
771
- const serverConn = this.mcp.mcpConnections[server.id];
772
- mcpState.servers[server.id] = {
773
- auth_url: server.auth_url,
774
- capabilities: serverConn?.serverCapabilities ?? null,
775
- instructions: serverConn?.instructions ?? null,
776
- name: server.name,
777
- server_url: server.server_url,
778
- // mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
779
- state: serverConn?.connectionState ?? "authenticating"
780
- };
1046
+ if (servers && Array.isArray(servers) && servers.length > 0) {
1047
+ for (const server of servers) {
1048
+ const serverConn = this.mcp.mcpConnections[server.id];
1049
+ mcpState.servers[server.id] = {
1050
+ auth_url: server.auth_url,
1051
+ capabilities: serverConn?.serverCapabilities ?? null,
1052
+ instructions: serverConn?.instructions ?? null,
1053
+ name: server.name,
1054
+ server_url: server.server_url,
1055
+ // mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
1056
+ state: serverConn?.connectionState ?? "authenticating"
1057
+ };
1058
+ }
781
1059
  }
782
1060
  return mcpState;
783
1061
  }
1062
+ broadcastMcpServers() {
1063
+ this.broadcast(
1064
+ JSON.stringify({
1065
+ mcp: this.getMcpServers(),
1066
+ type: "cf_agent_mcp_servers" /* CF_AGENT_MCP_SERVERS */
1067
+ })
1068
+ );
1069
+ }
1070
+ /**
1071
+ * Handle OAuth callback response using MCPClientManager configuration
1072
+ * @param result OAuth callback result
1073
+ * @param request The original request (needed for base URL)
1074
+ * @returns Response for the OAuth callback
1075
+ */
1076
+ handleOAuthCallbackResponse(result, request) {
1077
+ const config = this.mcp.getOAuthCallbackConfig();
1078
+ if (config?.customHandler) {
1079
+ return config.customHandler(result);
1080
+ }
1081
+ if (config?.successRedirect && result.authSuccess) {
1082
+ return Response.redirect(config.successRedirect);
1083
+ }
1084
+ if (config?.errorRedirect && !result.authSuccess) {
1085
+ return Response.redirect(
1086
+ `${config.errorRedirect}?error=${encodeURIComponent(result.authError || "Unknown error")}`
1087
+ );
1088
+ }
1089
+ const baseUrl = new URL(request.url).origin;
1090
+ return Response.redirect(baseUrl);
1091
+ }
784
1092
  };
785
1093
  /**
786
1094
  * Agent configuration options
787
1095
  */
788
- Agent.options = {
1096
+ _Agent.options = {
789
1097
  /** Whether the Agent should hibernate when inactive */
790
1098
  hibernate: true
791
1099
  // default to hibernate
792
1100
  };
1101
+ var Agent = _Agent;
1102
+ var wrappedClasses = /* @__PURE__ */ new Set();
793
1103
  async function routeAgentRequest(request, env, options) {
794
1104
  const corsHeaders = options?.cors === true ? {
795
1105
  "Access-Control-Allow-Credentials": "true",
@@ -825,7 +1135,126 @@ async function routeAgentRequest(request, env, options) {
825
1135
  }
826
1136
  return response;
827
1137
  }
828
- async function routeAgentEmail(_email, _env, _options) {
1138
+ function createHeaderBasedEmailResolver() {
1139
+ return async (email, _env) => {
1140
+ const messageId = email.headers.get("message-id");
1141
+ if (messageId) {
1142
+ const messageIdMatch = messageId.match(/<([^@]+)@([^>]+)>/);
1143
+ if (messageIdMatch) {
1144
+ const [, agentId2, domain] = messageIdMatch;
1145
+ const agentName2 = domain.split(".")[0];
1146
+ return { agentName: agentName2, agentId: agentId2 };
1147
+ }
1148
+ }
1149
+ const references = email.headers.get("references");
1150
+ if (references) {
1151
+ const referencesMatch = references.match(
1152
+ /<([A-Za-z0-9+/]{43}=)@([^>]+)>/
1153
+ );
1154
+ if (referencesMatch) {
1155
+ const [, base64Id, domain] = referencesMatch;
1156
+ const agentId2 = Buffer.from(base64Id, "base64").toString("hex");
1157
+ const agentName2 = domain.split(".")[0];
1158
+ return { agentName: agentName2, agentId: agentId2 };
1159
+ }
1160
+ }
1161
+ const agentName = email.headers.get("x-agent-name");
1162
+ const agentId = email.headers.get("x-agent-id");
1163
+ if (agentName && agentId) {
1164
+ return { agentName, agentId };
1165
+ }
1166
+ return null;
1167
+ };
1168
+ }
1169
+ function createAddressBasedEmailResolver(defaultAgentName) {
1170
+ return async (email, _env) => {
1171
+ const emailMatch = email.to.match(/^([^+@]+)(?:\+([^@]+))?@(.+)$/);
1172
+ if (!emailMatch) {
1173
+ return null;
1174
+ }
1175
+ const [, localPart, subAddress] = emailMatch;
1176
+ if (subAddress) {
1177
+ return {
1178
+ agentName: localPart,
1179
+ agentId: subAddress
1180
+ };
1181
+ }
1182
+ return {
1183
+ agentName: defaultAgentName,
1184
+ agentId: localPart
1185
+ };
1186
+ };
1187
+ }
1188
+ function createCatchAllEmailResolver(agentName, agentId) {
1189
+ return async () => ({ agentName, agentId });
1190
+ }
1191
+ var agentMapCache = /* @__PURE__ */ new WeakMap();
1192
+ async function routeAgentEmail(email, env, options) {
1193
+ const routingInfo = await options.resolver(email, env);
1194
+ if (!routingInfo) {
1195
+ console.warn("No routing information found for email, dropping message");
1196
+ return;
1197
+ }
1198
+ if (!agentMapCache.has(env)) {
1199
+ const map = {};
1200
+ for (const [key, value] of Object.entries(env)) {
1201
+ if (value && typeof value === "object" && "idFromName" in value && typeof value.idFromName === "function") {
1202
+ map[key] = value;
1203
+ map[camelCaseToKebabCase(key)] = value;
1204
+ }
1205
+ }
1206
+ agentMapCache.set(env, map);
1207
+ }
1208
+ const agentMap = agentMapCache.get(env);
1209
+ const namespace = agentMap[routingInfo.agentName];
1210
+ if (!namespace) {
1211
+ const availableAgents = Object.keys(agentMap).filter((key) => !key.includes("-")).join(", ");
1212
+ throw new Error(
1213
+ `Agent namespace '${routingInfo.agentName}' not found in environment. Available agents: ${availableAgents}`
1214
+ );
1215
+ }
1216
+ const agent = await getAgentByName(
1217
+ namespace,
1218
+ routingInfo.agentId
1219
+ );
1220
+ const serialisableEmail = {
1221
+ getRaw: async () => {
1222
+ const reader = email.raw.getReader();
1223
+ const chunks = [];
1224
+ let done = false;
1225
+ while (!done) {
1226
+ const { value, done: readerDone } = await reader.read();
1227
+ done = readerDone;
1228
+ if (value) {
1229
+ chunks.push(value);
1230
+ }
1231
+ }
1232
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
1233
+ const combined = new Uint8Array(totalLength);
1234
+ let offset = 0;
1235
+ for (const chunk of chunks) {
1236
+ combined.set(chunk, offset);
1237
+ offset += chunk.length;
1238
+ }
1239
+ return combined;
1240
+ },
1241
+ headers: email.headers,
1242
+ rawSize: email.rawSize,
1243
+ setReject: (reason) => {
1244
+ email.setReject(reason);
1245
+ },
1246
+ forward: (rcptTo, headers) => {
1247
+ return email.forward(rcptTo, headers);
1248
+ },
1249
+ reply: (options2) => {
1250
+ return email.reply(
1251
+ new EmailMessage(options2.from, options2.to, options2.raw)
1252
+ );
1253
+ },
1254
+ from: email.from,
1255
+ to: email.to
1256
+ };
1257
+ await agent._onEmail(serialisableEmail);
829
1258
  }
830
1259
  async function getAgentByName(namespace, name, options) {
831
1260
  return getServerByName(namespace, name, options);
@@ -849,7 +1278,7 @@ var StreamingResponse = class {
849
1278
  id: this._id,
850
1279
  result: chunk,
851
1280
  success: true,
852
- type: "rpc"
1281
+ type: "rpc" /* RPC */
853
1282
  };
854
1283
  this._connection.send(JSON.stringify(response));
855
1284
  }
@@ -867,7 +1296,7 @@ var StreamingResponse = class {
867
1296
  id: this._id,
868
1297
  result: finalChunk,
869
1298
  success: true,
870
- type: "rpc"
1299
+ type: "rpc" /* RPC */
871
1300
  };
872
1301
  this._connection.send(JSON.stringify(response));
873
1302
  }
@@ -899,12 +1328,16 @@ function isLocalMode() {
899
1328
 
900
1329
  export {
901
1330
  genericObservability,
1331
+ callable,
902
1332
  unstable_callable,
903
1333
  getCurrentAgent,
904
1334
  Agent,
905
1335
  routeAgentRequest,
1336
+ createHeaderBasedEmailResolver,
1337
+ createAddressBasedEmailResolver,
1338
+ createCatchAllEmailResolver,
906
1339
  routeAgentEmail,
907
1340
  getAgentByName,
908
1341
  StreamingResponse
909
1342
  };
910
- //# sourceMappingURL=chunk-JFRK72K3.js.map
1343
+ //# sourceMappingURL=chunk-2Y6KNRNP.js.map