agents 0.23.0 → 0.24.0

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 (98) hide show
  1. package/dist/{agent-routing-DE5zmCQ8.d.ts → agent-routing-B2XLNMxq.d.ts} +196 -189
  2. package/dist/agent-routing.d.ts +1 -1
  3. package/dist/agent-tool-types.d.ts +26 -26
  4. package/dist/{agent-tools-DtXMTDGM.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
  5. package/dist/agent-tools.d.ts +21 -21
  6. package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
  7. package/dist/capability-B4WbF81e.js.map +1 -0
  8. package/dist/{capability-runner-Be_-PLR1.d.ts → capability-runner-BUBa6Ake.d.ts} +40 -15
  9. package/dist/chat/index.d.ts +14 -11
  10. package/dist/chat/index.js +11 -7
  11. package/dist/chat/index.js.map +1 -1
  12. package/dist/chat-sdk/index.d.ts +3 -3
  13. package/dist/chat-sdk/index.js +1 -1
  14. package/dist/client-BxdkCuVy.d.ts +411 -0
  15. package/dist/client-C9DAjZIY.js +518 -0
  16. package/dist/client-C9DAjZIY.js.map +1 -0
  17. package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
  18. package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
  19. package/dist/client.d.ts +27 -283
  20. package/dist/client.js +2 -274
  21. package/dist/current-agent-C4w86kcN.d.ts +93 -0
  22. package/dist/{current-agent-Da_C9a3b.d.ts → durable-object-lifecycle-ei7M7lqB.d.ts} +13 -122
  23. package/dist/index-Dlgtd3Mj.d.ts +78 -0
  24. package/dist/index.d.ts +59 -59
  25. package/dist/index.js +2 -2
  26. package/dist/internal_context.d.ts +1 -1
  27. package/dist/lifecycle/index.d.ts +19 -17
  28. package/dist/lifecycle/index.js +2 -2
  29. package/dist/{lifecycle-CMRGjZdw.js → lifecycle-Mm_jQh7r.js} +36 -21
  30. package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
  31. package/dist/mcp/client/index.d.ts +20 -20
  32. package/dist/mcp/client/index.js +1 -1
  33. package/dist/mcp/index.d.ts +35 -35
  34. package/dist/mcp/index.js +2 -2
  35. package/dist/queue/index.d.ts +123 -0
  36. package/dist/queue/index.js +2 -0
  37. package/dist/queue-BC9F5cUo.js +406 -0
  38. package/dist/queue-BC9F5cUo.js.map +1 -0
  39. package/dist/react.d.ts +33 -15
  40. package/dist/react.js +31 -8
  41. package/dist/react.js.map +1 -1
  42. package/dist/{retries-D9Ds-1lz.d.ts → retries-D9B2UCq3.d.ts} +9 -3
  43. package/dist/retries.d.ts +5 -3
  44. package/dist/retries.js +9 -1
  45. package/dist/retries.js.map +1 -1
  46. package/dist/routing/index.d.ts +2 -2
  47. package/dist/routing/index.js +1 -1
  48. package/dist/{scheduler-Dwh85ZGl.d.ts → scheduler-BGq6M5Kd.d.ts} +6 -6
  49. package/dist/{scheduler-DD9NdYbF.js → scheduler-D_KHqxBa.js} +4 -11
  50. package/dist/scheduler-D_KHqxBa.js.map +1 -0
  51. package/dist/schedules/index.d.ts +1 -1
  52. package/dist/schedules/index.js +1 -1
  53. package/dist/serializable.d.ts +1 -1
  54. package/dist/sessions/index.d.ts +1 -1
  55. package/dist/sessions/index.js +1 -1
  56. package/dist/{src-DlSHshb2.js → src-BNU3ZiJM.js} +126 -393
  57. package/dist/src-BNU3ZiJM.js.map +1 -0
  58. package/dist/state/index.d.ts +6 -0
  59. package/dist/state/index.js +137 -0
  60. package/dist/state/index.js.map +1 -0
  61. package/dist/streams/index.d.ts +1 -1
  62. package/dist/streams/index.js +1 -1
  63. package/dist/{streams-D6tJ0NN9.d.ts → streams-BcE8JP2X.d.ts} +2 -2
  64. package/dist/{streams-DZKgAj9b.js → streams-CCPRV6dt.js} +2 -2
  65. package/dist/{streams-DZKgAj9b.js.map → streams-CCPRV6dt.js.map} +1 -1
  66. package/dist/sub-routing.d.ts +12 -12
  67. package/dist/tasks/index.d.ts +1 -1
  68. package/dist/tasks/index.js +1 -1
  69. package/dist/{tasks-ylZgBjhj.js → tasks-D4nLqVSI.js} +3 -3
  70. package/dist/{tasks-ylZgBjhj.js.map → tasks-D4nLqVSI.js.map} +1 -1
  71. package/dist/{tasks-BRJ5zgya.d.ts → tasks-V2lCT8ZV.d.ts} +5 -5
  72. package/dist/transport-protocol-BxyngQ_R.js +25 -0
  73. package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
  74. package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
  75. package/dist/types-DCD6BNZH.d.ts +70 -0
  76. package/dist/voice/index.d.ts +2 -2
  77. package/dist/websockets/index.d.ts +178 -69
  78. package/dist/websockets/index.js +3 -2
  79. package/dist/websockets-D7IzWbZb.js +1005 -0
  80. package/dist/websockets-D7IzWbZb.js.map +1 -0
  81. package/dist/workflow-types.d.ts +25 -25
  82. package/dist/workflows.d.ts +21 -21
  83. package/dist/workflows.js +1 -1
  84. package/docs/agent-class.md +2 -2
  85. package/docs/client-sdk.md +30 -0
  86. package/docs/index.md +1 -1
  87. package/docs/lifecycle.md +97 -22
  88. package/docs/queue.md +135 -241
  89. package/docs/retries.md +1 -1
  90. package/docs/sub-agents.md +3 -3
  91. package/package.json +12 -2
  92. package/dist/capability-BjSKYpzg.js.map +0 -1
  93. package/dist/client.js.map +0 -1
  94. package/dist/lifecycle-CMRGjZdw.js.map +0 -1
  95. package/dist/scheduler-DD9NdYbF.js.map +0 -1
  96. package/dist/src-DlSHshb2.js.map +0 -1
  97. package/dist/websockets-DUfRHPRq.js +0 -502
  98. package/dist/websockets-DUfRHPRq.js.map +0 -1
@@ -5,22 +5,24 @@ import { n as getCurrentAgent$1, t as __DO_NOT_USE_WILL_BREAK__agentContext } fr
5
5
  import "./internal_context.js";
6
6
  import { copyCallableMetadata, decoratedMethods, getCallableMetadata, isCallableMethod } from "./callable-decorator.js";
7
7
  import "./types.js";
8
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
8
9
  import { signAgentHeaders } from "./email.js";
9
10
  import { sendAgentEmail } from "./email-send.js";
10
- import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
11
11
  import { n as withInvocationScope, r as writeSpanAttributes, t as tracer } from "./cloudflare-Dzvc7V2N.js";
12
12
  import { parseSubAgentPath } from "./sub-routing.js";
13
- import { t as LifecycleCapability } from "./capability-BjSKYpzg.js";
13
+ import { a as getConnectionFlag, c as isConnectionReadonly, d as setConnectionProtocolEnabled, f as setConnectionReadonly, i as ensureConnectionWrapped, l as registerInternalConnectionKeys, o as getConnectionRawState, s as isConnectionProtocolEnabled, t as WebSockets, u as setConnectionFlag } from "./websockets-D7IzWbZb.js";
14
+ import { t as LifecycleCapability } from "./capability-B4WbF81e.js";
14
15
  import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
15
- import { a as abortWithoutAlarmRetry, i as setLifecycleRouteTransport, n as setLifecycleEventSink, r as setLifecycleHostInvoker, t as Lifecycle } from "./lifecycle-CMRGjZdw.js";
16
+ import { a as abortWithoutAlarmRetry, i as setLifecycleRouteTransport, n as setLifecycleEventSink, r as setLifecycleHostInvoker, t as Lifecycle } from "./lifecycle-Mm_jQh7r.js";
16
17
  import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
17
18
  import { SqlError } from "./sql-error.js";
18
- import { o as callablesFromDecorated, t as WebSockets } from "./websockets-DUfRHPRq.js";
19
- import { a as ensureMcpServerTable, d as DisposableStore, i as normalizeServerId, l as RPC_DO_PREFIX, o as MCPConnectionState, t as MCPClientManager } from "./client-jagG8a9_.js";
19
+ import { a as ensureMcpServerTable, d as DisposableStore, i as normalizeServerId, l as RPC_DO_PREFIX, o as MCPConnectionState, t as MCPClientManager } from "./client-fyQrLGkD.js";
20
20
  import { DurableObjectOAuthClientProvider } from "./mcp/client/do-oauth-client-provider.js";
21
21
  import { genericObservability } from "./observability/index.js";
22
- import { n as setSchedulerCallbackResolver, t as Scheduler } from "./scheduler-DD9NdYbF.js";
23
- import { n as setTaskDefinitionResolver, r as setTaskRoutedMemoryLimitHandler, t as Tasks } from "./tasks-ylZgBjhj.js";
22
+ import { n as setSchedulerCallbackResolver, t as Scheduler } from "./scheduler-D_KHqxBa.js";
23
+ import { n as setQueueCallbackResolver, t as Queue } from "./queue-BC9F5cUo.js";
24
+ import { n as setTaskDefinitionResolver, r as setTaskRoutedMemoryLimitHandler, t as Tasks } from "./tasks-D4nLqVSI.js";
25
+ import { State } from "./state/index.js";
24
26
  import { AsyncLocalStorage } from "node:async_hooks";
25
27
  import { DurableObject, RpcTarget, exports } from "cloudflare:workers";
26
28
  import { nanoid } from "nanoid";
@@ -412,14 +414,16 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
412
414
  }
