agents 0.22.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 (215) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-B2XLNMxq.d.ts} +1094 -443
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +26 -26
  5. package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
  6. package/dist/agent-tools.d.ts +21 -21
  7. package/dist/browser/ai.js +4 -1
  8. package/dist/browser/ai.js.map +1 -1
  9. package/dist/browser/tanstack-ai.js.map +1 -1
  10. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  11. package/dist/callable-decorator.d.ts +18 -0
  12. package/dist/callable-decorator.js +71 -0
  13. package/dist/callable-decorator.js.map +1 -0
  14. package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
  15. package/dist/capability-B4WbF81e.js.map +1 -0
  16. package/dist/capability-runner-BUBa6Ake.d.ts +484 -0
  17. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  18. package/dist/channels/ai-sdk.d.ts +46 -0
  19. package/dist/channels/ai-sdk.js +120 -0
  20. package/dist/channels/ai-sdk.js.map +1 -0
  21. package/dist/channels/email.d.ts +95 -0
  22. package/dist/channels/email.js +323 -0
  23. package/dist/channels/email.js.map +1 -0
  24. package/dist/channels/index.d.ts +233 -0
  25. package/dist/channels/index.js +608 -0
  26. package/dist/channels/index.js.map +1 -0
  27. package/dist/channels/slack.d.ts +140 -0
  28. package/dist/channels/slack.js +614 -0
  29. package/dist/channels/slack.js.map +1 -0
  30. package/dist/channels/tanstack-ai.d.ts +39 -0
  31. package/dist/channels/tanstack-ai.js +17 -0
  32. package/dist/channels/tanstack-ai.js.map +1 -0
  33. package/dist/channels/telegram.d.ts +106 -0
  34. package/dist/channels/telegram.js +427 -0
  35. package/dist/channels/telegram.js.map +1 -0
  36. package/dist/channels/voice.d.ts +45 -0
  37. package/dist/channels/voice.js +122 -0
  38. package/dist/channels/voice.js.map +1 -0
  39. package/dist/chat/index.d.ts +2319 -2010
  40. package/dist/chat/index.js +892 -518
  41. package/dist/chat/index.js.map +1 -1
  42. package/dist/chat-sdk/index.d.ts +7 -7
  43. package/dist/chat-sdk/index.js +1 -1
  44. package/dist/client-BxdkCuVy.d.ts +411 -0
  45. package/dist/client-C9DAjZIY.js +518 -0
  46. package/dist/client-C9DAjZIY.js.map +1 -0
  47. package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
  48. package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
  49. package/dist/client.d.ts +27 -283
  50. package/dist/client.js +2 -274
  51. package/dist/context/index.d.ts +216 -0
  52. package/dist/context/index.js +454 -0
  53. package/dist/context/index.js.map +1 -0
  54. package/dist/current-agent-C4w86kcN.d.ts +93 -0
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  57. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  58. package/dist/diagnostics-C4jcz3VK.js +360 -0
  59. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  60. package/dist/durable-object-lifecycle-ei7M7lqB.d.ts +157 -0
  61. package/dist/index-BB0kqhIz.d.ts +101 -0
  62. package/dist/index-BVVgDSdq.d.ts +1 -0
  63. package/dist/index-Dlgtd3Mj.d.ts +78 -0
  64. package/dist/index-XDkuQ7zm.d.ts +89 -0
  65. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  66. package/dist/index.d.ts +92 -83
  67. package/dist/index.js +4 -3
  68. package/dist/ingress-BfetZbMO.js +83 -0
  69. package/dist/ingress-BfetZbMO.js.map +1 -0
  70. package/dist/internal-CYlgHl1l.js +59 -0
  71. package/dist/internal-CYlgHl1l.js.map +1 -0
  72. package/dist/internal_context.d.ts +1 -1
  73. package/dist/lifecycle/index.d.ts +39 -19
  74. package/dist/lifecycle/index.js +2 -2
  75. package/dist/lifecycle-Mm_jQh7r.js +1314 -0
  76. package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
  77. package/dist/mcp/client/index.d.ts +20 -20
  78. package/dist/mcp/client/index.js +1 -1
  79. package/dist/mcp/index.d.ts +35 -35
  80. package/dist/mcp/index.js +2 -2
  81. package/dist/observability/index.d.ts +1 -1
  82. package/dist/observability/index.js +1 -1
  83. package/dist/queue/index.d.ts +123 -0
  84. package/dist/queue/index.js +2 -0
  85. package/dist/queue-BC9F5cUo.js +406 -0
  86. package/dist/queue-BC9F5cUo.js.map +1 -0
  87. package/dist/react.d.ts +34 -16
  88. package/dist/react.js +31 -8
  89. package/dist/react.js.map +1 -1
  90. package/dist/{retries-CAvxtG9d.d.ts → retries-D9B2UCq3.d.ts} +23 -6
  91. package/dist/retries.d.ts +10 -6
  92. package/dist/retries.js +21 -1
  93. package/dist/retries.js.map +1 -1
  94. package/dist/routing/index.d.ts +137 -0
  95. package/dist/routing/index.js +244 -0
  96. package/dist/routing/index.js.map +1 -0
  97. package/dist/sanitize-D9TujEK8.js +79 -0
  98. package/dist/sanitize-D9TujEK8.js.map +1 -0
  99. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-BGq6M5Kd.d.ts} +20 -21
  100. package/dist/scheduler-D_KHqxBa.js +658 -0
  101. package/dist/scheduler-D_KHqxBa.js.map +1 -0
  102. package/dist/schedules/index.d.ts +1 -1
  103. package/dist/schedules/index.js +1 -1
  104. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  105. package/dist/serializable.d.ts +1 -1
  106. package/dist/sessions/index.d.ts +441 -0
  107. package/dist/sessions/index.js +2063 -0
  108. package/dist/sessions/index.js.map +1 -0
  109. package/dist/skills/index.d.ts +99 -0
  110. package/dist/skills/index.js +254 -5
  111. package/dist/skills/index.js.map +1 -1
  112. package/dist/{src-5W6JNKVb.js → src-BNU3ZiJM.js} +1524 -1441
  113. package/dist/src-BNU3ZiJM.js.map +1 -0
  114. package/dist/state/index.d.ts +6 -0
  115. package/dist/state/index.js +137 -0
  116. package/dist/state/index.js.map +1 -0
  117. package/dist/streams/index.d.ts +120 -0
  118. package/dist/streams/index.js +107 -0
  119. package/dist/streams/index.js.map +1 -0
  120. package/dist/streams-BcE8JP2X.d.ts +370 -0
  121. package/dist/streams-CCPRV6dt.js +709 -0
  122. package/dist/streams-CCPRV6dt.js.map +1 -0
  123. package/dist/sub-routing.d.ts +12 -12
  124. package/dist/surface-bZZJqBka.js +17 -0
  125. package/dist/surface-bZZJqBka.js.map +1 -0
  126. package/dist/tasks/index.d.ts +64 -0
  127. package/dist/tasks/index.js +2 -0
  128. package/dist/tasks-D4nLqVSI.js +1656 -0
  129. package/dist/tasks-D4nLqVSI.js.map +1 -0
  130. package/dist/tasks-V2lCT8ZV.d.ts +517 -0
  131. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  132. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  133. package/dist/text-stream-CpdiKrJB.js +272 -0
  134. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  135. package/dist/tokens-nHAKcN6M.js +52 -0
  136. package/dist/tokens-nHAKcN6M.js.map +1 -0
  137. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  138. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  139. package/dist/transport-protocol-BxyngQ_R.js +25 -0
  140. package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
  141. package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
  142. package/dist/types-B7LojTe4.d.ts +202 -0
  143. package/dist/types-DCD6BNZH.d.ts +70 -0
  144. package/dist/types-_Faxb570.d.ts +439 -0
  145. package/dist/voice/client.d.ts +226 -0
  146. package/dist/voice/client.js +932 -0
  147. package/dist/voice/client.js.map +1 -0
  148. package/dist/voice/errors.d.ts +43 -0
  149. package/dist/voice/errors.js +41 -0
  150. package/dist/voice/errors.js.map +1 -0
  151. package/dist/voice/index.d.ts +271 -0
  152. package/dist/voice/index.js +1812 -0
  153. package/dist/voice/index.js.map +1 -0
  154. package/dist/voice/react.d.ts +167 -0
  155. package/dist/voice/react.js +234 -0
  156. package/dist/voice/react.js.map +1 -0
  157. package/dist/voice/sfu.d.ts +71 -0
  158. package/dist/voice/sfu.js +157 -0
  159. package/dist/voice/sfu.js.map +1 -0
  160. package/dist/voice/text.d.ts +6 -0
  161. package/dist/voice/text.js +2 -0
  162. package/dist/voice/types.d.ts +58 -0
  163. package/dist/voice/types.js +18 -0
  164. package/dist/voice/types.js.map +1 -0
  165. package/dist/voice/workers-ai.d.ts +136 -0
  166. package/dist/voice/workers-ai.js +568 -0
  167. package/dist/voice/workers-ai.js.map +1 -0
  168. package/dist/websockets/index.d.ts +301 -0
  169. package/dist/websockets/index.js +3 -0
  170. package/dist/websockets-D7IzWbZb.js +1005 -0
  171. package/dist/websockets-D7IzWbZb.js.map +1 -0
  172. package/dist/workflow-types.d.ts +25 -25
  173. package/dist/workflows.d.ts +21 -21
  174. package/dist/workflows.js +1 -1
  175. package/docs/agent-class.md +4 -4
  176. package/docs/agent-tools.md +2 -1
  177. package/docs/channels.md +323 -0
  178. package/docs/chat-agents.md +6 -13
  179. package/docs/client-sdk.md +30 -0
  180. package/docs/context.md +131 -0
  181. package/docs/index.md +16 -13
  182. package/docs/lifecycle.md +179 -57
  183. package/docs/long-running-agents.md +2 -2
  184. package/docs/mcp-servers.md +5 -1
  185. package/docs/queue.md +135 -241
  186. package/docs/resumable-streaming.md +1 -1
  187. package/docs/retries.md +1 -1
  188. package/docs/routing.md +105 -0
  189. package/docs/sessions.md +237 -871
  190. package/docs/streams.md +213 -0
  191. package/docs/sub-agents.md +184 -124
  192. package/docs/tasks.md +246 -0
  193. package/docs/voice.md +745 -0
  194. package/package.json +126 -14
  195. package/dist/capability-BjSKYpzg.js.map +0 -1
  196. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  197. package/dist/client.js.map +0 -1
  198. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  199. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  200. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  201. package/dist/current-agent-CuMErtly.d.ts +0 -283
  202. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  203. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  204. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  205. package/dist/experimental/memory/session/index.d.ts +0 -671
  206. package/dist/experimental/memory/session/index.js +0 -2379
  207. package/dist/experimental/memory/session/index.js.map +0 -1
  208. package/dist/experimental/memory/utils/index.d.ts +0 -96
  209. package/dist/experimental/memory/utils/index.js +0 -79
  210. package/dist/experimental/memory/utils/index.js.map +0 -1
  211. package/dist/scheduler-CR9RHGos.js +0 -857
  212. package/dist/scheduler-CR9RHGos.js.map +0 -1
  213. package/dist/src-5W6JNKVb.js.map +0 -1
  214. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  215. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler-D_KHqxBa.js","names":[],"sources":["../src/schedules/schedule-timing.ts","../src/schedules/scheduler.ts"],"sourcesContent":["/**\n * Pure timing rules for persistent schedules.\n *\n * A `ScheduleTiming` is the parsed \"when and how it runs\" half of a\n * `Schedule` — everything except identity, callback, and payload. Parsing\n * user-facing inputs here keeps Scheduler's storage code to one insert path.\n */\n\nimport { parseCronExpression } from \"cron-schedule\";\n\n/** Longest allowed gap between interval executions: 30 days. */\nexport const MAX_INTERVAL_SECONDS = 30 * 24 * 60 * 60;\n\n/** When and how one schedule runs; a `Schedule` minus identity and payload. */\nexport type ScheduleTiming =\n | {\n /** One-time execution at a specific date. */\n readonly type: \"scheduled\";\n /** Unix timestamp in seconds. */\n readonly time: number;\n }\n | {\n /** One-time execution after a relative delay. */\n readonly type: \"delayed\";\n /** Unix timestamp in seconds. */\n readonly time: number;\n /** Delay from creation in seconds. */\n readonly delayInSeconds: number;\n }\n | {\n /** Recurring execution from a cron expression. */\n readonly type: \"cron\";\n /** Unix timestamp in seconds for the next execution. */\n readonly time: number;\n /** Cron expression defining the recurrence. */\n readonly cron: string;\n }\n | {\n /** Recurring execution at a fixed interval. */\n readonly type: \"interval\";\n /** Unix timestamp in seconds for the next execution. */\n readonly time: number;\n /** Number of seconds between executions. */\n readonly intervalSeconds: number;\n };\n\n/** True when this timing repeats and therefore deduplicates by default. */\nexport function isRecurring(timing: ScheduleTiming): boolean {\n return timing.type === \"cron\" || timing.type === \"interval\";\n}\n\n/**\n * Next wall-clock execution time for a cron expression.\n *\n * @param cron - A standard cron expression.\n * @param nowMs - Current epoch time in milliseconds.\n * @returns The next execution epoch time in milliseconds.\n * @throws For an unparseable cron expression.\n */\nexport function nextCronTimeMs(cron: string, nowMs: number): number {\n return parseCronExpression(cron).getNextDate(new Date(nowMs)).getTime();\n}\n\n/**\n * Parse a user-facing `when` into schedule timing.\n *\n * A `Date` runs once at that date, a number runs once after that many\n * seconds, and a string is a recurring cron expression.\n *\n * @param when - The requested execution time or recurrence.\n * @param nowMs - Current epoch time in milliseconds.\n * @param callback - Callback name, used only in error messages.\n * @returns The parsed timing.\n * @throws For a `when` value that is not a `Date`, number, or string.\n */\nexport function parseWhen(\n when: Date | string | number,\n nowMs: number,\n callback: string\n): ScheduleTiming {\n if (when instanceof Date) {\n return { type: \"scheduled\", time: Math.floor(when.getTime() / 1000) };\n }\n if (typeof when === \"number\") {\n return {\n type: \"delayed\",\n time: Math.floor((nowMs + when * 1000) / 1000),\n delayInSeconds: when\n };\n }\n if (typeof when === \"string\") {\n return {\n type: \"cron\",\n time: Math.floor(nextCronTimeMs(when, nowMs) / 1000),\n cron: when\n };\n }\n throw new Error(\n `Invalid schedule type: ${JSON.stringify(when)}(${typeof when}) trying to schedule ${callback}`\n );\n}\n\n/**\n * Reject an interval outside the supported range.\n *\n * @param intervalSeconds - The requested gap between executions.\n * @throws For a non-positive interval or one longer than 30 days.\n */\nexport function validateIntervalSeconds(intervalSeconds: number): void {\n if (typeof intervalSeconds !== \"number\" || intervalSeconds <= 0) {\n throw new Error(\"intervalSeconds must be a positive number\");\n }\n if (intervalSeconds > MAX_INTERVAL_SECONDS) {\n throw new Error(\n `intervalSeconds cannot exceed ${MAX_INTERVAL_SECONDS} seconds (30 days)`\n );\n }\n}\n\n/**\n * Parse a fixed interval into schedule timing.\n *\n * @param intervalSeconds - Seconds between executions.\n * @param nowMs - Current epoch time in milliseconds.\n * @returns The parsed timing with the first execution one interval from now.\n * @throws For an interval outside the supported range.\n */\nexport function parseInterval(\n intervalSeconds: number,\n nowMs: number\n): ScheduleTiming {\n validateIntervalSeconds(intervalSeconds);\n return {\n type: \"interval\",\n time: Math.floor((nowMs + intervalSeconds * 1000) / 1000),\n intervalSeconds\n };\n}\n","/**\n * Lifecycle scheduling vocabulary. Scheduler validates schedules, resolves\n * named callbacks, and pushes jobs into the Lifecycle-owned job queue;\n * Lifecycle runs the alarm event loop, retry policy, and physical alarm\n * arming. Scheduler owns no storage of its own — each schedule is one job\n * whose `fn` is the callback name and whose payload carries the schedule's\n * timing vocabulary.\n */\n\nimport {\n LifecycleCapability,\n type LifecycleRouteAddress,\n type LifecycleRouteContext\n} from \"../lifecycle/capability\";\nimport type {\n LifecycleJob,\n LifecycleJobContext,\n LifecycleJobOutcome\n} from \"../lifecycle/job-queue\";\nimport {\n isDurableObjectCodeUpdateReset,\n isPlatformFailure,\n resolveRetryConfig,\n tryN,\n validateRetryOptions\n} from \"../retries\";\nimport type { RetryOptions } from \"../retries\";\nimport type { SchedulerEventType, SchedulerOptions } from \"./options\";\nimport {\n isRecurring,\n nextCronTimeMs,\n parseInterval,\n parseWhen,\n validateIntervalSeconds,\n type ScheduleTiming\n} from \"./schedule-timing\";\nimport type {\n RecoveryLoopScheduleOptions,\n Schedule,\n ScheduleCriteria,\n ScheduleOptions,\n ScheduleStorageRow,\n SchedulerCallbacks,\n SchedulerHandlers,\n SchedulerPayload\n} from \"./types\";\n\n/**\n * A resolved fallback handler for a callback name outside the registered map.\n */\ntype ResolvedSchedulerCallback = (\n payload: unknown,\n schedule: Schedule<unknown>\n) => unknown;\n\nconst schedulerCallbackResolvers = new WeakMap<\n object,\n (name: string) => ResolvedSchedulerCallback | undefined\n>();\n\n/**\n * @internal Supply a composition-root fallback for callback names outside the\n * registered map. Agent uses this to keep its historical name-based\n * scheduling API (`this.schedule(60, \"methodName\")`) working: the resolver\n * looks the method up on the Agent, and the resolved handler still runs\n * inside the Lifecycle host boundary.\n */\nexport function setSchedulerCallbackResolver(\n scheduler: Scheduler<never>,\n resolver: (name: string) => ResolvedSchedulerCallback | undefined\n): void {\n schedulerCallbackResolvers.set(scheduler, resolver);\n}\n\nconst SCHEDULE_SCHEMA_VERSION_KEY = \"cf_agents:schedules_schema_version\";\n/** Version 2: schedule rows live in the Lifecycle job queue. */\nconst CURRENT_SCHEDULE_SCHEMA_VERSION = 2;\n\n/**\n * Legacy schedule callbacks whose rows drive chat recovery loops from before\n * the job queue carried breaker membership. The migration is the one place\n * allowed to know legacy names (it already drops `_cf_keepAliveHeartbeat`\n * rows by name): a recovery row migrated without its `recoveryLoop` flag\n * would escape the alarm memory-limit breaker (#1825) and could re-trigger\n * a doomed loop on an upgraded object.\n */\nconst LEGACY_RECOVERY_LOOP_CALLBACKS = new Set([\n \"_chatRecoveryContinue\",\n \"_chatRecoveryRetry\"\n]);\n\nconst DEFAULT_RETRY: Required<RetryOptions> = {\n maxAttempts: 3,\n baseDelayMs: 100,\n maxDelayMs: 3000\n};\n\n/**\n * The schedule timing vocabulary carried in one job's payload. The callback\n * name is the job's `fn`; the user payload rides in `payload`.\n */\ntype SchedulerJobPayload = {\n readonly payload: unknown;\n readonly type: \"scheduled\" | \"delayed\" | \"cron\" | \"interval\";\n /** The caller-supplied retry override, unresolved, for public projection.\n The job's own retry options are fully resolved against the Scheduler\n defaults at push so the Lifecycle driver applies the configured\n policy. */\n readonly retry?: RetryOptions;\n readonly delayInSeconds?: number;\n readonly cron?: string;\n readonly intervalSeconds?: number;\n readonly owner_path?: string | null;\n readonly owner_path_key?: string | null;\n};\n\ntype SchedulerRouteMessage =\n | {\n readonly type: \"schedule\";\n readonly when: Date | string | number;\n readonly callback: string;\n readonly payload?: unknown;\n readonly options?: ScheduleOptions;\n }\n | {\n readonly type: \"every\";\n readonly intervalSeconds: number;\n readonly callback: string;\n readonly payload?: unknown;\n readonly options?: ScheduleOptions;\n }\n | { readonly type: \"get\" | \"cancel\"; readonly id: string }\n | { readonly type: \"list\"; readonly criteria?: ScheduleCriteria }\n | {\n readonly type: \"dispatch\";\n readonly id: string;\n readonly fn: string;\n readonly job: SchedulerJobPayload;\n readonly retry?: RetryOptions;\n };\n\ntype InsertResult<T> = {\n readonly schedule: Schedule<T>;\n readonly created: boolean;\n};\n\nfunction isSchedulerJobPayload(value: unknown): value is SchedulerJobPayload {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as SchedulerJobPayload).type === \"string\"\n );\n}\n\n/**\n * Persistent task scheduling for a Lifecycle Object.\n *\n * Register callbacks in the constructor and install the instance with\n * `Lifecycle.use()`. Scheduler validates schedules and pushes them into the\n * Lifecycle job queue; Lifecycle owns the physical alarm and the alarm\n * event loop, and Scheduler runs registered callbacks through Lifecycle's\n * host invocation boundary when its jobs come due.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class Scheduler<\n Handlers extends SchedulerHandlers = SchedulerCallbacks\n> extends LifecycleCapability {\n readonly #handlers: SchedulerHandlers;\n readonly #retryDefaults: Required<RetryOptions>;\n readonly #hungScheduleTimeoutSeconds: number;\n readonly #onError: ((error: unknown) => void | Promise<void>) | undefined;\n readonly #warnedStartupCallbacks = new Set<string>();\n\n /**\n * Create a persistent Scheduler.\n *\n * @param options - Registered callbacks plus optional retry,\n * hung-interval, and error policy. Registering `callbacks` types\n * {@link set} and {@link every} against the map — names and\n * payloads are checked where the handlers are declared and where they are\n * scheduled. Names outside the map are rejected unless a composition-root\n * resolver supplies them — the internal aperture behind `Agent`'s\n * name-based scheduling API.\n */\n constructor(options: SchedulerOptions<Handlers> = {}) {\n super(\"scheduler\");\n this.#handlers = options.callbacks ?? {};\n // Retry defaults are resolved, not validated, here: a host whose\n // historically tolerated invalid retry config throws at construction\n // would brick every entry point of its Durable Object. Invalid defaults\n // surface per execution as schedule:error instead, and per-schedule\n // retry overrides are still validated when each schedule is created.\n this.#retryDefaults = resolveRetryConfig(options.retry, DEFAULT_RETRY);\n this.#hungScheduleTimeoutSeconds = options.hungScheduleTimeoutSeconds ?? 30;\n this.#onError = options.onError;\n }\n\n // ── Lifecycle capability hooks ───────────────────────────────────────────\n\n /** Migrate legacy schedule storage into the Lifecycle job queue. */\n async onStart(): Promise<void> {\n this.#warnedStartupCallbacks.clear();\n const storage = this.lifecycle.storage;\n const version =\n (await storage.get<number>(SCHEDULE_SCHEMA_VERSION_KEY)) ?? 0;\n if (version >= CURRENT_SCHEDULE_SCHEMA_VERSION) return;\n\n await this.#migrateLegacyScheduleTable(storage);\n await storage.put(\n SCHEDULE_SCHEMA_VERSION_KEY,\n CURRENT_SCHEDULE_SCHEMA_VERSION\n );\n }\n\n /**\n * Move every `cf_agents_schedules` row into the job queue and drop the\n * table. Idempotent: a missing table means a fresh object or a completed\n * migration. Times convert from epoch seconds to epoch milliseconds.\n */\n async #migrateLegacyScheduleTable(\n storage: DurableObjectStorage\n ): Promise<void> {\n const tables = storage.sql\n .exec(\n \"SELECT name FROM sqlite_master WHERE type='table' AND name='cf_agents_schedules'\"\n )\n .toArray();\n if (tables.length === 0) return;\n\n const rows = storage.sql\n .exec(\"SELECT * FROM cf_agents_schedules\")\n .toArray() as unknown as ScheduleStorageRow[];\n for (const row of rows) {\n // Keep-alive heartbeats stopped using schedule rows long ago; drop\n // orphans instead of migrating them.\n if (row.callback === \"_cf_keepAliveHeartbeat\") continue;\n let payload: unknown;\n try {\n payload =\n typeof row.payload === \"string\" ? JSON.parse(row.payload) : undefined;\n } catch (error) {\n console.error(\n `Skipping schedule \"${row.id}\" during job-queue migration: ` +\n \"its payload is not valid JSON\",\n error\n );\n continue;\n }\n let retry: RetryOptions | undefined;\n try {\n retry =\n typeof row.retry_options === \"string\"\n ? (JSON.parse(row.retry_options) as RetryOptions)\n : undefined;\n } catch {\n retry = undefined;\n }\n await this.lifecycle.jobs.push({\n id: row.id,\n fn: row.callback,\n time: row.time * 1000,\n payload: {\n payload,\n retry,\n type: row.type,\n delayInSeconds: row.delayInSeconds ?? undefined,\n cron: row.cron ?? undefined,\n intervalSeconds: row.intervalSeconds ?? undefined,\n owner_path: row.owner_path ?? null,\n owner_path_key: row.owner_path_key ?? null\n } satisfies SchedulerJobPayload,\n retry: resolveRetryConfig(retry, this.#retryDefaults),\n singleflight: row.type === \"interval\",\n hungTimeoutSeconds: this.#hungScheduleTimeoutSeconds,\n recoveryLoop: LEGACY_RECOVERY_LOOP_CALLBACKS.has(row.callback)\n });\n }\n storage.sql.exec(\"DROP TABLE cf_agents_schedules\");\n }\n\n /** Drive one due schedule job dispatched by the Lifecycle event loop. */\n async onJob(\n context: LifecycleJobContext\n ): Promise<LifecycleJobOutcome | void> {\n const { job, attempt } = context;\n const timing = job.payload;\n if (!isSchedulerJobPayload(timing)) {\n console.error(`Malformed schedule job ${job.id}; dropping it`);\n return undefined;\n }\n\n if (attempt === 1) {\n this.#emit(\"schedule:execute\", { callback: job.fn, id: job.id });\n } else {\n this.#emit(\"schedule:retry\", {\n callback: job.fn,\n id: job.id,\n attempt,\n maxAttempts: resolveRetryConfig(job.retry, this.#retryDefaults)\n .maxAttempts\n });\n }\n\n if (timing.owner_path) {\n // A routed schedule executes inside its owning Lifecycle; retries run\n // there too, so this dispatch is a single routed attempt.\n try {\n await this.lifecycle.routes.to(\n {\n key: timing.owner_path_key ?? timing.owner_path,\n data: timing.owner_path\n },\n {\n type: \"dispatch\",\n id: job.id,\n fn: job.fn,\n job: timing,\n retry: job.retry\n } satisfies SchedulerRouteMessage\n );\n } catch (error) {\n if (isPlatformFailure(error)) {\n // Preserve the job; Lifecycle defers platform-class failures to a\n // fresh invocation or the memory-limit breaker.\n throw error;\n }\n console.error(\n `error dispatching scheduled callback \"${job.fn}\"`,\n error\n );\n this.#emit(\"schedule:error\", {\n callback: job.fn,\n id: job.id,\n error: error instanceof Error ? error.message : String(error),\n attempts: 0\n });\n try {\n await this.#onError?.(error);\n } catch {\n // swallow onError errors\n }\n // Leave the job due so a later alarm cycle can retry dispatch, for\n // example once a transport can resolve its owner again.\n return \"yield\";\n }\n return this.#recurrenceOutcome(timing);\n }\n\n const handler = this.#resolveCallback(job.fn);\n if (!handler) {\n console.error(`callback ${job.fn} not found`);\n return this.#recurrenceOutcome(timing);\n }\n const schedule = this.#jobToSchedule<unknown>(job, timing);\n await this.lifecycle.runInHostContext(() =>\n handler(timing.payload, schedule)\n );\n return this.#recurrenceOutcome(timing);\n }\n\n /** Observe one schedule's terminal application failure. */\n async onJobError(\n context: LifecycleJobContext,\n error: unknown\n ): Promise<LifecycleJobOutcome | void> {\n const { job } = context;\n const timing = job.payload;\n if (!isSchedulerJobPayload(timing)) return undefined;\n const { maxAttempts } = resolveRetryConfig(job.retry, this.#retryDefaults);\n console.error(\n `error executing callback \"${job.fn}\" after ${maxAttempts} attempts`,\n error\n );\n this.#emit(\"schedule:error\", {\n callback: job.fn,\n id: job.id,\n error: error instanceof Error ? error.message : String(error),\n attempts: maxAttempts\n });\n try {\n await this.#onError?.(error);\n } catch {\n // swallow onError errors\n }\n return this.#recurrenceOutcome(timing);\n }\n\n /** Advance a recurring schedule; complete a one-shot. */\n #recurrenceOutcome(timing: SchedulerJobPayload): LifecycleJobOutcome {\n if (timing.type === \"cron\") {\n return { rescheduleAt: nextCronTimeMs(timing.cron ?? \"\", Date.now()) };\n }\n if (timing.type === \"interval\") {\n return {\n rescheduleAt: Date.now() + (timing.intervalSeconds ?? 0) * 1000\n };\n }\n return undefined;\n }\n\n /** Handle Scheduler protocol messages routed by another Lifecycle. */\n async onRoute(context: LifecycleRouteContext): Promise<unknown> {\n const message = context.payload as SchedulerRouteMessage;\n const owner = context.source ?? null;\n switch (message.type) {\n case \"schedule\":\n return this.#insert(\n owner,\n parseWhen(message.when, Date.now(), message.callback),\n message.callback,\n message.payload,\n message.options\n );\n case \"every\":\n return this.#insert(\n owner,\n parseInterval(message.intervalSeconds, Date.now()),\n message.callback,\n message.payload,\n message.options\n );\n case \"get\":\n return this.#getForOwner(owner, message.id);\n case \"list\":\n return this.#listForOwner(owner, message.criteria);\n case \"cancel\":\n return this.#cancelForOwner(owner, message.id);\n case \"dispatch\":\n await this.#executeRouted(\n message.id,\n message.fn,\n message.job,\n message.retry\n );\n return true;\n default:\n throw new Error(\"Unknown routed Scheduler message\");\n }\n }\n\n /**\n * Execute a routed schedule locally with the historical retry handling.\n * Runs on the owning (facet) Scheduler, outside the root's event loop, so\n * it applies its own in-process retry budget. Platform-class failures on a\n * one-shot re-throw so the root preserves the job and the durable alarm\n * retries on a fresh invocation.\n */\n async #executeRouted(\n id: string,\n fn: string,\n timing: SchedulerJobPayload,\n retry: RetryOptions | undefined\n ): Promise<void> {\n const handler = this.#resolveCallback(fn);\n if (!handler) {\n console.error(`callback ${fn} not found`);\n return;\n }\n const { maxAttempts, baseDelayMs, maxDelayMs } = resolveRetryConfig(\n retry,\n this.#retryDefaults\n );\n const isOneShot = timing.type === \"delayed\" || timing.type === \"scheduled\";\n const schedule = this.#payloadToSchedule<unknown>(id, fn, timing);\n try {\n await tryN(\n maxAttempts,\n async (attempt) => {\n if (attempt > 1) {\n this.#emit(\"schedule:retry\", {\n callback: fn,\n id,\n attempt,\n maxAttempts\n });\n }\n await this.lifecycle.runInHostContext(() =>\n handler(timing.payload, schedule)\n );\n },\n {\n baseDelayMs,\n maxDelayMs,\n shouldRetry: (error) =>\n !(isOneShot && isDurableObjectCodeUpdateReset(error))\n }\n );\n } catch (error) {\n if (isOneShot && isPlatformFailure(error)) {\n throw error;\n }\n console.error(\n `error executing callback \"${fn}\" after ${maxAttempts} attempts`,\n error\n );\n this.#emit(\"schedule:error\", {\n callback: fn,\n id,\n error: error instanceof Error ? error.message : String(error),\n attempts: maxAttempts\n });\n try {\n await this.#onError?.(error);\n } catch {\n // swallow onError errors\n }\n }\n }\n\n // ── Scheduling API ───────────────────────────────────────────────────────\n\n /** Set a delayed, dated, or cron schedule for a registered callback. */\n async set<Name extends keyof Handlers & string>(\n when: Date | string | number,\n callback: Name,\n payload?: SchedulerPayload<Handlers[Name]>,\n options?: ScheduleOptions\n ): Promise<Schedule<SchedulerPayload<Handlers[Name]>>> {\n await this.lifecycle.ready();\n this.#validateSchedule(when, callback, options);\n const result = this.lifecycle.routes.source\n ? ((await this.lifecycle.routes.toRoot({\n type: \"schedule\",\n when,\n callback,\n payload,\n options\n } satisfies SchedulerRouteMessage)) as InsertResult<\n SchedulerPayload<Handlers[Name]>\n >)\n : await this.#insert<SchedulerPayload<Handlers[Name]>>(\n null,\n parseWhen(when, Date.now(), callback),\n callback,\n payload,\n options\n );\n this.#emitCreated(result);\n return result.schedule;\n }\n\n /** Set a fixed-interval schedule for a registered callback. */\n async every<Name extends keyof Handlers & string>(\n intervalSeconds: number,\n callback: Name,\n payload?: SchedulerPayload<Handlers[Name]>,\n options?: ScheduleOptions\n ): Promise<Schedule<SchedulerPayload<Handlers[Name]>>> {\n await this.lifecycle.ready();\n this.#validateInterval(intervalSeconds, callback, options?.retry);\n const result = this.lifecycle.routes.source\n ? ((await this.lifecycle.routes.toRoot({\n type: \"every\",\n intervalSeconds,\n callback,\n payload,\n options\n } satisfies SchedulerRouteMessage)) as InsertResult<\n SchedulerPayload<Handlers[Name]>\n >)\n : await this.#insert<SchedulerPayload<Handlers[Name]>>(\n null,\n parseInterval(intervalSeconds, Date.now()),\n callback,\n payload,\n options\n );\n this.#emitCreated(result);\n return result.schedule;\n }\n\n /** Get a schedule by ID. Works inside routed sub-agents. */\n async get(id: string): Promise<Schedule<unknown> | undefined> {\n await this.lifecycle.ready();\n return this.lifecycle.routes.source\n ? ((await this.lifecycle.routes.toRoot({\n type: \"get\",\n id\n } satisfies SchedulerRouteMessage)) as Schedule<unknown> | undefined)\n : this.#getForOwner(null, id);\n }\n\n /** List schedules matching criteria. Works inside routed sub-agents. */\n async list(criteria: ScheduleCriteria = {}): Promise<Schedule<unknown>[]> {\n await this.lifecycle.ready();\n return this.lifecycle.routes.source\n ? ((await this.lifecycle.routes.toRoot({\n type: \"list\",\n criteria\n } satisfies SchedulerRouteMessage)) as Schedule<unknown>[])\n : this.#listForOwner(null, criteria);\n }\n\n /**\n * Cancel one schedule owned by this Scheduler.\n *\n * @param id - ID of the schedule to cancel.\n * @returns True when a schedule was cancelled, false when none matched.\n */\n async cancel(id: string): Promise<boolean> {\n await this.lifecycle.ready();\n const result = this.lifecycle.routes.source\n ? ((await this.lifecycle.routes.toRoot({\n type: \"cancel\",\n id\n } satisfies SchedulerRouteMessage)) as {\n ok: boolean;\n callback?: string;\n })\n : await this.#cancelForOwner(null, id);\n if (result.ok && result.callback) {\n this.#emit(\"schedule:cancel\", { callback: result.callback, id });\n }\n return result.ok;\n }\n\n // ── Host-owned policy apertures ──────────────────────────────────────────\n\n /**\n * @internal Synchronous read backing Agent's deprecated `getSchedule()`.\n * Not part of the primitive's contract — use {@link get}. Cannot cross\n * Durable Object boundaries and throws inside routed sub-agents.\n */\n __DO_NOT_USE_WILL_REMOVE__getSchedule<T = string>(\n id: string\n ): Schedule<T> | undefined {\n if (this.lifecycle.routes.source) {\n throw new Error(\n \"getSchedule() is synchronous and cannot read routed schedule storage. \" +\n \"Use await getScheduleById(id) on Agent, or await scheduler.get(id) \" +\n \"on a standalone Scheduler.\"\n );\n }\n return this.#getForOwner(null, id);\n }\n\n /**\n * @internal Synchronous read backing Agent's deprecated `getSchedules()`.\n * Not part of the primitive's contract — use {@link list}. Cannot cross\n * Durable Object boundaries and throws inside routed sub-agents.\n */\n __DO_NOT_USE_WILL_REMOVE__getSchedules<T = string>(\n criteria: ScheduleCriteria = {}\n ): Schedule<T>[] {\n if (this.lifecycle.routes.source) {\n throw new Error(\n \"getSchedules() is synchronous and cannot read routed schedule storage. \" +\n \"Use await listSchedules(criteria) on Agent, or await \" +\n \"scheduler.list(criteria) on a standalone Scheduler.\"\n );\n }\n return this.#listForOwner(null, criteria);\n }\n\n /** @internal Remove schedules owned by one routed Lifecycle subtree. */\n async __DO_NOT_USE_WILL_BREAK__cleanupRoutePrefix(\n prefix: string\n ): Promise<void> {\n for (const { job, timing } of this.#ownedJobs()) {\n const ownerKey = timing.owner_path_key ?? timing.owner_path;\n if (!timing.owner_path || ownerKey === null || ownerKey === undefined) {\n continue;\n }\n if (ownerKey !== prefix && !ownerKey.startsWith(`${prefix}/`)) continue;\n this.#emit(\"schedule:cancel\", { callback: job.fn, id: job.id });\n await this.lifecycle.jobs.cancel(job.id);\n }\n }\n\n // ── Validation ───────────────────────────────────────────────────────────\n\n #validateSchedule(\n when: Date | string | number,\n callback: string,\n options?: ScheduleOptions\n ): void {\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n if (!this.#hasCallback(callback)) {\n throw new Error(\n `Unknown scheduled callback \"${callback}\": not registered on this Scheduler`\n );\n }\n if (options?.retry) {\n validateRetryOptions(options.retry, this.#retryDefaults);\n }\n if (\n !(when instanceof Date) &&\n typeof when !== \"number\" &&\n typeof when !== \"string\"\n ) {\n throw new Error(\n `Invalid schedule type: ${JSON.stringify(when)}(${typeof when}) trying to schedule ${callback}`\n );\n }\n this.#warnWhenScheduledDuringStartup(when, callback, options);\n }\n\n #validateInterval(\n intervalSeconds: number,\n callback: string,\n retry?: RetryOptions\n ): void {\n validateIntervalSeconds(intervalSeconds);\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n if (!this.#hasCallback(callback)) {\n throw new Error(\n `Unknown scheduled callback \"${callback}\": not registered on this Scheduler`\n );\n }\n if (retry) validateRetryOptions(retry, this.#retryDefaults);\n }\n\n /**\n * A non-idempotent one-shot created during startup accumulates one row per\n * Durable Object wake, whether it came from the host's onStart or another\n * startup hook. Warn once per callback; an explicit `idempotent` choice\n * (either value) opts out.\n */\n #warnWhenScheduledDuringStartup(\n when: Date | string | number,\n callback: string,\n options?: ScheduleOptions\n ): void {\n if (this.lifecycle.status() !== \"starting\") return;\n if (options?.idempotent !== undefined) return;\n if (typeof when === \"string\") return;\n if (this.#warnedStartupCallbacks.has(callback)) return;\n this.#warnedStartupCallbacks.add(callback);\n console.warn(\n `Scheduling \"${callback}\" during startup (e.g. onStart()) without ` +\n `{ idempotent: true } creates a new row on every Durable Object ` +\n `restart, which can cause duplicate executions. Pass ` +\n `{ idempotent: true } to deduplicate, or use an interval schedule ` +\n `for recurring tasks.`\n );\n }\n\n /** Resolve a name to its registered or composition-root-supplied handler. */\n #resolveCallback(name: string): ResolvedSchedulerCallback | undefined {\n const handler = this.#handlers[name];\n if (handler) {\n // SAFETY: registered handlers are constrained with `never` parameters\n // so concrete handler types satisfy the map under contravariance; the\n // payload passed at dispatch was persisted with this handler's name.\n return handler as ResolvedSchedulerCallback;\n }\n return schedulerCallbackResolvers.get(this)?.(name);\n }\n\n /** True when a name resolves to a runnable callback. */\n #hasCallback(name: string): boolean {\n return this.#resolveCallback(name) !== undefined;\n }\n\n // ── Jobs ─────────────────────────────────────────────────────────────────\n\n /** Every schedule job this Scheduler owns, with its parsed vocabulary. */\n #ownedJobs(): Array<{ job: LifecycleJob; timing: SchedulerJobPayload }> {\n const owned: Array<{ job: LifecycleJob; timing: SchedulerJobPayload }> = [];\n for (const job of this.lifecycle.jobs.list()) {\n if (isSchedulerJobPayload(job.payload)) {\n owned.push({ job, timing: job.payload });\n }\n }\n return owned;\n }\n\n /**\n * Push a schedule job for the given owner, or return the existing job\n * when an idempotent request matches one. One-shot timings deduplicate only\n * when `idempotent: true` is passed; recurring timings deduplicate unless\n * `idempotent: false` opts out. `created: false` marks a dedup hit so\n * callers suppress the `schedule:create` event.\n */\n async #insert<T = string>(\n owner: LifecycleRouteAddress | null,\n timing: ScheduleTiming,\n callback: string,\n payload: unknown,\n options?: ScheduleOptions\n ): Promise<InsertResult<T>> {\n // Recurring timings deduplicate unless explicitly opted out; one-shot\n // timings deduplicate on any truthy value (historic Agent behavior).\n const idempotent = isRecurring(timing)\n ? options?.idempotent !== false\n : Boolean(options?.idempotent);\n // Not part of public ScheduleOptions. See RecoveryLoopScheduleOptions.\n const recoveryLoop = (\n options as Partial<RecoveryLoopScheduleOptions> | undefined\n )?.recoveryLoop;\n\n if (idempotent) {\n const existing = this.#findMatchingJob(\n owner?.key ?? null,\n timing,\n callback,\n JSON.stringify(payload)\n );\n if (existing) {\n // A dedup hit onto a row without breaker membership the caller asks\n // for (a row migrated from the legacy schedule table) re-pushes the\n // same durable intent in place with the flag — otherwise the row\n // would escape the alarm memory-limit breaker (#1825) forever.\n if (recoveryLoop && !existing.job.recoveryLoop) {\n await this.lifecycle.jobs.push({\n id: existing.job.id,\n fn: existing.job.fn,\n time: existing.job.time,\n payload: existing.job.payload,\n retry: existing.job.retry,\n singleflight: existing.job.singleflight,\n exclusive: existing.job.exclusive,\n hungTimeoutSeconds: this.#hungScheduleTimeoutSeconds,\n recoveryLoop: true\n });\n }\n // A dedup hit still re-arms so a lost physical alarm recovers, as\n // idempotent re-scheduling on startup historically guaranteed.\n await this.lifecycle.jobs.rearm();\n return {\n schedule: this.#jobToSchedule<T>(existing.job, existing.timing),\n created: false\n };\n }\n }\n\n const jobPayload: SchedulerJobPayload = {\n payload,\n retry: options?.retry,\n type: timing.type,\n delayInSeconds:\n timing.type === \"delayed\" ? timing.delayInSeconds : undefined,\n cron: timing.type === \"cron\" ? timing.cron : undefined,\n intervalSeconds:\n timing.type === \"interval\" ? timing.intervalSeconds : undefined,\n owner_path: owner?.data ?? null,\n owner_path_key: owner?.key ?? null\n };\n const job = await this.lifecycle.jobs.push({\n fn: callback,\n time: timing.time * 1000,\n payload: jobPayload,\n retry: resolveRetryConfig(options?.retry, this.#retryDefaults),\n singleflight: timing.type === \"interval\",\n hungTimeoutSeconds: this.#hungScheduleTimeoutSeconds,\n recoveryLoop\n });\n\n return {\n schedule: {\n id: job.id,\n callback,\n // SAFETY: payload is optional at the call site; historical API shape\n // types an omitted payload as the schedule's payload type.\n payload: payload as T,\n retry: options?.retry,\n ...timing\n },\n created: true\n };\n }\n\n /** Find the job an idempotent insert deduplicates onto, if any. */\n #findMatchingJob(\n ownerKey: string | null,\n timing: ScheduleTiming,\n callback: string,\n payloadJson: string\n ): { job: LifecycleJob; timing: SchedulerJobPayload } | undefined {\n for (const owned of this.#ownedJobs()) {\n const { job, timing: candidate } = owned;\n if (candidate.type !== timing.type) continue;\n if (job.fn !== callback) continue;\n if ((candidate.owner_path_key ?? null) !== ownerKey) continue;\n if (JSON.stringify(candidate.payload) !== payloadJson) continue;\n if (timing.type === \"cron\" && candidate.cron !== timing.cron) continue;\n if (\n timing.type === \"interval\" &&\n candidate.intervalSeconds !== timing.intervalSeconds\n ) {\n continue;\n }\n return owned;\n }\n return undefined;\n }\n\n #jobToSchedule<T>(\n job: LifecycleJob,\n timing: SchedulerJobPayload\n ): Schedule<T> {\n return this.#payloadToSchedule<T>(\n job.id,\n job.fn,\n timing,\n Math.floor(job.time / 1000)\n );\n }\n\n #payloadToSchedule<T>(\n id: string,\n fn: string,\n timing: SchedulerJobPayload,\n timeSeconds?: number\n ): Schedule<T> {\n const base = {\n callback: fn,\n id,\n payload: timing.payload as T,\n retry: timing.retry\n };\n const time = timeSeconds ?? 0;\n switch (timing.type) {\n case \"scheduled\":\n return { ...base, time, type: \"scheduled\" };\n case \"delayed\":\n return {\n ...base,\n delayInSeconds: timing.delayInSeconds ?? 0,\n time,\n type: \"delayed\"\n };\n case \"cron\":\n return { ...base, cron: timing.cron ?? \"\", time, type: \"cron\" };\n case \"interval\":\n return {\n ...base,\n intervalSeconds: timing.intervalSeconds ?? 0,\n time,\n type: \"interval\"\n };\n }\n }\n\n #getForOwner<T = string>(\n owner: LifecycleRouteAddress | null,\n id: string\n ): Schedule<T> | undefined {\n const ownerKey = owner?.key ?? null;\n const job = this.lifecycle.jobs.get(id);\n if (!job || !isSchedulerJobPayload(job.payload)) return undefined;\n if ((job.payload.owner_path_key ?? null) !== ownerKey) return undefined;\n return this.#jobToSchedule<T>(job, job.payload);\n }\n\n #listForOwner<T = string>(\n owner: LifecycleRouteAddress | null,\n criteria: ScheduleCriteria = {}\n ): Schedule<T>[] {\n const ownerKey = owner?.key ?? null;\n const startSeconds = criteria.timeRange\n ? Math.floor((criteria.timeRange.start ?? new Date(0)).getTime() / 1000)\n : null;\n const endSeconds = criteria.timeRange\n ? Math.floor(\n (criteria.timeRange.end ?? new Date(999999999999999)).getTime() / 1000\n )\n : null;\n\n const schedules: Schedule<T>[] = [];\n for (const { job, timing } of this.#ownedJobs()) {\n if ((timing.owner_path_key ?? null) !== ownerKey) continue;\n if (criteria.id && job.id !== criteria.id) continue;\n if (criteria.type && timing.type !== criteria.type) continue;\n const timeSeconds = Math.floor(job.time / 1000);\n if (startSeconds !== null && timeSeconds < startSeconds) continue;\n if (endSeconds !== null && timeSeconds > endSeconds) continue;\n schedules.push(this.#jobToSchedule<T>(job, timing));\n }\n return schedules;\n }\n\n async #cancelForOwner(\n owner: LifecycleRouteAddress | null,\n id: string\n ): Promise<{ ok: boolean; callback?: string }> {\n const ownerKey = owner?.key ?? null;\n const job = this.lifecycle.jobs.get(id);\n if (!job || !isSchedulerJobPayload(job.payload)) return { ok: false };\n if ((job.payload.owner_path_key ?? null) !== ownerKey) {\n return { ok: false };\n }\n const callback = job.fn;\n await this.lifecycle.jobs.cancel(id);\n return { ok: true, callback };\n }\n\n // ── Events ───────────────────────────────────────────────────────────────\n\n #emit(type: SchedulerEventType, payload: Record<string, unknown>): void {\n this.lifecycle.events.emit(type, payload);\n }\n\n #emitCreated(result: InsertResult<unknown>): void {\n if (!result.created) return;\n this.#emit(\"schedule:create\", {\n callback: result.schedule.callback,\n id: result.schedule.id\n });\n }\n}\n"],"mappings":"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"}
