agents 0.7.4 → 0.7.6

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 (81) hide show
  1. package/dist/ai-chat-agent.js +3 -4
  2. package/dist/ai-chat-agent.js.map +1 -1
  3. package/dist/ai-chat-v5-migration.js +3 -4
  4. package/dist/ai-chat-v5-migration.js.map +1 -1
  5. package/dist/ai-react.js +3 -4
  6. package/dist/ai-react.js.map +1 -1
  7. package/dist/ai-types.js +1 -2
  8. package/dist/ai-types.js.map +1 -1
  9. package/dist/cli/index.js +2 -4
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/client-K8Z-u76l.js +1468 -0
  12. package/dist/client-K8Z-u76l.js.map +1 -0
  13. package/dist/client.js +1 -2
  14. package/dist/client.js.map +1 -1
  15. package/dist/codemode/ai.js +2 -2
  16. package/dist/do-oauth-client-provider-C2jurFjW.d.ts +78 -0
  17. package/dist/email-U_MG7UET.d.ts +157 -0
  18. package/dist/email.d.ts +16 -146
  19. package/dist/email.js +2 -2
  20. package/dist/email.js.map +1 -1
  21. package/dist/experimental/forever.d.ts +26 -71
  22. package/dist/experimental/forever.js +2 -3
  23. package/dist/experimental/forever.js.map +1 -1
  24. package/dist/experimental/memory/session/index.js +3 -12
  25. package/dist/experimental/memory/session/index.js.map +1 -1
  26. package/dist/experimental/workspace.d.ts +273 -0
  27. package/dist/experimental/workspace.js +1265 -0
  28. package/dist/experimental/workspace.js.map +1 -0
  29. package/dist/index-BS_jL8MI.d.ts +492 -0
  30. package/dist/index-WBy5hmm3.d.ts +2840 -0
  31. package/dist/index.d.ts +49 -1320
  32. package/dist/index.js +281 -138
  33. package/dist/index.js.map +1 -1
  34. package/dist/internal_context-DgcmHqS1.d.ts +37 -0
  35. package/dist/internal_context.d.ts +5 -32
  36. package/dist/internal_context.js +1 -2
  37. package/dist/internal_context.js.map +1 -1
  38. package/dist/mcp/client.d.ts +2 -575
  39. package/dist/mcp/client.js +1 -847
  40. package/dist/mcp/do-oauth-client-provider.d.ts +2 -61
  41. package/dist/mcp/do-oauth-client-provider.js +1 -2
  42. package/dist/mcp/do-oauth-client-provider.js.map +1 -1
  43. package/dist/mcp/index.d.ts +2 -95
  44. package/dist/mcp/index.js +60 -57
  45. package/dist/mcp/index.js.map +1 -1
  46. package/dist/mcp/x402.js +1 -2
  47. package/dist/mcp/x402.js.map +1 -1
  48. package/dist/observability/index.d.ts +2 -93
  49. package/dist/observability/index.js +4 -3
  50. package/dist/observability/index.js.map +1 -1
  51. package/dist/react.d.ts +1 -2
  52. package/dist/react.js +1 -2
  53. package/dist/react.js.map +1 -1
  54. package/dist/retries-DXMQGhG3.d.ts +79 -0
  55. package/dist/retries.d.ts +7 -72
  56. package/dist/retries.js +1 -1
  57. package/dist/retries.js.map +1 -1
  58. package/dist/schedule.js +1 -2
  59. package/dist/schedule.js.map +1 -1
  60. package/dist/serializable.js +1 -1
  61. package/dist/types-BB1plA51.d.ts +15 -0
  62. package/dist/types.d.ts +1 -14
  63. package/dist/types.js +1 -1
  64. package/dist/types.js.map +1 -1
  65. package/dist/utils.js +1 -1
  66. package/dist/workflow-types-CZNXKj_D.d.ts +260 -0
  67. package/dist/workflow-types.d.ts +23 -235
  68. package/dist/workflow-types.js +1 -1
  69. package/dist/workflow-types.js.map +1 -1
  70. package/dist/workflows.d.ts +22 -23
  71. package/dist/workflows.js +5 -6
  72. package/dist/workflows.js.map +1 -1
  73. package/package.json +25 -13
  74. package/dist/agent-eZnMHidZ.d.ts +0 -273
  75. package/dist/client-connection-D3Wcd6Q6.js +0 -603
  76. package/dist/client-connection-D3Wcd6Q6.js.map +0 -1
  77. package/dist/client-storage-BPjfP_is.d.ts +0 -604
  78. package/dist/experimental/sub-agent.d.ts +0 -205
  79. package/dist/experimental/sub-agent.js +0 -191
  80. package/dist/experimental/sub-agent.js.map +0 -1
  81. package/dist/mcp/client.js.map +0 -1