413
415
  /**
414
416
  * Clean root-owned bookkeeping for a sub-tree of facets: bulk-cancel
415
- * schedules and routed Task wake mirrors under the owner-path prefix,
416
- * and delete root-side facet fiber recovery leases for the same sub-tree.
417
+ * schedules, queue items, and routed Task wake mirrors under the
418
+ * owner-path prefix, and delete root-side facet fiber recovery leases for
419
+ * the same sub-tree.
417
420
  */
418
421
  async cleanupPrefix(ownerPath) {
419
422
  const prefix = agentPathKey(ownerPath);
420
423
  if (prefix) {
421
424
  await _classPrivateFieldGet2(_host, this).scheduler.__DO_NOT_USE_WILL_BREAK__cleanupRoutePrefix(prefix);
422
425
  await _classPrivateFieldGet2(_host, this).tasks.__DO_NOT_USE_WILL_BREAK__cleanupRoutePrefix(prefix);
426
+ await _classPrivateFieldGet2(_host, this)._queue.__DO_NOT_USE_WILL_BREAK__cleanupRoutePrefix(prefix);
423
427
  }
424
428
  this.deleteRunRowsForPrefix(ownerPath);
425
429
  await _classPrivateFieldGet2(_host, this)._syncHostJobs();
@@ -747,12 +751,12 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
747
751
  async setConnectionState(connectionId, state) {
748
752
  const connection = _classPrivateFieldGet2(_host, this)._webSockets.getConnection(connectionId);
749
753
  if (!connection || !this.connectionHasChildTarget(connection)) return null;
750
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
754
+ ensureConnectionWrapped(connection);
751
755
  connection.setState(state);
752
756
  return this.getForwardedState(connection);
753
757
  }
754
758
  connectionTargetPath(connection) {
755
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
759
+ ensureConnectionWrapped(connection);
756
760
  const outerUri = _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY);
757
761
  if (typeof outerUri !== "string") return null;
758
762
  return _assertClassBrand(_DynamicAgentsInternal_brand, this, _pathFromOuterUri).call(this, outerUri)?.path ?? null;
@@ -762,7 +766,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
762
766
  return a.every((step, index) => step.className === b[index]?.className && step.name === b[index]?.name);
763
767
  }
764
768
  connectionHasChildTarget(connection) {
765
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
769
+ ensureConnectionWrapped(connection);
766
770
  return typeof _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY) === "string";
767
771
  }
768
772
  connectionTargetsChild(connection) {
@@ -799,7 +803,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
799
803
  const request = new Request(meta.uri ?? "http://placeholder/", { headers: meta.requestHeaders });
800
804
  if (await this.forwardWebSocketConnect(connection, request, { gate: true })) return;
801
805
  if (_classPrivateFieldGet2(_host, this).shouldConnectionBeReadonly(connection, { request })) _classPrivateFieldGet2(_host, this).setConnectionReadonly(connection, true);
802
- if (!_classPrivateFieldGet2(_host, this).shouldSendProtocolMessages(connection, { request })) _classPrivateFieldGet2(_host, this)._setConnectionNoProtocol(connection);
806
+ if (!_classPrivateFieldGet2(_host, this).shouldSendProtocolMessages(connection, { request })) setConnectionProtocolEnabled(connection, false);
803
807
  const childTags = await _classPrivateFieldGet2(_host, this).getConnectionTags(connection, { request });
804
808
  connection.tags = [connection.id, ...childTags.filter((tag) => tag !== connection.id)];
805
809
  this.storeVirtualConnection(connection);
@@ -881,7 +885,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
881
885
  removeEventListener() {}
882
886
  };