@@ -8,7 +8,7 @@ import {
8
8
  r as SchedulerOptions,
9
9
  s as SchedulerCallbacks,
10
10
  t as Scheduler
11
- } from "../scheduler-DQoTGoAW.js";
11
+ } from "../scheduler-BGq6M5Kd.js";
12
12
  export {
13
13
  type Schedule,
14
14
  type ScheduleCriteria,
@@ -1,2 +1,2 @@
1
- import { t as Scheduler } from "../scheduler-CR9RHGos.js";
1
+ import { t as Scheduler } from "../scheduler-D_KHqxBa.js";
2
2
  export { Scheduler };
@@ -0,0 +1,68 @@
1
+ //#region src/voice/text-stream.d.ts
2
+ /**
3
+ * Utilities for normalising various text-producing sources into a uniform
4
+ * `AsyncGenerator<string>`. This lets `onTurn()` return any of:
5
+ *
6
+ * - A plain `string`
7
+ * - An `AsyncIterable<string>` (deprecated for AI SDK `textStream`)
8
+ * - An `AsyncIterable` of AI SDK `stream` parts
9
+ * - A `ReadableStream<Uint8Array>` (e.g. a raw `fetch` response body
10
+ * containing newline-delimited JSON / SSE)
11
+ * - A `ReadableStream<string>`
12
+ *
13
+ * The generator yields individual text chunks as they become available.
14
+ */
15
+ /** Union of every source type that {@link iterateText} accepts. */
16
+ type TextSource = string | TextReadableStream | AsyncIterable<unknown>;
17
+ type TextReadableStreamReader = {
18
+ read(): Promise<ReadableStreamReadResult<unknown>>;
19
+ };
20
+ interface TextReadableStream {
21
+ getReader(): TextReadableStreamReader;
22
+ }
23
+ /**
24
+ * Turn any {@link TextSource} into a lazy async generator of string chunks.
25
+ *
26
+ * - `string` → yields the string once (if non-empty).
27
+ * - `ReadableStream<string>` → yields each chunk directly.
28
+ * - `ReadableStream<Uint8Array>` → decodes and parses as newline-delimited
29
+ * JSON (NDJSON) / SSE (`data: …` lines), extracting text from common AI
30
+ * response formats.
31
+ * - `AsyncIterable<string>` → re-yields each chunk.
32
+ */
33
+ declare function iterateText(source: TextSource): AsyncGenerator<string>;
34
+ //#endregion
35
+ //#region src/voice/sentence-chunker.d.ts
36
+ /**
37
+ * Sentence chunker — accumulates streaming text and yields complete sentences.
38
+ *
39
+ * Isolated and testable: no dependencies on the voice pipeline, Agent, or AI APIs.
40
+ * Feed it tokens via `add()`, get back sentences via the return value.
41
+ * Call `flush()` at end-of-stream to get any remaining text.
42
+ *
43
+ * Current implementation: splits on sentence-ending punctuation (. ! ?) followed
44
+ * by a space or end-of-input. This is intentionally simple — optimize later with
45
+ * better heuristics (abbreviations, decimal numbers, quoted speech, etc.).
46
+ */
47
+ declare class SentenceChunker {
48
+ #private;
49
+ /**
50
+ * Add a chunk of text (e.g. a streamed LLM token).
51
+ * Returns an array of complete sentences extracted from the buffer.
52
+ * May return 0, 1, or multiple sentences depending on the input.
53
+ */
54
+ add(text: string): string[];
55
+ /**
56
+ * Flush any remaining text in the buffer as a final sentence.
57
+ * Call this when the LLM stream ends.
58
+ * Returns the remaining text (trimmed), or an empty array if nothing is left.
59
+ */
60
+ flush(): string[];
61
+ /**
62
+ * Reset the chunker, discarding any buffered text.
63
+ */
64
+ reset(): void;
65
+ }
66
+ //#endregion
67
+ export { TextSource as n, iterateText as r, SentenceChunker as t };
68
+ //# sourceMappingURL=sentence-chunker-BAidJ4DA.d.ts.map
@@ -1,4 +1,4 @@
1
- import { j as StreamingResponse } from "./agent-routing-CnkaHb-v.js";
1
+ import { k as StreamingResponse } from "./agent-routing-B2XLNMxq.js";
2
2
 
3
3
  //#region src/serializable.d.ts
4
4
  type SerializablePrimitive = undefined | null | string | number | boolean;
@@ -0,0 +1,441 @@
1
+ import { s as LifecycleCapability } from "../capability-runner-BUBa6Ake.js";
2
+ import {
3
+ a as RecentHistoryResult,
4
+ c as SessionChangeListener,
5
+ d as SessionRowStat,
6
+ f as SessionsOptions,
7
+ i as HistoryReadOptions,
8
+ l as SessionMessage,
9
+ m as WriteOptions,
10
+ n as AppendResult,
11
+ o as SearchResult,
12
+ p as StoredCompaction,
13
+ r as HistoryBatchReadOptions,
14
+ s as SessionChangeEvent,
15
+ t as AppendOptions,
16
+ u as SessionMessagePart
17
+ } from "../types-B7LojTe4.js";
18
+
19
+ //#region src/sessions/compaction-helpers.d.ts
20
+ /** Prefix for all compaction messages (overlays and summaries) */
21
+ declare const COMPACTION_PREFIX = "compaction_";
22
+ /** Check if a message is a compaction message */
23
+ declare function isCompactionMessage(msg: SessionMessage): boolean;
24
+ /**
25
+ * Result of a compaction function — describes the overlay to store.
26
+ */
27
+ interface CompactResult {
28
+ /** First message ID in the compacted range */
29
+ fromMessageId: string;
30
+ /** Last message ID in the compacted range */
31
+ toMessageId: string;
32
+ /** Summary text to store as the overlay */
33
+ summary: string;
34
+ }
35
+ interface CompactOptions {
36
+ /** Calls the model to summarize; receives a prompt, returns its text. */
37
+ summarize: (prompt: string) => Promise<string>;
38
+ /**
39
+ * Token budget for the recent tail kept verbatim. Older messages above the
40
+ * protected head are summarized into one overlay. Default 20,000.
41
+ */
42
+ keepRecentTokens?: number;
43
+ }
44
+ /**
45
+ * Reference compaction implementation.
46
+ *
47
+ * Implements the full hermes-style compaction algorithm:
48
+ * 1. Protect head messages (first N)
49
+ * 2. Protect tail by token budget (walk backward)
50
+ * 3. Align boundaries to tool call groups
51
+ * 4. Summarize middle section with LLM (structured format)
52
+ * 5. Iterative summary updates on subsequent compactions
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * import { createCompactFunction } from "agents/sessions";
57
+ *
58
+ * sessions
59
+ * .session()
60
+ * .onCompaction(
61
+ * createCompactFunction({
62
+ * summarize: (prompt) => generateText({ model, prompt }).then((r) => r.text)
63
+ * })
64
+ * )
65
+ * .compactAfter(100_000);
66
+ * ```
67
+ */
68
+ declare function createCompactFunction(
69
+ opts: CompactOptions
70
+ ): (messages: SessionMessage[]) => Promise<CompactResult | null>;
71
+ //#endregion
72
+ //#region src/sessions/io.d.ts
73
+ /** @internal SQLite and telemetry supplied by the Sessions capability. */
74
+ type SqlParam = ArrayBuffer | string | number | null;
75
+ interface SessionsIo {
76
+ /** Run a read and return every row. */
77
+ sql<T>(query: string, params: SqlParam[]): T[];
78
+ /** Run a write (or DDL) and return the rows it wrote. */
79
+ sqlWrite(query: string, params: SqlParam[]): number;
80
+ /** One synchronous SQLite transaction. */
81
+ transaction<T>(fn: () => T): T;
82
+ /** Capability telemetry event. */
83
+ emit(type: string, payload: Record<string, unknown>): void;
84
+ }
85
+ //#endregion
86
+ //#region src/sessions/core.d.ts
87
+ type UpdateOutcome = "missing" | "unchanged" | "updated";
88
+ declare class SessionsCore {
89
+ #private;
90
+ readonly io: SessionsIo;
91
+ constructor(options: SessionsOptions, io: SessionsIo);
92
+ ensureTables(): void;
93
+ /**
94
+ * Lift the legacy `assistant_*` message and compaction tables.
95
+ *
96
+ * The copy is pure SQL, so SQLite streams it rather than materializing rows
97
+ * in the isolate. Each source is then verified row by row against its
98
+ * destination and DROPPED: keeping tombstones would leave every upgraded
99
+ * object holding its history twice inside the same 10 GB. A table whose
100
+ * verification fails is left in place with a `session:migration:incomplete`
101
+ * event, and the method returns false so the caller leaves the schema
102
+ * version unstamped and retries on a later start. `assistant_config`
103
+ * belongs to Think, which lifts and drops it itself.
104
+ */
105
+ migrateLegacy(): boolean;
106
+ subscribe(listener: SessionChangeListener): () => void;
107
+ /**
108
+ * Dispatch after a durable write. A listener that throws must not turn a
109
+ * committed write into a rejected call, so failures are reported through
110
+ * telemetry and dispatch continues.
111
+ */
112
+ notify(event: SessionChangeEvent): Promise<void>;
113
+ exists(sessionId: string, id: string): boolean;
114
+ getMessage(sessionId: string, id: string): SessionMessage | null;
115
+ /**
116
+ * Drop the in-memory tail and token-total caches for a session. For a
117
+ * caller whose enclosing transaction rolled back after an append or update
118
+ * ran inside it: the rows are gone but the caches already moved. The next
119
+ * read re-derives both from storage.
120
+ */
121
+ forgetCaches(sessionId: string): void;
122
+ latestLeafId(sessionId: string): string | null;
123
+ getLatestLeaf(sessionId: string): SessionMessage | null;
124
+ getBranches(sessionId: string, messageId: string): SessionMessage[];
125
+ /**
126
+ * The active branch path as content-free rows, root → leaf. Recurses over
127
+ * (id, parent_id) only — carrying content through the recursive queue
128
+ * materializes the transcript several times inside SQLite (#1710).
129
+ * `bytes` counts the message row, its continuation rows, AND the payloads
130
+ * it points at, charged at the size they take once inlined, so a byte
131
+ * budget over these rows bounds real hydrated memory.
132
+ */
133
+ pathRowStats(sessionId: string, leafId?: string | null): SessionRowStat[];
134
+ /**
135
+ * Stream the path ending at `leafId` (default: active leaf), root → leaf
136
+ * (or leaf → root with `newestFirst`), compaction overlays collapsed. Peak
137
+ * memory is one bounded content window — never the whole transcript.
138
+ */
139
+ streamHistory(
140
+ sessionId: string,
141
+ options: HistoryReadOptions
142
+ ): AsyncGenerator<SessionMessage, void, undefined>;
143
+ getHistory(
144
+ sessionId: string,
145
+ options: HistoryReadOptions
146
+ ): Promise<SessionMessage[]>;
147
+ /**
148
+ * Byte-budgeted read of the most recent messages on the active branch
149
+ * path — the longest suffix whose stored size fits `maxContentBytes`.
150
+ *
151
+ * There is no message-count floor: one used to exist, and it admitted
152
+ * rows regardless of size, so a window of media-heavy messages could
153
+ * hydrate far past the limit meant to bound it. The newest message is
154
+ * always returned even if it alone exceeds the budget, since returning
155
+ * nothing is worse. Overlays whose anchors fall outside the window are
156
+ * skipped, showing the raw recent messages.
157
+ */
158
+ getRecentHistory(
159
+ sessionId: string,
160
+ maxContentBytes: number,
161
+ leafId?: string | null
162
+ ): Promise<RecentHistoryResult>;
163
+ /**
164
+ * Heuristic token estimate for the active path with compaction overlays
165
+ * applied: stamped per-row estimates, minus compacted spans, plus their
166
+ * summaries. Derived from content-free rows on each call; it gates cheap
167
+ * triggers only, and model-reported usage stays authoritative.
168
+ */
169
+ tokenEstimate(sessionId: string): number;
170
+ stripReservedMetadata(message: SessionMessage): SessionMessage;
171
+ /**
172
+ * Stamped row estimate: the part heuristic over the message as written,
173
+ * plus a weight per inline file payload so media never counts as zero.
174
+ */
175
+ estimateRowTokens(message: SessionMessage): number;
176
+ /**
177
+ * Durable append. The caller has already sanitized the message. Message,
178
+ * continuation, attachment, and FTS rows commit in one synchronous SQLite
179
+ * transaction. Returns the stored message: the input itself when it was
180
+ * inserted (extraction is lossless, so the two are identical), or the row
181
+ * already holding the id when it was not.
182
+ */
183
+ append(
184
+ sessionId: string,
185
+ message: SessionMessage,
186
+ parentId: string | null | undefined,
187
+ tokenEstimate: number
188
+ ): {
189
+ inserted: boolean;
190
+ message: SessionMessage;
191
+ };
192
+ /**
193
+ * Durable update of an existing row. An identical row writes nothing: no
194
+ * row, no continuation, no FTS, no event. The no-op guard compares the
195
+ * FULL reassembled content, not just the slice the message row holds.
196
+ */
197
+ update(
198
+ sessionId: string,
199
+ message: SessionMessage,
200
+ tokenEstimate: number
201
+ ): UpdateOutcome;
202
+ /**
203
+ * Delete rows, SPLICING children to their grandparent so a mid-chain
204
+ * delete never decapitates older history. Only surviving boundary children
205
+ * are rewired: a prefix delete writes one boundary child, not one child
206
+ * per deleted message.
207
+ */
208
+ deleteMessages(sessionId: string, messageIds: string[]): void;
209
+ clearMessages(sessionId: string): void;
210
+ addCompaction(
211
+ sessionId: string,
212
+ summary: string,
213
+ fromMessageId: string,
214
+ toMessageId: string
215
+ ): StoredCompaction;
216
+ getCompactions(sessionId: string): StoredCompaction[];
217
+ search(sessionId: string, query: string, limit: number): SearchResult[];
218
+ /**
219
+ * Import one historical message verbatim (migrations, cross-DO moves):
220
+ * explicit parent and timestamp, stamped estimate, no change-feed events.
221
+ */
222
+ /** Returns `false` when the id already exists and nothing was written. */
223
+ importMessage(
224
+ sessionId: string,
225
+ message: SessionMessage,
226
+ options: {
227
+ parentId: string | null;
228
+ createdAt: number;
229
+ }
230
+ ): boolean;
231
+ }
232
+ //#endregion
233
+ //#region src/sessions/handle.d.ts
234
+ /** Summarizes a branch into an overlay. */
235
+ type CompactionFunction = (
236
+ messages: SessionMessage[]
237
+ ) => Promise<CompactResult | null>;
238
+ declare class Session {
239
+ #private;
240
+ readonly sessionId: string;
241
+ /** @internal Constructed by the Sessions capability only. */
242
+ constructor(
243
+ sessionId: string,
244
+ core: SessionsCore,
245
+ ready: () => Promise<void>
246
+ );
247
+ /** Register the function `compact()` calls to summarize a branch. */
248
+ onCompaction(fn: CompactionFunction): this;
249
+ /**
250
+ * Auto-compact after an append once the estimated token count crosses the
251
+ * threshold. Requires `onCompaction()`. The estimate is derived from the
252
+ * stamped per-row estimates, never from the transcript.
253
+ */
254
+ compactAfter(tokenThreshold: number): this;
255
+ /**
256
+ * Stream the active branch path root → leaf (leaf → root with
257
+ * `newestFirst`) with compaction overlays applied. Peak memory is one
258
+ * bounded content window, never the whole transcript, and a consumer that
259
+ * breaks out early leaves the rows it never reached unread.
260
+ */
261
+ history(
262
+ options?: HistoryReadOptions
263
+ ): AsyncGenerator<SessionMessage, void, undefined>;
264
+ /**
265
+ * Stream history in bounded non-empty batches. Both message count and
266
+ * serialized bytes bound each batch; a single large message is yielded by
267
+ * itself.
268
+ */
269
+ historyBatches(
270
+ options?: HistoryBatchReadOptions
271
+ ): AsyncGenerator<SessionMessage[], void, undefined>;
272
+ /**
273
+ * Materialize the whole selected path. Prefer `history()` or
274
+ * `getRecentHistory()` inside a Durable Object: this holds every message
275
+ * of the branch in memory at once.
276
+ */
277
+ getHistory(options?: HistoryReadOptions): Promise<SessionMessage[]>;
278
+ /**
279
+ * Byte-budgeted read of the most recent messages on the active branch path
280
+ * (always at least the leaf). The budget counts each row, its continuation
281
+ * rows, and the payloads it points at, so it bounds hydrated memory (#1710).
282
+ */
283
+ getRecentHistory(
284
+ maxContentBytes: number,
285
+ options?: Pick<HistoryReadOptions, "leafId">
286
+ ): Promise<RecentHistoryResult>;
287
+ /**
288
+ * Per-row stored sizes (row plus continuation rows and attachments) and
289
+ * stamped token estimates for the active branch path (root → leaf)
290
+ * WITHOUT loading message content.
291
+ */
292
+ getHistoryRowStats(leafId?: string | null): Promise<SessionRowStat[]>;
293
+ getMessage(id: string): Promise<SessionMessage | null>;
294
+ getLatestLeaf(): Promise<SessionMessage | null>;
295
+ getBranches(messageId: string): Promise<SessionMessage[]>;
296
+ /**
297
+ * Full-text search over this session's text parts. The index is built on
298
+ * the first call and maintained from then on.
299
+ */
300
+ search(
301
+ query: string,
302
+ options?: {
303
+ limit?: number;
304
+ }
305
+ ): Promise<SearchResult[]>;
306
+ /**
307
+ * Append one message. Idempotent on id: a repeated append returns the row
308
+ * already stored and dispatches an `append` event with `inserted: false`.
309
+ */
310
+ appendMessage(
311
+ message: SessionMessage,
312
+ options?: AppendOptions
313
+ ): Promise<AppendResult>;
314
+ /**
315
+ * Update one stored row. Returns the stored form, or `null` when the id is
316
+ * not in this session. An unchanged message writes nothing and dispatches
317
+ * no event.
318
+ */
319
+ updateMessage(
320
+ message: SessionMessage,
321
+ options?: WriteOptions
322
+ ): Promise<SessionMessage | null>;
323
+ /**
324
+ * @internal Synchronous write aperture for same-isolate first-party
325
+ * machinery that must commit a message inside a caller-owned SQLite
326
+ * transaction — the stream cutover, where the finished message and the
327
+ * discard of its stream rows land together. Bypasses readiness (the
328
+ * caller owns startup ordering) and defers everything that follows a
329
+ * write — the change-feed dispatch and auto-compaction: call the returned
330
+ * `after()` once the transaction commits, or subscribers (the host's
331
+ * message mirror) never hear about the write. If the transaction rolls
332
+ * back after an `upsert` ran inside it, call `abandon()`: the write is
333
+ * gone but the in-memory tail and token-total caches already moved.
334
+ * Will break without notice; never use from application code.
335
+ */
336
+ __DO_NOT_USE_WILL_BREAK__sync(): {
337
+ upsert(
338
+ message: SessionMessage,
339
+ options?: AppendOptions
340
+ ): {
341
+ result: AppendResult;
342
+ after: () => Promise<void>;
343
+ };
344
+ abandon(): void;
345
+ };
346
+ upsertMessage(
347
+ message: SessionMessage,
348
+ options?: AppendOptions
349
+ ): Promise<AppendResult>;
350
+ /**
351
+ * Import one historical message verbatim (migrations, cross-object moves):
352
+ * explicit parent and timestamp. A row actually written dispatches an
353
+ * `import` change event so a host cache can mark itself stale; it is not
354
+ * an `append`, so a cache does not patch itself per imported row, and an
355
+ * id that already exists writes nothing and dispatches nothing.
356
+ */
357
+ importMessage(
358
+ message: SessionMessage,
359
+ options: {
360
+ parentId: string | null;
361
+ createdAt: number;
362
+ }
363
+ ): Promise<void>;
364
+ deleteMessages(messageIds: string[]): Promise<void>;
365
+ clearMessages(): Promise<void>;
366
+ /**
367
+ * Store an overlay directly. Dispatches a `compaction` change event: the
368
+ * rows are untouched, but what a path read returns has changed.
369
+ */
370
+ addCompaction(
371
+ summary: string,
372
+ fromMessageId: string,
373
+ toMessageId: string
374
+ ): Promise<StoredCompaction>;
375
+ getCompactions(): Promise<StoredCompaction[]>;
376
+ /**
377
+ * Run the registered compaction function and store the result as an
378
+ * overlay. When `leafId` is given, compact that root-to-leaf branch instead
379
+ * of the active branch. Requires `onCompaction()`. A compaction function
380
+ * that throws is reported through the `session:error` capability event and
381
+ * the call returns `null`.
382
+ */
383
+ compact(leafId?: string | null): Promise<CompactResult | null>;
384
+ }
385
+ //#endregion
386
+ //#region src/sessions/sessions.d.ts
387
+ /**
388
+ * Durable conversation history for a Lifecycle Object.
389
+ *
390
+ * `session()` returns a per-session handle for reads (streamed, byte
391
+ * budgeted), writes (sanitized, media offloaded), branch navigation, and
392
+ * compaction overlays. `subscribe()` is the change feed a cache-owning host
393
+ * mirrors.
394
+ *
395
+ * @experimental The API surface may change before stabilizing.
396
+ */
397
+ declare class Sessions extends LifecycleCapability {
398
+ #private;
399
+ constructor(options?: SessionsOptions);
400
+ /** Migrate session storage during Lifecycle startup. */
401
+ onStart(): Promise<void>;
402
+ /**
403
+ * The handle for one session. The default (empty) id is the primary path:
404
+ * in the one-object-per-conversation model a Durable Object holds exactly
405
+ * one session. Handles are cached, so per-session configuration (the
406
+ * compaction trigger) survives repeated calls.
407
+ */
408
+ session(sessionId?: string): Session;
409
+ /**
410
+ * Subscribe to the change feed: ordered dispatch after every durable
411
+ * write, with the stored message. The host cache mirror lives here;
412
+ * telemetry additionally flows through capability events.
413
+ */
414
+ subscribe(listener: SessionChangeListener): () => void;
415
+ }
416
+ //#endregion
417
+ export {
418
+ type AppendOptions,
419
+ type AppendResult,
420
+ COMPACTION_PREFIX,
421
+ type CompactOptions,
422
+ type CompactResult,
423
+ type CompactionFunction,
424
+ type HistoryBatchReadOptions,
425
+ type HistoryReadOptions,
426
+ type RecentHistoryResult,
427
+ type SearchResult,
428
+ Session,
429
+ type SessionChangeEvent,
430
+ type SessionChangeListener,
431
+ type SessionMessage,
432
+ type SessionMessagePart,
433
+ type SessionRowStat,
434
+ Sessions,
435
+ type SessionsOptions,
436
+ type StoredCompaction,
437
+ type WriteOptions,
438
+ createCompactFunction,
439
+ isCompactionMessage
440
+ };
441
+ //# sourceMappingURL=index.d.ts.map