package/dist/index.js CHANGED
@@ -3,15 +3,13 @@ import { camelCaseToKebabCase } from "./utils.js";
3
3
  import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
4
4
  import { __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context.js";
5
5
  import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
6
- import { a as RPC_DO_PREFIX, n as MCPConnectionState, s as DisposableStore } from "./client-connection-D3Wcd6Q6.js";
6
+ import { o as RPC_DO_PREFIX, r as MCPConnectionState, s as DisposableStore, t as MCPClientManager } from "./client-K8Z-u76l.js";
7
7
  import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
8
- import { MCPClientManager } from "./mcp/client.js";
9
8
  import { genericObservability } from "./observability/index.js";
10
9
  import { parseCronExpression } from "cron-schedule";
11
10
  import { nanoid } from "nanoid";
12
11
  import { EmailMessage } from "cloudflare:email";
13
12
  import { Server, getServerByName, routePartykitRequest } from "partyserver";
14
-
15
13
  //#region src/index.ts
16
14
  /**
17
15
  * Type guard for RPC request messages
@@ -67,6 +65,14 @@ function getNextCronTime(cron) {
67
65
  return parseCronExpression(cron).getNextDate();
68
66
  }
69
67
  const KEEP_ALIVE_INTERVAL_MS = 3e4;
68
+ /**
69
+ * Schema version for the Agent's internal SQLite tables.
70
+ * Bump this when adding new tables, columns, or migrations.
71
+ * The constructor stores this as a row in cf_agents_state and checks it
72
+ * on wake to skip DDL on established DOs.
73
+ */
74
+ const CURRENT_SCHEMA_VERSION = 1;
75
+ const SCHEMA_VERSION_ROW_ID = "cf_schema_version";
70
76
  const STATE_ROW_ID = "cf_state_row_id";
71
77
  const STATE_WAS_CHANGED = "cf_state_was_changed";
72
78
  const DEFAULT_STATE = {};
@@ -85,7 +91,11 @@ const CF_NO_PROTOCOL_KEY = "_cf_no_protocol";
85
91
  * The set of all internal keys stored in connection state that must be
86
92
  * hidden from user code and preserved across setState calls.
87
93
  */
88
- const CF_INTERNAL_KEYS = new Set([CF_READONLY_KEY, CF_NO_PROTOCOL_KEY]);
94
+ const CF_INTERNAL_KEYS = new Set([
95
+ CF_READONLY_KEY,
96
+ CF_NO_PROTOCOL_KEY,
97
+ "_cf_voiceInCall"
98
+ ]);
89
99
  /** Check if a raw connection state object contains any internal keys. */
90
100
  function rawHasInternalKeys(raw) {
91
101
  for (const key of Object.keys(raw)) if (CF_INTERNAL_KEYS.has(key)) return true;
@@ -207,14 +217,11 @@ var Agent = class Agent extends Server {
207
217
  */
208
218
  get state() {
209
219
  if (this._state !== DEFAULT_STATE) return this._state;
210
- const wasChanged = this.sql`
211
- SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}
212
- `;
213
220
  const result = this.sql`
214
221
  SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
215
222
  `;
216
- if (wasChanged[0]?.state === "true" || result[0]?.state) {
217
- const state = result[0]?.state;
223
+ if (result.length > 0) {
224
+ const state = result[0].state;
218
225
  try {
219
226
  this._state = JSON.parse(state);
220
227
  } catch (e) {
@@ -224,7 +231,6 @@ var Agent = class Agent extends Server {
224
231
  this._setStateInternal(this.initialState);
225
232
  } else {
226
233
  this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_ROW_ID}`;
227
- this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}`;
228
234
  return;
229
235
  }
230
236
  }
@@ -234,9 +240,6 @@ var Agent = class Agent extends Server {
234
240
  this._setStateInternal(this.initialState);
235
241
  return this.initialState;
236
242
  }
237
- static {
238
- this.options = { hibernate: true };
239
- }
240
243
  get _resolvedOptions() {
241
244
  if (this._cachedOptions) return this._cachedOptions;
242
245
  const ctor = this.constructor;
@@ -282,6 +285,138 @@ var Agent = class Agent extends Server {
282
285
  throw new SqlError(query, e);
283
286
  }
284
287
  }
288
+ /**
289
+ * Create all internal tables and run migrations if needed.
290
+ * Called by the constructor on every wake. Idempotent — skips DDL when
291
+ * the stored schema version matches CURRENT_SCHEMA_VERSION.
292
+ *
293
+ * Protected so that test agents can re-run the real migration path
294
+ * after manipulating DB state (since ctx.abort() is unavailable in
295
+ * local dev and the constructor only runs once per DO instance).
296
+ */
297
+ _ensureSchema() {
298
+ this.sql`
299
+ CREATE TABLE IF NOT EXISTS cf_agents_state (
300
+ id TEXT PRIMARY KEY NOT NULL,
301
+ state TEXT
302
+ )
303
+ `;
304
+ const versionRow = this.sql`
305
+ SELECT state FROM cf_agents_state WHERE id = ${SCHEMA_VERSION_ROW_ID}
306
+ `;
307
+ if ((versionRow.length > 0 ? Number(versionRow[0].state) : 0) < CURRENT_SCHEMA_VERSION) {
308
+ this.sql`
309
+ CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (
310
+ id TEXT PRIMARY KEY NOT NULL,
311
+ name TEXT NOT NULL,
312
+ server_url TEXT NOT NULL,
313
+ callback_url TEXT NOT NULL,
314
+ client_id TEXT,
315
+ auth_url TEXT,
316
+ server_options TEXT
317
+ )
318
+ `;
319
+ this.sql`
320
+ CREATE TABLE IF NOT EXISTS cf_agents_queues (
321
+ id TEXT PRIMARY KEY NOT NULL,
322
+ payload TEXT,
323
+ callback TEXT,
324
+ created_at INTEGER DEFAULT (unixepoch())
325
+ )
326
+ `;
327
+ this.sql`
328
+ CREATE TABLE IF NOT EXISTS cf_agents_schedules (
329
+ id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
330
+ callback TEXT,
331
+ payload TEXT,
332
+ type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),
333
+ time INTEGER,
334
+ delayInSeconds INTEGER,
335
+ cron TEXT,
336
+ intervalSeconds INTEGER,
337
+ running INTEGER DEFAULT 0,
338
+ created_at INTEGER DEFAULT (unixepoch()),
339
+ execution_started_at INTEGER,
340
+ retry_options TEXT
341
+ )
342
+ `;
343
+ const addColumnIfNotExists = (sql) => {
344
+ try {
345
+ this.ctx.storage.sql.exec(sql);
346
+ } catch (e) {
347
+ if (!(e instanceof Error ? e.message : String(e)).toLowerCase().includes("duplicate column")) throw e;
348
+ }
349
+ };
350
+ addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN intervalSeconds INTEGER");
351
+ addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN running INTEGER DEFAULT 0");
352
+ addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN execution_started_at INTEGER");
353
+ addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN retry_options TEXT");
354
+ addColumnIfNotExists("ALTER TABLE cf_agents_queues ADD COLUMN retry_options TEXT");
355
+ {
356
+ const rows = this.ctx.storage.sql.exec("SELECT sql FROM sqlite_master WHERE type='table' AND name='cf_agents_schedules'").toArray();
357
+ if (rows.length > 0) {
358
+ if (!String(rows[0].sql).includes("'interval'")) {
359
+ this.ctx.storage.sql.exec("DROP TABLE IF EXISTS cf_agents_schedules_new");
360
+ this.ctx.storage.sql.exec(`
361
+ CREATE TABLE cf_agents_schedules_new (
362
+ id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
363
+ callback TEXT,
364
+ payload TEXT,
365
+ type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),
366
+ time INTEGER,
367
+ delayInSeconds INTEGER,
368
+ cron TEXT,
369
+ intervalSeconds INTEGER,
370
+ running INTEGER DEFAULT 0,
371
+ created_at INTEGER DEFAULT (unixepoch()),
372
+ execution_started_at INTEGER,
373
+ retry_options TEXT
374
+ )
375
+ `);
376
+ this.ctx.storage.sql.exec(`
377
+ INSERT INTO cf_agents_schedules_new
378
+ (id, callback, payload, type, time, delayInSeconds, cron,
379
+ intervalSeconds, running, created_at, execution_started_at, retry_options)
380
+ SELECT id, callback, payload, type, time, delayInSeconds, cron,
381
+ intervalSeconds, running, created_at, execution_started_at, retry_options
382
+ FROM cf_agents_schedules
383
+ `);
384
+ this.ctx.storage.sql.exec("DROP TABLE cf_agents_schedules");
385
+ this.ctx.storage.sql.exec("ALTER TABLE cf_agents_schedules_new RENAME TO cf_agents_schedules");
386
+ }
387
+ }
388
+ }
389
+ this.sql`
390
+ CREATE TABLE IF NOT EXISTS cf_agents_workflows (
391
+ id TEXT PRIMARY KEY NOT NULL,
392
+ workflow_id TEXT NOT NULL UNIQUE,
393
+ workflow_name TEXT NOT NULL,
394
+ status TEXT NOT NULL CHECK(status IN (
395
+ 'queued', 'running', 'paused', 'errored',
396
+ 'terminated', 'complete', 'waiting',
397
+ 'waitingForPause', 'unknown'
398
+ )),
399
+ metadata TEXT,
400
+ error_name TEXT,
401
+ error_message TEXT,
402
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
403
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
404
+ completed_at INTEGER
405
+ )
406
+ `;
407
+ this.sql`
408
+ CREATE INDEX IF NOT EXISTS idx_workflows_status ON cf_agents_workflows(status)
409
+ `;
410
+ this.sql`
411
+ CREATE INDEX IF NOT EXISTS idx_workflows_name ON cf_agents_workflows(workflow_name)
412
+ `;
413
+ this.ctx.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", STATE_WAS_CHANGED);
414
+ this.sql`
415
+ INSERT OR REPLACE INTO cf_agents_state (id, state)
416
+ VALUES (${SCHEMA_VERSION_ROW_ID}, ${String(CURRENT_SCHEMA_VERSION)})
417
+ `;
418
+ }
419
+ }
285
420
  constructor(ctx, env) {
286
421
  super(ctx, env);
287
422
  this._state = DEFAULT_STATE;
@@ -289,6 +424,7 @@ var Agent = class Agent extends Server {
289
424
  this._destroyed = false;
290
425
  this._rawStateAccessors = /* @__PURE__ */ new WeakMap();
291
426
  this._persistenceHookMode = "none";
427
+ this._isFacet = false;
292
428
  this._ParentClass = Object.getPrototypeOf(this).constructor;
293
429
  this.initialState = DEFAULT_STATE;
294
430
  this.observability = genericObservability;
@@ -297,117 +433,7 @@ var Agent = class Agent extends Server {
297
433
  this._autoWrapCustomMethods();
298
434
  wrappedClasses.add(this.constructor);
299
435
  }
300
- this.sql`
301
- CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (
302
- id TEXT PRIMARY KEY NOT NULL,
303
- name TEXT NOT NULL,
304
- server_url TEXT NOT NULL,
305
- callback_url TEXT NOT NULL,
306
- client_id TEXT,
307
- auth_url TEXT,
308
- server_options TEXT
309
- )
310
- `;
311
- this.sql`
312
- CREATE TABLE IF NOT EXISTS cf_agents_state (
313
- id TEXT PRIMARY KEY NOT NULL,
314
- state TEXT
315
- )
316
- `;
317
- this.sql`
318
- CREATE TABLE IF NOT EXISTS cf_agents_queues (
319
- id TEXT PRIMARY KEY NOT NULL,
320
- payload TEXT,
321
- callback TEXT,
322
- created_at INTEGER DEFAULT (unixepoch())
323
- )
324
- `;
325
- this.sql`
326
- CREATE TABLE IF NOT EXISTS cf_agents_schedules (
327
- id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
328
- callback TEXT,
329
- payload TEXT,
330
- type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),
331
- time INTEGER,
332
- delayInSeconds INTEGER,
333
- cron TEXT,
334
- intervalSeconds INTEGER,
335
- running INTEGER DEFAULT 0,
336
- created_at INTEGER DEFAULT (unixepoch()),
337
- execution_started_at INTEGER,
338
- retry_options TEXT
339
- )
340
- `;
341
- const addColumnIfNotExists = (sql) => {
342
- try {
343
- this.ctx.storage.sql.exec(sql);
344
- } catch (e) {
345
- if (!(e instanceof Error ? e.message : String(e)).toLowerCase().includes("duplicate column")) throw e;
346
- }
347
- };
348
- addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN intervalSeconds INTEGER");
349
- addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN running INTEGER DEFAULT 0");
350
- addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN execution_started_at INTEGER");
351
- addColumnIfNotExists("ALTER TABLE cf_agents_schedules ADD COLUMN retry_options TEXT");
352
- addColumnIfNotExists("ALTER TABLE cf_agents_queues ADD COLUMN retry_options TEXT");
353
- {
354
- const rows = this.ctx.storage.sql.exec("SELECT sql FROM sqlite_master WHERE type='table' AND name='cf_agents_schedules'").toArray();
355
- if (rows.length > 0) {
356
- if (!String(rows[0].sql).includes("'interval'")) {
357
- this.ctx.storage.sql.exec("DROP TABLE IF EXISTS cf_agents_schedules_new");
358
- this.ctx.storage.sql.exec(`
359
- CREATE TABLE cf_agents_schedules_new (
360
- id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),
361
- callback TEXT,
362
- payload TEXT,
363
- type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),
364
- time INTEGER,
365
- delayInSeconds INTEGER,
366
- cron TEXT,
367
- intervalSeconds INTEGER,
368
- running INTEGER DEFAULT 0,
369
- created_at INTEGER DEFAULT (unixepoch()),
370
- execution_started_at INTEGER,
371
- retry_options TEXT
372
- )
373
- `);
374
- this.ctx.storage.sql.exec(`
375
- INSERT INTO cf_agents_schedules_new
376
- (id, callback, payload, type, time, delayInSeconds, cron,
377
- intervalSeconds, running, created_at, execution_started_at, retry_options)
378
- SELECT id, callback, payload, type, time, delayInSeconds, cron,
379
- intervalSeconds, running, created_at, execution_started_at, retry_options
380
- FROM cf_agents_schedules
381
- `);
382
- this.ctx.storage.sql.exec("DROP TABLE cf_agents_schedules");
383
- this.ctx.storage.sql.exec("ALTER TABLE cf_agents_schedules_new RENAME TO cf_agents_schedules");
384
- }
385
- }
386
- }
387
- this.sql`
388
- CREATE TABLE IF NOT EXISTS cf_agents_workflows (
389
- id TEXT PRIMARY KEY NOT NULL,
390
- workflow_id TEXT NOT NULL UNIQUE,
391
- workflow_name TEXT NOT NULL,
392
- status TEXT NOT NULL CHECK(status IN (
393
- 'queued', 'running', 'paused', 'errored',
394
- 'terminated', 'complete', 'waiting',
395
- 'waitingForPause', 'unknown'
396
- )),
397
- metadata TEXT,
398
- error_name TEXT,
399
- error_message TEXT,
400
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
401
- updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
402
- completed_at INTEGER
403
- )
404
- `;
405
- this.sql`
406
- CREATE INDEX IF NOT EXISTS idx_workflows_status ON cf_agents_workflows(status)
407
- `;
408
- this.sql`
409
- CREATE INDEX IF NOT EXISTS idx_workflows_name ON cf_agents_workflows(workflow_name)
410
- `;
436
+ this._ensureSchema();
411
437
  this.mcp = new MCPClientManager(this._ParentClass.name, "0.0.1", {
412
438
  storage: this.ctx.storage,
413
439
  createAuthProvider: (callbackUrl) => this.createMcpOAuthProvider(callbackUrl)
@@ -607,6 +633,7 @@ var Agent = class Agent extends Server {
607
633
  request: void 0,
608
634
  email: void 0
609
635
  }, async () => {
636
+ if (await this.ctx.storage.get("cf_agents_is_facet")) this._isFacet = true;
610
637
  await this._tryCatch(async () => {
611
638
  await this.mcp.restoreConnectionsFromStorage(this.name);
612
639
  await this._restoreRpcMcpServers();
@@ -657,10 +684,6 @@ var Agent = class Agent extends Server {
657
684
  this.sql`
658
685
  INSERT OR REPLACE INTO cf_agents_state (id, state)
659
686
  VALUES (${STATE_ROW_ID}, ${JSON.stringify(nextState)})
660
- `;
661
- this.sql`
662
- INSERT OR REPLACE INTO cf_agents_state (id, state)
663
- VALUES (${STATE_WAS_CHANGED}, ${JSON.stringify(true)})
664
687
  `;
665
688
  this._broadcastProtocol(JSON.stringify({
666
689
  state: nextState,
@@ -788,6 +811,44 @@ var Agent = class Agent extends Server {
788
811
  return !!this._rawStateAccessors.get(connection).getRaw()?.[CF_READONLY_KEY];
789
812
  }
790
813
  /**
814
+ * ⚠️ INTERNAL — DO NOT USE IN APPLICATION CODE. ⚠️
815
+ *
816
+ * Read an internal `_cf_`-prefixed flag from the raw connection state,
817
+ * bypassing the user-facing state wrapper that strips internal keys.
818
+ *
819
+ * This exists for framework mixins (e.g. voice) that need to persist
820
+ * flags in the connection attachment across hibernation. Application
821
+ * code should use `connection.state` and `connection.setState()` instead.
822
+ *
823
+ * @internal
824
+ */
825
+ _unsafe_getConnectionFlag(connection, key) {
826
+ this._ensureConnectionWrapped(connection);
827
+ return this._rawStateAccessors.get(connection).getRaw()?.[key];
828
+ }
829
+ /**
830
+ * ⚠️ INTERNAL — DO NOT USE IN APPLICATION CODE. ⚠️
831
+ *
832
+ * Write an internal `_cf_`-prefixed flag to the raw connection state,
833
+ * bypassing the user-facing state wrapper. The key must be registered
834
+ * in `CF_INTERNAL_KEYS` so it is preserved across user `setState` calls
835
+ * and hidden from `connection.state`.
836
+ *
837
+ * @internal
838
+ */
839
+ _unsafe_setConnectionFlag(connection, key, value) {
840
+ this._ensureConnectionWrapped(connection);
841
+ const accessors = this._rawStateAccessors.get(connection);
842
+ const raw = accessors.getRaw() ?? {};
843
+ if (value === void 0) {
844
+ const { [key]: _, ...rest } = raw;
845
+ accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);
846
+ } else accessors.setRaw({
847
+ ...raw,
848
+ [key]: value
849
+ });
850
+ }
851
+ /**
791
852
  * Override this method to determine if a connection should be readonly on connect
792
853
  * @param _connection The connection that is being established
793
854
  * @param _ctx Connection context
@@ -1187,6 +1248,7 @@ var Agent = class Agent extends Server {
1187
1248
  * @returns Schedule object representing the scheduled task
1188
1249
  */
1189
1250
  async schedule(when, callback, payload, options) {
1251
+ if (this._isFacet) throw new Error("Scheduling is not supported in sub-agents. Schedule from the parent agent instead.");
1190
1252
  const id = nanoid(9);
1191
1253
  if (options?.retry) validateRetryOptions(options.retry, this._resolvedOptions.retry);
1192
1254
  const retryJson = options?.retry ? JSON.stringify(options.retry) : null;
@@ -1283,6 +1345,7 @@ var Agent = class Agent extends Server {
1283
1345
  * @returns Schedule object representing the scheduled task
1284
1346
  */
1285
1347
  async scheduleEvery(intervalSeconds, callback, payload, options) {
1348
+ if (this._isFacet) throw new Error("Scheduling is not supported in sub-agents. Schedule from the parent agent instead.");
1286
1349
  const MAX_INTERVAL_SECONDS = 720 * 60 * 60;
1287
1350
  if (typeof intervalSeconds !== "number" || intervalSeconds <= 0) throw new Error("intervalSeconds must be a positive number");
1288
1351
  if (intervalSeconds > MAX_INTERVAL_SECONDS) throw new Error(`intervalSeconds cannot exceed ${MAX_INTERVAL_SECONDS} seconds (30 days)`);
@@ -1390,6 +1453,7 @@ var Agent = class Agent extends Server {
1390
1453
  * @returns true if the task was cancelled, false if the task was not found
1391
1454
  */
1392
1455
  async cancelSchedule(id) {
1456
+ if (this._isFacet) throw new Error("Scheduling is not supported in sub-agents. Schedule from the parent agent instead.");
1393
1457
  const schedule = this.getSchedule(id);
1394
1458
  if (!schedule) return false;
1395
1459
  this._emit("schedule:cancel", {
@@ -1421,6 +1485,7 @@ var Agent = class Agent extends Server {
1421
1485
  * ```
1422
1486
  */
1423
1487
  async keepAlive() {
1488
+ if (this._isFacet) throw new Error("keepAlive() is not supported in sub-agents. Use keepAlive() from the parent agent instead.");
1424
1489
  const heartbeatSeconds = Math.ceil(KEEP_ALIVE_INTERVAL_MS / 1e3);
1425
1490
  const schedule = await this.scheduleEvery(heartbeatSeconds, "_cf_keepAliveHeartbeat", void 0, { _idempotent: false });
1426
1491
  let disposed = false;
@@ -1471,10 +1536,10 @@ var Agent = class Agent extends Server {
1471
1536
  LIMIT 1
1472
1537
  `;
1473
1538
  if (!result) return;
1474
- if (result.length > 0 && "time" in result[0]) {
1475
- const nextTime = result[0].time * 1e3;
1476
- await this.ctx.storage.setAlarm(nextTime);
1477
- }
1539
+ let nextTimeMs = null;
1540
+ if (result.length > 0 && "time" in result[0]) nextTimeMs = result[0].time * 1e3;
1541
+ if (nextTimeMs !== null) await this.ctx.storage.setAlarm(nextTimeMs);
1542
+ else await this.ctx.storage.deleteAlarm();
1478
1543
  }
1479
1544
  /**
1480
1545
  * Override PartyServer's onAlarm hook as a no-op.
@@ -1575,6 +1640,81 @@ var Agent = class Agent extends Server {
1575
1640
  await this._scheduleNextAlarm();
1576
1641
  }
1577
1642
  /**
1643
+ * Marks this agent as running inside a facet (sub-agent). Once set,
1644
+ * scheduling methods throw a clear error instead of crashing on
1645
+ * `setAlarm()` (which is not supported in facets).
1646
+ * @internal
1647
+ */
1648
+ async _cf_markAsFacet() {
1649
+ this._isFacet = true;
1650
+ await this.ctx.storage.put("cf_agents_is_facet", true);
1651
+ }
1652
+ /**
1653
+ * Get or create a named sub-agent — a child Durable Object (facet)
1654
+ * with its own isolated SQLite storage running on the same machine.
1655
+ *
1656
+ * The child class must extend `Agent` and be exported from the worker
1657
+ * entry point. The first call for a given name triggers the child's
1658
+ * `onStart()`. Subsequent calls return the existing instance.
1659
+ *
1660
+ * @experimental Requires the `"experimental"` compatibility flag.
1661
+ *
1662
+ * @param cls The Agent subclass (must be exported from the worker)
1663
+ * @param name Unique name for this child instance
1664
+ * @returns A typed RPC stub for calling methods on the child
1665
+ *
1666
+ * @example
1667
+ * ```typescript
1668
+ * const searcher = await this.subAgent(SearchAgent, "main-search");
1669
+ * const results = await searcher.search("cloudflare agents");
1670
+ * ```
1671
+ */
1672
+ async subAgent(cls, name) {
1673
+ const ctx = this.ctx;
1674
+ if (!ctx.facets || !ctx.exports) throw new Error("subAgent() requires the \"experimental\" compatibility flag. Add it to your wrangler.jsonc compatibility_flags.");
1675
+ if (!ctx.exports[cls.name]) throw new Error(`Sub-agent class "${cls.name}" not found in worker exports. Make sure the class is exported from your worker entry point and that the export name matches the class name.`);
1676
+ const facetKey = `${cls.name}\0${name}`;
1677
+ const stub = ctx.facets.get(facetKey, () => ({ class: ctx.exports[cls.name] }));
1678
+ const req = new Request("http://dummy-example.cloudflare.com/cdn-cgi/partyserver/set-name/");
1679
+ req.headers.set("x-partykit-room", name);
1680
+ await stub.fetch(req).then((res) => res.text());
1681
+ await stub._cf_markAsFacet();
1682
+ return stub;
1683
+ }
1684
+ /**
1685
+ * Forcefully abort a running sub-agent. The child stops executing
1686
+ * immediately and will be restarted on next {@link subAgent} call.
1687
+ * Pending RPC calls receive the reason as an error.
1688
+ * Transitively aborts the child's own children.
1689
+ *
1690
+ * @experimental Requires the `"experimental"` compatibility flag.
1691
+ *
1692
+ * @param cls The Agent subclass used when creating the child
1693
+ * @param name Name of the child to abort
1694
+ * @param reason Error thrown to pending/future RPC callers
1695
+ */
1696
+ abortSubAgent(cls, name, reason) {
1697
+ const ctx = this.ctx;
1698
+ if (!ctx.facets) throw new Error("abortSubAgent() requires the \"experimental\" compatibility flag.");
1699
+ const facetKey = `${cls.name}\0${name}`;
1700
+ ctx.facets.abort(facetKey, reason);
1701
+ }
1702
+ /**
1703
+ * Delete a sub-agent: abort it if running, then permanently wipe its
1704
+ * storage. Transitively deletes the child's own children.
1705
+ *
1706
+ * @experimental Requires the `"experimental"` compatibility flag.
1707
+ *
1708
+ * @param cls The Agent subclass used when creating the child
1709
+ * @param name Name of the child to delete
1710
+ */
1711
+ deleteSubAgent(cls, name) {
1712
+ const ctx = this.ctx;
1713
+ if (!ctx.facets) throw new Error("deleteSubAgent() requires the \"experimental\" compatibility flag.");
1714
+ const facetKey = `${cls.name}\0${name}`;
1715
+ ctx.facets.delete(facetKey);
1716
+ }
1717
+ /**
1578
1718
  * Destroy the Agent, removing all state and scheduled tasks
1579
1719
  */
1580
1720
  async destroy() {
@@ -1583,7 +1723,7 @@ var Agent = class Agent extends Server {
1583
1723
  this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
1584
1724
  this.sql`DROP TABLE IF EXISTS cf_agents_queues`;
1585
1725
  this.sql`DROP TABLE IF EXISTS cf_agents_workflows`;
1586
- await this.ctx.storage.deleteAlarm();
1726
+ if (!this._isFacet) await this.ctx.storage.deleteAlarm();
1587
1727
  await this.ctx.storage.deleteAll();
1588
1728
  this._disposables.dispose();
1589
1729
  await this.mcp.dispose();
@@ -2319,7 +2459,7 @@ var Agent = class Agent extends Server {
2319
2459
  * @param workflowId - ID of the workflow
2320
2460
  * @param progress - Typed progress data (default: DefaultProgress)
2321
2461
  */
2322
- async onWorkflowProgress(_workflowName, _workflowId, _progress) {}
2462
+ async onWorkflowProgress(workflowName, workflowId, progress) {}
2323
2463
  /**
2324
2464
  * Called when a workflow completes successfully.
2325
2465
  * Override to handle completion.
@@ -2328,7 +2468,7 @@ var Agent = class Agent extends Server {
2328
2468
  * @param workflowId - ID of the workflow
2329
2469
  * @param result - Optional result data
2330
2470
  */
2331
- async onWorkflowComplete(_workflowName, _workflowId, _result) {}
2471
+ async onWorkflowComplete(workflowName, workflowId, result) {}
2332
2472
  /**
2333
2473
  * Called when a workflow encounters an error.
2334
2474
  * Override to handle errors.
@@ -2337,7 +2477,9 @@ var Agent = class Agent extends Server {
2337
2477
  * @param workflowId - ID of the workflow
2338
2478
  * @param error - Error message
2339
2479
  */
2340
- async onWorkflowError(_workflowName, _workflowId, _error) {}
2480
+ async onWorkflowError(workflowName, workflowId, error) {
2481
+ console.error(`Workflow error [${workflowName}/${workflowId}]: ${error}\nOverride onWorkflowError() in your Agent to handle workflow errors.`);
2482
+ }
2341
2483
  /**
2342
2484
  * Called when a workflow sends a custom event.
2343
2485
  * Override to handle custom events.
@@ -2346,7 +2488,7 @@ var Agent = class Agent extends Server {
2346
2488
  * @param workflowId - ID of the workflow
2347
2489
  * @param event - Custom event payload
2348
2490
  */
2349
- async onWorkflowEvent(_workflowName, _workflowId, _event) {}
2491
+ async onWorkflowEvent(workflowName, workflowId, event) {}
2350
2492
  /**
2351
2493
  * Handle a workflow callback via RPC.
2352
2494
  * @internal - Called by AgentWorkflow, do not call directly
@@ -2603,6 +2745,7 @@ var Agent = class Agent extends Server {
2603
2745
  return Response.redirect(baseOrigin);
2604
2746
  }
2605
2747
  };
2748
+ Agent.options = { hibernate: true };
2606
2749
  const wrappedClasses = /* @__PURE__ */ new Set();
2607
2750
  /**
2608
2751
  * Route a request to the appropriate Agent
@@ -2772,7 +2915,7 @@ var StreamingResponse = class {
2772
2915
  return true;
2773
2916
  }
2774
2917
  };
2775
-
2776
2918
  //#endregion
2777
2919
  export { Agent, DEFAULT_AGENT_STATIC_OPTIONS, DurableObjectOAuthClientProvider, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, routeAgentEmail, routeAgentRequest, unstable_callable };
2920
+
2778
2921
  //# sourceMappingURL=index.js.map