883
887
  stored.connection = connection;
884
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
888
+ ensureConnectionWrapped(connection);
885
889
  return connection;
886
890
  }
887
891
  storeVirtualConnection(connection) {
@@ -921,8 +925,7 @@ var DynamicAgentsInternal = class extends LifecycleCapability {
921
925
  for (const meta of metas) _classPrivateFieldGet2(_virtualConnections, this).set(meta.id, { meta });
922
926
  }
923
927
  getRawConnectionState(connection) {
924
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
925
- return _classPrivateFieldGet2(_host, this)._rawStateAccessors.get(connection)?.getRaw() ?? null;
928
+ return getConnectionRawState(connection);
926
929
  }
927
930
  getForwardedState(connection) {
928
931
  const raw = this.getRawConnectionState(connection);
@@ -1022,7 +1025,7 @@ function _reportConnectionOperationFailure(connectionId, operation, error) {
1022
1025
  });
1023
1026
  }
1024
1027
  function _connectionMetaForPath(connection, ownerPath) {
1025
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
1028
+ ensureConnectionWrapped(connection);
1026
1029
  const outerUri = _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY);
1027
1030
  if (typeof outerUri !== "string") return null;
1028
1031
  const target = _assertClassBrand(_DynamicAgentsInternal_brand, this, _pathFromOuterUri).call(this, outerUri, ownerPath);
@@ -1072,7 +1075,7 @@ function _createConnectionBridge(connection) {
1072
1075
  });
1073
1076
  }
1074
1077
  async function _resolveConnection(connection, request, options = { gate: false }) {
1075
- _classPrivateFieldGet2(_host, this)._ensureConnectionWrapped(connection);
1078
+ ensureConnectionWrapped(connection);
1076
1079
  const outerUri = _classPrivateFieldGet2(_host, this)._unsafe_getConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY);
1077
1080
  const uri = typeof outerUri === "string" ? outerUri : connection.uri;
1078
1081
  if (!uri) return null;
@@ -1213,12 +1216,6 @@ function sendRpcResponseIfOpen(connection, response) {
1213
1216
  function isRPCRequest(msg) {
1214
1217
  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);
1215
1218
  }
1216
- /**
1217
- * Type guard for state update messages
1218
- */
1219
- function isStateUpdateMessage(msg) {
1220
- return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "cf_agent_state" && "state" in msg;
1221
- }
1222
1219
  const _fiberALS = new AsyncLocalStorage();
1223
1220
  const DEFAULT_KEEP_ALIVE_INTERVAL_MS = 3e4;
1224
1221
  const DEFAULT_AGENT_TOOL_RECOVERY_TIMEOUT_MS = 2e3;
@@ -1247,57 +1244,15 @@ const DETACHED_NOTIFY_CALLBACK = "_cfDetachedNotifyFinish";
1247
1244
  /**
1248
1245
  * Schema version for the Agent's internal SQLite tables.
1249
1246
  * Bump this when adding new tables, columns, or migrations.
1250
- * The constructor stores this as a row in cf_agents_state and checks it
1251
- * on wake to skip DDL on established DOs.
1247
+ * The constructor stores this under a namespaced KV key (the same convention
1248
+ * every capability uses for its own schema version) and checks it on wake to
1249
+ * skip DDL on established DOs.
1252
1250
  */
1253
1251
  const CURRENT_SCHEMA_VERSION = 11;
1254
- const SCHEMA_VERSION_ROW_ID = "cf_schema_version";
1255
- const STATE_ROW_ID = "cf_state_row_id";
1256
- const STATE_WAS_CHANGED = "cf_state_was_changed";
1252
+ const SCHEMA_VERSION_KEY = "cf_agents:schema_version";
1253
+ const LEGACY_SCHEMA_VERSION_ROW_ID = "cf_schema_version";
1257
1254
  const DEFAULT_STATE = {};
1258
- /**
1259
- * Internal key used to store the readonly flag in connection state.
1260
- * Prefixed with _cf_ to avoid collision with user state keys.
1261
- */
1262
- const CF_READONLY_KEY = "_cf_readonly";
1263
- /**
1264
- * Internal key used to store the no-protocol flag in connection state.
1265
- * When set, protocol messages (identity, state sync, MCP servers) are not
1266
- * sent to this connection — neither on connect nor via broadcasts.
1267
- */
1268
- const CF_NO_PROTOCOL_KEY = "_cf_no_protocol";
1269
- /**
1270
- * The set of all internal keys stored in connection state that must be
1271
- * hidden from user code and preserved across setState calls.
1272
- */
1273
- const CF_INTERNAL_KEYS = /* @__PURE__ */ new Set([
1274
- CF_READONLY_KEY,
1275
- CF_NO_PROTOCOL_KEY,
1276
- "_cf_voiceInCall",
1277
- CF_SUB_AGENT_OUTER_URL_KEY,
1278
- CF_SUB_AGENT_TAGS_KEY
1279
- ]);
1280
- /** Check if a raw connection state object contains any internal keys. */
1281
- function rawHasInternalKeys(raw) {
1282
- for (const key of Object.keys(raw)) if (CF_INTERNAL_KEYS.has(key)) return true;
1283
- return false;
1284
- }
1285
- /** Return a copy of `raw` with all internal keys removed, or null if no user keys remain. */
1286
- function stripInternalKeys(raw) {
1287
- const result = {};
1288
- let hasUserKeys = false;
1289
- for (const key of Object.keys(raw)) if (!CF_INTERNAL_KEYS.has(key)) {
1290
- result[key] = raw[key];
1291
- hasUserKeys = true;
1292
- }
1293
- return hasUserKeys ? result : null;
1294
- }
1295
- /** Return a copy containing only the internal keys present in `raw`. */
1296
- function extractInternalFlags(raw) {
1297
- const result = {};
1298
- for (const key of Object.keys(raw)) if (CF_INTERNAL_KEYS.has(key)) result[key] = raw[key];
1299
- return result;
1300
- }
1255
+ registerInternalConnectionKeys("_cf_voiceInCall", CF_SUB_AGENT_OUTER_URL_KEY, CF_SUB_AGENT_TAGS_KEY);
1301
1256
  /** Max length for error strings broadcast to clients. */
1302
1257
  const MAX_ERROR_STRING_LENGTH = 500;
1303
1258
  /**
@@ -1388,27 +1343,6 @@ const DEFAULT_AGENT_STATIC_OPTIONS = {
1388
1343
  */
1389
1344
  maxAlarmMemoryLimitStrikes: 3
1390
1345
  };
1391
- /**
1392
- * Parse the raw `retry_options` TEXT column from a SQLite row into a
1393
- * typed `RetryOptions` object, or `undefined` if not set.
1394
- */
1395
- function parseRetryOptions(row) {
1396
- const raw = row.retry_options;
1397
- if (typeof raw !== "string") return void 0;
1398
- return JSON.parse(raw);
1399
- }
1400
- /**
1401
- * Resolve per-task retry options against class-level defaults and call
1402
- * `tryN`. This is the retry-execution path for queue flush; Scheduler owns
1403
- * its own copy for schedule callbacks.
1404
- */
1405
- function resolveRetryConfig(taskRetry, defaults) {
1406
- return {
1407
- maxAttempts: taskRetry?.maxAttempts ?? defaults.maxAttempts,
1408
- baseDelayMs: taskRetry?.baseDelayMs ?? defaults.baseDelayMs,
1409
- maxDelayMs: taskRetry?.maxDelayMs ?? defaults.maxDelayMs
1410
- };
1411
- }
1412
1346
  /** Compatibility alias for the lifecycle-owned current Agent accessor. */
1413
1347
  const getCurrentAgent = getCurrentAgent$1;
1414
1348
  /**
@@ -1433,7 +1367,7 @@ function withAgentContext(method) {
1433
1367
  /**
1434
1368
  * Base class for creating Agent implementations
1435
1369
  * @template Env Environment type containing bindings
1436
- * @template State State type to store within the Agent
1370
+ * @template TState State type to store within the Agent
1437
1371
  */
1438
1372
  var Agent = class Agent extends DurableObject {
1439
1373
  /** Run user initialization after lifecycle components have started. */
@@ -1505,31 +1439,16 @@ var Agent = class Agent extends DurableObject {
1505
1439
  return this.ctx.id.toString();
1506
1440
  }
1507
1441
  /**
1508
- * Current state of the Agent
1442
+ * Current state of the Agent.
1443
+ *
1444
+ * Delegates to the State capability, which owns lazy load and the
1445
+ * in-memory cache; Agent seeds `initialState` on first access.
1509
1446
  */
1510
1447
  get state() {
1511
- if (this._state !== DEFAULT_STATE) return this._state;
1512
- const result = this.sql`
1513
- SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}
1514
- `;
1515
- if (result.length > 0) {
1516
- const state = result[0].state;
1517
- try {
1518
- this._state = JSON.parse(state);
1519
- } catch (e) {
1520
- console.error("Failed to parse stored state, falling back to initialState:", e);
1521
- if (this.initialState !== DEFAULT_STATE) {
1522
- this._state = this.initialState;
1523
- this._setStateInternal(this.initialState);
1524
- } else {
1525
- this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_ROW_ID}`;
1526
- return;
1527
- }
1528
- }
1529
- return this._state;
1530
- }
1531
- if (this.initialState === DEFAULT_STATE) return;
1532
- this._setStateInternal(this.initialState);
1448
+ const stored = this._state.get();
1449
+ if (stored !== void 0) return stored;
1450
+ if (this.initialState === DEFAULT_STATE) return void 0;
1451
+ this._state.set(this.initialState, "server");
1533
1452
  return this.initialState;
1534
1453
  }
1535
1454
  get _resolvedOptions() {
@@ -1615,26 +1534,9 @@ var Agent = class Agent extends DurableObject {
1615
1534
  * local dev and the constructor only runs once per DO instance).
1616
1535
  */
1617
1536
  _ensureSchema() {
1618
- this.sql`
1619
- CREATE TABLE IF NOT EXISTS cf_agents_state (
1620
- id TEXT PRIMARY KEY NOT NULL,
1621
- state TEXT
1622
- )
1623
- `;
1624
- const versionRow = this.sql`
1625
- SELECT state FROM cf_agents_state WHERE id = ${SCHEMA_VERSION_ROW_ID}
1626
- `;
1627
- const schemaVersion = versionRow.length > 0 ? Number(versionRow[0].state) : 0;
1537
+ const schemaVersion = this._readSchemaVersion();
1628
1538
  if (schemaVersion < CURRENT_SCHEMA_VERSION) {
1629
1539
  ensureMcpServerTable(this.ctx.storage);
1630
- this.sql`
1631
- CREATE TABLE IF NOT EXISTS cf_agents_queues (
1632
- id TEXT PRIMARY KEY NOT NULL,
1633
- payload TEXT,
1634
- callback TEXT,
1635
- created_at INTEGER DEFAULT (unixepoch())
1636
- )
1637
- `;
1638
1540
  const addColumnIfNotExists = (sql) => {
1639
1541
  try {
1640
1542
  this.ctx.storage.sql.exec(sql);
@@ -1642,7 +1544,6 @@ var Agent = class Agent extends DurableObject {
1642
1544
  if (!(error instanceof Error ? error.message : String(error)).toLowerCase().includes("duplicate column")) throw error;
1643
1545
  }
1644
1546
  };
1645
- addColumnIfNotExists("ALTER TABLE cf_agents_queues ADD COLUMN retry_options TEXT");
1646
1547
  this.sql`
1647
1548
  CREATE TABLE IF NOT EXISTS cf_agents_workflows (
1648
1549
  id TEXT PRIMARY KEY NOT NULL,
@@ -1667,7 +1568,6 @@ var Agent = class Agent extends DurableObject {
1667
1568
  this.sql`
1668
1569
  CREATE INDEX IF NOT EXISTS idx_workflows_name ON cf_agents_workflows(workflow_name)
1669
1570
  `;
1670
- this.ctx.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", STATE_WAS_CHANGED);
1671
1571
  this.sql`
1672
1572
  CREATE TABLE IF NOT EXISTS cf_agents_runs (
1673
1573
  id TEXT PRIMARY KEY NOT NULL,
@@ -1752,10 +1652,7 @@ var Agent = class Agent extends DurableObject {
1752
1652
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN detached_no_progress_budget_ms INTEGER");
1753
1653
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN last_progress_at INTEGER");
1754
1654
  addColumnIfNotExists("ALTER TABLE cf_agent_tool_runs ADD COLUMN detached_on_milestones TEXT");
1755
- this.sql`
1756
- INSERT OR REPLACE INTO cf_agents_state (id, state)
1757
- VALUES (${SCHEMA_VERSION_ROW_ID}, ${String(CURRENT_SCHEMA_VERSION)})
1758
- `;
1655
+ this.ctx.storage.kv.put(SCHEMA_VERSION_KEY, CURRENT_SCHEMA_VERSION);
1759
1656
  }
1760
1657
  this._schemaInitialization = {
1761
1658
  previousVersion: schemaVersion,
@@ -1763,9 +1660,31 @@ var Agent = class Agent extends DurableObject {
1763
1660
  migrated: schemaVersion < CURRENT_SCHEMA_VERSION
1764
1661
  };
1765
1662
  }
1663
+ /**
1664
+ * Read the Agent's schema version from its KV key. A DO created before the
1665
+ * State capability owned `cf_agents_state` has the version as a row in that
1666
+ * table instead: read it once, move it to the key, and delete the row so the
1667
+ * table is left with a single owner. Synchronous (`storage.kv`) because the
1668
+ * constructor gates DDL on it.
1669
+ */
1670
+ _readSchemaVersion() {
1671
+ const stored = this.ctx.storage.kv.get(SCHEMA_VERSION_KEY);
1672
+ if (stored !== void 0) return stored;
1673
+ if (!(this.ctx.storage.sql.exec("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'cf_agents_state'").toArray().length > 0)) return 0;
1674
+ const rows = this.ctx.storage.sql.exec("SELECT state FROM cf_agents_state WHERE id = ?", LEGACY_SCHEMA_VERSION_ROW_ID).toArray();
1675
+ if (rows.length === 0) return 0;
1676
+ const version = Number(rows[0].state) || 0;
1677
+ this.ctx.storage.kv.put(SCHEMA_VERSION_KEY, version);
1678
+ this.ctx.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", LEGACY_SCHEMA_VERSION_ROW_ID);
1679
+ return version;
1680
+ }
1766
1681
  constructor(ctx, env) {
1767
1682
  super(ctx, env);
1768
1683
  this.lifecycle = Lifecycle.install(this, { maxAlarmMemoryLimitStrikes: this._resolvedOptions.maxAlarmMemoryLimitStrikes });
1684
+ this._state = new State({
1685
+ validateStateChange: (nextState, source) => this.validateStateChange(nextState, source),
1686
+ onChanged: (nextState, source) => this._handleStateChanged(nextState, source)
1687
+ });
1769
1688
  this._webSockets = new WebSockets({
1770
1689
  handlers: {
1771
1690
  onConnect: (connection, ctx) => this.onConnect(connection, ctx),
@@ -1773,13 +1692,12 @@ var Agent = class Agent extends DurableObject {
1773
1692
  onClose: (connection, code, reason, wasClean) => this.onClose(connection, code, reason, wasClean),
1774
1693
  onError: (connection, error) => this.onError(connection, error)
1775
1694
  },
1776
- callables: callablesFromDecorated(this),
1695
+ protocol: false,
1696
+ state: this._state,
1777
1697
  getConnectionTags: (connection, ctx) => this.getConnectionTags(connection, ctx)
1778
1698
  });
1779
- this._state = DEFAULT_STATE;
1780
1699
  this._disposables = new DisposableStore();
1781
1700
  this._destroyed = false;
1782
- this._rawStateAccessors = /* @__PURE__ */ new WeakMap();
1783
1701
  this._persistenceHookMode = "none";
1784
1702
  this._isFacet = false;
1785
1703
  this._protocolBroadcastExcludeIds = /* @__PURE__ */ new Set();
@@ -1797,7 +1715,6 @@ var Agent = class Agent extends DurableObject {
1797
1715
  this._ParentClass = Object.getPrototypeOf(this).constructor;
1798
1716
  this.initialState = DEFAULT_STATE;
1799
1717
  this.observability = genericObservability;
1800
- this._flushingQueue = false;
1801
1718
  this.maxConcurrentAgentTools = Infinity;
1802
1719
  const routeHost = this;
1803
1720
  setLifecycleRouteTransport(this.lifecycle, {
@@ -1832,6 +1749,20 @@ var Agent = class Agent extends DurableObject {
1832
1749
  if (typeof method !== "function") return void 0;
1833
1750
  return (payload, schedule) => method.call(this, payload, schedule);
1834
1751
  });
1752
+ this._queue = new Queue({
1753
+ retry: this._resolvedOptions.retry,
1754
+ onError: (error) => runInInvocation({
1755
+ agent: this,
1756
+ connection: void 0,
1757
+ request: void 0,
1758
+ email: void 0
1759
+ }, () => this.onError(error))
1760
+ });
1761
+ setQueueCallbackResolver(this._queue, (name) => {
1762
+ const method = this[name];
1763
+ if (typeof method !== "function") return void 0;
1764
+ return (payload, item) => method.call(this, payload, item);
1765
+ });
1835
1766
  this.tasks = new Tasks({ onError: (error) => this.onError(error) });
1836
1767
  setTaskRoutedMemoryLimitHandler(this.tasks, (context) => {
1837
1768
  return this.onAlarmMemoryLimit?.call(this, context);
@@ -1857,7 +1788,7 @@ var Agent = class Agent extends DurableObject {
1857
1788
  createAuthProvider: (callbackUrl) => this.createMcpOAuthProvider(callbackUrl)
1858
1789
  });
1859
1790
  });
1860
- this.lifecycle.use(this.scheduler).use(this.mcp).use(this._webSockets, { fallback: true }).use(this.tasks).use(this._dynamicAgents);
1791
+ this.lifecycle.use(this.scheduler).use(this._queue).use(this.mcp).use(this._state).use(this._webSockets).use(this.tasks).use(this._dynamicAgents);
1861
1792
  let mcpBroadcastReady = false;
1862
1793
  this._disposables.add(this.mcp.onServerStateChanged(() => {
1863
1794
  if (mcpBroadcastReady) this.broadcastMcpServers();
@@ -1907,7 +1838,7 @@ var Agent = class Agent extends DurableObject {
1907
1838
  this.onMessage = async (connection, message) => {
1908
1839
  const replyBridge = dynamicAgentRpcReplyContext.getStore()?.bridge;
1909
1840
  if (await __DO_NOT_USE_WILL_BREAK__agentContext.exit(() => this._cf_forwardSubAgentWebSocketMessage(connection, message, replyBridge))) return;
1910
- this._ensureConnectionWrapped(connection);
1841
+ ensureConnectionWrapped(connection);
1911
1842
  return runInInvocation({
1912
1843
  agent: this,
1913
1844
  connection,
@@ -1921,25 +1852,7 @@ var Agent = class Agent extends DurableObject {
1921
1852
  } catch (_e) {
1922
1853
  return this._tryCatch(() => _onMessage(connection, message));
1923
1854
  }
1924
- if (isStateUpdateMessage(parsed)) {
1925
- if (this.isConnectionReadonly(connection)) {
1926
- connection.send(JSON.stringify({
1927
- type: "cf_agent_state_error",
1928
- error: "Connection is readonly"
1929
- }));
1930
- return;
1931
- }
1932
- try {
1933
- this._setStateInternal(parsed.state, connection);
1934
- } catch (e) {
1935
- console.error("[Agent] State update rejected:", e);
1936
- connection.send(JSON.stringify({
1937
- type: "cf_agent_state_error",
1938
- error: "State update rejected"
1939
- }));
1940
- }
1941
- return;
1942
- }
1855
+ if (this._webSockets.applyStateFrame(connection, parsed)) return;
1943
1856
  if (isRPCRequest(parsed)) {
1944
1857
  try {
1945
1858
  const { id, method, args } = parsed;
@@ -2003,7 +1916,7 @@ var Agent = class Agent extends DurableObject {
2003
1916
  };
2004
1917
  const _onConnect = this.onConnect.bind(this);
2005
1918
  this.onConnect = async (connection, ctx) => {
2006
- this._ensureConnectionWrapped(connection);
1919
+ ensureConnectionWrapped(connection);
2007
1920
  const subAgentOuterUrl = ctx.request.headers.get(SUB_AGENT_OUTER_URL_HEADER);
2008
1921
  if (subAgentOuterUrl) this._unsafe_setConnectionFlag(connection, CF_SUB_AGENT_OUTER_URL_KEY, subAgentOuterUrl);
2009
1922
  if (await __DO_NOT_USE_WILL_BREAK__agentContext.exit(() => this._cf_forwardSubAgentWebSocketConnect(connection, ctx.request, { gate: false }))) return;
@@ -2023,11 +1936,10 @@ var Agent = class Agent extends DurableObject {
2023
1936
  console.warn(`[Agent] ${ctor.name}: sending instance name "${this.name}" to clients via sendIdentityOnConnect (the name is not visible in the URL with custom routing). If this name is sensitive, add \`static options = { sendIdentityOnConnect: false }\` to opt out. Set it to true to silence this message.`);
2024
1937
  }
2025
1938
  }
2026
- connection.send(JSON.stringify({
1939
+ this._webSockets.sendIdentity(connection, {
2027
1940
  name: this.name,
2028
- agent: camelCaseToKebabCase(this._ParentClass.name),
2029
- type: "cf_agent_identity"
2030
- }));
1941
+ agent: camelCaseToKebabCase(this._ParentClass.name)
1942
+ });
2031
1943
  }
2032
1944
  const wasExcludedFromStateInitBroadcast = this._protocolBroadcastExcludeIds.has(connection.id);
2033
1945
  let currentState;
@@ -2037,15 +1949,12 @@ var Agent = class Agent extends DurableObject {
2037
1949
  } finally {
2038
1950
  if (!wasExcludedFromStateInitBroadcast) this._protocolBroadcastExcludeIds.delete(connection.id);
2039
1951
  }
2040
- if (currentState !== void 0) connection.send(JSON.stringify({
2041
- state: currentState,
2042
- type: "cf_agent_state"
2043
- }));
1952
+ if (currentState !== void 0) this._webSockets.sendState(connection);
2044
1953
  connection.send(JSON.stringify({
2045
1954
  mcp: this.getMcpServers(),
2046
1955
  type: "cf_agent_mcp_servers"
2047
1956
  }));
2048
- } else this._setConnectionNoProtocol(connection);
1957
+ } else this._webSockets.setProtocolEnabled(connection, false);
2049
1958
  this._emit("connect", { connectionId: connection.id });
2050
1959
  await this._replayAgentToolRuns(connection);
2051
1960
  return this._tryCatch(() => _onConnect(connection, ctx));
@@ -2142,13 +2051,14 @@ var Agent = class Agent extends DurableObject {
2142
2051
  for (const conn of this.getConnections()) if (!this.isConnectionProtocolEnabled(conn)) exclude.push(conn.id);
2143
2052
  this.broadcast(msg, exclude);
2144
2053
  }
2145
- _setStateInternal(nextState, source = "server") {
2146
- this.validateStateChange(nextState, source);
2147
- this._state = nextState;
2148
- this.sql`
2149
- INSERT OR REPLACE INTO cf_agents_state (id, state)
2150
- VALUES (${STATE_ROW_ID}, ${JSON.stringify(nextState)})
2151
- `;
2054
+ /**
2055
+ * React to a persisted state change from the State capability.
2056
+ *
2057
+ * Reproduces the pre-migration steps 3-4: broadcast the new state to
2058
+ * protocol-enabled connections (excluding the originating connection) and
2059
+ * run the notification hook off the invocation tail.
2060
+ */
2061
+ _handleStateChanged(nextState, source) {
2152
2062
  this._broadcastProtocol(JSON.stringify({
2153
2063
  state: nextState,
2154
2064
  type: "cf_agent_state"
@@ -2180,69 +2090,7 @@ var Agent = class Agent extends DurableObject {
2180
2090
  setState(state) {
2181
2091
  const store = __DO_NOT_USE_WILL_BREAK__agentContext.getStore();
2182
2092
  if (store?.connection && this.isConnectionReadonly(store.connection)) throw new Error("Connection is readonly");
2183
- this._setStateInternal(state, "server");
2184
- }
2185
- /**
2186
- * Wraps connection.state and connection.setState so that internal
2187
- * _cf_-prefixed flags (readonly, no-protocol) are hidden from user code
2188
- * and cannot be accidentally overwritten.
2189
- *
2190
- * Idempotent — safe to call multiple times on the same connection.
2191
- * After hibernation, the _rawStateAccessors WeakMap is empty but the
2192
- * connection's state getter still reads from the persisted WebSocket
2193
- * attachment. Calling this method re-captures the raw getter so that
2194
- * predicate methods (isConnectionReadonly, isConnectionProtocolEnabled)
2195
- * work correctly post-hibernation.
2196
- */
2197
- _ensureConnectionWrapped(connection) {
2198
- if (this._rawStateAccessors.has(connection)) return;
2199
- const descriptor = Object.getOwnPropertyDescriptor(connection, "state");
2200
- let getRaw;
2201
- let setRaw;
2202
- if (descriptor?.get) {
2203
- getRaw = descriptor.get.bind(connection);
2204
- setRaw = connection.setState.bind(connection);
2205
- } else {
2206
- let rawState = connection.state ?? null;
2207
- getRaw = () => rawState;
2208
- setRaw = (state) => {
2209
- rawState = state;
2210
- return rawState;
2211
- };
2212
- }
2213
- this._rawStateAccessors.set(connection, {
2214
- getRaw,
2215
- setRaw
2216
- });
2217
- Object.defineProperty(connection, "state", {
2218
- configurable: true,
2219
- enumerable: true,
2220
- get() {
2221
- const raw = getRaw();
2222
- if (raw != null && typeof raw === "object" && rawHasInternalKeys(raw)) return stripInternalKeys(raw);
2223
- return raw;
2224
- }
2225
- });
2226
- Object.defineProperty(connection, "setState", {
2227
- configurable: true,
2228
- writable: true,
2229
- value(stateOrFn) {
2230
- const raw = getRaw();
2231
- const flags = raw != null && typeof raw === "object" ? extractInternalFlags(raw) : {};
2232
- const hasFlags = Object.keys(flags).length > 0;
2233
- let newUserState;
2234
- if (typeof stateOrFn === "function") newUserState = stateOrFn(hasFlags ? stripInternalKeys(raw) : raw);
2235
- else newUserState = stateOrFn;
2236
- if (hasFlags) {
2237
- if (newUserState != null && typeof newUserState === "object") return setRaw({
2238
- ...newUserState,
2239
- ...flags
2240
- });
2241
- return setRaw(flags);
2242
- }
2243
- return setRaw(newUserState);
2244
- }
2245
- });
2093
+ this._state.set(state, "server");
2246
2094
  }
2247
2095
  /**
2248
2096
  * Mark a connection as readonly or readwrite
@@ -2250,17 +2098,7 @@ var Agent = class Agent extends DurableObject {
2250
2098
  * @param readonly Whether the connection should be readonly (default: true)
2251
2099
  */
2252
2100
  setConnectionReadonly(connection, readonly = true) {
2253
- this._ensureConnectionWrapped(connection);
2254
- const accessors = this._rawStateAccessors.get(connection);
2255
- const raw = accessors.getRaw() ?? {};
2256
- if (readonly) accessors.setRaw({
2257
- ...raw,
2258
- [CF_READONLY_KEY]: true
2259
- });
2260
- else {
2261
- const { [CF_READONLY_KEY]: _, ...rest } = raw;
2262
- accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);
2263
- }
2101
+ setConnectionReadonly(connection, readonly);
2264
2102
  }
2265
2103
  /**
2266
2104
  * Check if a connection is marked as readonly.
@@ -2271,8 +2109,7 @@ var Agent = class Agent extends DurableObject {
2271
2109
  * @returns True if the connection is readonly
2272
2110
  */
2273
2111
  isConnectionReadonly(connection) {
2274
- this._ensureConnectionWrapped(connection);
2275
- return !!this._rawStateAccessors.get(connection).getRaw()?.[CF_READONLY_KEY];
2112
+ return isConnectionReadonly(connection);
2276
2113
  }
2277
2114
  /**
2278
2115
  * ⚠️ INTERNAL — DO NOT USE IN APPLICATION CODE. ⚠️
@@ -2287,30 +2124,20 @@ var Agent = class Agent extends DurableObject {
2287
2124
  * @internal
2288
2125
  */
2289
2126
  _unsafe_getConnectionFlag(connection, key) {
2290
- this._ensureConnectionWrapped(connection);
2291
- return this._rawStateAccessors.get(connection).getRaw()?.[key];
2127
+ return getConnectionFlag(connection, key);
2292
2128
  }
2293
2129
  /**
2294
2130
  * ⚠️ INTERNAL — DO NOT USE IN APPLICATION CODE. ⚠️
2295
2131
  *
2296
2132
  * Write an internal `_cf_`-prefixed flag to the raw connection state,
2297
2133
  * bypassing the user-facing state wrapper. The key must be registered
2298
- * in `CF_INTERNAL_KEYS` so it is preserved across user `setState` calls
2299
- * and hidden from `connection.state`.
2134
+ * with `registerInternalConnectionKeys` so it is preserved across user
2135
+ * `setState` calls and hidden from `connection.state`.
2300
2136
  *
2301
2137
  * @internal
2302
2138
  */
2303
2139
  _unsafe_setConnectionFlag(connection, key, value) {
2304
- this._ensureConnectionWrapped(connection);
2305
- const accessors = this._rawStateAccessors.get(connection);
2306
- const raw = accessors.getRaw() ?? {};
2307
- if (value === void 0) {
2308
- const { [key]: _, ...rest } = raw;
2309
- accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);
2310
- } else accessors.setRaw({
2311
- ...raw,
2312
- [key]: value
2313
- });
2140
+ setConnectionFlag(connection, key, value);
2314
2141
  }
2315
2142
  /**
2316
2143
  * Override this method to determine if a connection should be readonly on connect
@@ -2351,21 +2178,7 @@ var Agent = class Agent extends DurableObject {
2351
2178
  * @returns True if the connection receives protocol messages
2352
2179
  */
2353
2180
  isConnectionProtocolEnabled(connection) {
2354
- this._ensureConnectionWrapped(connection);
2355
- return !this._rawStateAccessors.get(connection).getRaw()?.[CF_NO_PROTOCOL_KEY];
2356
- }
2357
- /**
2358
- * Mark a connection as having protocol messages disabled.
2359
- * Called internally when shouldSendProtocolMessages returns false.
2360
- */
2361
- _setConnectionNoProtocol(connection) {
2362
- this._ensureConnectionWrapped(connection);
2363
- const accessors = this._rawStateAccessors.get(connection);
2364
- const raw = accessors.getRaw() ?? {};
2365
- accessors.setRaw({
2366
- ...raw,
2367
- [CF_NO_PROTOCOL_KEY]: true
2368
- });
2181
+ return isConnectionProtocolEnabled(connection);
2369
2182
  }
2370
2183
  /**
2371
2184
  * Called before the Agent's state is persisted and broadcast.
@@ -2610,111 +2423,42 @@ var Agent = class Agent extends DurableObject {
2610
2423
  });
2611
2424
  }
2612
2425
  /**
2613
- * Queue a task to be executed in the future
2426
+ * Queue a task to run in the background.
2427
+ *
2428
+ * The item is durable: it runs from the Lifecycle alarm event loop after
2429
+ * this call returns, in push order, one at a time, with retries per
2430
+ * `options.retry`, and survives the Durable Object leaving memory.
2614
2431
  * @param callback Name of the method to call
2615
2432
  * @param payload Payload to pass to the callback
2616
2433
  * @param options Options for the queued task
2617
2434
  * @param options.retry Retry options for the callback execution
2435
+ * @param options.id Stable id; a push with an existing id replaces that item
2618
2436
  * @returns The ID of the queued task
2619
2437
  */
2620
2438
  async queue(callback, payload, options) {
2621
- const id = nanoid(9);
2622
2439
  if (typeof callback !== "string") throw new Error("Callback must be a string");
2623
2440
  if (typeof this[callback] !== "function") throw new Error(`this.${callback} is not a function`);
2624
- if (options?.retry) validateRetryOptions(options.retry, this._resolvedOptions.retry);
2625
- const retryJson = options?.retry ? JSON.stringify(options.retry) : null;
2626
- this.sql`
2627
- INSERT OR REPLACE INTO cf_agents_queues (id, payload, callback, retry_options)
2628
- VALUES (${id}, ${JSON.stringify(payload)}, ${callback}, ${retryJson})
2629
- `;
2630
- this._emit("queue:create", {
2631
- callback,
2632
- id
2633
- });
2634
- this._flushQueue().catch((e) => {
2635
- console.error("Error flushing queue:", e);
2636
- });
2637
- return id;
2638
- }
2639
- async _flushQueue() {
2640
- if (this._flushingQueue) return;
2641
- this._flushingQueue = true;
2642
- try {
2643
- while (true) {
2644
- const result = this.sql`
2645
- SELECT * FROM cf_agents_queues
2646
- ORDER BY created_at ASC
2647
- `;
2648
- if (!result || result.length === 0) break;
2649
- for (const row of result || []) {
2650
- const callback = this[row.callback];
2651
- if (!callback) {
2652
- console.error(`callback ${row.callback} not found`);
2653
- await this.dequeue(row.id);
2654
- continue;
2655
- }
2656
- const { connection, request, email } = __DO_NOT_USE_WILL_BREAK__agentContext.getStore() || {};
2657
- await runInInvocation({
2658
- agent: this,
2659
- connection,
2660
- request,
2661
- email
2662
- }, async () => {
2663
- const { maxAttempts, baseDelayMs, maxDelayMs } = resolveRetryConfig(parseRetryOptions(row), this._resolvedOptions.retry);
2664
- const parsedPayload = JSON.parse(row.payload);
2665
- try {
2666
- await tryN(maxAttempts, async (attempt) => {
2667
- if (attempt > 1) this._emit("queue:retry", {
2668
- callback: row.callback,
2669
- id: row.id,
2670
- attempt,
2671
- maxAttempts
2672
- });
2673
- await callback.bind(this)(parsedPayload, row);
2674
- }, {
2675
- baseDelayMs,
2676
- maxDelayMs
2677
- });
2678
- } catch (e) {
2679
- console.error(`queue callback "${row.callback}" failed after ${maxAttempts} attempts`, e);
2680
- this._emit("queue:error", {
2681
- callback: row.callback,
2682
- id: row.id,
2683
- error: e instanceof Error ? e.message : String(e),
2684
- attempts: maxAttempts
2685
- });
2686
- try {
2687
- await this.onError(e);
2688
- } catch {}
2689
- } finally {
2690
- this.dequeue(row.id);
2691
- }
2692
- }, { detached: true });
2693
- }
2694
- }
2695
- } finally {
2696
- this._flushingQueue = false;
2697
- }
2441
+ return (await this._queue.push(callback, payload, options)).id;
2698
2442
  }
2699
2443
  /**
2700
2444
  * Dequeue a task by ID
2701
2445
  * @param id ID of the task to dequeue
2702
2446
  */
2703
2447
  dequeue(id) {
2704
- this.sql`DELETE FROM cf_agents_queues WHERE id = ${id}`;
2448
+ return this._queue.cancel(id);
2705
2449
  }
2706
2450
  /**
2707
2451
  * Dequeue all tasks
2708
2452
  */
2709
2453
  dequeueAll() {
2710
- this.sql`DELETE FROM cf_agents_queues`;
2454
+ return this._queue.cancelAll();
2711
2455
  }
2712
2456
  /**
2713
2457
  * Dequeue all tasks by callback
2714
2458
  * @param callback Name of the callback to dequeue
2715
2459
  */
2716
2460
  dequeueAllByCallback(callback) {
2717
- this.sql`DELETE FROM cf_agents_queues WHERE callback = ${callback}`;
2461
+ return this._queue.cancelAll(callback);
2718
2462
  }
2719
2463
  /**
2720
2464
  * Get a queued task by ID
@@ -2722,31 +2466,16 @@ var Agent = class Agent extends DurableObject {
2722
2466
  * @returns The task or undefined if not found
2723
2467
  */
2724
2468
  getQueue(id) {
2725
- const result = this.sql`
2726
- SELECT * FROM cf_agents_queues WHERE id = ${id}
2727
- `;
2728
- if (!result || result.length === 0) return void 0;
2729
- const row = result[0];
2730
- return {
2731
- ...row,
2732
- payload: JSON.parse(row.payload),
2733
- retry: parseRetryOptions(row)
2734
- };
2469
+ return this._queue.get(id);
2735
2470
  }
2736
2471
  /**
2737
- * Get all queues by key and value
2472
+ * Get all queued tasks whose payload has `key` equal to `value`
2738
2473
  * @param key Key to filter by
2739
2474
  * @param value Value to filter by
2740
2475
  * @returns Array of matching QueueItem objects
2741
2476
  */
2742
- getQueues(key, value) {
2743
- return this.sql`
2744
- SELECT * FROM cf_agents_queues
2745
- `.filter((row) => JSON.parse(row.payload)[key] === value).map((row) => ({
2746
- ...row,
2747
- payload: JSON.parse(row.payload),
2748
- retry: parseRetryOptions(row)
2749
- }));
2477
+ async getQueues(key, value) {
2478
+ return (await this._queue.list()).filter((item) => typeof item.payload === "object" && item.payload !== null && item.payload[key] === value);
2750
2479
  }
2751
2480
  _lifecycleRouteAddress() {
2752
2481
  return this._dynamicAgents.lifecycleRouteAddress();
@@ -3540,12 +3269,16 @@ var Agent = class Agent extends DurableObject {
3540
3269
  }
3541
3270
  } finally {
3542
3271
  this._runFiberActiveFibers.delete(id);
3543
- this._withAgentSpan("finalize_fiber", "fiber", {
3544
- "cloudflare.agents.fiber.id": id,
3545
- "cloudflare.agents.fiber.name": name
3546
- }, () => {
3547
- this.sql`DELETE FROM cf_agents_runs WHERE id = ${id}`;
3548
- });
3272
+ try {
3273
+ this._withAgentSpan("finalize_fiber", "fiber", {
3274
+ "cloudflare.agents.fiber.id": id,
3275
+ "cloudflare.agents.fiber.name": name
3276
+ }, () => {
3277
+ this.sql`DELETE FROM cf_agents_runs WHERE id = ${id}`;
3278
+ });
3279
+ } catch (error) {
3280
+ console.error(`[Agent] Failed to finalize fiber "${name}" (${id}); leaving run row for recovery:`, error);
3281
+ }
3549
3282
  dispose();
3550
3283
  if (root && registeredFacetRun) try {
3551
3284
  await root._cf_unregisterFacetRun(this.selfPath, id);
@@ -6960,4 +6693,4 @@ var StreamingResponse = class {
6960
6693
  //#endregion
6961
6694
  export { routeAgentEmail as a, getCurrentAgent as i, DEFAULT_AGENT_STATIC_OPTIONS as n, StreamingResponse as r, Agent as t };
6962
6695
 
6963
- //# sourceMappingURL=src-DlSHshb2.js.map
6696
+ //# sourceMappingURL=src-BNU3ZiJM.js.map