agents 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +5 -1
- package/dist/index.js +44 -35
- package/dist/index.js.map +1 -1
- package/dist/internal_context.d.ts +6 -2
- package/dist/internal_context.js +6 -2
- package/dist/internal_context.js.map +1 -1
- package/package.json +2 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AgentEmail,
|
|
3
|
+
__DO_NOT_USE_WILL_BREAK__agentContext
|
|
4
|
+
} from "./internal_context.js";
|
|
2
5
|
import { EmailResolver, createHeaderBasedEmailResolver } from "./email.js";
|
|
3
6
|
import {
|
|
4
7
|
l as TransportType,
|
|
@@ -1134,6 +1137,7 @@ export {
|
|
|
1134
1137
|
StreamingResponse,
|
|
1135
1138
|
type TransportType,
|
|
1136
1139
|
type WSMessage,
|
|
1140
|
+
__DO_NOT_USE_WILL_BREAK__agentContext,
|
|
1137
1141
|
callable,
|
|
1138
1142
|
createHeaderBasedEmailResolver,
|
|
1139
1143
|
getAgentByName,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MessageType } from "./types.js";
|
|
2
2
|
import { camelCaseToKebabCase } from "./utils.js";
|
|
3
3
|
import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
|
|
4
|
-
import {
|
|
4
|
+
import { __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context.js";
|
|
5
5
|
import { i as DisposableStore, n as MCPConnectionState } from "./client-connection-CGMuV62J.js";
|
|
6
6
|
import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
|
|
7
7
|
import { MCPClientManager } from "./mcp/client.js";
|
|
@@ -85,7 +85,7 @@ const DEFAULT_AGENT_STATIC_OPTIONS = {
|
|
|
85
85
|
hungScheduleTimeoutSeconds: 30
|
|
86
86
|
};
|
|
87
87
|
function getCurrentAgent() {
|
|
88
|
-
const store =
|
|
88
|
+
const store = __DO_NOT_USE_WILL_BREAK__agentContext.getStore();
|
|
89
89
|
if (!store) return {
|
|
90
90
|
agent: void 0,
|
|
91
91
|
connection: void 0,
|
|
@@ -104,7 +104,7 @@ function withAgentContext(method) {
|
|
|
104
104
|
return function(...args) {
|
|
105
105
|
const { connection, request, email, agent } = getCurrentAgent();
|
|
106
106
|
if (agent === this) return method.apply(this, args);
|
|
107
|
-
return
|
|
107
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
108
108
|
agent: this,
|
|
109
109
|
connection,
|
|
110
110
|
request,
|
|
@@ -215,7 +215,7 @@ var Agent = class Agent extends Server {
|
|
|
215
215
|
console.warn(`Forcing reset of hung interval schedule ${row.id} (started ${elapsedSeconds}s ago)`);
|
|
216
216
|
}
|
|
217
217
|
if (row.type === "interval") this.sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;
|
|
218
|
-
await
|
|
218
|
+
await __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
219
219
|
agent: this,
|
|
220
220
|
connection: void 0,
|
|
221
221
|
request: void 0,
|
|
@@ -361,7 +361,7 @@ var Agent = class Agent extends Server {
|
|
|
361
361
|
}
|
|
362
362
|
const _onRequest = this.onRequest.bind(this);
|
|
363
363
|
this.onRequest = (request) => {
|
|
364
|
-
return
|
|
364
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
365
365
|
agent: this,
|
|
366
366
|
connection: void 0,
|
|
367
367
|
request,
|
|
@@ -376,7 +376,7 @@ var Agent = class Agent extends Server {
|
|
|
376
376
|
const _onMessage = this.onMessage.bind(this);
|
|
377
377
|
this.onMessage = async (connection, message) => {
|
|
378
378
|
this._ensureConnectionWrapped(connection);
|
|
379
|
-
return
|
|
379
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
380
380
|
agent: this,
|
|
381
381
|
connection,
|
|
382
382
|
request: void 0,
|
|
@@ -473,7 +473,7 @@ var Agent = class Agent extends Server {
|
|
|
473
473
|
const _onConnect = this.onConnect.bind(this);
|
|
474
474
|
this.onConnect = (connection, ctx) => {
|
|
475
475
|
this._ensureConnectionWrapped(connection);
|
|
476
|
-
return
|
|
476
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
477
477
|
agent: this,
|
|
478
478
|
connection,
|
|
479
479
|
request: ctx.request,
|
|
@@ -505,7 +505,7 @@ var Agent = class Agent extends Server {
|
|
|
505
505
|
};
|
|
506
506
|
const _onStart = this.onStart.bind(this);
|
|
507
507
|
this.onStart = async (props) => {
|
|
508
|
-
return
|
|
508
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
509
509
|
agent: this,
|
|
510
510
|
connection: void 0,
|
|
511
511
|
request: void 0,
|
|
@@ -557,10 +557,10 @@ var Agent = class Agent extends Server {
|
|
|
557
557
|
state: nextState,
|
|
558
558
|
type: MessageType.CF_AGENT_STATE
|
|
559
559
|
}), source !== "server" ? [source.id] : []);
|
|
560
|
-
const { connection, request, email } =
|
|
560
|
+
const { connection, request, email } = __DO_NOT_USE_WILL_BREAK__agentContext.getStore() || {};
|
|
561
561
|
this.ctx.waitUntil((async () => {
|
|
562
562
|
try {
|
|
563
|
-
await
|
|
563
|
+
await __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
564
564
|
agent: this,
|
|
565
565
|
connection,
|
|
566
566
|
request,
|
|
@@ -588,7 +588,7 @@ var Agent = class Agent extends Server {
|
|
|
588
588
|
* @throws Error if called from a readonly connection context
|
|
589
589
|
*/
|
|
590
590
|
setState(state) {
|
|
591
|
-
const store =
|
|
591
|
+
const store = __DO_NOT_USE_WILL_BREAK__agentContext.getStore();
|
|
592
592
|
if (store?.connection && this.isConnectionReadonly(store.connection)) throw new Error("Connection is readonly");
|
|
593
593
|
this._setStateInternal(state, "server");
|
|
594
594
|
}
|
|
@@ -743,7 +743,7 @@ var Agent = class Agent extends Server {
|
|
|
743
743
|
* @param email Email message to process
|
|
744
744
|
*/
|
|
745
745
|
async _onEmail(email) {
|
|
746
|
-
return
|
|
746
|
+
return __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
747
747
|
agent: this,
|
|
748
748
|
connection: void 0,
|
|
749
749
|
request: void 0,
|
|
@@ -879,31 +879,40 @@ var Agent = class Agent extends Server {
|
|
|
879
879
|
async _flushQueue() {
|
|
880
880
|
if (this._flushingQueue) return;
|
|
881
881
|
this._flushingQueue = true;
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
882
|
+
try {
|
|
883
|
+
while (true) {
|
|
884
|
+
const result = this.sql`
|
|
885
|
+
SELECT * FROM cf_agents_queues
|
|
886
|
+
ORDER BY created_at ASC
|
|
887
|
+
`;
|
|
888
|
+
if (!result || result.length === 0) break;
|
|
889
|
+
for (const row of result || []) {
|
|
890
|
+
const callback = this[row.callback];
|
|
891
|
+
if (!callback) {
|
|
892
|
+
console.error(`callback ${row.callback} not found`);
|
|
893
|
+
await this.dequeue(row.id);
|
|
894
|
+
continue;
|
|
895
|
+
}
|
|
896
|
+
const { connection, request, email } = __DO_NOT_USE_WILL_BREAK__agentContext.getStore() || {};
|
|
897
|
+
try {
|
|
898
|
+
await __DO_NOT_USE_WILL_BREAK__agentContext.run({
|
|
899
|
+
agent: this,
|
|
900
|
+
connection,
|
|
901
|
+
request,
|
|
902
|
+
email
|
|
903
|
+
}, async () => {
|
|
904
|
+
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
905
|
+
});
|
|
906
|
+
} catch (e) {
|
|
907
|
+
console.error(`Queue callback ${String(row.callback)} failed for row ${row.id}:`, e);
|
|
908
|
+
} finally {
|
|
909
|
+
await this.dequeue(row.id);
|
|
910
|
+
}
|
|
893
911
|
}
|
|
894
|
-
const { connection, request, email } = agentContext.getStore() || {};
|
|
895
|
-
await agentContext.run({
|
|
896
|
-
agent: this,
|
|
897
|
-
connection,
|
|
898
|
-
request,
|
|
899
|
-
email
|
|
900
|
-
}, async () => {
|
|
901
|
-
await callback.bind(this)(JSON.parse(row.payload), row);
|
|
902
|
-
await this.dequeue(row.id);
|
|
903
|
-
});
|
|
904
912
|
}
|
|
913
|
+
} finally {
|
|
914
|
+
this._flushingQueue = false;
|
|
905
915
|
}
|
|
906
|
-
this._flushingQueue = false;
|
|
907
916
|
}
|
|
908
917
|
/**
|
|
909
918
|
* Dequeue a task by ID
|
|
@@ -2314,5 +2323,5 @@ var StreamingResponse = class {
|
|
|
2314
2323
|
};
|
|
2315
2324
|
|
|
2316
2325
|
//#endregion
|
|
2317
|
-
export { Agent, DEFAULT_AGENT_STATIC_OPTIONS, SqlError, StreamingResponse, callable, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, routeAgentEmail, routeAgentRequest, unstable_callable };
|
|
2326
|
+
export { Agent, DEFAULT_AGENT_STATIC_OPTIONS, SqlError, StreamingResponse, __DO_NOT_USE_WILL_BREAK__agentContext, callable, createHeaderBasedEmailResolver, getAgentByName, getCurrentAgent, routeAgentEmail, routeAgentRequest, unstable_callable };
|
|
2318
2327
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { agentContext, type AgentEmail } from \"./internal_context\";\nimport type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { signAgentHeaders } from \"./email\";\n\nimport type {\n Prompt,\n Resource,\n ServerCapabilities,\n Tool\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { parseCronExpression } from \"cron-schedule\";\nimport { nanoid } from \"nanoid\";\nimport { EmailMessage } from \"cloudflare:email\";\nimport {\n type Connection,\n type ConnectionContext,\n type PartyServerOptions,\n Server,\n type WSMessage,\n getServerByName,\n routePartykitRequest\n} from \"partyserver\";\nimport { camelCaseToKebabCase } from \"./utils\";\nimport { MCPClientManager, type MCPClientOAuthResult } from \"./mcp/client\";\nimport type {\n WorkflowCallback,\n WorkflowTrackingRow,\n WorkflowStatus,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\nimport { MCPConnectionState } from \"./mcp/client-connection\";\nimport {\n DurableObjectOAuthClientProvider,\n type AgentMcpOAuthProvider\n} from \"./mcp/do-oauth-client-provider\";\nimport type { TransportType } from \"./mcp/types\";\nimport { genericObservability, type Observability } from \"./observability\";\nimport { DisposableStore } from \"./core/events\";\nimport { MessageType } from \"./types\";\n\nexport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\n\n/**\n * RPC request message from client\n */\nexport type RPCRequest = {\n type: \"rpc\";\n id: string;\n method: string;\n args: unknown[];\n};\n\n/**\n * State update message from client\n */\nexport type StateUpdateMessage = {\n type: MessageType.CF_AGENT_STATE;\n state: unknown;\n};\n\n/**\n * RPC response message to client\n */\nexport type RPCResponse = {\n type: MessageType.RPC;\n id: string;\n} & (\n | {\n success: true;\n result: unknown;\n done?: false;\n }\n | {\n success: true;\n result: unknown;\n done: true;\n }\n | {\n success: false;\n error: string;\n }\n);\n\n/**\n * Type guard for RPC request messages\n */\nfunction isRPCRequest(msg: unknown): msg is RPCRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === MessageType.RPC &&\n \"id\" in msg &&\n typeof msg.id === \"string\" &&\n \"method\" in msg &&\n typeof msg.method === \"string\" &&\n \"args\" in msg &&\n Array.isArray((msg as RPCRequest).args)\n );\n}\n\n/**\n * Type guard for state update messages\n */\nfunction isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === MessageType.CF_AGENT_STATE &&\n \"state\" in msg\n );\n}\n\n/**\n * Metadata for a callable method\n */\nexport type CallableMetadata = {\n /** Optional description of what the method does */\n description?: string;\n /** Whether the method supports streaming responses */\n streaming?: boolean;\n};\n\nconst callableMetadata = new WeakMap<Function, CallableMetadata>();\n\n/**\n * Error class for SQL execution failures, containing the query that failed\n */\nexport class SqlError extends Error {\n /** The SQL query that failed */\n readonly query: string;\n\n constructor(query: string, cause: unknown) {\n const message = cause instanceof Error ? cause.message : String(cause);\n super(`SQL query failed: ${message}`, { cause });\n this.name = \"SqlError\";\n this.query = query;\n }\n}\n\n/**\n * Decorator that marks a method as callable by clients\n * @param metadata Optional metadata about the callable method\n */\nexport function callable(metadata: CallableMetadata = {}) {\n return function callableDecorator<This, Args extends unknown[], Return>(\n target: (this: This, ...args: Args) => Return,\n _context: ClassMethodDecoratorContext\n ) {\n if (!callableMetadata.has(target)) {\n callableMetadata.set(target, metadata);\n }\n\n return target;\n };\n}\n\nlet didWarnAboutUnstableCallable = false;\n\n/**\n * Decorator that marks a method as callable by clients\n * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version\n * @param metadata Optional metadata about the callable method\n */\nexport const unstable_callable = (metadata: CallableMetadata = {}) => {\n if (!didWarnAboutUnstableCallable) {\n didWarnAboutUnstableCallable = true;\n console.warn(\n \"unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version.\"\n );\n }\n return callable(metadata);\n};\n\nexport type QueueItem<T = string> = {\n id: string;\n payload: T;\n callback: keyof Agent<Cloudflare.Env>;\n created_at: number;\n};\n\n/**\n * Represents a scheduled task within an Agent\n * @template T Type of the payload data\n */\nexport type Schedule<T = string> = {\n /** Unique identifier for the schedule */\n id: string;\n /** Name of the method to be called */\n callback: string;\n /** Data to be passed to the callback */\n payload: T;\n} & (\n | {\n /** Type of schedule for one-time execution at a specific time */\n type: \"scheduled\";\n /** Timestamp when the task should execute */\n time: number;\n }\n | {\n /** Type of schedule for delayed execution */\n type: \"delayed\";\n /** Timestamp when the task should execute */\n time: number;\n /** Number of seconds to delay execution */\n delayInSeconds: number;\n }\n | {\n /** Type of schedule for recurring execution based on cron expression */\n type: \"cron\";\n /** Timestamp for the next execution */\n time: number;\n /** Cron expression defining the schedule */\n cron: string;\n }\n | {\n /** Type of schedule for recurring execution at fixed intervals */\n type: \"interval\";\n /** Timestamp for the next execution */\n time: number;\n /** Number of seconds between executions */\n intervalSeconds: number;\n }\n);\n\nfunction getNextCronTime(cron: string) {\n const interval = parseCronExpression(cron);\n return interval.getNextDate();\n}\n\nexport type { TransportType } from \"./mcp/types\";\nexport type {\n AgentMcpOAuthProvider,\n /** @deprecated Use {@link AgentMcpOAuthProvider} instead. */\n AgentsOAuthProvider\n} from \"./mcp/do-oauth-client-provider\";\n\n/**\n * MCP Server state update message from server -> Client\n */\nexport type MCPServerMessage = {\n type: MessageType.CF_AGENT_MCP_SERVERS;\n mcp: MCPServersState;\n};\n\nexport type MCPServersState = {\n servers: {\n [id: string]: MCPServer;\n };\n tools: (Tool & { serverId: string })[];\n prompts: (Prompt & { serverId: string })[];\n resources: (Resource & { serverId: string })[];\n};\n\nexport type MCPServer = {\n name: string;\n server_url: string;\n auth_url: string | null;\n // This state is specifically about the temporary process of getting a token (if needed).\n // Scope outside of that can't be relied upon because when the DO sleeps, there's no way\n // to communicate a change to a non-ready state.\n state: MCPConnectionState;\n error: string | null;\n instructions: string | null;\n capabilities: ServerCapabilities | null;\n};\n\n/**\n * Options for adding an MCP server\n */\nexport type AddMcpServerOptions = {\n /** OAuth callback host (auto-derived from request if omitted) */\n callbackHost?: string;\n /**\n * Custom callback URL path — bypasses the default `/agents/{class}/{name}/callback` construction.\n * Required when `sendIdentityOnConnect` is `false` to prevent leaking the instance name.\n * When set, the callback URL becomes `{callbackHost}/{callbackPath}`.\n * The developer must route this path to the agent instance via `getAgentByName`.\n * Should be a plain path (e.g., `/mcp-callback`) — do not include query strings or fragments.\n */\n callbackPath?: string;\n /** Agents routing prefix (default: \"agents\") */\n agentsPrefix?: string;\n /** MCP client options */\n client?: ConstructorParameters<typeof Client>[1];\n /** Transport options */\n transport?: {\n /** Custom headers for authentication (e.g., bearer tokens, CF Access) */\n headers?: HeadersInit;\n /** Transport type: \"sse\", \"streamable-http\", or \"auto\" (default) */\n type?: TransportType;\n };\n};\n\nconst STATE_ROW_ID = \"cf_state_row_id\";\nconst STATE_WAS_CHANGED = \"cf_state_was_changed\";\n\nconst DEFAULT_STATE = {} as unknown;\n\n/**\n * Internal key used to store the readonly flag in connection state.\n * Prefixed with _cf_ to avoid collision with user state keys.\n */\nconst CF_READONLY_KEY = \"_cf_readonly\";\n\n/**\n * Tracks which agent constructors have already emitted the onStateUpdate\n * deprecation warning, so it fires at most once per class.\n */\nconst _onStateUpdateWarnedClasses = new WeakSet<Function>();\n\n/**\n * Default options for Agent configuration.\n * Child classes can override specific options without spreading.\n */\nexport const DEFAULT_AGENT_STATIC_OPTIONS = {\n /** Whether the Agent should hibernate when inactive */\n hibernate: true,\n /** Whether to send identity (name, agent) to clients on connect */\n sendIdentityOnConnect: true,\n /**\n * Timeout in seconds before a running interval schedule is considered \"hung\"\n * and force-reset. Increase this if you have callbacks that legitimately\n * take longer than 30 seconds.\n */\n hungScheduleTimeoutSeconds: 30\n};\n\ntype ResolvedAgentOptions = typeof DEFAULT_AGENT_STATIC_OPTIONS;\n\n/**\n * Configuration options for the Agent.\n * Override in subclasses via `static options`.\n * All fields are optional - defaults are applied at runtime.\n * Note: `hibernate` defaults to `true` if not specified.\n */\nexport type AgentStaticOptions = Partial<ResolvedAgentOptions>;\n\nexport function getCurrentAgent<\n T extends Agent<Cloudflare.Env> = Agent<Cloudflare.Env>\n>(): {\n agent: T | undefined;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n} {\n const store = agentContext.getStore() as\n | {\n agent: T;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n }\n | undefined;\n if (!store) {\n return {\n agent: undefined,\n connection: undefined,\n request: undefined,\n email: undefined\n };\n }\n return store;\n}\n\n/**\n * Wraps a method to run within the agent context, ensuring getCurrentAgent() works properly\n * @param agent The agent instance\n * @param method The method to wrap\n * @returns A wrapped method that runs within the agent context\n */\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic callable constraint\nfunction withAgentContext<T extends (...args: any[]) => any>(\n method: T\n): (\n this: Agent<Cloudflare.Env, unknown>,\n ...args: Parameters<T>\n) => ReturnType<T> {\n return function (...args: Parameters<T>): ReturnType<T> {\n const { connection, request, email, agent } = getCurrentAgent();\n\n if (agent === this) {\n // already wrapped, so we can just call the method\n return method.apply(this, args);\n }\n // not wrapped, so we need to wrap it\n return agentContext.run({ agent: this, connection, request, email }, () => {\n return method.apply(this, args);\n });\n };\n}\n\n/**\n * Extract string keys from Env where the value is a Workflow binding.\n */\ntype WorkflowBinding<E> = {\n [K in keyof E & string]: E[K] extends Workflow ? K : never;\n}[keyof E & string];\n\n/**\n * Type for workflow name parameter.\n * When Env has typed Workflow bindings, provides autocomplete for those keys.\n * Also accepts any string for dynamic use cases and compatibility.\n * The `string & {}` trick preserves autocomplete while allowing any string.\n */\ntype WorkflowName<E> = WorkflowBinding<E> | (string & {});\n\n/**\n * Base class for creating Agent implementations\n * @template Env Environment type containing bindings\n * @template State State type to store within the Agent\n */\nexport class Agent<\n Env extends Cloudflare.Env = Cloudflare.Env,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends Server<Env, Props> {\n private _state = DEFAULT_STATE as State;\n private _disposables = new DisposableStore();\n private _destroyed = false;\n\n /**\n * Stores raw state accessors for wrapped connections.\n * Used by setConnectionReadonly/isConnectionReadonly to read/write the\n * _cf_readonly flag without going through the user-facing state/setState.\n */\n private _rawStateAccessors = new WeakMap<\n Connection,\n {\n getRaw: () => Record<string, unknown> | null;\n setRaw: (state: unknown) => unknown;\n }\n >();\n\n /**\n * Cached persistence-hook dispatch mode, computed once in the constructor.\n * - \"new\" → call onStateChanged\n * - \"old\" → call onStateUpdate (deprecated)\n * - \"none\" → neither hook is overridden, skip entirely\n */\n private _persistenceHookMode: \"new\" | \"old\" | \"none\" = \"none\";\n\n private _ParentClass: typeof Agent<Env, State> =\n Object.getPrototypeOf(this).constructor;\n\n readonly mcp: MCPClientManager;\n\n /**\n * Initial state for the Agent\n * Override to provide default state values\n */\n initialState: State = DEFAULT_STATE as State;\n\n /**\n * Current state of the Agent\n */\n get state(): State {\n if (this._state !== DEFAULT_STATE) {\n // state was previously set, and populated internal state\n return this._state;\n }\n // looks like this is the first time the state is being accessed\n // check if the state was set in a previous life\n const wasChanged = this.sql<{ state: \"true\" | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}\n `;\n\n // ok, let's pick up the actual state from the db\n const result = this.sql<{ state: State | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}\n `;\n\n if (\n wasChanged[0]?.state === \"true\" ||\n // we do this check for people who updated their code before we shipped wasChanged\n result[0]?.state\n ) {\n const state = result[0]?.state as string; // could be null?\n\n try {\n this._state = JSON.parse(state);\n } catch (e) {\n console.error(\n \"Failed to parse stored state, falling back to initialState:\",\n e\n );\n if (this.initialState !== DEFAULT_STATE) {\n this._state = this.initialState;\n // Persist the fixed state to prevent future parse errors\n this._setStateInternal(this.initialState);\n } else {\n // No initialState defined - clear corrupted data to prevent infinite retry loop\n this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_ROW_ID}`;\n this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}`;\n return undefined as State;\n }\n }\n return this._state;\n }\n\n // ok, this is the first time the state is being accessed\n // and the state was not set in a previous life\n // so we need to set the initial state (if provided)\n if (this.initialState === DEFAULT_STATE) {\n // no initial state provided, so we return undefined\n return undefined as State;\n }\n // initial state provided, so we set the state,\n // update db and return the initial state\n this._setStateInternal(this.initialState);\n return this.initialState;\n }\n\n /**\n * Agent configuration options.\n * Override in subclasses - only specify what you want to change.\n * @example\n * class SecureAgent extends Agent {\n * static options = { sendIdentityOnConnect: false };\n * }\n */\n static options: AgentStaticOptions = { hibernate: true };\n\n /**\n * Resolved options (merges defaults with subclass overrides)\n */\n private get _resolvedOptions(): ResolvedAgentOptions {\n const ctor = this.constructor as typeof Agent;\n return {\n hibernate:\n ctor.options?.hibernate ?? DEFAULT_AGENT_STATIC_OPTIONS.hibernate,\n sendIdentityOnConnect:\n ctor.options?.sendIdentityOnConnect ??\n DEFAULT_AGENT_STATIC_OPTIONS.sendIdentityOnConnect,\n hungScheduleTimeoutSeconds:\n ctor.options?.hungScheduleTimeoutSeconds ??\n DEFAULT_AGENT_STATIC_OPTIONS.hungScheduleTimeoutSeconds\n };\n }\n\n /**\n * The observability implementation to use for the Agent\n */\n observability?: Observability = genericObservability;\n\n /**\n * Execute SQL queries against the Agent's database\n * @template T Type of the returned rows\n * @param strings SQL query template strings\n * @param values Values to be inserted into the query\n * @returns Array of query results\n */\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n let query = \"\";\n try {\n // Construct the SQL query with placeholders\n query = strings.reduce(\n (acc, str, i) => acc + str + (i < values.length ? \"?\" : \"\"),\n \"\"\n );\n\n // Execute the SQL query with the provided values\n return [...this.ctx.storage.sql.exec(query, ...values)] as T[];\n } catch (e) {\n throw this.onError(new SqlError(query, e));\n }\n }\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n\n if (!wrappedClasses.has(this.constructor)) {\n // Auto-wrap custom methods with agent context\n this._autoWrapCustomMethods();\n wrappedClasses.add(this.constructor);\n }\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (\n id TEXT PRIMARY KEY NOT NULL,\n name TEXT NOT NULL,\n server_url TEXT NOT NULL,\n callback_url TEXT NOT NULL,\n client_id TEXT,\n auth_url TEXT,\n server_options TEXT\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_state (\n id TEXT PRIMARY KEY NOT NULL,\n state TEXT\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_queues (\n id TEXT PRIMARY KEY NOT NULL,\n payload TEXT,\n callback TEXT,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_schedules (\n id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),\n callback TEXT,\n payload TEXT,\n type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),\n time INTEGER,\n delayInSeconds INTEGER,\n cron TEXT,\n intervalSeconds INTEGER,\n running INTEGER DEFAULT 0,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n // Migration: Add columns for interval scheduling (for existing agents)\n // Use raw exec to avoid error logging through onError for expected failures\n const addColumnIfNotExists = (sql: string) => {\n try {\n this.ctx.storage.sql.exec(sql);\n } catch (e) {\n // Only ignore \"duplicate column\" errors, re-throw unexpected errors\n const message = e instanceof Error ? e.message : String(e);\n if (!message.toLowerCase().includes(\"duplicate column\")) {\n throw e;\n }\n }\n };\n\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN intervalSeconds INTEGER\"\n );\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN running INTEGER DEFAULT 0\"\n );\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN execution_started_at INTEGER\"\n );\n\n // Workflow tracking table for Agent-Workflow integration\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_workflows (\n id TEXT PRIMARY KEY NOT NULL,\n workflow_id TEXT NOT NULL UNIQUE,\n workflow_name TEXT NOT NULL,\n status TEXT NOT NULL CHECK(status IN (\n 'queued', 'running', 'paused', 'errored',\n 'terminated', 'complete', 'waiting',\n 'waitingForPause', 'unknown'\n )),\n metadata TEXT,\n error_name TEXT,\n error_message TEXT,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n completed_at INTEGER\n )\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS idx_workflows_status ON cf_agents_workflows(status)\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS idx_workflows_name ON cf_agents_workflows(workflow_name)\n `;\n\n // Initialize MCPClientManager AFTER tables are created\n this.mcp = new MCPClientManager(this._ParentClass.name, \"0.0.1\", {\n storage: this.ctx.storage\n });\n\n // Broadcast server state whenever MCP state changes (register, connect, OAuth, remove, etc.)\n this._disposables.add(\n this.mcp.onServerStateChanged(async () => {\n this.broadcastMcpServers();\n })\n );\n\n // Emit MCP observability events\n this._disposables.add(\n this.mcp.onObservabilityEvent((event) => {\n this.observability?.emit(event);\n })\n );\n // Compute persistence-hook dispatch mode once.\n // Throws immediately if both hooks are overridden on the same class.\n {\n const proto = Object.getPrototypeOf(this);\n const hasOwnNew = Object.prototype.hasOwnProperty.call(\n proto,\n \"onStateChanged\"\n );\n const hasOwnOld = Object.prototype.hasOwnProperty.call(\n proto,\n \"onStateUpdate\"\n );\n\n if (hasOwnNew && hasOwnOld) {\n throw new Error(\n `[Agent] Cannot override both onStateChanged and onStateUpdate. ` +\n `Remove onStateUpdate — it has been renamed to onStateChanged.`\n );\n }\n\n if (hasOwnOld) {\n const ctor = this.constructor;\n if (!_onStateUpdateWarnedClasses.has(ctor)) {\n _onStateUpdateWarnedClasses.add(ctor);\n console.warn(\n `[Agent] onStateUpdate is deprecated. Rename to onStateChanged — the behavior is identical.`\n );\n }\n }\n\n const base = Agent.prototype;\n if (proto.onStateChanged !== base.onStateChanged) {\n this._persistenceHookMode = \"new\";\n } else if (proto.onStateUpdate !== base.onStateUpdate) {\n this._persistenceHookMode = \"old\";\n }\n // default \"none\" already set in field initializer\n }\n\n const _onRequest = this.onRequest.bind(this);\n this.onRequest = (request: Request) => {\n return agentContext.run(\n { agent: this, connection: undefined, request, email: undefined },\n async () => {\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n\n // Handle MCP OAuth callback if this is one\n const oauthResponse = await this.handleMcpOAuthCallback(request);\n if (oauthResponse) {\n return oauthResponse;\n }\n\n return this._tryCatch(() => _onRequest(request));\n }\n );\n };\n\n const _onMessage = this.onMessage.bind(this);\n this.onMessage = async (connection: Connection, message: WSMessage) => {\n this._ensureConnectionWrapped(connection);\n return agentContext.run(\n { agent: this, connection, request: undefined, email: undefined },\n async () => {\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n if (typeof message !== \"string\") {\n return this._tryCatch(() => _onMessage(connection, message));\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(message);\n } catch (_e) {\n // silently fail and let the onMessage handler handle it\n return this._tryCatch(() => _onMessage(connection, message));\n }\n\n if (isStateUpdateMessage(parsed)) {\n // Check if connection is readonly\n if (this.isConnectionReadonly(connection)) {\n // Send error response back to the connection\n connection.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"Connection is readonly\"\n })\n );\n return;\n }\n try {\n this._setStateInternal(parsed.state as State, connection);\n } catch (e) {\n // validateStateChange (or another sync error) rejected the update.\n // Log the full error server-side, send a generic message to the client.\n console.error(\"[Agent] State update rejected:\", e);\n connection.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"State update rejected\"\n })\n );\n }\n return;\n }\n\n if (isRPCRequest(parsed)) {\n try {\n const { id, method, args } = parsed;\n\n // Check if method exists and is callable\n const methodFn = this[method as keyof this];\n if (typeof methodFn !== \"function\") {\n throw new Error(`Method ${method} does not exist`);\n }\n\n if (!this._isCallable(method)) {\n throw new Error(`Method ${method} is not callable`);\n }\n\n const metadata = callableMetadata.get(methodFn as Function);\n\n // For streaming methods, pass a StreamingResponse object\n if (metadata?.streaming) {\n const stream = new StreamingResponse(connection, id);\n\n this.observability?.emit(\n {\n displayMessage: `RPC streaming call to ${method}`,\n id: nanoid(),\n payload: {\n method,\n streaming: true\n },\n timestamp: Date.now(),\n type: \"rpc\"\n },\n this.ctx\n );\n\n try {\n await methodFn.apply(this, [stream, ...args]);\n } catch (err) {\n // Log error server-side for observability\n console.error(`Error in streaming method \"${method}\":`, err);\n // Auto-close stream with error if method throws before closing\n if (!stream.isClosed) {\n stream.error(\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n return;\n }\n\n // For regular methods, execute and send response\n const result = await methodFn.apply(this, args);\n\n this.observability?.emit(\n {\n displayMessage: `RPC call to ${method}`,\n id: nanoid(),\n payload: {\n method,\n streaming: metadata?.streaming\n },\n timestamp: Date.now(),\n type: \"rpc\"\n },\n this.ctx\n );\n\n const response: RPCResponse = {\n done: true,\n id,\n result,\n success: true,\n type: MessageType.RPC\n };\n connection.send(JSON.stringify(response));\n } catch (e) {\n // Send error response\n const response: RPCResponse = {\n error:\n e instanceof Error ? e.message : \"Unknown error occurred\",\n id: parsed.id,\n success: false,\n type: MessageType.RPC\n };\n connection.send(JSON.stringify(response));\n console.error(\"RPC error:\", e);\n }\n return;\n }\n\n return this._tryCatch(() => _onMessage(connection, message));\n }\n );\n };\n\n const _onConnect = this.onConnect.bind(this);\n this.onConnect = (connection: Connection, ctx: ConnectionContext) => {\n this._ensureConnectionWrapped(connection);\n // TODO: This is a hack to ensure the state is sent after the connection is established\n // must fix this\n return agentContext.run(\n { agent: this, connection, request: ctx.request, email: undefined },\n async () => {\n // Check if connection should be readonly before sending any messages\n // so that the flag is set before the client can respond\n if (this.shouldConnectionBeReadonly(connection, ctx)) {\n this.setConnectionReadonly(connection, true);\n }\n\n // Send agent identity first so client knows which instance it's connected to\n // Can be disabled via static options for security-sensitive instance names\n if (this._resolvedOptions.sendIdentityOnConnect) {\n connection.send(\n JSON.stringify({\n name: this.name,\n agent: camelCaseToKebabCase(this._ParentClass.name),\n type: MessageType.CF_AGENT_IDENTITY\n })\n );\n }\n\n if (this.state) {\n connection.send(\n JSON.stringify({\n state: this.state,\n type: MessageType.CF_AGENT_STATE\n })\n );\n }\n\n connection.send(\n JSON.stringify({\n mcp: this.getMcpServers(),\n type: MessageType.CF_AGENT_MCP_SERVERS\n })\n );\n\n this.observability?.emit(\n {\n displayMessage: \"Connection established\",\n id: nanoid(),\n payload: {\n connectionId: connection.id\n },\n timestamp: Date.now(),\n type: \"connect\"\n },\n this.ctx\n );\n return this._tryCatch(() => _onConnect(connection, ctx));\n }\n );\n };\n\n const _onStart = this.onStart.bind(this);\n this.onStart = async (props?: Props) => {\n return agentContext.run(\n {\n agent: this,\n connection: undefined,\n request: undefined,\n email: undefined\n },\n async () => {\n await this._tryCatch(async () => {\n await this.mcp.restoreConnectionsFromStorage(this.name);\n this.broadcastMcpServers();\n\n // Check for orphaned workflows (tracked but binding no longer exists)\n this._checkOrphanedWorkflows();\n\n return _onStart(props);\n });\n }\n );\n };\n }\n\n /**\n * Check for workflows referencing unknown bindings and warn with migration suggestion.\n */\n private _checkOrphanedWorkflows(): void {\n // Get distinct workflow names with counts by active/completed status\n const distinctNames = this.sql<{\n workflow_name: string;\n total: number;\n active: number;\n completed: number;\n }>`\n SELECT \n workflow_name,\n COUNT(*) as total,\n SUM(CASE WHEN status NOT IN ('complete', 'errored', 'terminated') THEN 1 ELSE 0 END) as active,\n SUM(CASE WHEN status IN ('complete', 'errored', 'terminated') THEN 1 ELSE 0 END) as completed\n FROM cf_agents_workflows \n GROUP BY workflow_name\n `;\n\n const orphaned = distinctNames.filter(\n (row) => !this._findWorkflowBindingByName(row.workflow_name)\n );\n\n if (orphaned.length > 0) {\n const currentBindings = this._getWorkflowBindingNames();\n for (const {\n workflow_name: oldName,\n total,\n active,\n completed\n } of orphaned) {\n const suggestion =\n currentBindings.length === 1\n ? `this.migrateWorkflowBinding('${oldName}', '${currentBindings[0]}')`\n : `this.migrateWorkflowBinding('${oldName}', '<NEW_BINDING_NAME>')`;\n const breakdown =\n active > 0 && completed > 0\n ? ` (${active} active, ${completed} completed)`\n : active > 0\n ? ` (${active} active)`\n : ` (${completed} completed)`;\n console.warn(\n `[Agent] Found ${total} workflow(s) referencing unknown binding '${oldName}'${breakdown}. ` +\n `If you renamed the binding, call: ${suggestion}`\n );\n }\n }\n }\n\n private _setStateInternal(\n nextState: State,\n source: Connection | \"server\" = \"server\"\n ): void {\n // Validation/gating hook (sync only)\n this.validateStateChange(nextState, source);\n\n // Persist state\n this._state = nextState;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_ROW_ID}, ${JSON.stringify(nextState)})\n `;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_WAS_CHANGED}, ${JSON.stringify(true)})\n `;\n\n // Broadcast state to connected clients immediately\n this.broadcast(\n JSON.stringify({\n state: nextState,\n type: MessageType.CF_AGENT_STATE\n }),\n source !== \"server\" ? [source.id] : []\n );\n\n // Notification hook (non-gating). Run after broadcast and do not block.\n // Use waitUntil for reliability after the handler returns.\n const { connection, request, email } = agentContext.getStore() || {};\n this.ctx.waitUntil(\n (async () => {\n try {\n await agentContext.run(\n { agent: this, connection, request, email },\n async () => {\n this.observability?.emit(\n {\n displayMessage: \"State updated\",\n id: nanoid(),\n payload: {},\n timestamp: Date.now(),\n type: \"state:update\"\n },\n this.ctx\n );\n await this._callStatePersistenceHook(nextState, source);\n }\n );\n } catch (e) {\n // onStateChanged/onStateUpdate errors should not affect state or broadcasts\n try {\n await this.onError(e);\n } catch {\n // swallow\n }\n }\n })()\n );\n }\n\n /**\n * Update the Agent's state\n * @param state New state to set\n * @throws Error if called from a readonly connection context\n */\n setState(state: State): void {\n // Check if the current context has a readonly connection\n const store = agentContext.getStore();\n if (store?.connection && this.isConnectionReadonly(store.connection)) {\n throw new Error(\"Connection is readonly\");\n }\n this._setStateInternal(state, \"server\");\n }\n\n /**\n * Wraps connection.state and connection.setState so that the internal\n * _cf_readonly flag is hidden from user code and cannot be accidentally\n * overwritten. Must be called before any user code sees the connection.\n *\n * Idempotent — safe to call multiple times on the same connection.\n */\n private _ensureConnectionWrapped(connection: Connection) {\n if (this._rawStateAccessors.has(connection)) return;\n\n // Determine whether `state` is an accessor (getter) or a data property.\n // partyserver always defines `state` as a getter via Object.defineProperties,\n // but we handle the data-property case to stay robust for hibernate: false\n // and any future connection implementations.\n const descriptor = Object.getOwnPropertyDescriptor(connection, \"state\");\n\n let getRaw: () => Record<string, unknown> | null;\n let setRaw: (state: unknown) => unknown;\n\n if (descriptor?.get) {\n // Accessor property — bind the original getter directly.\n // The getter reads from the serialized WebSocket attachment, so it\n // always returns the latest value even after setState updates it.\n getRaw = descriptor.get.bind(connection) as () => Record<\n string,\n unknown\n > | null;\n setRaw = connection.setState.bind(connection);\n } else {\n // Data property — track raw state in a closure variable.\n // Reading `connection.state` after our override would call our filtered\n // getter (circular), so we snapshot the value here and keep it in sync.\n let rawState = (connection.state ?? null) as Record<\n string,\n unknown\n > | null;\n getRaw = () => rawState;\n setRaw = (state: unknown) => {\n rawState = state as Record<string, unknown> | null;\n return rawState;\n };\n }\n\n this._rawStateAccessors.set(connection, { getRaw, setRaw });\n\n const CF_KEY = CF_READONLY_KEY;\n\n // Override state getter to hide the readonly flag from user code\n Object.defineProperty(connection, \"state\", {\n configurable: true,\n enumerable: true,\n get() {\n const raw = getRaw();\n if (raw != null && typeof raw === \"object\" && CF_KEY in raw) {\n const { [CF_KEY]: _, ...userState } = raw;\n return Object.keys(userState).length > 0 ? userState : null;\n }\n return raw;\n }\n });\n\n // Override setState to preserve the readonly flag when user sets state\n Object.defineProperty(connection, \"setState\", {\n configurable: true,\n writable: true,\n value(stateOrFn: unknown | ((prev: unknown) => unknown)) {\n const raw = getRaw();\n const readonlyFlag =\n raw != null && typeof raw === \"object\"\n ? (raw as Record<string, unknown>)[CF_KEY]\n : undefined;\n\n let newUserState: unknown;\n if (typeof stateOrFn === \"function\") {\n // Pass only the user-visible state (without the readonly flag) to the callback\n let userVisible: unknown = raw;\n if (raw != null && typeof raw === \"object\" && CF_KEY in raw) {\n const { [CF_KEY]: _, ...rest } = raw;\n userVisible = Object.keys(rest).length > 0 ? rest : null;\n }\n newUserState = (stateOrFn as (prev: unknown) => unknown)(userVisible);\n } else {\n newUserState = stateOrFn;\n }\n\n // Merge back the readonly flag if it was set\n if (readonlyFlag !== undefined) {\n if (newUserState != null && typeof newUserState === \"object\") {\n return setRaw({\n ...(newUserState as Record<string, unknown>),\n [CF_KEY]: readonlyFlag\n });\n }\n // User set null — store just the flag\n return setRaw({ [CF_KEY]: readonlyFlag });\n }\n return setRaw(newUserState);\n }\n });\n }\n\n /**\n * Mark a connection as readonly or readwrite\n * @param connection The connection to mark\n * @param readonly Whether the connection should be readonly (default: true)\n */\n setConnectionReadonly(connection: Connection, readonly = true) {\n this._ensureConnectionWrapped(connection);\n const accessors = this._rawStateAccessors.get(connection)!;\n const raw = (accessors.getRaw() as Record<string, unknown> | null) ?? {};\n if (readonly) {\n accessors.setRaw({ ...raw, [CF_READONLY_KEY]: true });\n } else {\n // Remove the key entirely instead of storing false — avoids dead keys\n // accumulating in the connection attachment.\n const { [CF_READONLY_KEY]: _, ...rest } = raw;\n accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);\n }\n }\n\n /**\n * Check if a connection is marked as readonly\n * @param connection The connection to check\n * @returns True if the connection is readonly\n */\n isConnectionReadonly(connection: Connection): boolean {\n const accessors = this._rawStateAccessors.get(connection);\n if (accessors) {\n return !!(accessors.getRaw() as Record<string, unknown> | null)?.[\n CF_READONLY_KEY\n ];\n }\n // Connection hasn't been wrapped yet — the flag can't have been set via\n // setConnectionReadonly (which always wraps first), so default to false.\n return false;\n }\n\n /**\n * Override this method to determine if a connection should be readonly on connect\n * @param _connection The connection that is being established\n * @param _ctx Connection context\n * @returns True if the connection should be readonly\n */\n shouldConnectionBeReadonly(\n _connection: Connection,\n _ctx: ConnectionContext\n ): boolean {\n return false;\n }\n\n /**\n * Called before the Agent's state is persisted and broadcast.\n * Override to validate or reject an update by throwing an error.\n *\n * IMPORTANT: This hook must be synchronous.\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n validateStateChange(nextState: State, source: Connection | \"server\") {\n // override this to validate state updates\n }\n\n /**\n * Called after the Agent's state has been persisted and broadcast to all clients.\n * This is a notification hook — errors here are routed to onError and do not\n * affect state persistence or client broadcasts.\n *\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n onStateChanged(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates after persist + broadcast\n }\n\n /**\n * @deprecated Renamed to `onStateChanged` — the behavior is identical.\n * `onStateUpdate` will be removed in the next major version.\n *\n * Called after the Agent's state has been persisted and broadcast to all clients.\n * This is a server-side notification hook. For the client-side state callback,\n * see the `onStateUpdate` option in `useAgent` / `AgentClient`.\n *\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates (deprecated — use onStateChanged)\n }\n\n /**\n * Dispatch to the appropriate persistence hook based on the mode\n * cached in the constructor. No prototype walks at call time.\n */\n private async _callStatePersistenceHook(\n state: State | undefined,\n source: Connection | \"server\"\n ): Promise<void> {\n switch (this._persistenceHookMode) {\n case \"new\":\n await this.onStateChanged(state, source);\n break;\n case \"old\":\n await this.onStateUpdate(state, source);\n break;\n // \"none\": neither hook overridden — skip\n }\n }\n\n /**\n * Called when the Agent receives an email via routeAgentEmail()\n * Override this method to handle incoming emails\n * @param email Email message to process\n */\n async _onEmail(email: AgentEmail) {\n // nb: we use this roundabout way of getting to onEmail\n // because of https://github.com/cloudflare/workerd/issues/4499\n return agentContext.run(\n { agent: this, connection: undefined, request: undefined, email: email },\n async () => {\n if (\"onEmail\" in this && typeof this.onEmail === \"function\") {\n return this._tryCatch(() =>\n (this.onEmail as (email: AgentEmail) => Promise<void>)(email)\n );\n } else {\n console.log(\"Received email from:\", email.from, \"to:\", email.to);\n console.log(\"Subject:\", email.headers.get(\"subject\"));\n console.log(\n \"Implement onEmail(email: AgentEmail): Promise<void> in your agent to process emails\"\n );\n }\n }\n );\n }\n\n /**\n * Reply to an email\n * @param email The email to reply to\n * @param options Options for the reply\n * @param options.secret Secret for signing agent headers (enables secure reply routing).\n * Required if the email was routed via createSecureReplyEmailResolver.\n * Pass explicit `null` to opt-out of signing (not recommended for secure routing).\n * @returns void\n */\n async replyToEmail(\n email: AgentEmail,\n options: {\n fromName: string;\n subject?: string | undefined;\n body: string;\n contentType?: string;\n headers?: Record<string, string>;\n secret?: string | null;\n }\n ): Promise<void> {\n return this._tryCatch(async () => {\n // Enforce signing for emails routed via createSecureReplyEmailResolver\n if (email._secureRouted && options.secret === undefined) {\n throw new Error(\n \"This email was routed via createSecureReplyEmailResolver. \" +\n \"You must pass a secret to replyToEmail() to sign replies, \" +\n \"or pass explicit null to opt-out (not recommended).\"\n );\n }\n\n const agentName = camelCaseToKebabCase(this._ParentClass.name);\n const agentId = this.name;\n\n const { createMimeMessage } = await import(\"mimetext\");\n const msg = createMimeMessage();\n msg.setSender({ addr: email.to, name: options.fromName });\n msg.setRecipient(email.from);\n msg.setSubject(\n options.subject || `Re: ${email.headers.get(\"subject\")}` || \"No subject\"\n );\n msg.addMessage({\n contentType: options.contentType || \"text/plain\",\n data: options.body\n });\n\n const domain = email.from.split(\"@\")[1];\n const messageId = `<${agentId}@${domain}>`;\n msg.setHeader(\"In-Reply-To\", email.headers.get(\"Message-ID\")!);\n msg.setHeader(\"Message-ID\", messageId);\n msg.setHeader(\"X-Agent-Name\", agentName);\n msg.setHeader(\"X-Agent-ID\", agentId);\n\n // Sign headers if secret is provided (enables secure reply routing)\n if (typeof options.secret === \"string\") {\n const signedHeaders = await signAgentHeaders(\n options.secret,\n agentName,\n agentId\n );\n msg.setHeader(\"X-Agent-Sig\", signedHeaders[\"X-Agent-Sig\"]);\n msg.setHeader(\"X-Agent-Sig-Ts\", signedHeaders[\"X-Agent-Sig-Ts\"]);\n }\n\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n msg.setHeader(key, value);\n }\n }\n await email.reply({\n from: email.to,\n raw: msg.asRaw(),\n to: email.from\n });\n });\n }\n\n private async _tryCatch<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n /**\n * Automatically wrap custom methods with agent context\n * This ensures getCurrentAgent() works in all custom methods without decorators\n */\n private _autoWrapCustomMethods() {\n // Collect all methods from base prototypes (Agent and Server)\n const basePrototypes = [Agent.prototype, Server.prototype];\n const baseMethods = new Set<string>();\n for (const baseProto of basePrototypes) {\n let proto = baseProto;\n while (proto && proto !== Object.prototype) {\n const methodNames = Object.getOwnPropertyNames(proto);\n for (const methodName of methodNames) {\n baseMethods.add(methodName);\n }\n proto = Object.getPrototypeOf(proto);\n }\n }\n // Get all methods from the current instance's prototype chain\n let proto = Object.getPrototypeOf(this);\n let depth = 0;\n while (proto && proto !== Object.prototype && depth < 10) {\n const methodNames = Object.getOwnPropertyNames(proto);\n for (const methodName of methodNames) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);\n\n // Skip if it's a private method, a base method, a getter, or not a function,\n if (\n baseMethods.has(methodName) ||\n methodName.startsWith(\"_\") ||\n !descriptor ||\n !!descriptor.get ||\n typeof descriptor.value !== \"function\"\n ) {\n continue;\n }\n\n // Now, methodName is confirmed to be a custom method/function\n // Wrap the custom method with context\n /* oxlint-disable @typescript-eslint/no-explicit-any -- dynamic method wrapping requires any */\n const wrappedFunction = withAgentContext(\n this[methodName as keyof this] as (...args: any[]) => any\n ) as any;\n /* oxlint-enable @typescript-eslint/no-explicit-any */\n\n // if the method is callable, copy the metadata from the original method\n if (this._isCallable(methodName)) {\n callableMetadata.set(\n wrappedFunction,\n callableMetadata.get(this[methodName as keyof this] as Function)!\n );\n }\n\n // set the wrapped function on the prototype\n this.constructor.prototype[methodName as keyof this] = wrappedFunction;\n }\n\n proto = Object.getPrototypeOf(proto);\n depth++;\n }\n }\n\n override onError(\n connection: Connection,\n error: unknown\n ): void | Promise<void>;\n override onError(error: unknown): void | Promise<void>;\n override onError(connectionOrError: Connection | unknown, error?: unknown) {\n let theError: unknown;\n if (connectionOrError && error) {\n theError = error;\n // this is a websocket connection error\n console.error(\n \"Error on websocket connection:\",\n (connectionOrError as Connection).id,\n theError\n );\n console.error(\n \"Override onError(connection, error) to handle websocket connection errors\"\n );\n } else {\n theError = connectionOrError;\n // this is a server error\n console.error(\"Error on server:\", theError);\n console.error(\"Override onError(error) to handle server errors\");\n }\n throw theError;\n }\n\n /**\n * Render content (not implemented in base class)\n */\n render() {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Queue a task to be executed in the future\n * @param payload Payload to pass to the callback\n * @param callback Name of the method to call\n * @returns The ID of the queued task\n */\n async queue<T = unknown>(callback: keyof this, payload: T): Promise<string> {\n const id = nanoid(9);\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_queues (id, payload, callback)\n VALUES (${id}, ${JSON.stringify(payload)}, ${callback})\n `;\n\n void this._flushQueue().catch((e) => {\n console.error(\"Error flushing queue:\", e);\n });\n\n return id;\n }\n\n private _flushingQueue = false;\n\n private async _flushQueue() {\n if (this._flushingQueue) {\n return;\n }\n this._flushingQueue = true;\n while (true) {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues\n ORDER BY created_at ASC\n `;\n\n if (!result || result.length === 0) {\n break;\n }\n\n for (const row of result || []) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n continue;\n }\n const { connection, request, email } = agentContext.getStore() || {};\n await agentContext.run(\n {\n agent: this,\n connection,\n request,\n email\n },\n async () => {\n // TODO: add retries and backoff\n await (\n callback as (\n payload: unknown,\n queueItem: QueueItem<string>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n await this.dequeue(row.id);\n }\n );\n }\n }\n this._flushingQueue = false;\n }\n\n /**\n * Dequeue a task by ID\n * @param id ID of the task to dequeue\n */\n async dequeue(id: string) {\n this.sql`DELETE FROM cf_agents_queues WHERE id = ${id}`;\n }\n\n /**\n * Dequeue all tasks\n */\n async dequeueAll() {\n this.sql`DELETE FROM cf_agents_queues`;\n }\n\n /**\n * Dequeue all tasks by callback\n * @param callback Name of the callback to dequeue\n */\n async dequeueAllByCallback(callback: string) {\n this.sql`DELETE FROM cf_agents_queues WHERE callback = ${callback}`;\n }\n\n /**\n * Get a queued task by ID\n * @param id ID of the task to get\n * @returns The task or undefined if not found\n */\n async getQueue(id: string): Promise<QueueItem<string> | undefined> {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues WHERE id = ${id}\n `;\n return result\n ? { ...result[0], payload: JSON.parse(result[0].payload) }\n : undefined;\n }\n\n /**\n * Get all queues by key and value\n * @param key Key to filter by\n * @param value Value to filter by\n * @returns Array of matching QueueItem objects\n */\n async getQueues(key: string, value: string): Promise<QueueItem<string>[]> {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues\n `;\n return result.filter((row) => JSON.parse(row.payload)[key] === value);\n }\n\n /**\n * Schedule a task to be executed in the future\n * @template T Type of the payload data\n * @param when When to execute the task (Date, seconds delay, or cron expression)\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async schedule<T = string>(\n when: Date | string | number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n const id = nanoid(9);\n\n const emitScheduleCreate = (schedule: Schedule<T>) =>\n this.observability?.emit(\n {\n displayMessage: `Schedule ${schedule.id} created`,\n id: nanoid(),\n payload: {\n callback: callback as string,\n id: id\n },\n timestamp: Date.now(),\n type: \"schedule:create\"\n },\n this.ctx\n );\n\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n if (when instanceof Date) {\n const timestamp = Math.floor(when.getTime() / 1000);\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'scheduled', ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"scheduled\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n if (typeof when === \"number\") {\n const time = new Date(Date.now() + when * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, delayInSeconds, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'delayed', ${when}, ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n delayInSeconds: when,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"delayed\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n if (typeof when === \"string\") {\n const nextExecutionTime = getNextCronTime(when);\n const timestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, cron, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'cron', ${when}, ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n cron: when,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"cron\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n throw new Error(\n `Invalid schedule type: ${JSON.stringify(when)}(${typeof when}) trying to schedule ${callback}`\n );\n }\n\n /**\n * Schedule a task to run repeatedly at a fixed interval\n * @template T Type of the payload data\n * @param intervalSeconds Number of seconds between executions\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async scheduleEvery<T = string>(\n intervalSeconds: number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n // DO alarms have a max schedule time of 30 days\n const MAX_INTERVAL_SECONDS = 30 * 24 * 60 * 60; // 30 days in seconds\n\n if (typeof intervalSeconds !== \"number\" || intervalSeconds <= 0) {\n throw new Error(\"intervalSeconds must be a positive number\");\n }\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 if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n const id = nanoid(9);\n const time = new Date(Date.now() + intervalSeconds * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, intervalSeconds, time, running)\n VALUES (${id}, ${callback}, ${JSON.stringify(payload)}, 'interval', ${intervalSeconds}, ${timestamp}, 0)\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n id,\n intervalSeconds,\n payload: payload as T,\n time: timestamp,\n type: \"interval\"\n };\n\n this.observability?.emit(\n {\n displayMessage: `Schedule ${schedule.id} created`,\n id: nanoid(),\n payload: {\n callback: callback as string,\n id: id\n },\n timestamp: Date.now(),\n type: \"schedule:create\"\n },\n this.ctx\n );\n\n return schedule;\n }\n\n /**\n * Get a scheduled task by ID\n * @template T Type of the payload data\n * @param id ID of the scheduled task\n * @returns The Schedule object or undefined if not found\n */\n async getSchedule<T = string>(id: string): Promise<Schedule<T> | undefined> {\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE id = ${id}\n `;\n if (!result || result.length === 0) {\n return undefined;\n }\n\n return { ...result[0], payload: JSON.parse(result[0].payload) as T };\n }\n\n /**\n * Get scheduled tasks matching the given criteria\n * @template T Type of the payload data\n * @param criteria Criteria to filter schedules\n * @returns Array of matching Schedule objects\n */\n getSchedules<T = string>(\n criteria: {\n id?: string;\n type?: \"scheduled\" | \"delayed\" | \"cron\" | \"interval\";\n timeRange?: { start?: Date; end?: Date };\n } = {}\n ): Schedule<T>[] {\n let query = \"SELECT * FROM cf_agents_schedules WHERE 1=1\";\n const params = [];\n\n if (criteria.id) {\n query += \" AND id = ?\";\n params.push(criteria.id);\n }\n\n if (criteria.type) {\n query += \" AND type = ?\";\n params.push(criteria.type);\n }\n\n if (criteria.timeRange) {\n query += \" AND time >= ? AND time <= ?\";\n const start = criteria.timeRange.start || new Date(0);\n const end = criteria.timeRange.end || new Date(999999999999999);\n params.push(\n Math.floor(start.getTime() / 1000),\n Math.floor(end.getTime() / 1000)\n );\n }\n\n const result = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray()\n .map((row) => ({\n ...row,\n payload: JSON.parse(row.payload as string) as T\n })) as Schedule<T>[];\n\n return result;\n }\n\n /**\n * Cancel a scheduled task\n * @param id ID of the task to cancel\n * @returns true if the task was cancelled, false if the task was not found\n */\n async cancelSchedule(id: string): Promise<boolean> {\n const schedule = await this.getSchedule(id);\n if (!schedule) {\n return false;\n }\n\n this.observability?.emit(\n {\n displayMessage: `Schedule ${id} cancelled`,\n id: nanoid(),\n payload: {\n callback: schedule.callback,\n id: schedule.id\n },\n timestamp: Date.now(),\n type: \"schedule:cancel\"\n },\n this.ctx\n );\n\n this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;\n\n await this._scheduleNextAlarm();\n return true;\n }\n\n private async _scheduleNextAlarm() {\n // Find the next schedule that needs to be executed\n const result = this.sql`\n SELECT time FROM cf_agents_schedules\n WHERE time >= ${Math.floor(Date.now() / 1000)}\n ORDER BY time ASC\n LIMIT 1\n `;\n if (!result) return;\n\n if (result.length > 0 && \"time\" in result[0]) {\n const nextTime = (result[0].time as number) * 1000;\n await this.ctx.storage.setAlarm(nextTime);\n }\n }\n\n /**\n * Method called when an alarm fires.\n * Executes any scheduled tasks that are due.\n *\n * @remarks\n * To schedule a task, please use the `this.schedule` method instead.\n * See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}\n */\n public readonly alarm = async () => {\n const now = Math.floor(Date.now() / 1000);\n\n // Get all schedules that should be executed now\n const result = this.sql<\n Schedule<string> & { running?: number; intervalSeconds?: number }\n >`\n SELECT * FROM cf_agents_schedules WHERE time <= ${now}\n `;\n\n if (result && Array.isArray(result)) {\n for (const row of result) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n continue;\n }\n\n // Overlap prevention for interval schedules with hung callback detection\n if (row.type === \"interval\" && row.running === 1) {\n const executionStartedAt =\n (row as { execution_started_at?: number }).execution_started_at ??\n 0;\n const hungTimeoutSeconds =\n this._resolvedOptions.hungScheduleTimeoutSeconds;\n const elapsedSeconds = now - executionStartedAt;\n\n if (elapsedSeconds < hungTimeoutSeconds) {\n console.warn(\n `Skipping interval schedule ${row.id}: previous execution still running`\n );\n continue;\n }\n // Previous execution appears hung, force reset and re-execute\n console.warn(\n `Forcing reset of hung interval schedule ${row.id} (started ${elapsedSeconds}s ago)`\n );\n }\n\n // Mark interval as running before execution\n if (row.type === \"interval\") {\n this\n .sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;\n }\n\n await agentContext.run(\n {\n agent: this,\n connection: undefined,\n request: undefined,\n email: undefined\n },\n async () => {\n try {\n this.observability?.emit(\n {\n displayMessage: `Schedule ${row.id} executed`,\n id: nanoid(),\n payload: {\n callback: row.callback,\n id: row.id\n },\n timestamp: Date.now(),\n type: \"schedule:execute\"\n },\n this.ctx\n );\n\n await (\n callback as (\n payload: unknown,\n schedule: Schedule<unknown>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n } catch (e) {\n console.error(`error executing callback \"${row.callback}\"`, e);\n // Route schedule errors through onError for consistency\n try {\n await this.onError(e);\n } catch {\n // swallow onError errors\n }\n }\n }\n );\n\n if (this._destroyed) return;\n\n if (row.type === \"cron\") {\n // Update next execution time for cron schedules\n const nextExecutionTime = getNextCronTime(row.cron);\n const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else if (row.type === \"interval\") {\n // Reset running flag and schedule next interval execution\n const nextTimestamp =\n Math.floor(Date.now() / 1000) + (row.intervalSeconds ?? 0);\n\n this.sql`\n UPDATE cf_agents_schedules SET running = 0, time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else {\n // Delete one-time schedules after execution\n this.sql`\n DELETE FROM cf_agents_schedules WHERE id = ${row.id}\n `;\n }\n }\n }\n if (this._destroyed) return;\n\n // Schedule the next alarm\n await this._scheduleNextAlarm();\n };\n\n /**\n * Destroy the Agent, removing all state and scheduled tasks\n */\n async destroy() {\n // drop all tables\n this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;\n this.sql`DROP TABLE IF EXISTS cf_agents_state`;\n this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;\n this.sql`DROP TABLE IF EXISTS cf_agents_queues`;\n this.sql`DROP TABLE IF EXISTS cf_agents_workflows`;\n\n // delete all alarms\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n\n this._disposables.dispose();\n await this.mcp.dispose();\n\n this._destroyed = true;\n\n // `ctx.abort` throws an uncatchable error, so we yield to the event loop\n // to avoid capturing it and let handlers finish cleaning up\n setTimeout(() => {\n this.ctx.abort(\"destroyed\");\n }, 0);\n\n this.observability?.emit(\n {\n displayMessage: \"Agent destroyed\",\n id: nanoid(),\n payload: {},\n timestamp: Date.now(),\n type: \"destroy\"\n },\n this.ctx\n );\n }\n\n /**\n * Check if a method is callable\n * @param method The method name to check\n * @returns True if the method is marked as callable\n */\n private _isCallable(method: string): boolean {\n return callableMetadata.has(this[method as keyof this] as Function);\n }\n\n /**\n * Get all methods marked as callable on this Agent\n * @returns A map of method names to their metadata\n */\n getCallableMethods(): Map<string, CallableMetadata> {\n const result = new Map<string, CallableMetadata>();\n\n // Walk the entire prototype chain to find callable methods from parent classes\n let prototype = Object.getPrototypeOf(this);\n while (prototype && prototype !== Object.prototype) {\n for (const name of Object.getOwnPropertyNames(prototype)) {\n if (name === \"constructor\") continue;\n // Don't override child class methods (first one wins)\n if (result.has(name)) continue;\n\n try {\n const fn = prototype[name];\n if (typeof fn === \"function\") {\n const meta = callableMetadata.get(fn as Function);\n if (meta) {\n result.set(name, meta);\n }\n }\n } catch (e) {\n // Skip properties that can't be accessed (e.g., private members with #)\n // These throw TypeError when accessed\n if (!(e instanceof TypeError)) {\n throw e;\n }\n }\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return result;\n }\n\n // ==========================================\n // Workflow Integration Methods\n // ==========================================\n\n /**\n * Start a workflow and track it in this Agent's database.\n * Automatically injects agent identity into the workflow params.\n *\n * @template P - Type of params to pass to the workflow\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param params - Params to pass to the workflow\n * @param options - Optional workflow options\n * @returns The workflow instance ID\n *\n * @example\n * ```typescript\n * const workflowId = await this.runWorkflow(\n * 'MY_WORKFLOW',\n * { taskId: '123', data: 'process this' }\n * );\n * ```\n */\n async runWorkflow<P = unknown>(\n workflowName: WorkflowName<Env>,\n params: P,\n options?: RunWorkflowOptions\n ): Promise<string> {\n // Look up the workflow binding by name\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n // Find the binding name for this Agent's namespace\n const agentBindingName =\n options?.agentBinding ?? this._findAgentBindingName();\n if (!agentBindingName) {\n throw new Error(\n \"Could not detect Agent binding name from class name. \" +\n \"Pass it explicitly via options.agentBinding\"\n );\n }\n\n // Generate workflow ID if not provided\n const workflowId = options?.id ?? nanoid();\n\n // Inject agent identity and workflow name into params\n const augmentedParams = {\n ...params,\n __agentName: this.name,\n __agentBinding: agentBindingName,\n __workflowName: workflowName\n };\n\n // Create the workflow instance\n const instance = await workflow.create({\n id: workflowId,\n params: augmentedParams\n });\n\n // Track the workflow in our database\n const id = nanoid();\n const metadataJson = options?.metadata\n ? JSON.stringify(options.metadata)\n : null;\n try {\n this.sql`\n INSERT INTO cf_agents_workflows (id, workflow_id, workflow_name, status, metadata)\n VALUES (${id}, ${instance.id}, ${workflowName}, 'queued', ${metadataJson})\n `;\n } catch (e) {\n if (\n e instanceof Error &&\n e.message.includes(\"UNIQUE constraint failed\")\n ) {\n throw new Error(\n `Workflow with ID \"${workflowId}\" is already being tracked`\n );\n }\n throw e;\n }\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${instance.id} started`,\n id: nanoid(),\n payload: {\n workflowId: instance.id,\n workflowName: workflowName\n },\n timestamp: Date.now(),\n type: \"workflow:start\"\n },\n this.ctx\n );\n\n return instance.id;\n }\n\n /**\n * Send an event to a running workflow.\n * The workflow can wait for this event using step.waitForEvent().\n *\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param workflowId - ID of the workflow instance\n * @param event - Event to send\n *\n * @example\n * ```typescript\n * await this.sendWorkflowEvent(\n * 'MY_WORKFLOW',\n * workflowId,\n * { type: 'approval', payload: { approved: true } }\n * );\n * ```\n */\n async sendWorkflowEvent(\n workflowName: WorkflowName<Env>,\n workflowId: string,\n event: WorkflowEventPayload\n ): Promise<void> {\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n await instance.sendEvent(event);\n\n this.observability?.emit(\n {\n displayMessage: `Event sent to workflow ${workflowId}`,\n id: nanoid(),\n payload: {\n workflowId,\n eventType: event.type\n },\n timestamp: Date.now(),\n type: \"workflow:event\"\n },\n this.ctx\n );\n }\n\n /**\n * Approve a waiting workflow.\n * Sends an approval event to the workflow that can be received by waitForApproval().\n *\n * @param workflowId - ID of the workflow to approve\n * @param data - Optional approval data (reason, metadata)\n *\n * @example\n * ```typescript\n * await this.approveWorkflow(workflowId, {\n * reason: 'Approved by admin',\n * metadata: { approvedBy: userId }\n * });\n * ```\n */\n async approveWorkflow(\n workflowId: string,\n data?: { reason?: string; metadata?: Record<string, unknown> }\n ): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n await this.sendWorkflowEvent(\n workflowInfo.workflowName as WorkflowName<Env>,\n workflowId,\n {\n type: \"approval\",\n payload: {\n approved: true,\n reason: data?.reason,\n metadata: data?.metadata\n }\n }\n );\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} approved`,\n id: nanoid(),\n payload: { workflowId, reason: data?.reason },\n timestamp: Date.now(),\n type: \"workflow:approved\"\n },\n this.ctx\n );\n }\n\n /**\n * Reject a waiting workflow.\n * Sends a rejection event to the workflow that will cause waitForApproval() to throw.\n *\n * @param workflowId - ID of the workflow to reject\n * @param data - Optional rejection data (reason)\n *\n * @example\n * ```typescript\n * await this.rejectWorkflow(workflowId, {\n * reason: 'Request denied by admin'\n * });\n * ```\n */\n async rejectWorkflow(\n workflowId: string,\n data?: { reason?: string }\n ): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n await this.sendWorkflowEvent(\n workflowInfo.workflowName as WorkflowName<Env>,\n workflowId,\n {\n type: \"approval\",\n payload: {\n approved: false,\n reason: data?.reason\n }\n }\n );\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} rejected`,\n id: nanoid(),\n payload: { workflowId, reason: data?.reason },\n timestamp: Date.now(),\n type: \"workflow:rejected\"\n },\n this.ctx\n );\n }\n\n /**\n * Terminate a running workflow.\n * This immediately stops the workflow and sets its status to \"terminated\".\n *\n * @param workflowId - ID of the workflow to terminate (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is already completed/errored/terminated (from Cloudflare)\n *\n * @note `terminate()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.terminateWorkflow(workflowId);\n * ```\n */\n async terminateWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.terminate();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"terminateWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n // Update tracking table with new status\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} terminated`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:terminated\"\n },\n this.ctx\n );\n }\n\n /**\n * Pause a running workflow.\n * The workflow can be resumed later with resumeWorkflow().\n *\n * @param workflowId - ID of the workflow to pause (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is not running (from Cloudflare)\n *\n * @note `pause()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.pauseWorkflow(workflowId);\n * ```\n */\n async pauseWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.pause();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"pauseWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} paused`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:paused\"\n },\n this.ctx\n );\n }\n\n /**\n * Resume a paused workflow.\n *\n * @param workflowId - ID of the workflow to resume (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is not paused (from Cloudflare)\n *\n * @note `resume()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.resumeWorkflow(workflowId);\n * ```\n */\n async resumeWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.resume();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"resumeWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} resumed`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:resumed\"\n },\n this.ctx\n );\n }\n\n /**\n * Restart a workflow instance.\n * This re-runs the workflow from the beginning with the same ID.\n *\n * @param workflowId - ID of the workflow to restart (must be tracked via runWorkflow)\n * @param options - Optional settings\n * @param options.resetTracking - If true (default), resets created_at and clears error fields.\n * If false, preserves original timestamps.\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n *\n * @note `restart()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * // Reset tracking (default)\n * await this.restartWorkflow(workflowId);\n *\n * // Preserve original timestamps\n * await this.restartWorkflow(workflowId, { resetTracking: false });\n * ```\n */\n async restartWorkflow(\n workflowId: string,\n options: { resetTracking?: boolean } = {}\n ): Promise<void> {\n const { resetTracking = true } = options;\n\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.restart();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"restartWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n if (resetTracking) {\n // Reset tracking fields for fresh start\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'queued',\n created_at = ${now},\n updated_at = ${now},\n completed_at = NULL,\n error_name = NULL,\n error_message = NULL\n WHERE workflow_id = ${workflowId}\n `;\n } else {\n // Just update status from Cloudflare\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n }\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} restarted`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:restarted\"\n },\n this.ctx\n );\n }\n\n /**\n * Find a workflow binding by its name.\n */\n private _findWorkflowBindingByName(\n workflowName: string\n ): Workflow | undefined {\n const binding = (this.env as Record<string, unknown>)[workflowName];\n if (\n binding &&\n typeof binding === \"object\" &&\n \"create\" in binding &&\n \"get\" in binding\n ) {\n return binding as Workflow;\n }\n return undefined;\n }\n\n /**\n * Get all workflow binding names from the environment.\n */\n private _getWorkflowBindingNames(): string[] {\n const names: string[] = [];\n for (const [key, value] of Object.entries(\n this.env as Record<string, unknown>\n )) {\n if (\n value &&\n typeof value === \"object\" &&\n \"create\" in value &&\n \"get\" in value\n ) {\n names.push(key);\n }\n }\n return names;\n }\n\n /**\n * Get the status of a workflow and update the tracking record.\n *\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param workflowId - ID of the workflow instance\n * @returns The workflow status\n */\n async getWorkflowStatus(\n workflowName: WorkflowName<Env>,\n workflowId: string\n ): Promise<InstanceStatus> {\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n const status = await instance.status();\n\n // Update the tracking record\n this._updateWorkflowTracking(workflowId, status);\n\n return status;\n }\n\n /**\n * Get a tracked workflow by ID.\n *\n * @param workflowId - Workflow instance ID\n * @returns Workflow info or undefined if not found\n */\n getWorkflow(workflowId: string): WorkflowInfo | undefined {\n const rows = this.sql<WorkflowTrackingRow>`\n SELECT * FROM cf_agents_workflows WHERE workflow_id = ${workflowId}\n `;\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n return this._rowToWorkflowInfo(rows[0]);\n }\n\n /**\n * Query tracked workflows with cursor-based pagination.\n *\n * @param criteria - Query criteria including optional cursor for pagination\n * @returns WorkflowPage with workflows, total count, and next cursor\n *\n * @example\n * ```typescript\n * // First page\n * const page1 = this.getWorkflows({ status: 'running', limit: 20 });\n *\n * // Next page\n * if (page1.nextCursor) {\n * const page2 = this.getWorkflows({\n * status: 'running',\n * limit: 20,\n * cursor: page1.nextCursor\n * });\n * }\n * ```\n */\n getWorkflows(criteria: WorkflowQueryCriteria = {}): WorkflowPage {\n const limit = Math.min(criteria.limit ?? 50, 100);\n const isAsc = criteria.orderBy === \"asc\";\n\n // Get total count (ignores cursor and limit)\n const total = this._countWorkflows(criteria);\n\n // Build base query\n let query = \"SELECT * FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n // Apply cursor for keyset pagination\n if (criteria.cursor) {\n const cursor = this._decodeCursor(criteria.cursor);\n if (isAsc) {\n // ASC: get items after cursor\n query +=\n \" AND (created_at > ? OR (created_at = ? AND workflow_id > ?))\";\n } else {\n // DESC: get items before cursor\n query +=\n \" AND (created_at < ? OR (created_at = ? AND workflow_id < ?))\";\n }\n params.push(cursor.createdAt, cursor.createdAt, cursor.workflowId);\n }\n\n // Order by created_at and workflow_id for consistent keyset pagination\n query += ` ORDER BY created_at ${isAsc ? \"ASC\" : \"DESC\"}, workflow_id ${isAsc ? \"ASC\" : \"DESC\"}`;\n\n // Fetch limit + 1 to detect if there are more pages\n query += \" LIMIT ?\";\n params.push(limit + 1);\n\n const rows = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray() as WorkflowTrackingRow[];\n\n const hasMore = rows.length > limit;\n const resultRows = hasMore ? rows.slice(0, limit) : rows;\n const workflows = resultRows.map((row) => this._rowToWorkflowInfo(row));\n\n // Build next cursor from last item\n const nextCursor =\n hasMore && workflows.length > 0\n ? this._encodeCursor(workflows[workflows.length - 1])\n : null;\n\n return { workflows, total, nextCursor };\n }\n\n /**\n * Count workflows matching criteria (for pagination total).\n */\n private _countWorkflows(\n criteria: Omit<WorkflowQueryCriteria, \"limit\" | \"cursor\" | \"orderBy\"> & {\n createdBefore?: Date;\n }\n ): number {\n let query = \"SELECT COUNT(*) as count FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n if (criteria.createdBefore) {\n query += \" AND created_at < ?\";\n params.push(Math.floor(criteria.createdBefore.getTime() / 1000));\n }\n\n const result = this.ctx.storage.sql.exec(query, ...params).toArray() as {\n count: number;\n }[];\n\n return result[0]?.count ?? 0;\n }\n\n /**\n * Encode a cursor from workflow info for pagination.\n * Stores createdAt as Unix timestamp in seconds (matching DB storage).\n */\n private _encodeCursor(workflow: WorkflowInfo): string {\n return btoa(\n JSON.stringify({\n c: Math.floor(workflow.createdAt.getTime() / 1000),\n i: workflow.workflowId\n })\n );\n }\n\n /**\n * Decode a pagination cursor.\n * Returns createdAt as Unix timestamp in seconds (matching DB storage).\n */\n private _decodeCursor(cursor: string): {\n createdAt: number;\n workflowId: string;\n } {\n try {\n const data = JSON.parse(atob(cursor));\n if (typeof data.c !== \"number\" || typeof data.i !== \"string\") {\n throw new Error(\"Invalid cursor structure\");\n }\n return { createdAt: data.c, workflowId: data.i };\n } catch {\n throw new Error(\n \"Invalid pagination cursor. The cursor may be malformed or corrupted.\"\n );\n }\n }\n\n /**\n * Delete a workflow tracking record.\n *\n * @param workflowId - ID of the workflow to delete\n * @returns true if a record was deleted, false if not found\n */\n deleteWorkflow(workflowId: string): boolean {\n // First check if workflow exists\n const existing = this.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_workflows WHERE workflow_id = ${workflowId}\n `;\n if (!existing[0] || existing[0].count === 0) {\n return false;\n }\n this.sql`DELETE FROM cf_agents_workflows WHERE workflow_id = ${workflowId}`;\n return true;\n }\n\n /**\n * Delete workflow tracking records matching criteria.\n * Useful for cleaning up old completed/errored workflows.\n *\n * @param criteria - Criteria for which workflows to delete\n * @returns Number of records matching criteria (expected deleted count)\n *\n * @example\n * ```typescript\n * // Delete all completed workflows created more than 7 days ago\n * const deleted = this.deleteWorkflows({\n * status: 'complete',\n * createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n * });\n *\n * // Delete all errored and terminated workflows\n * const deleted = this.deleteWorkflows({\n * status: ['errored', 'terminated']\n * });\n * ```\n */\n deleteWorkflows(\n criteria: Omit<WorkflowQueryCriteria, \"limit\" | \"orderBy\"> & {\n createdBefore?: Date;\n } = {}\n ): number {\n let query = \"DELETE FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n if (criteria.createdBefore) {\n query += \" AND created_at < ?\";\n params.push(Math.floor(criteria.createdBefore.getTime() / 1000));\n }\n\n const cursor = this.ctx.storage.sql.exec(query, ...params);\n return cursor.rowsWritten;\n }\n\n /**\n * Migrate workflow tracking records from an old binding name to a new one.\n * Use this after renaming a workflow binding in wrangler.toml.\n *\n * @param oldName - Previous workflow binding name\n * @param newName - New workflow binding name\n * @returns Number of records migrated\n *\n * @example\n * ```typescript\n * // After renaming OLD_WORKFLOW to NEW_WORKFLOW in wrangler.toml\n * async onStart() {\n * const migrated = this.migrateWorkflowBinding('OLD_WORKFLOW', 'NEW_WORKFLOW');\n * }\n * ```\n */\n migrateWorkflowBinding(oldName: string, newName: string): number {\n // Validate new binding exists\n if (!this._findWorkflowBindingByName(newName)) {\n throw new Error(`Workflow binding '${newName}' not found in environment`);\n }\n\n const result = this.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_workflows WHERE workflow_name = ${oldName}\n `;\n const count = result[0]?.count ?? 0;\n\n if (count > 0) {\n this\n .sql`UPDATE cf_agents_workflows SET workflow_name = ${newName} WHERE workflow_name = ${oldName}`;\n console.log(\n `[Agent] Migrated ${count} workflow(s) from '${oldName}' to '${newName}'`\n );\n }\n\n return count;\n }\n\n /**\n * Update workflow tracking record from InstanceStatus\n */\n private _updateWorkflowTracking(\n workflowId: string,\n status: InstanceStatus\n ): void {\n const statusName = status.status;\n const now = Math.floor(Date.now() / 1000);\n\n // Determine if workflow is complete\n const completedStatuses: WorkflowStatus[] = [\n \"complete\",\n \"errored\",\n \"terminated\"\n ];\n const completedAt = completedStatuses.includes(statusName) ? now : null;\n\n // Extract error info if present\n const errorName = status.error?.name ?? null;\n const errorMessage = status.error?.message ?? null;\n\n this.sql`\n UPDATE cf_agents_workflows\n SET status = ${statusName},\n error_name = ${errorName},\n error_message = ${errorMessage},\n updated_at = ${now},\n completed_at = ${completedAt}\n WHERE workflow_id = ${workflowId}\n `;\n }\n\n /**\n * Convert a database row to WorkflowInfo\n */\n private _rowToWorkflowInfo(row: WorkflowTrackingRow): WorkflowInfo {\n return {\n id: row.id,\n workflowId: row.workflow_id,\n workflowName: row.workflow_name,\n status: row.status,\n metadata: row.metadata ? JSON.parse(row.metadata) : null,\n error: row.error_name\n ? { name: row.error_name, message: row.error_message ?? \"\" }\n : null,\n createdAt: new Date(row.created_at * 1000),\n updatedAt: new Date(row.updated_at * 1000),\n completedAt: row.completed_at ? new Date(row.completed_at * 1000) : null\n };\n }\n\n /**\n * Find the binding name for this Agent's namespace by matching class name.\n * Returns undefined if no match found - use options.agentBinding as fallback.\n */\n private _findAgentBindingName(): string | undefined {\n const className = this._ParentClass.name;\n for (const [key, value] of Object.entries(\n this.env as Record<string, unknown>\n )) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n // Check if this namespace's binding name matches our class name\n if (\n key === className ||\n camelCaseToKebabCase(key) === camelCaseToKebabCase(className)\n ) {\n return key;\n }\n }\n }\n return undefined;\n }\n\n // ==========================================\n // Workflow Lifecycle Callbacks\n // ==========================================\n\n /**\n * Handle a callback from a workflow.\n * Called when the Agent receives a callback at /_workflow/callback.\n * Override this to handle all callback types in one place.\n *\n * @param callback - The callback payload\n */\n async onWorkflowCallback(callback: WorkflowCallback): Promise<void> {\n const now = Math.floor(Date.now() / 1000);\n\n switch (callback.type) {\n case \"progress\":\n // Update tracking status to \"running\" when receiving progress\n // Only transition from queued/waiting to avoid overwriting terminal states\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'running', updated_at = ${now}\n WHERE workflow_id = ${callback.workflowId} AND status IN ('queued', 'waiting')\n `;\n await this.onWorkflowProgress(\n callback.workflowName,\n callback.workflowId,\n callback.progress\n );\n break;\n case \"complete\":\n // Update tracking status to \"complete\"\n // Don't overwrite if already terminated/paused (race condition protection)\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'complete', updated_at = ${now}, completed_at = ${now}\n WHERE workflow_id = ${callback.workflowId}\n AND status NOT IN ('terminated', 'paused')\n `;\n await this.onWorkflowComplete(\n callback.workflowName,\n callback.workflowId,\n callback.result\n );\n break;\n case \"error\":\n // Update tracking status to \"errored\"\n // Don't overwrite if already terminated/paused (race condition protection)\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'errored', updated_at = ${now}, completed_at = ${now},\n error_name = 'WorkflowError', error_message = ${callback.error}\n WHERE workflow_id = ${callback.workflowId}\n AND status NOT IN ('terminated', 'paused')\n `;\n await this.onWorkflowError(\n callback.workflowName,\n callback.workflowId,\n callback.error\n );\n break;\n case \"event\":\n // No status change for events - they can occur at any stage\n await this.onWorkflowEvent(\n callback.workflowName,\n callback.workflowId,\n callback.event\n );\n break;\n }\n }\n\n /**\n * Called when a workflow reports progress.\n * Override to handle progress updates.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param progress - Typed progress data (default: DefaultProgress)\n */\n async onWorkflowProgress(\n _workflowName: string,\n _workflowId: string,\n _progress: unknown\n ): Promise<void> {\n // Override to handle progress updates\n }\n\n /**\n * Called when a workflow completes successfully.\n * Override to handle completion.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param result - Optional result data\n */\n async onWorkflowComplete(\n _workflowName: string,\n _workflowId: string,\n _result?: unknown\n ): Promise<void> {\n // Override to handle completion\n }\n\n /**\n * Called when a workflow encounters an error.\n * Override to handle errors.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param error - Error message\n */\n async onWorkflowError(\n _workflowName: string,\n _workflowId: string,\n _error: string\n ): Promise<void> {\n // Override to handle errors\n }\n\n /**\n * Called when a workflow sends a custom event.\n * Override to handle custom events.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param event - Custom event payload\n */\n async onWorkflowEvent(\n _workflowName: string,\n _workflowId: string,\n _event: unknown\n ): Promise<void> {\n // Override to handle custom events\n }\n\n // ============================================================\n // Internal RPC methods for AgentWorkflow communication\n // These are called via DO RPC, not exposed via HTTP\n // ============================================================\n\n /**\n * Handle a workflow callback via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n async _workflow_handleCallback(callback: WorkflowCallback): Promise<void> {\n await this.onWorkflowCallback(callback);\n }\n\n /**\n * Broadcast a message to all connected clients via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n _workflow_broadcast(message: unknown): void {\n this.broadcast(JSON.stringify(message));\n }\n\n /**\n * Update agent state via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n _workflow_updateState(\n action: \"set\" | \"merge\" | \"reset\",\n state?: unknown\n ): void {\n if (action === \"set\") {\n this.setState(state as State);\n } else if (action === \"merge\") {\n const currentState = this.state ?? ({} as State);\n this.setState({\n ...currentState,\n ...(state as Record<string, unknown>)\n } as State);\n } else if (action === \"reset\") {\n this.setState(this.initialState);\n }\n }\n\n /**\n * Connect to a new MCP Server\n *\n * @example\n * // Simple usage\n * await this.addMcpServer(\"github\", \"https://mcp.github.com\");\n *\n * @example\n * // With options (preferred for custom headers, transport, etc.)\n * await this.addMcpServer(\"github\", \"https://mcp.github.com\", {\n * transport: { headers: { \"Authorization\": \"Bearer ...\" } }\n * });\n *\n * @example\n * // Legacy 5-parameter signature (still supported)\n * await this.addMcpServer(\"github\", url, callbackHost, agentsPrefix, options);\n *\n * @param serverName Name of the MCP server\n * @param url MCP Server URL\n * @param callbackHostOrOptions Options object, or callback host string (legacy)\n * @param agentsPrefix agents routing prefix if not using `agents` (legacy)\n * @param options MCP client and transport options (legacy)\n * @returns Server id and state - either \"authenticating\" with authUrl, or \"ready\"\n * @throws If connection or discovery fails\n */\n async addMcpServer(\n serverName: string,\n url: string,\n callbackHostOrOptions?: string | AddMcpServerOptions,\n agentsPrefix?: string,\n options?: {\n client?: ConstructorParameters<typeof Client>[1];\n transport?: {\n headers?: HeadersInit;\n type?: TransportType;\n };\n }\n ): Promise<\n | {\n id: string;\n state: typeof MCPConnectionState.AUTHENTICATING;\n authUrl: string;\n }\n | {\n id: string;\n state: typeof MCPConnectionState.READY;\n authUrl?: undefined;\n }\n > {\n // Normalize arguments - support both new options API and legacy positional API\n let resolvedCallbackHost: string | undefined;\n let resolvedAgentsPrefix: string;\n let resolvedOptions:\n | {\n client?: ConstructorParameters<typeof Client>[1];\n transport?: {\n headers?: HeadersInit;\n type?: TransportType;\n };\n }\n | undefined;\n\n let resolvedCallbackPath: string | undefined;\n\n if (\n typeof callbackHostOrOptions === \"object\" &&\n callbackHostOrOptions !== null\n ) {\n // New API: options object as third parameter\n resolvedCallbackHost = callbackHostOrOptions.callbackHost;\n resolvedCallbackPath = callbackHostOrOptions.callbackPath;\n resolvedAgentsPrefix = callbackHostOrOptions.agentsPrefix ?? \"agents\";\n resolvedOptions = {\n client: callbackHostOrOptions.client,\n transport: callbackHostOrOptions.transport\n };\n } else {\n // Legacy API: positional parameters\n resolvedCallbackHost = callbackHostOrOptions;\n resolvedAgentsPrefix = agentsPrefix ?? \"agents\";\n resolvedOptions = options;\n }\n\n // Enforce callbackPath when sendIdentityOnConnect is false\n if (!this._resolvedOptions.sendIdentityOnConnect && !resolvedCallbackPath) {\n throw new Error(\n \"callbackPath is required in addMcpServer options when sendIdentityOnConnect is false — \" +\n \"the default callback URL would expose the instance name. \" +\n \"Provide a callbackPath and route the callback request to this agent via getAgentByName.\"\n );\n }\n\n // If callbackHost is not provided, derive it from the current request\n if (!resolvedCallbackHost) {\n const { request } = getCurrentAgent();\n if (!request) {\n throw new Error(\n \"callbackHost is required when not called within a request context\"\n );\n }\n\n // Extract the origin from the request\n const requestUrl = new URL(request.url);\n resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;\n }\n\n // Build the callback URL: use callbackPath if provided, otherwise default to /agents/{class}/{name}/callback\n const normalizedHost = resolvedCallbackHost.replace(/\\/$/, \"\");\n const callbackUrl = resolvedCallbackPath\n ? `${normalizedHost}/${resolvedCallbackPath.replace(/^\\//, \"\")}`\n : `${normalizedHost}/${resolvedAgentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;\n\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n\n const id = nanoid(8);\n\n const authProvider = this.createMcpOAuthProvider(callbackUrl);\n authProvider.serverId = id;\n\n // Use the transport type specified in options, or default to \"auto\"\n const transportType: TransportType =\n resolvedOptions?.transport?.type ?? \"auto\";\n\n // allows passing through transport headers if necessary\n // this handles some non-standard bearer auth setups (i.e. MCP server behind CF access instead of OAuth)\n let headerTransportOpts: SSEClientTransportOptions = {};\n if (resolvedOptions?.transport?.headers) {\n headerTransportOpts = {\n eventSourceInit: {\n fetch: (url, init) =>\n fetch(url, {\n ...init,\n headers: resolvedOptions?.transport?.headers\n })\n },\n requestInit: {\n headers: resolvedOptions?.transport?.headers\n }\n };\n }\n\n // Register server (also saves to storage)\n await this.mcp.registerServer(id, {\n url,\n name: serverName,\n callbackUrl,\n client: resolvedOptions?.client,\n transport: {\n ...headerTransportOpts,\n authProvider,\n type: transportType\n }\n });\n\n const result = await this.mcp.connectToServer(id);\n\n if (result.state === MCPConnectionState.FAILED) {\n // Server stays in storage so user can retry via connectToServer(id)\n throw new Error(\n `Failed to connect to MCP server at ${url}: ${result.error}`\n );\n }\n\n if (result.state === MCPConnectionState.AUTHENTICATING) {\n return { id, state: result.state, authUrl: result.authUrl };\n }\n\n // State is CONNECTED - discover capabilities\n const discoverResult = await this.mcp.discoverIfConnected(id);\n\n if (discoverResult && !discoverResult.success) {\n // Server stays in storage - connection is still valid, user can retry discovery\n throw new Error(\n `Failed to discover MCP server capabilities: ${discoverResult.error}`\n );\n }\n\n return { id, state: MCPConnectionState.READY };\n }\n\n async removeMcpServer(id: string) {\n await this.mcp.removeServer(id);\n }\n\n getMcpServers(): MCPServersState {\n const mcpState: MCPServersState = {\n prompts: this.mcp.listPrompts(),\n resources: this.mcp.listResources(),\n servers: {},\n tools: this.mcp.listTools()\n };\n\n const servers = this.mcp.listServers();\n\n if (servers && Array.isArray(servers) && servers.length > 0) {\n for (const server of servers) {\n const serverConn = this.mcp.mcpConnections[server.id];\n\n // Determine the default state when no connection exists\n let defaultState: \"authenticating\" | \"not-connected\" = \"not-connected\";\n if (!serverConn && server.auth_url) {\n // If there's an auth_url but no connection, it's waiting for OAuth\n defaultState = \"authenticating\";\n }\n\n mcpState.servers[server.id] = {\n auth_url: server.auth_url,\n capabilities: serverConn?.serverCapabilities ?? null,\n error: serverConn?.connectionError ?? null,\n instructions: serverConn?.instructions ?? null,\n name: server.name,\n server_url: server.server_url,\n state: serverConn?.connectionState ?? defaultState\n };\n }\n }\n\n return mcpState;\n }\n\n /**\n * Create the OAuth provider used when connecting to MCP servers that require authentication.\n *\n * Override this method in a subclass to supply a custom OAuth provider implementation,\n * for example to use pre-registered client credentials, mTLS-based authentication,\n * or any other OAuth flow beyond dynamic client registration.\n *\n * @example\n * // Custom OAuth provider\n * class MyAgent extends Agent {\n * createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {\n * return new MyCustomOAuthProvider(\n * this.ctx.storage,\n * this.name,\n * callbackUrl\n * );\n * }\n * }\n *\n * @param callbackUrl The OAuth callback URL for the authorization flow\n * @returns An {@link AgentMcpOAuthProvider} instance used by {@link addMcpServer}\n */\n createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {\n return new DurableObjectOAuthClientProvider(\n this.ctx.storage,\n this.name,\n callbackUrl\n );\n }\n\n private broadcastMcpServers() {\n this.broadcast(\n JSON.stringify({\n mcp: this.getMcpServers(),\n type: MessageType.CF_AGENT_MCP_SERVERS\n })\n );\n }\n\n /**\n * Handle MCP OAuth callback request if it's an OAuth callback.\n *\n * This method encapsulates the entire OAuth callback flow:\n * 1. Checks if the request is an MCP OAuth callback\n * 2. Processes the OAuth code exchange\n * 3. Establishes the connection if successful\n * 4. Broadcasts MCP server state updates\n * 5. Returns the appropriate HTTP response\n *\n * @param request The incoming HTTP request\n * @returns Response if this was an OAuth callback, null otherwise\n */\n private async handleMcpOAuthCallback(\n request: Request\n ): Promise<Response | null> {\n // Check if this is an OAuth callback request\n const isCallback = this.mcp.isCallbackRequest(request);\n if (!isCallback) {\n return null;\n }\n\n // Handle the OAuth callback (exchanges code for token, clears OAuth credentials from storage)\n // This fires onServerStateChanged event which triggers broadcast\n const result = await this.mcp.handleCallbackRequest(request);\n\n // If auth was successful, establish the connection in the background\n if (result.authSuccess) {\n this.mcp.establishConnection(result.serverId).catch((error) => {\n console.error(\n \"[Agent handleMcpOAuthCallback] Connection establishment failed:\",\n error\n );\n });\n }\n\n this.broadcastMcpServers();\n\n // Return the HTTP response for the OAuth callback\n return this.handleOAuthCallbackResponse(result, request);\n }\n\n /**\n * Handle OAuth callback response using MCPClientManager configuration\n * @param result OAuth callback result\n * @param request The original request (needed for base URL)\n * @returns Response for the OAuth callback\n */\n private handleOAuthCallbackResponse(\n result: MCPClientOAuthResult,\n request: Request\n ): Response {\n const config = this.mcp.getOAuthCallbackConfig();\n\n // Use custom handler if configured\n if (config?.customHandler) {\n return config.customHandler(result);\n }\n\n const baseOrigin = new URL(request.url).origin;\n\n // Redirect to success URL if configured\n if (config?.successRedirect && result.authSuccess) {\n try {\n return Response.redirect(\n new URL(config.successRedirect, baseOrigin).href\n );\n } catch (e) {\n console.error(\n \"Invalid successRedirect URL:\",\n config.successRedirect,\n e\n );\n return Response.redirect(baseOrigin);\n }\n }\n\n // Redirect to error URL if configured\n if (config?.errorRedirect && !result.authSuccess) {\n try {\n const errorUrl = `${config.errorRedirect}?error=${encodeURIComponent(\n result.authError || \"Unknown error\"\n )}`;\n return Response.redirect(new URL(errorUrl, baseOrigin).href);\n } catch (e) {\n console.error(\"Invalid errorRedirect URL:\", config.errorRedirect, e);\n return Response.redirect(baseOrigin);\n }\n }\n\n // Default: redirect to base URL\n return Response.redirect(baseOrigin);\n }\n}\n\n// A set of classes that have been wrapped with agent context\nconst wrappedClasses = new Set<typeof Agent.prototype.constructor>();\n\n/**\n * Namespace for creating Agent instances\n * @template Agentic Type of the Agent class\n * @deprecated Use DurableObjectNamespace instead\n */\nexport type AgentNamespace<Agentic extends Agent<Cloudflare.Env>> =\n DurableObjectNamespace<Agentic>;\n\n/**\n * Agent's durable context\n */\nexport type AgentContext = DurableObjectState;\n\n/**\n * Configuration options for Agent routing\n */\nexport type AgentOptions<Env> = PartyServerOptions<Env>;\n\n/**\n * Route a request to the appropriate Agent\n * @param request Request to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n * @returns Response from the Agent or undefined if no route matched\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n) {\n return routePartykitRequest(request, env as Record<string, unknown>, {\n prefix: \"agents\",\n ...(options as PartyServerOptions<Record<string, unknown>>)\n });\n}\n\n// Email routing - deprecated resolver kept in root for upgrade discoverability\n// Other email utilities moved to agents/email subpath\nexport { createHeaderBasedEmailResolver } from \"./email\";\n\nimport type { EmailResolver } from \"./email\";\n\nexport type EmailRoutingOptions<Env> = AgentOptions<Env> & {\n resolver: EmailResolver<Env>;\n /**\n * Callback invoked when no routing information is found for an email.\n * Use this to reject the email or perform custom handling.\n * If not provided, a warning is logged and the email is dropped.\n */\n onNoRoute?: (email: ForwardableEmailMessage) => void | Promise<void>;\n};\n\n// Cache the agent namespace map for email routing\n// This maps both kebab-case and original names to namespaces\nconst agentMapCache = new WeakMap<\n Record<string, unknown>,\n Record<string, unknown>\n>();\n\n/**\n * Route an email to the appropriate Agent\n * @param email The email to route\n * @param env The environment containing the Agent bindings\n * @param options The options for routing the email\n * @returns A promise that resolves when the email has been routed\n */\nexport async function routeAgentEmail<\n Env extends Cloudflare.Env = Cloudflare.Env\n>(\n email: ForwardableEmailMessage,\n env: Env,\n options: EmailRoutingOptions<Env>\n): Promise<void> {\n const routingInfo = await options.resolver(email, env);\n\n if (!routingInfo) {\n if (options.onNoRoute) {\n await options.onNoRoute(email);\n } else {\n console.warn(\"No routing information found for email, dropping message\");\n }\n return;\n }\n\n // Build a map that includes both original names and kebab-case versions\n if (!agentMapCache.has(env as Record<string, unknown>)) {\n const map: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(env as Record<string, unknown>)) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n // Add both the original name and kebab-case version\n map[key] = value;\n map[camelCaseToKebabCase(key)] = value;\n }\n }\n agentMapCache.set(env as Record<string, unknown>, map);\n }\n\n const agentMap = agentMapCache.get(env as Record<string, unknown>)!;\n const namespace = agentMap[routingInfo.agentName];\n\n if (!namespace) {\n // Provide helpful error message listing available agents\n const availableAgents = Object.keys(agentMap)\n .filter((key) => !key.includes(\"-\")) // Show only original names, not kebab-case duplicates\n .join(\", \");\n throw new Error(\n `Agent namespace '${routingInfo.agentName}' not found in environment. Available agents: ${availableAgents}`\n );\n }\n\n const agent = await getAgentByName(\n namespace as unknown as DurableObjectNamespace<Agent<Env>>,\n routingInfo.agentId\n );\n\n // let's make a serialisable version of the email\n const serialisableEmail: AgentEmail = {\n getRaw: async () => {\n const reader = email.raw.getReader();\n const chunks: Uint8Array[] = [];\n\n let done = false;\n while (!done) {\n const { value, done: readerDone } = await reader.read();\n done = readerDone;\n if (value) {\n chunks.push(value);\n }\n }\n\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return combined;\n },\n headers: email.headers,\n rawSize: email.rawSize,\n setReject: (reason: string) => {\n email.setReject(reason);\n },\n forward: (rcptTo: string, headers?: Headers) => {\n return email.forward(rcptTo, headers);\n },\n reply: (replyOptions: { from: string; to: string; raw: string }) => {\n return email.reply(\n new EmailMessage(replyOptions.from, replyOptions.to, replyOptions.raw)\n );\n },\n from: email.from,\n to: email.to,\n _secureRouted: routingInfo._secureRouted\n };\n\n await agent._onEmail(serialisableEmail);\n}\n\n/**\n * Get or create an Agent by name\n * @template Env Environment type containing bindings\n * @template T Type of the Agent class\n * @param namespace Agent namespace\n * @param name Name of the Agent instance\n * @param options Options for Agent creation\n * @returns Promise resolving to an Agent instance stub\n */\nexport async function getAgentByName<\n Env extends Cloudflare.Env = Cloudflare.Env,\n T extends Agent<Env> = Agent<Env>,\n Props extends Record<string, unknown> = Record<string, unknown>\n>(\n namespace: DurableObjectNamespace<T>,\n name: string,\n options?: {\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n props?: Props;\n }\n) {\n return getServerByName<Env, T>(namespace, name, options);\n}\n\n/**\n * A wrapper for streaming responses in callable methods\n */\nexport class StreamingResponse {\n private _connection: Connection;\n private _id: string;\n private _closed = false;\n\n constructor(connection: Connection, id: string) {\n this._connection = connection;\n this._id = id;\n }\n\n /**\n * Whether the stream has been closed (via end() or error())\n */\n get isClosed(): boolean {\n return this._closed;\n }\n\n /**\n * Send a chunk of data to the client\n * @param chunk The data to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n send(chunk: unknown): boolean {\n if (this._closed) {\n console.warn(\n \"StreamingResponse.send() called after stream was closed - data not sent\"\n );\n return false;\n }\n const response: RPCResponse = {\n done: false,\n id: this._id,\n result: chunk,\n success: true,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n\n /**\n * End the stream and send the final chunk (if any)\n * @param finalChunk Optional final chunk of data to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n end(finalChunk?: unknown): boolean {\n if (this._closed) {\n return false;\n }\n this._closed = true;\n const response: RPCResponse = {\n done: true,\n id: this._id,\n result: finalChunk,\n success: true,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n\n /**\n * Send an error to the client and close the stream\n * @param message Error message to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n error(message: string): boolean {\n if (this._closed) {\n return false;\n }\n this._closed = true;\n const response: RPCResponse = {\n error: message,\n id: this._id,\n success: false,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["agentContext"],"sources":["../src/index.ts"],"sourcesContent":["import type { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n __DO_NOT_USE_WILL_BREAK__agentContext as agentContext,\n type AgentEmail\n} from \"./internal_context\";\nexport { __DO_NOT_USE_WILL_BREAK__agentContext } from \"./internal_context\";\nimport type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { signAgentHeaders } from \"./email\";\n\nimport type {\n Prompt,\n Resource,\n ServerCapabilities,\n Tool\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { parseCronExpression } from \"cron-schedule\";\nimport { nanoid } from \"nanoid\";\nimport { EmailMessage } from \"cloudflare:email\";\nimport {\n type Connection,\n type ConnectionContext,\n type PartyServerOptions,\n Server,\n type WSMessage,\n getServerByName,\n routePartykitRequest\n} from \"partyserver\";\nimport { camelCaseToKebabCase } from \"./utils\";\nimport { MCPClientManager, type MCPClientOAuthResult } from \"./mcp/client\";\nimport type {\n WorkflowCallback,\n WorkflowTrackingRow,\n WorkflowStatus,\n RunWorkflowOptions,\n WorkflowEventPayload,\n WorkflowInfo,\n WorkflowQueryCriteria,\n WorkflowPage\n} from \"./workflow-types\";\nimport { MCPConnectionState } from \"./mcp/client-connection\";\nimport {\n DurableObjectOAuthClientProvider,\n type AgentMcpOAuthProvider\n} from \"./mcp/do-oauth-client-provider\";\nimport type { TransportType } from \"./mcp/types\";\nimport { genericObservability, type Observability } from \"./observability\";\nimport { DisposableStore } from \"./core/events\";\nimport { MessageType } from \"./types\";\n\nexport type { Connection, ConnectionContext, WSMessage } from \"partyserver\";\n\n/**\n * RPC request message from client\n */\nexport type RPCRequest = {\n type: \"rpc\";\n id: string;\n method: string;\n args: unknown[];\n};\n\n/**\n * State update message from client\n */\nexport type StateUpdateMessage = {\n type: MessageType.CF_AGENT_STATE;\n state: unknown;\n};\n\n/**\n * RPC response message to client\n */\nexport type RPCResponse = {\n type: MessageType.RPC;\n id: string;\n} & (\n | {\n success: true;\n result: unknown;\n done?: false;\n }\n | {\n success: true;\n result: unknown;\n done: true;\n }\n | {\n success: false;\n error: string;\n }\n);\n\n/**\n * Type guard for RPC request messages\n */\nfunction isRPCRequest(msg: unknown): msg is RPCRequest {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === MessageType.RPC &&\n \"id\" in msg &&\n typeof msg.id === \"string\" &&\n \"method\" in msg &&\n typeof msg.method === \"string\" &&\n \"args\" in msg &&\n Array.isArray((msg as RPCRequest).args)\n );\n}\n\n/**\n * Type guard for state update messages\n */\nfunction isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {\n return (\n typeof msg === \"object\" &&\n msg !== null &&\n \"type\" in msg &&\n msg.type === MessageType.CF_AGENT_STATE &&\n \"state\" in msg\n );\n}\n\n/**\n * Metadata for a callable method\n */\nexport type CallableMetadata = {\n /** Optional description of what the method does */\n description?: string;\n /** Whether the method supports streaming responses */\n streaming?: boolean;\n};\n\nconst callableMetadata = new WeakMap<Function, CallableMetadata>();\n\n/**\n * Error class for SQL execution failures, containing the query that failed\n */\nexport class SqlError extends Error {\n /** The SQL query that failed */\n readonly query: string;\n\n constructor(query: string, cause: unknown) {\n const message = cause instanceof Error ? cause.message : String(cause);\n super(`SQL query failed: ${message}`, { cause });\n this.name = \"SqlError\";\n this.query = query;\n }\n}\n\n/**\n * Decorator that marks a method as callable by clients\n * @param metadata Optional metadata about the callable method\n */\nexport function callable(metadata: CallableMetadata = {}) {\n return function callableDecorator<This, Args extends unknown[], Return>(\n target: (this: This, ...args: Args) => Return,\n _context: ClassMethodDecoratorContext\n ) {\n if (!callableMetadata.has(target)) {\n callableMetadata.set(target, metadata);\n }\n\n return target;\n };\n}\n\nlet didWarnAboutUnstableCallable = false;\n\n/**\n * Decorator that marks a method as callable by clients\n * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version\n * @param metadata Optional metadata about the callable method\n */\nexport const unstable_callable = (metadata: CallableMetadata = {}) => {\n if (!didWarnAboutUnstableCallable) {\n didWarnAboutUnstableCallable = true;\n console.warn(\n \"unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version.\"\n );\n }\n return callable(metadata);\n};\n\nexport type QueueItem<T = string> = {\n id: string;\n payload: T;\n callback: keyof Agent<Cloudflare.Env>;\n created_at: number;\n};\n\n/**\n * Represents a scheduled task within an Agent\n * @template T Type of the payload data\n */\nexport type Schedule<T = string> = {\n /** Unique identifier for the schedule */\n id: string;\n /** Name of the method to be called */\n callback: string;\n /** Data to be passed to the callback */\n payload: T;\n} & (\n | {\n /** Type of schedule for one-time execution at a specific time */\n type: \"scheduled\";\n /** Timestamp when the task should execute */\n time: number;\n }\n | {\n /** Type of schedule for delayed execution */\n type: \"delayed\";\n /** Timestamp when the task should execute */\n time: number;\n /** Number of seconds to delay execution */\n delayInSeconds: number;\n }\n | {\n /** Type of schedule for recurring execution based on cron expression */\n type: \"cron\";\n /** Timestamp for the next execution */\n time: number;\n /** Cron expression defining the schedule */\n cron: string;\n }\n | {\n /** Type of schedule for recurring execution at fixed intervals */\n type: \"interval\";\n /** Timestamp for the next execution */\n time: number;\n /** Number of seconds between executions */\n intervalSeconds: number;\n }\n);\n\nfunction getNextCronTime(cron: string) {\n const interval = parseCronExpression(cron);\n return interval.getNextDate();\n}\n\nexport type { TransportType } from \"./mcp/types\";\nexport type {\n AgentMcpOAuthProvider,\n /** @deprecated Use {@link AgentMcpOAuthProvider} instead. */\n AgentsOAuthProvider\n} from \"./mcp/do-oauth-client-provider\";\n\n/**\n * MCP Server state update message from server -> Client\n */\nexport type MCPServerMessage = {\n type: MessageType.CF_AGENT_MCP_SERVERS;\n mcp: MCPServersState;\n};\n\nexport type MCPServersState = {\n servers: {\n [id: string]: MCPServer;\n };\n tools: (Tool & { serverId: string })[];\n prompts: (Prompt & { serverId: string })[];\n resources: (Resource & { serverId: string })[];\n};\n\nexport type MCPServer = {\n name: string;\n server_url: string;\n auth_url: string | null;\n // This state is specifically about the temporary process of getting a token (if needed).\n // Scope outside of that can't be relied upon because when the DO sleeps, there's no way\n // to communicate a change to a non-ready state.\n state: MCPConnectionState;\n error: string | null;\n instructions: string | null;\n capabilities: ServerCapabilities | null;\n};\n\n/**\n * Options for adding an MCP server\n */\nexport type AddMcpServerOptions = {\n /** OAuth callback host (auto-derived from request if omitted) */\n callbackHost?: string;\n /**\n * Custom callback URL path — bypasses the default `/agents/{class}/{name}/callback` construction.\n * Required when `sendIdentityOnConnect` is `false` to prevent leaking the instance name.\n * When set, the callback URL becomes `{callbackHost}/{callbackPath}`.\n * The developer must route this path to the agent instance via `getAgentByName`.\n * Should be a plain path (e.g., `/mcp-callback`) — do not include query strings or fragments.\n */\n callbackPath?: string;\n /** Agents routing prefix (default: \"agents\") */\n agentsPrefix?: string;\n /** MCP client options */\n client?: ConstructorParameters<typeof Client>[1];\n /** Transport options */\n transport?: {\n /** Custom headers for authentication (e.g., bearer tokens, CF Access) */\n headers?: HeadersInit;\n /** Transport type: \"sse\", \"streamable-http\", or \"auto\" (default) */\n type?: TransportType;\n };\n};\n\nconst STATE_ROW_ID = \"cf_state_row_id\";\nconst STATE_WAS_CHANGED = \"cf_state_was_changed\";\n\nconst DEFAULT_STATE = {} as unknown;\n\n/**\n * Internal key used to store the readonly flag in connection state.\n * Prefixed with _cf_ to avoid collision with user state keys.\n */\nconst CF_READONLY_KEY = \"_cf_readonly\";\n\n/**\n * Tracks which agent constructors have already emitted the onStateUpdate\n * deprecation warning, so it fires at most once per class.\n */\nconst _onStateUpdateWarnedClasses = new WeakSet<Function>();\n\n/**\n * Default options for Agent configuration.\n * Child classes can override specific options without spreading.\n */\nexport const DEFAULT_AGENT_STATIC_OPTIONS = {\n /** Whether the Agent should hibernate when inactive */\n hibernate: true,\n /** Whether to send identity (name, agent) to clients on connect */\n sendIdentityOnConnect: true,\n /**\n * Timeout in seconds before a running interval schedule is considered \"hung\"\n * and force-reset. Increase this if you have callbacks that legitimately\n * take longer than 30 seconds.\n */\n hungScheduleTimeoutSeconds: 30\n};\n\ntype ResolvedAgentOptions = typeof DEFAULT_AGENT_STATIC_OPTIONS;\n\n/**\n * Configuration options for the Agent.\n * Override in subclasses via `static options`.\n * All fields are optional - defaults are applied at runtime.\n * Note: `hibernate` defaults to `true` if not specified.\n */\nexport type AgentStaticOptions = Partial<ResolvedAgentOptions>;\n\nexport function getCurrentAgent<\n T extends Agent<Cloudflare.Env> = Agent<Cloudflare.Env>\n>(): {\n agent: T | undefined;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n} {\n const store = agentContext.getStore() as\n | {\n agent: T;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n }\n | undefined;\n if (!store) {\n return {\n agent: undefined,\n connection: undefined,\n request: undefined,\n email: undefined\n };\n }\n return store;\n}\n\n/**\n * Wraps a method to run within the agent context, ensuring getCurrentAgent() works properly\n * @param agent The agent instance\n * @param method The method to wrap\n * @returns A wrapped method that runs within the agent context\n */\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic callable constraint\nfunction withAgentContext<T extends (...args: any[]) => any>(\n method: T\n): (\n this: Agent<Cloudflare.Env, unknown>,\n ...args: Parameters<T>\n) => ReturnType<T> {\n return function (...args: Parameters<T>): ReturnType<T> {\n const { connection, request, email, agent } = getCurrentAgent();\n\n if (agent === this) {\n // already wrapped, so we can just call the method\n return method.apply(this, args);\n }\n // not wrapped, so we need to wrap it\n return agentContext.run({ agent: this, connection, request, email }, () => {\n return method.apply(this, args);\n });\n };\n}\n\n/**\n * Extract string keys from Env where the value is a Workflow binding.\n */\ntype WorkflowBinding<E> = {\n [K in keyof E & string]: E[K] extends Workflow ? K : never;\n}[keyof E & string];\n\n/**\n * Type for workflow name parameter.\n * When Env has typed Workflow bindings, provides autocomplete for those keys.\n * Also accepts any string for dynamic use cases and compatibility.\n * The `string & {}` trick preserves autocomplete while allowing any string.\n */\ntype WorkflowName<E> = WorkflowBinding<E> | (string & {});\n\n/**\n * Base class for creating Agent implementations\n * @template Env Environment type containing bindings\n * @template State State type to store within the Agent\n */\nexport class Agent<\n Env extends Cloudflare.Env = Cloudflare.Env,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends Server<Env, Props> {\n private _state = DEFAULT_STATE as State;\n private _disposables = new DisposableStore();\n private _destroyed = false;\n\n /**\n * Stores raw state accessors for wrapped connections.\n * Used by setConnectionReadonly/isConnectionReadonly to read/write the\n * _cf_readonly flag without going through the user-facing state/setState.\n */\n private _rawStateAccessors = new WeakMap<\n Connection,\n {\n getRaw: () => Record<string, unknown> | null;\n setRaw: (state: unknown) => unknown;\n }\n >();\n\n /**\n * Cached persistence-hook dispatch mode, computed once in the constructor.\n * - \"new\" → call onStateChanged\n * - \"old\" → call onStateUpdate (deprecated)\n * - \"none\" → neither hook is overridden, skip entirely\n */\n private _persistenceHookMode: \"new\" | \"old\" | \"none\" = \"none\";\n\n private _ParentClass: typeof Agent<Env, State> =\n Object.getPrototypeOf(this).constructor;\n\n readonly mcp: MCPClientManager;\n\n /**\n * Initial state for the Agent\n * Override to provide default state values\n */\n initialState: State = DEFAULT_STATE as State;\n\n /**\n * Current state of the Agent\n */\n get state(): State {\n if (this._state !== DEFAULT_STATE) {\n // state was previously set, and populated internal state\n return this._state;\n }\n // looks like this is the first time the state is being accessed\n // check if the state was set in a previous life\n const wasChanged = this.sql<{ state: \"true\" | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}\n `;\n\n // ok, let's pick up the actual state from the db\n const result = this.sql<{ state: State | undefined }>`\n SELECT state FROM cf_agents_state WHERE id = ${STATE_ROW_ID}\n `;\n\n if (\n wasChanged[0]?.state === \"true\" ||\n // we do this check for people who updated their code before we shipped wasChanged\n result[0]?.state\n ) {\n const state = result[0]?.state as string; // could be null?\n\n try {\n this._state = JSON.parse(state);\n } catch (e) {\n console.error(\n \"Failed to parse stored state, falling back to initialState:\",\n e\n );\n if (this.initialState !== DEFAULT_STATE) {\n this._state = this.initialState;\n // Persist the fixed state to prevent future parse errors\n this._setStateInternal(this.initialState);\n } else {\n // No initialState defined - clear corrupted data to prevent infinite retry loop\n this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_ROW_ID}`;\n this.sql`DELETE FROM cf_agents_state WHERE id = ${STATE_WAS_CHANGED}`;\n return undefined as State;\n }\n }\n return this._state;\n }\n\n // ok, this is the first time the state is being accessed\n // and the state was not set in a previous life\n // so we need to set the initial state (if provided)\n if (this.initialState === DEFAULT_STATE) {\n // no initial state provided, so we return undefined\n return undefined as State;\n }\n // initial state provided, so we set the state,\n // update db and return the initial state\n this._setStateInternal(this.initialState);\n return this.initialState;\n }\n\n /**\n * Agent configuration options.\n * Override in subclasses - only specify what you want to change.\n * @example\n * class SecureAgent extends Agent {\n * static options = { sendIdentityOnConnect: false };\n * }\n */\n static options: AgentStaticOptions = { hibernate: true };\n\n /**\n * Resolved options (merges defaults with subclass overrides)\n */\n private get _resolvedOptions(): ResolvedAgentOptions {\n const ctor = this.constructor as typeof Agent;\n return {\n hibernate:\n ctor.options?.hibernate ?? DEFAULT_AGENT_STATIC_OPTIONS.hibernate,\n sendIdentityOnConnect:\n ctor.options?.sendIdentityOnConnect ??\n DEFAULT_AGENT_STATIC_OPTIONS.sendIdentityOnConnect,\n hungScheduleTimeoutSeconds:\n ctor.options?.hungScheduleTimeoutSeconds ??\n DEFAULT_AGENT_STATIC_OPTIONS.hungScheduleTimeoutSeconds\n };\n }\n\n /**\n * The observability implementation to use for the Agent\n */\n observability?: Observability = genericObservability;\n\n /**\n * Execute SQL queries against the Agent's database\n * @template T Type of the returned rows\n * @param strings SQL query template strings\n * @param values Values to be inserted into the query\n * @returns Array of query results\n */\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n let query = \"\";\n try {\n // Construct the SQL query with placeholders\n query = strings.reduce(\n (acc, str, i) => acc + str + (i < values.length ? \"?\" : \"\"),\n \"\"\n );\n\n // Execute the SQL query with the provided values\n return [...this.ctx.storage.sql.exec(query, ...values)] as T[];\n } catch (e) {\n throw this.onError(new SqlError(query, e));\n }\n }\n constructor(ctx: AgentContext, env: Env) {\n super(ctx, env);\n\n if (!wrappedClasses.has(this.constructor)) {\n // Auto-wrap custom methods with agent context\n this._autoWrapCustomMethods();\n wrappedClasses.add(this.constructor);\n }\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (\n id TEXT PRIMARY KEY NOT NULL,\n name TEXT NOT NULL,\n server_url TEXT NOT NULL,\n callback_url TEXT NOT NULL,\n client_id TEXT,\n auth_url TEXT,\n server_options TEXT\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_state (\n id TEXT PRIMARY KEY NOT NULL,\n state TEXT\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_queues (\n id TEXT PRIMARY KEY NOT NULL,\n payload TEXT,\n callback TEXT,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_schedules (\n id TEXT PRIMARY KEY NOT NULL DEFAULT (randomblob(9)),\n callback TEXT,\n payload TEXT,\n type TEXT NOT NULL CHECK(type IN ('scheduled', 'delayed', 'cron', 'interval')),\n time INTEGER,\n delayInSeconds INTEGER,\n cron TEXT,\n intervalSeconds INTEGER,\n running INTEGER DEFAULT 0,\n created_at INTEGER DEFAULT (unixepoch())\n )\n `;\n\n // Migration: Add columns for interval scheduling (for existing agents)\n // Use raw exec to avoid error logging through onError for expected failures\n const addColumnIfNotExists = (sql: string) => {\n try {\n this.ctx.storage.sql.exec(sql);\n } catch (e) {\n // Only ignore \"duplicate column\" errors, re-throw unexpected errors\n const message = e instanceof Error ? e.message : String(e);\n if (!message.toLowerCase().includes(\"duplicate column\")) {\n throw e;\n }\n }\n };\n\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN intervalSeconds INTEGER\"\n );\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN running INTEGER DEFAULT 0\"\n );\n addColumnIfNotExists(\n \"ALTER TABLE cf_agents_schedules ADD COLUMN execution_started_at INTEGER\"\n );\n\n // Workflow tracking table for Agent-Workflow integration\n this.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_workflows (\n id TEXT PRIMARY KEY NOT NULL,\n workflow_id TEXT NOT NULL UNIQUE,\n workflow_name TEXT NOT NULL,\n status TEXT NOT NULL CHECK(status IN (\n 'queued', 'running', 'paused', 'errored',\n 'terminated', 'complete', 'waiting',\n 'waitingForPause', 'unknown'\n )),\n metadata TEXT,\n error_name TEXT,\n error_message TEXT,\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\n updated_at INTEGER NOT NULL DEFAULT (unixepoch()),\n completed_at INTEGER\n )\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS idx_workflows_status ON cf_agents_workflows(status)\n `;\n\n this.sql`\n CREATE INDEX IF NOT EXISTS idx_workflows_name ON cf_agents_workflows(workflow_name)\n `;\n\n // Initialize MCPClientManager AFTER tables are created\n this.mcp = new MCPClientManager(this._ParentClass.name, \"0.0.1\", {\n storage: this.ctx.storage\n });\n\n // Broadcast server state whenever MCP state changes (register, connect, OAuth, remove, etc.)\n this._disposables.add(\n this.mcp.onServerStateChanged(async () => {\n this.broadcastMcpServers();\n })\n );\n\n // Emit MCP observability events\n this._disposables.add(\n this.mcp.onObservabilityEvent((event) => {\n this.observability?.emit(event);\n })\n );\n // Compute persistence-hook dispatch mode once.\n // Throws immediately if both hooks are overridden on the same class.\n {\n const proto = Object.getPrototypeOf(this);\n const hasOwnNew = Object.prototype.hasOwnProperty.call(\n proto,\n \"onStateChanged\"\n );\n const hasOwnOld = Object.prototype.hasOwnProperty.call(\n proto,\n \"onStateUpdate\"\n );\n\n if (hasOwnNew && hasOwnOld) {\n throw new Error(\n `[Agent] Cannot override both onStateChanged and onStateUpdate. ` +\n `Remove onStateUpdate — it has been renamed to onStateChanged.`\n );\n }\n\n if (hasOwnOld) {\n const ctor = this.constructor;\n if (!_onStateUpdateWarnedClasses.has(ctor)) {\n _onStateUpdateWarnedClasses.add(ctor);\n console.warn(\n `[Agent] onStateUpdate is deprecated. Rename to onStateChanged — the behavior is identical.`\n );\n }\n }\n\n const base = Agent.prototype;\n if (proto.onStateChanged !== base.onStateChanged) {\n this._persistenceHookMode = \"new\";\n } else if (proto.onStateUpdate !== base.onStateUpdate) {\n this._persistenceHookMode = \"old\";\n }\n // default \"none\" already set in field initializer\n }\n\n const _onRequest = this.onRequest.bind(this);\n this.onRequest = (request: Request) => {\n return agentContext.run(\n { agent: this, connection: undefined, request, email: undefined },\n async () => {\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n\n // Handle MCP OAuth callback if this is one\n const oauthResponse = await this.handleMcpOAuthCallback(request);\n if (oauthResponse) {\n return oauthResponse;\n }\n\n return this._tryCatch(() => _onRequest(request));\n }\n );\n };\n\n const _onMessage = this.onMessage.bind(this);\n this.onMessage = async (connection: Connection, message: WSMessage) => {\n this._ensureConnectionWrapped(connection);\n return agentContext.run(\n { agent: this, connection, request: undefined, email: undefined },\n async () => {\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n if (typeof message !== \"string\") {\n return this._tryCatch(() => _onMessage(connection, message));\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(message);\n } catch (_e) {\n // silently fail and let the onMessage handler handle it\n return this._tryCatch(() => _onMessage(connection, message));\n }\n\n if (isStateUpdateMessage(parsed)) {\n // Check if connection is readonly\n if (this.isConnectionReadonly(connection)) {\n // Send error response back to the connection\n connection.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"Connection is readonly\"\n })\n );\n return;\n }\n try {\n this._setStateInternal(parsed.state as State, connection);\n } catch (e) {\n // validateStateChange (or another sync error) rejected the update.\n // Log the full error server-side, send a generic message to the client.\n console.error(\"[Agent] State update rejected:\", e);\n connection.send(\n JSON.stringify({\n type: MessageType.CF_AGENT_STATE_ERROR,\n error: \"State update rejected\"\n })\n );\n }\n return;\n }\n\n if (isRPCRequest(parsed)) {\n try {\n const { id, method, args } = parsed;\n\n // Check if method exists and is callable\n const methodFn = this[method as keyof this];\n if (typeof methodFn !== \"function\") {\n throw new Error(`Method ${method} does not exist`);\n }\n\n if (!this._isCallable(method)) {\n throw new Error(`Method ${method} is not callable`);\n }\n\n const metadata = callableMetadata.get(methodFn as Function);\n\n // For streaming methods, pass a StreamingResponse object\n if (metadata?.streaming) {\n const stream = new StreamingResponse(connection, id);\n\n this.observability?.emit(\n {\n displayMessage: `RPC streaming call to ${method}`,\n id: nanoid(),\n payload: {\n method,\n streaming: true\n },\n timestamp: Date.now(),\n type: \"rpc\"\n },\n this.ctx\n );\n\n try {\n await methodFn.apply(this, [stream, ...args]);\n } catch (err) {\n // Log error server-side for observability\n console.error(`Error in streaming method \"${method}\":`, err);\n // Auto-close stream with error if method throws before closing\n if (!stream.isClosed) {\n stream.error(\n err instanceof Error ? err.message : String(err)\n );\n }\n }\n return;\n }\n\n // For regular methods, execute and send response\n const result = await methodFn.apply(this, args);\n\n this.observability?.emit(\n {\n displayMessage: `RPC call to ${method}`,\n id: nanoid(),\n payload: {\n method,\n streaming: metadata?.streaming\n },\n timestamp: Date.now(),\n type: \"rpc\"\n },\n this.ctx\n );\n\n const response: RPCResponse = {\n done: true,\n id,\n result,\n success: true,\n type: MessageType.RPC\n };\n connection.send(JSON.stringify(response));\n } catch (e) {\n // Send error response\n const response: RPCResponse = {\n error:\n e instanceof Error ? e.message : \"Unknown error occurred\",\n id: parsed.id,\n success: false,\n type: MessageType.RPC\n };\n connection.send(JSON.stringify(response));\n console.error(\"RPC error:\", e);\n }\n return;\n }\n\n return this._tryCatch(() => _onMessage(connection, message));\n }\n );\n };\n\n const _onConnect = this.onConnect.bind(this);\n this.onConnect = (connection: Connection, ctx: ConnectionContext) => {\n this._ensureConnectionWrapped(connection);\n // TODO: This is a hack to ensure the state is sent after the connection is established\n // must fix this\n return agentContext.run(\n { agent: this, connection, request: ctx.request, email: undefined },\n async () => {\n // Check if connection should be readonly before sending any messages\n // so that the flag is set before the client can respond\n if (this.shouldConnectionBeReadonly(connection, ctx)) {\n this.setConnectionReadonly(connection, true);\n }\n\n // Send agent identity first so client knows which instance it's connected to\n // Can be disabled via static options for security-sensitive instance names\n if (this._resolvedOptions.sendIdentityOnConnect) {\n connection.send(\n JSON.stringify({\n name: this.name,\n agent: camelCaseToKebabCase(this._ParentClass.name),\n type: MessageType.CF_AGENT_IDENTITY\n })\n );\n }\n\n if (this.state) {\n connection.send(\n JSON.stringify({\n state: this.state,\n type: MessageType.CF_AGENT_STATE\n })\n );\n }\n\n connection.send(\n JSON.stringify({\n mcp: this.getMcpServers(),\n type: MessageType.CF_AGENT_MCP_SERVERS\n })\n );\n\n this.observability?.emit(\n {\n displayMessage: \"Connection established\",\n id: nanoid(),\n payload: {\n connectionId: connection.id\n },\n timestamp: Date.now(),\n type: \"connect\"\n },\n this.ctx\n );\n return this._tryCatch(() => _onConnect(connection, ctx));\n }\n );\n };\n\n const _onStart = this.onStart.bind(this);\n this.onStart = async (props?: Props) => {\n return agentContext.run(\n {\n agent: this,\n connection: undefined,\n request: undefined,\n email: undefined\n },\n async () => {\n await this._tryCatch(async () => {\n await this.mcp.restoreConnectionsFromStorage(this.name);\n this.broadcastMcpServers();\n\n // Check for orphaned workflows (tracked but binding no longer exists)\n this._checkOrphanedWorkflows();\n\n return _onStart(props);\n });\n }\n );\n };\n }\n\n /**\n * Check for workflows referencing unknown bindings and warn with migration suggestion.\n */\n private _checkOrphanedWorkflows(): void {\n // Get distinct workflow names with counts by active/completed status\n const distinctNames = this.sql<{\n workflow_name: string;\n total: number;\n active: number;\n completed: number;\n }>`\n SELECT \n workflow_name,\n COUNT(*) as total,\n SUM(CASE WHEN status NOT IN ('complete', 'errored', 'terminated') THEN 1 ELSE 0 END) as active,\n SUM(CASE WHEN status IN ('complete', 'errored', 'terminated') THEN 1 ELSE 0 END) as completed\n FROM cf_agents_workflows \n GROUP BY workflow_name\n `;\n\n const orphaned = distinctNames.filter(\n (row) => !this._findWorkflowBindingByName(row.workflow_name)\n );\n\n if (orphaned.length > 0) {\n const currentBindings = this._getWorkflowBindingNames();\n for (const {\n workflow_name: oldName,\n total,\n active,\n completed\n } of orphaned) {\n const suggestion =\n currentBindings.length === 1\n ? `this.migrateWorkflowBinding('${oldName}', '${currentBindings[0]}')`\n : `this.migrateWorkflowBinding('${oldName}', '<NEW_BINDING_NAME>')`;\n const breakdown =\n active > 0 && completed > 0\n ? ` (${active} active, ${completed} completed)`\n : active > 0\n ? ` (${active} active)`\n : ` (${completed} completed)`;\n console.warn(\n `[Agent] Found ${total} workflow(s) referencing unknown binding '${oldName}'${breakdown}. ` +\n `If you renamed the binding, call: ${suggestion}`\n );\n }\n }\n }\n\n private _setStateInternal(\n nextState: State,\n source: Connection | \"server\" = \"server\"\n ): void {\n // Validation/gating hook (sync only)\n this.validateStateChange(nextState, source);\n\n // Persist state\n this._state = nextState;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_ROW_ID}, ${JSON.stringify(nextState)})\n `;\n this.sql`\n INSERT OR REPLACE INTO cf_agents_state (id, state)\n VALUES (${STATE_WAS_CHANGED}, ${JSON.stringify(true)})\n `;\n\n // Broadcast state to connected clients immediately\n this.broadcast(\n JSON.stringify({\n state: nextState,\n type: MessageType.CF_AGENT_STATE\n }),\n source !== \"server\" ? [source.id] : []\n );\n\n // Notification hook (non-gating). Run after broadcast and do not block.\n // Use waitUntil for reliability after the handler returns.\n const { connection, request, email } = agentContext.getStore() || {};\n this.ctx.waitUntil(\n (async () => {\n try {\n await agentContext.run(\n { agent: this, connection, request, email },\n async () => {\n this.observability?.emit(\n {\n displayMessage: \"State updated\",\n id: nanoid(),\n payload: {},\n timestamp: Date.now(),\n type: \"state:update\"\n },\n this.ctx\n );\n await this._callStatePersistenceHook(nextState, source);\n }\n );\n } catch (e) {\n // onStateChanged/onStateUpdate errors should not affect state or broadcasts\n try {\n await this.onError(e);\n } catch {\n // swallow\n }\n }\n })()\n );\n }\n\n /**\n * Update the Agent's state\n * @param state New state to set\n * @throws Error if called from a readonly connection context\n */\n setState(state: State): void {\n // Check if the current context has a readonly connection\n const store = agentContext.getStore();\n if (store?.connection && this.isConnectionReadonly(store.connection)) {\n throw new Error(\"Connection is readonly\");\n }\n this._setStateInternal(state, \"server\");\n }\n\n /**\n * Wraps connection.state and connection.setState so that the internal\n * _cf_readonly flag is hidden from user code and cannot be accidentally\n * overwritten. Must be called before any user code sees the connection.\n *\n * Idempotent — safe to call multiple times on the same connection.\n */\n private _ensureConnectionWrapped(connection: Connection) {\n if (this._rawStateAccessors.has(connection)) return;\n\n // Determine whether `state` is an accessor (getter) or a data property.\n // partyserver always defines `state` as a getter via Object.defineProperties,\n // but we handle the data-property case to stay robust for hibernate: false\n // and any future connection implementations.\n const descriptor = Object.getOwnPropertyDescriptor(connection, \"state\");\n\n let getRaw: () => Record<string, unknown> | null;\n let setRaw: (state: unknown) => unknown;\n\n if (descriptor?.get) {\n // Accessor property — bind the original getter directly.\n // The getter reads from the serialized WebSocket attachment, so it\n // always returns the latest value even after setState updates it.\n getRaw = descriptor.get.bind(connection) as () => Record<\n string,\n unknown\n > | null;\n setRaw = connection.setState.bind(connection);\n } else {\n // Data property — track raw state in a closure variable.\n // Reading `connection.state` after our override would call our filtered\n // getter (circular), so we snapshot the value here and keep it in sync.\n let rawState = (connection.state ?? null) as Record<\n string,\n unknown\n > | null;\n getRaw = () => rawState;\n setRaw = (state: unknown) => {\n rawState = state as Record<string, unknown> | null;\n return rawState;\n };\n }\n\n this._rawStateAccessors.set(connection, { getRaw, setRaw });\n\n const CF_KEY = CF_READONLY_KEY;\n\n // Override state getter to hide the readonly flag from user code\n Object.defineProperty(connection, \"state\", {\n configurable: true,\n enumerable: true,\n get() {\n const raw = getRaw();\n if (raw != null && typeof raw === \"object\" && CF_KEY in raw) {\n const { [CF_KEY]: _, ...userState } = raw;\n return Object.keys(userState).length > 0 ? userState : null;\n }\n return raw;\n }\n });\n\n // Override setState to preserve the readonly flag when user sets state\n Object.defineProperty(connection, \"setState\", {\n configurable: true,\n writable: true,\n value(stateOrFn: unknown | ((prev: unknown) => unknown)) {\n const raw = getRaw();\n const readonlyFlag =\n raw != null && typeof raw === \"object\"\n ? (raw as Record<string, unknown>)[CF_KEY]\n : undefined;\n\n let newUserState: unknown;\n if (typeof stateOrFn === \"function\") {\n // Pass only the user-visible state (without the readonly flag) to the callback\n let userVisible: unknown = raw;\n if (raw != null && typeof raw === \"object\" && CF_KEY in raw) {\n const { [CF_KEY]: _, ...rest } = raw;\n userVisible = Object.keys(rest).length > 0 ? rest : null;\n }\n newUserState = (stateOrFn as (prev: unknown) => unknown)(userVisible);\n } else {\n newUserState = stateOrFn;\n }\n\n // Merge back the readonly flag if it was set\n if (readonlyFlag !== undefined) {\n if (newUserState != null && typeof newUserState === \"object\") {\n return setRaw({\n ...(newUserState as Record<string, unknown>),\n [CF_KEY]: readonlyFlag\n });\n }\n // User set null — store just the flag\n return setRaw({ [CF_KEY]: readonlyFlag });\n }\n return setRaw(newUserState);\n }\n });\n }\n\n /**\n * Mark a connection as readonly or readwrite\n * @param connection The connection to mark\n * @param readonly Whether the connection should be readonly (default: true)\n */\n setConnectionReadonly(connection: Connection, readonly = true) {\n this._ensureConnectionWrapped(connection);\n const accessors = this._rawStateAccessors.get(connection)!;\n const raw = (accessors.getRaw() as Record<string, unknown> | null) ?? {};\n if (readonly) {\n accessors.setRaw({ ...raw, [CF_READONLY_KEY]: true });\n } else {\n // Remove the key entirely instead of storing false — avoids dead keys\n // accumulating in the connection attachment.\n const { [CF_READONLY_KEY]: _, ...rest } = raw;\n accessors.setRaw(Object.keys(rest).length > 0 ? rest : null);\n }\n }\n\n /**\n * Check if a connection is marked as readonly\n * @param connection The connection to check\n * @returns True if the connection is readonly\n */\n isConnectionReadonly(connection: Connection): boolean {\n const accessors = this._rawStateAccessors.get(connection);\n if (accessors) {\n return !!(accessors.getRaw() as Record<string, unknown> | null)?.[\n CF_READONLY_KEY\n ];\n }\n // Connection hasn't been wrapped yet — the flag can't have been set via\n // setConnectionReadonly (which always wraps first), so default to false.\n return false;\n }\n\n /**\n * Override this method to determine if a connection should be readonly on connect\n * @param _connection The connection that is being established\n * @param _ctx Connection context\n * @returns True if the connection should be readonly\n */\n shouldConnectionBeReadonly(\n _connection: Connection,\n _ctx: ConnectionContext\n ): boolean {\n return false;\n }\n\n /**\n * Called before the Agent's state is persisted and broadcast.\n * Override to validate or reject an update by throwing an error.\n *\n * IMPORTANT: This hook must be synchronous.\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n validateStateChange(nextState: State, source: Connection | \"server\") {\n // override this to validate state updates\n }\n\n /**\n * Called after the Agent's state has been persisted and broadcast to all clients.\n * This is a notification hook — errors here are routed to onError and do not\n * affect state persistence or client broadcasts.\n *\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n onStateChanged(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates after persist + broadcast\n }\n\n /**\n * @deprecated Renamed to `onStateChanged` — the behavior is identical.\n * `onStateUpdate` will be removed in the next major version.\n *\n * Called after the Agent's state has been persisted and broadcast to all clients.\n * This is a server-side notification hook. For the client-side state callback,\n * see the `onStateUpdate` option in `useAgent` / `AgentClient`.\n *\n * @param state Updated state\n * @param source Source of the state update (\"server\" or a client connection)\n */\n // oxlint-disable-next-line eslint(no-unused-vars) -- params used by subclass overrides\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates (deprecated — use onStateChanged)\n }\n\n /**\n * Dispatch to the appropriate persistence hook based on the mode\n * cached in the constructor. No prototype walks at call time.\n */\n private async _callStatePersistenceHook(\n state: State | undefined,\n source: Connection | \"server\"\n ): Promise<void> {\n switch (this._persistenceHookMode) {\n case \"new\":\n await this.onStateChanged(state, source);\n break;\n case \"old\":\n await this.onStateUpdate(state, source);\n break;\n // \"none\": neither hook overridden — skip\n }\n }\n\n /**\n * Called when the Agent receives an email via routeAgentEmail()\n * Override this method to handle incoming emails\n * @param email Email message to process\n */\n async _onEmail(email: AgentEmail) {\n // nb: we use this roundabout way of getting to onEmail\n // because of https://github.com/cloudflare/workerd/issues/4499\n return agentContext.run(\n { agent: this, connection: undefined, request: undefined, email: email },\n async () => {\n if (\"onEmail\" in this && typeof this.onEmail === \"function\") {\n return this._tryCatch(() =>\n (this.onEmail as (email: AgentEmail) => Promise<void>)(email)\n );\n } else {\n console.log(\"Received email from:\", email.from, \"to:\", email.to);\n console.log(\"Subject:\", email.headers.get(\"subject\"));\n console.log(\n \"Implement onEmail(email: AgentEmail): Promise<void> in your agent to process emails\"\n );\n }\n }\n );\n }\n\n /**\n * Reply to an email\n * @param email The email to reply to\n * @param options Options for the reply\n * @param options.secret Secret for signing agent headers (enables secure reply routing).\n * Required if the email was routed via createSecureReplyEmailResolver.\n * Pass explicit `null` to opt-out of signing (not recommended for secure routing).\n * @returns void\n */\n async replyToEmail(\n email: AgentEmail,\n options: {\n fromName: string;\n subject?: string | undefined;\n body: string;\n contentType?: string;\n headers?: Record<string, string>;\n secret?: string | null;\n }\n ): Promise<void> {\n return this._tryCatch(async () => {\n // Enforce signing for emails routed via createSecureReplyEmailResolver\n if (email._secureRouted && options.secret === undefined) {\n throw new Error(\n \"This email was routed via createSecureReplyEmailResolver. \" +\n \"You must pass a secret to replyToEmail() to sign replies, \" +\n \"or pass explicit null to opt-out (not recommended).\"\n );\n }\n\n const agentName = camelCaseToKebabCase(this._ParentClass.name);\n const agentId = this.name;\n\n const { createMimeMessage } = await import(\"mimetext\");\n const msg = createMimeMessage();\n msg.setSender({ addr: email.to, name: options.fromName });\n msg.setRecipient(email.from);\n msg.setSubject(\n options.subject || `Re: ${email.headers.get(\"subject\")}` || \"No subject\"\n );\n msg.addMessage({\n contentType: options.contentType || \"text/plain\",\n data: options.body\n });\n\n const domain = email.from.split(\"@\")[1];\n const messageId = `<${agentId}@${domain}>`;\n msg.setHeader(\"In-Reply-To\", email.headers.get(\"Message-ID\")!);\n msg.setHeader(\"Message-ID\", messageId);\n msg.setHeader(\"X-Agent-Name\", agentName);\n msg.setHeader(\"X-Agent-ID\", agentId);\n\n // Sign headers if secret is provided (enables secure reply routing)\n if (typeof options.secret === \"string\") {\n const signedHeaders = await signAgentHeaders(\n options.secret,\n agentName,\n agentId\n );\n msg.setHeader(\"X-Agent-Sig\", signedHeaders[\"X-Agent-Sig\"]);\n msg.setHeader(\"X-Agent-Sig-Ts\", signedHeaders[\"X-Agent-Sig-Ts\"]);\n }\n\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n msg.setHeader(key, value);\n }\n }\n await email.reply({\n from: email.to,\n raw: msg.asRaw(),\n to: email.from\n });\n });\n }\n\n private async _tryCatch<T>(fn: () => T | Promise<T>) {\n try {\n return await fn();\n } catch (e) {\n throw this.onError(e);\n }\n }\n\n /**\n * Automatically wrap custom methods with agent context\n * This ensures getCurrentAgent() works in all custom methods without decorators\n */\n private _autoWrapCustomMethods() {\n // Collect all methods from base prototypes (Agent and Server)\n const basePrototypes = [Agent.prototype, Server.prototype];\n const baseMethods = new Set<string>();\n for (const baseProto of basePrototypes) {\n let proto = baseProto;\n while (proto && proto !== Object.prototype) {\n const methodNames = Object.getOwnPropertyNames(proto);\n for (const methodName of methodNames) {\n baseMethods.add(methodName);\n }\n proto = Object.getPrototypeOf(proto);\n }\n }\n // Get all methods from the current instance's prototype chain\n let proto = Object.getPrototypeOf(this);\n let depth = 0;\n while (proto && proto !== Object.prototype && depth < 10) {\n const methodNames = Object.getOwnPropertyNames(proto);\n for (const methodName of methodNames) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);\n\n // Skip if it's a private method, a base method, a getter, or not a function,\n if (\n baseMethods.has(methodName) ||\n methodName.startsWith(\"_\") ||\n !descriptor ||\n !!descriptor.get ||\n typeof descriptor.value !== \"function\"\n ) {\n continue;\n }\n\n // Now, methodName is confirmed to be a custom method/function\n // Wrap the custom method with context\n /* oxlint-disable @typescript-eslint/no-explicit-any -- dynamic method wrapping requires any */\n const wrappedFunction = withAgentContext(\n this[methodName as keyof this] as (...args: any[]) => any\n ) as any;\n /* oxlint-enable @typescript-eslint/no-explicit-any */\n\n // if the method is callable, copy the metadata from the original method\n if (this._isCallable(methodName)) {\n callableMetadata.set(\n wrappedFunction,\n callableMetadata.get(this[methodName as keyof this] as Function)!\n );\n }\n\n // set the wrapped function on the prototype\n this.constructor.prototype[methodName as keyof this] = wrappedFunction;\n }\n\n proto = Object.getPrototypeOf(proto);\n depth++;\n }\n }\n\n override onError(\n connection: Connection,\n error: unknown\n ): void | Promise<void>;\n override onError(error: unknown): void | Promise<void>;\n override onError(connectionOrError: Connection | unknown, error?: unknown) {\n let theError: unknown;\n if (connectionOrError && error) {\n theError = error;\n // this is a websocket connection error\n console.error(\n \"Error on websocket connection:\",\n (connectionOrError as Connection).id,\n theError\n );\n console.error(\n \"Override onError(connection, error) to handle websocket connection errors\"\n );\n } else {\n theError = connectionOrError;\n // this is a server error\n console.error(\"Error on server:\", theError);\n console.error(\"Override onError(error) to handle server errors\");\n }\n throw theError;\n }\n\n /**\n * Render content (not implemented in base class)\n */\n render() {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Queue a task to be executed in the future\n * @param payload Payload to pass to the callback\n * @param callback Name of the method to call\n * @returns The ID of the queued task\n */\n async queue<T = unknown>(callback: keyof this, payload: T): Promise<string> {\n const id = nanoid(9);\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_queues (id, payload, callback)\n VALUES (${id}, ${JSON.stringify(payload)}, ${callback})\n `;\n\n void this._flushQueue().catch((e) => {\n console.error(\"Error flushing queue:\", e);\n });\n\n return id;\n }\n\n private _flushingQueue = false;\n\n private async _flushQueue() {\n if (this._flushingQueue) {\n return;\n }\n this._flushingQueue = true;\n try {\n while (true) {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues\n ORDER BY created_at ASC\n `;\n\n if (!result || result.length === 0) {\n break;\n }\n\n for (const row of result || []) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n await this.dequeue(row.id);\n continue;\n }\n const { connection, request, email } = agentContext.getStore() || {};\n try {\n await agentContext.run(\n {\n agent: this,\n connection,\n request,\n email\n },\n async () => {\n // TODO: add retries and backoff\n await (\n callback as (\n payload: unknown,\n queueItem: QueueItem<string>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n }\n );\n } catch (e) {\n console.error(\n `Queue callback ${String(row.callback)} failed for row ${row.id}:`,\n e\n );\n } finally {\n await this.dequeue(row.id);\n }\n }\n }\n } finally {\n this._flushingQueue = false;\n }\n }\n\n /**\n * Dequeue a task by ID\n * @param id ID of the task to dequeue\n */\n async dequeue(id: string) {\n this.sql`DELETE FROM cf_agents_queues WHERE id = ${id}`;\n }\n\n /**\n * Dequeue all tasks\n */\n async dequeueAll() {\n this.sql`DELETE FROM cf_agents_queues`;\n }\n\n /**\n * Dequeue all tasks by callback\n * @param callback Name of the callback to dequeue\n */\n async dequeueAllByCallback(callback: string) {\n this.sql`DELETE FROM cf_agents_queues WHERE callback = ${callback}`;\n }\n\n /**\n * Get a queued task by ID\n * @param id ID of the task to get\n * @returns The task or undefined if not found\n */\n async getQueue(id: string): Promise<QueueItem<string> | undefined> {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues WHERE id = ${id}\n `;\n return result\n ? { ...result[0], payload: JSON.parse(result[0].payload) }\n : undefined;\n }\n\n /**\n * Get all queues by key and value\n * @param key Key to filter by\n * @param value Value to filter by\n * @returns Array of matching QueueItem objects\n */\n async getQueues(key: string, value: string): Promise<QueueItem<string>[]> {\n const result = this.sql<QueueItem<string>>`\n SELECT * FROM cf_agents_queues\n `;\n return result.filter((row) => JSON.parse(row.payload)[key] === value);\n }\n\n /**\n * Schedule a task to be executed in the future\n * @template T Type of the payload data\n * @param when When to execute the task (Date, seconds delay, or cron expression)\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async schedule<T = string>(\n when: Date | string | number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n const id = nanoid(9);\n\n const emitScheduleCreate = (schedule: Schedule<T>) =>\n this.observability?.emit(\n {\n displayMessage: `Schedule ${schedule.id} created`,\n id: nanoid(),\n payload: {\n callback: callback as string,\n id: id\n },\n timestamp: Date.now(),\n type: \"schedule:create\"\n },\n this.ctx\n );\n\n if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n if (when instanceof Date) {\n const timestamp = Math.floor(when.getTime() / 1000);\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'scheduled', ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"scheduled\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n if (typeof when === \"number\") {\n const time = new Date(Date.now() + when * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, delayInSeconds, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'delayed', ${when}, ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n delayInSeconds: when,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"delayed\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n if (typeof when === \"string\") {\n const nextExecutionTime = getNextCronTime(when);\n const timestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, cron, time)\n VALUES (${id}, ${callback}, ${JSON.stringify(\n payload\n )}, 'cron', ${when}, ${timestamp})\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n cron: when,\n id,\n payload: payload as T,\n time: timestamp,\n type: \"cron\"\n };\n\n emitScheduleCreate(schedule);\n\n return schedule;\n }\n throw new Error(\n `Invalid schedule type: ${JSON.stringify(when)}(${typeof when}) trying to schedule ${callback}`\n );\n }\n\n /**\n * Schedule a task to run repeatedly at a fixed interval\n * @template T Type of the payload data\n * @param intervalSeconds Number of seconds between executions\n * @param callback Name of the method to call\n * @param payload Data to pass to the callback\n * @returns Schedule object representing the scheduled task\n */\n async scheduleEvery<T = string>(\n intervalSeconds: number,\n callback: keyof this,\n payload?: T\n ): Promise<Schedule<T>> {\n // DO alarms have a max schedule time of 30 days\n const MAX_INTERVAL_SECONDS = 30 * 24 * 60 * 60; // 30 days in seconds\n\n if (typeof intervalSeconds !== \"number\" || intervalSeconds <= 0) {\n throw new Error(\"intervalSeconds must be a positive number\");\n }\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 if (typeof callback !== \"string\") {\n throw new Error(\"Callback must be a string\");\n }\n\n if (typeof this[callback] !== \"function\") {\n throw new Error(`this.${callback} is not a function`);\n }\n\n const id = nanoid(9);\n const time = new Date(Date.now() + intervalSeconds * 1000);\n const timestamp = Math.floor(time.getTime() / 1000);\n\n this.sql`\n INSERT OR REPLACE INTO cf_agents_schedules (id, callback, payload, type, intervalSeconds, time, running)\n VALUES (${id}, ${callback}, ${JSON.stringify(payload)}, 'interval', ${intervalSeconds}, ${timestamp}, 0)\n `;\n\n await this._scheduleNextAlarm();\n\n const schedule: Schedule<T> = {\n callback: callback,\n id,\n intervalSeconds,\n payload: payload as T,\n time: timestamp,\n type: \"interval\"\n };\n\n this.observability?.emit(\n {\n displayMessage: `Schedule ${schedule.id} created`,\n id: nanoid(),\n payload: {\n callback: callback as string,\n id: id\n },\n timestamp: Date.now(),\n type: \"schedule:create\"\n },\n this.ctx\n );\n\n return schedule;\n }\n\n /**\n * Get a scheduled task by ID\n * @template T Type of the payload data\n * @param id ID of the scheduled task\n * @returns The Schedule object or undefined if not found\n */\n async getSchedule<T = string>(id: string): Promise<Schedule<T> | undefined> {\n const result = this.sql<Schedule<string>>`\n SELECT * FROM cf_agents_schedules WHERE id = ${id}\n `;\n if (!result || result.length === 0) {\n return undefined;\n }\n\n return { ...result[0], payload: JSON.parse(result[0].payload) as T };\n }\n\n /**\n * Get scheduled tasks matching the given criteria\n * @template T Type of the payload data\n * @param criteria Criteria to filter schedules\n * @returns Array of matching Schedule objects\n */\n getSchedules<T = string>(\n criteria: {\n id?: string;\n type?: \"scheduled\" | \"delayed\" | \"cron\" | \"interval\";\n timeRange?: { start?: Date; end?: Date };\n } = {}\n ): Schedule<T>[] {\n let query = \"SELECT * FROM cf_agents_schedules WHERE 1=1\";\n const params = [];\n\n if (criteria.id) {\n query += \" AND id = ?\";\n params.push(criteria.id);\n }\n\n if (criteria.type) {\n query += \" AND type = ?\";\n params.push(criteria.type);\n }\n\n if (criteria.timeRange) {\n query += \" AND time >= ? AND time <= ?\";\n const start = criteria.timeRange.start || new Date(0);\n const end = criteria.timeRange.end || new Date(999999999999999);\n params.push(\n Math.floor(start.getTime() / 1000),\n Math.floor(end.getTime() / 1000)\n );\n }\n\n const result = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray()\n .map((row) => ({\n ...row,\n payload: JSON.parse(row.payload as string) as T\n })) as Schedule<T>[];\n\n return result;\n }\n\n /**\n * Cancel a scheduled task\n * @param id ID of the task to cancel\n * @returns true if the task was cancelled, false if the task was not found\n */\n async cancelSchedule(id: string): Promise<boolean> {\n const schedule = await this.getSchedule(id);\n if (!schedule) {\n return false;\n }\n\n this.observability?.emit(\n {\n displayMessage: `Schedule ${id} cancelled`,\n id: nanoid(),\n payload: {\n callback: schedule.callback,\n id: schedule.id\n },\n timestamp: Date.now(),\n type: \"schedule:cancel\"\n },\n this.ctx\n );\n\n this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;\n\n await this._scheduleNextAlarm();\n return true;\n }\n\n private async _scheduleNextAlarm() {\n // Find the next schedule that needs to be executed\n const result = this.sql`\n SELECT time FROM cf_agents_schedules\n WHERE time >= ${Math.floor(Date.now() / 1000)}\n ORDER BY time ASC\n LIMIT 1\n `;\n if (!result) return;\n\n if (result.length > 0 && \"time\" in result[0]) {\n const nextTime = (result[0].time as number) * 1000;\n await this.ctx.storage.setAlarm(nextTime);\n }\n }\n\n /**\n * Method called when an alarm fires.\n * Executes any scheduled tasks that are due.\n *\n * @remarks\n * To schedule a task, please use the `this.schedule` method instead.\n * See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}\n */\n public readonly alarm = async () => {\n const now = Math.floor(Date.now() / 1000);\n\n // Get all schedules that should be executed now\n const result = this.sql<\n Schedule<string> & { running?: number; intervalSeconds?: number }\n >`\n SELECT * FROM cf_agents_schedules WHERE time <= ${now}\n `;\n\n if (result && Array.isArray(result)) {\n for (const row of result) {\n const callback = this[row.callback as keyof Agent<Env>];\n if (!callback) {\n console.error(`callback ${row.callback} not found`);\n continue;\n }\n\n // Overlap prevention for interval schedules with hung callback detection\n if (row.type === \"interval\" && row.running === 1) {\n const executionStartedAt =\n (row as { execution_started_at?: number }).execution_started_at ??\n 0;\n const hungTimeoutSeconds =\n this._resolvedOptions.hungScheduleTimeoutSeconds;\n const elapsedSeconds = now - executionStartedAt;\n\n if (elapsedSeconds < hungTimeoutSeconds) {\n console.warn(\n `Skipping interval schedule ${row.id}: previous execution still running`\n );\n continue;\n }\n // Previous execution appears hung, force reset and re-execute\n console.warn(\n `Forcing reset of hung interval schedule ${row.id} (started ${elapsedSeconds}s ago)`\n );\n }\n\n // Mark interval as running before execution\n if (row.type === \"interval\") {\n this\n .sql`UPDATE cf_agents_schedules SET running = 1, execution_started_at = ${now} WHERE id = ${row.id}`;\n }\n\n await agentContext.run(\n {\n agent: this,\n connection: undefined,\n request: undefined,\n email: undefined\n },\n async () => {\n try {\n this.observability?.emit(\n {\n displayMessage: `Schedule ${row.id} executed`,\n id: nanoid(),\n payload: {\n callback: row.callback,\n id: row.id\n },\n timestamp: Date.now(),\n type: \"schedule:execute\"\n },\n this.ctx\n );\n\n await (\n callback as (\n payload: unknown,\n schedule: Schedule<unknown>\n ) => Promise<void>\n ).bind(this)(JSON.parse(row.payload as string), row);\n } catch (e) {\n console.error(`error executing callback \"${row.callback}\"`, e);\n // Route schedule errors through onError for consistency\n try {\n await this.onError(e);\n } catch {\n // swallow onError errors\n }\n }\n }\n );\n\n if (this._destroyed) return;\n\n if (row.type === \"cron\") {\n // Update next execution time for cron schedules\n const nextExecutionTime = getNextCronTime(row.cron);\n const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1000);\n\n this.sql`\n UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else if (row.type === \"interval\") {\n // Reset running flag and schedule next interval execution\n const nextTimestamp =\n Math.floor(Date.now() / 1000) + (row.intervalSeconds ?? 0);\n\n this.sql`\n UPDATE cf_agents_schedules SET running = 0, time = ${nextTimestamp} WHERE id = ${row.id}\n `;\n } else {\n // Delete one-time schedules after execution\n this.sql`\n DELETE FROM cf_agents_schedules WHERE id = ${row.id}\n `;\n }\n }\n }\n if (this._destroyed) return;\n\n // Schedule the next alarm\n await this._scheduleNextAlarm();\n };\n\n /**\n * Destroy the Agent, removing all state and scheduled tasks\n */\n async destroy() {\n // drop all tables\n this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;\n this.sql`DROP TABLE IF EXISTS cf_agents_state`;\n this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;\n this.sql`DROP TABLE IF EXISTS cf_agents_queues`;\n this.sql`DROP TABLE IF EXISTS cf_agents_workflows`;\n\n // delete all alarms\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n\n this._disposables.dispose();\n await this.mcp.dispose();\n\n this._destroyed = true;\n\n // `ctx.abort` throws an uncatchable error, so we yield to the event loop\n // to avoid capturing it and let handlers finish cleaning up\n setTimeout(() => {\n this.ctx.abort(\"destroyed\");\n }, 0);\n\n this.observability?.emit(\n {\n displayMessage: \"Agent destroyed\",\n id: nanoid(),\n payload: {},\n timestamp: Date.now(),\n type: \"destroy\"\n },\n this.ctx\n );\n }\n\n /**\n * Check if a method is callable\n * @param method The method name to check\n * @returns True if the method is marked as callable\n */\n private _isCallable(method: string): boolean {\n return callableMetadata.has(this[method as keyof this] as Function);\n }\n\n /**\n * Get all methods marked as callable on this Agent\n * @returns A map of method names to their metadata\n */\n getCallableMethods(): Map<string, CallableMetadata> {\n const result = new Map<string, CallableMetadata>();\n\n // Walk the entire prototype chain to find callable methods from parent classes\n let prototype = Object.getPrototypeOf(this);\n while (prototype && prototype !== Object.prototype) {\n for (const name of Object.getOwnPropertyNames(prototype)) {\n if (name === \"constructor\") continue;\n // Don't override child class methods (first one wins)\n if (result.has(name)) continue;\n\n try {\n const fn = prototype[name];\n if (typeof fn === \"function\") {\n const meta = callableMetadata.get(fn as Function);\n if (meta) {\n result.set(name, meta);\n }\n }\n } catch (e) {\n // Skip properties that can't be accessed (e.g., private members with #)\n // These throw TypeError when accessed\n if (!(e instanceof TypeError)) {\n throw e;\n }\n }\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return result;\n }\n\n // ==========================================\n // Workflow Integration Methods\n // ==========================================\n\n /**\n * Start a workflow and track it in this Agent's database.\n * Automatically injects agent identity into the workflow params.\n *\n * @template P - Type of params to pass to the workflow\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param params - Params to pass to the workflow\n * @param options - Optional workflow options\n * @returns The workflow instance ID\n *\n * @example\n * ```typescript\n * const workflowId = await this.runWorkflow(\n * 'MY_WORKFLOW',\n * { taskId: '123', data: 'process this' }\n * );\n * ```\n */\n async runWorkflow<P = unknown>(\n workflowName: WorkflowName<Env>,\n params: P,\n options?: RunWorkflowOptions\n ): Promise<string> {\n // Look up the workflow binding by name\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n // Find the binding name for this Agent's namespace\n const agentBindingName =\n options?.agentBinding ?? this._findAgentBindingName();\n if (!agentBindingName) {\n throw new Error(\n \"Could not detect Agent binding name from class name. \" +\n \"Pass it explicitly via options.agentBinding\"\n );\n }\n\n // Generate workflow ID if not provided\n const workflowId = options?.id ?? nanoid();\n\n // Inject agent identity and workflow name into params\n const augmentedParams = {\n ...params,\n __agentName: this.name,\n __agentBinding: agentBindingName,\n __workflowName: workflowName\n };\n\n // Create the workflow instance\n const instance = await workflow.create({\n id: workflowId,\n params: augmentedParams\n });\n\n // Track the workflow in our database\n const id = nanoid();\n const metadataJson = options?.metadata\n ? JSON.stringify(options.metadata)\n : null;\n try {\n this.sql`\n INSERT INTO cf_agents_workflows (id, workflow_id, workflow_name, status, metadata)\n VALUES (${id}, ${instance.id}, ${workflowName}, 'queued', ${metadataJson})\n `;\n } catch (e) {\n if (\n e instanceof Error &&\n e.message.includes(\"UNIQUE constraint failed\")\n ) {\n throw new Error(\n `Workflow with ID \"${workflowId}\" is already being tracked`\n );\n }\n throw e;\n }\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${instance.id} started`,\n id: nanoid(),\n payload: {\n workflowId: instance.id,\n workflowName: workflowName\n },\n timestamp: Date.now(),\n type: \"workflow:start\"\n },\n this.ctx\n );\n\n return instance.id;\n }\n\n /**\n * Send an event to a running workflow.\n * The workflow can wait for this event using step.waitForEvent().\n *\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param workflowId - ID of the workflow instance\n * @param event - Event to send\n *\n * @example\n * ```typescript\n * await this.sendWorkflowEvent(\n * 'MY_WORKFLOW',\n * workflowId,\n * { type: 'approval', payload: { approved: true } }\n * );\n * ```\n */\n async sendWorkflowEvent(\n workflowName: WorkflowName<Env>,\n workflowId: string,\n event: WorkflowEventPayload\n ): Promise<void> {\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n await instance.sendEvent(event);\n\n this.observability?.emit(\n {\n displayMessage: `Event sent to workflow ${workflowId}`,\n id: nanoid(),\n payload: {\n workflowId,\n eventType: event.type\n },\n timestamp: Date.now(),\n type: \"workflow:event\"\n },\n this.ctx\n );\n }\n\n /**\n * Approve a waiting workflow.\n * Sends an approval event to the workflow that can be received by waitForApproval().\n *\n * @param workflowId - ID of the workflow to approve\n * @param data - Optional approval data (reason, metadata)\n *\n * @example\n * ```typescript\n * await this.approveWorkflow(workflowId, {\n * reason: 'Approved by admin',\n * metadata: { approvedBy: userId }\n * });\n * ```\n */\n async approveWorkflow(\n workflowId: string,\n data?: { reason?: string; metadata?: Record<string, unknown> }\n ): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n await this.sendWorkflowEvent(\n workflowInfo.workflowName as WorkflowName<Env>,\n workflowId,\n {\n type: \"approval\",\n payload: {\n approved: true,\n reason: data?.reason,\n metadata: data?.metadata\n }\n }\n );\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} approved`,\n id: nanoid(),\n payload: { workflowId, reason: data?.reason },\n timestamp: Date.now(),\n type: \"workflow:approved\"\n },\n this.ctx\n );\n }\n\n /**\n * Reject a waiting workflow.\n * Sends a rejection event to the workflow that will cause waitForApproval() to throw.\n *\n * @param workflowId - ID of the workflow to reject\n * @param data - Optional rejection data (reason)\n *\n * @example\n * ```typescript\n * await this.rejectWorkflow(workflowId, {\n * reason: 'Request denied by admin'\n * });\n * ```\n */\n async rejectWorkflow(\n workflowId: string,\n data?: { reason?: string }\n ): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n await this.sendWorkflowEvent(\n workflowInfo.workflowName as WorkflowName<Env>,\n workflowId,\n {\n type: \"approval\",\n payload: {\n approved: false,\n reason: data?.reason\n }\n }\n );\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} rejected`,\n id: nanoid(),\n payload: { workflowId, reason: data?.reason },\n timestamp: Date.now(),\n type: \"workflow:rejected\"\n },\n this.ctx\n );\n }\n\n /**\n * Terminate a running workflow.\n * This immediately stops the workflow and sets its status to \"terminated\".\n *\n * @param workflowId - ID of the workflow to terminate (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is already completed/errored/terminated (from Cloudflare)\n *\n * @note `terminate()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.terminateWorkflow(workflowId);\n * ```\n */\n async terminateWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.terminate();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"terminateWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n // Update tracking table with new status\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} terminated`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:terminated\"\n },\n this.ctx\n );\n }\n\n /**\n * Pause a running workflow.\n * The workflow can be resumed later with resumeWorkflow().\n *\n * @param workflowId - ID of the workflow to pause (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is not running (from Cloudflare)\n *\n * @note `pause()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.pauseWorkflow(workflowId);\n * ```\n */\n async pauseWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.pause();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"pauseWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} paused`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:paused\"\n },\n this.ctx\n );\n }\n\n /**\n * Resume a paused workflow.\n *\n * @param workflowId - ID of the workflow to resume (must be tracked via runWorkflow)\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n * @throws Error if workflow is not paused (from Cloudflare)\n *\n * @note `resume()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * await this.resumeWorkflow(workflowId);\n * ```\n */\n async resumeWorkflow(workflowId: string): Promise<void> {\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.resume();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"resumeWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} resumed`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:resumed\"\n },\n this.ctx\n );\n }\n\n /**\n * Restart a workflow instance.\n * This re-runs the workflow from the beginning with the same ID.\n *\n * @param workflowId - ID of the workflow to restart (must be tracked via runWorkflow)\n * @param options - Optional settings\n * @param options.resetTracking - If true (default), resets created_at and clears error fields.\n * If false, preserves original timestamps.\n * @throws Error if workflow not found in tracking table\n * @throws Error if workflow binding not found in environment\n *\n * @note `restart()` is not yet supported in local development (wrangler dev).\n * It will throw an error locally but works when deployed to Cloudflare.\n *\n * @example\n * ```typescript\n * // Reset tracking (default)\n * await this.restartWorkflow(workflowId);\n *\n * // Preserve original timestamps\n * await this.restartWorkflow(workflowId, { resetTracking: false });\n * ```\n */\n async restartWorkflow(\n workflowId: string,\n options: { resetTracking?: boolean } = {}\n ): Promise<void> {\n const { resetTracking = true } = options;\n\n const workflowInfo = this.getWorkflow(workflowId);\n if (!workflowInfo) {\n throw new Error(`Workflow ${workflowId} not found in tracking table`);\n }\n\n const workflow = this._findWorkflowBindingByName(\n workflowInfo.workflowName as WorkflowName<Env>\n );\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowInfo.workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n try {\n await instance.restart();\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"Not implemented\")) {\n throw new Error(\n \"restartWorkflow() is not supported in local development. \" +\n \"Deploy to Cloudflare to use this feature. \" +\n \"Follow https://github.com/cloudflare/agents/issues/823 for details and updates.\"\n );\n }\n throw err;\n }\n\n if (resetTracking) {\n // Reset tracking fields for fresh start\n const now = Math.floor(Date.now() / 1000);\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'queued',\n created_at = ${now},\n updated_at = ${now},\n completed_at = NULL,\n error_name = NULL,\n error_message = NULL\n WHERE workflow_id = ${workflowId}\n `;\n } else {\n // Just update status from Cloudflare\n const status = await instance.status();\n this._updateWorkflowTracking(workflowId, status);\n }\n\n this.observability?.emit(\n {\n displayMessage: `Workflow ${workflowId} restarted`,\n id: nanoid(),\n payload: { workflowId, workflowName: workflowInfo.workflowName },\n timestamp: Date.now(),\n type: \"workflow:restarted\"\n },\n this.ctx\n );\n }\n\n /**\n * Find a workflow binding by its name.\n */\n private _findWorkflowBindingByName(\n workflowName: string\n ): Workflow | undefined {\n const binding = (this.env as Record<string, unknown>)[workflowName];\n if (\n binding &&\n typeof binding === \"object\" &&\n \"create\" in binding &&\n \"get\" in binding\n ) {\n return binding as Workflow;\n }\n return undefined;\n }\n\n /**\n * Get all workflow binding names from the environment.\n */\n private _getWorkflowBindingNames(): string[] {\n const names: string[] = [];\n for (const [key, value] of Object.entries(\n this.env as Record<string, unknown>\n )) {\n if (\n value &&\n typeof value === \"object\" &&\n \"create\" in value &&\n \"get\" in value\n ) {\n names.push(key);\n }\n }\n return names;\n }\n\n /**\n * Get the status of a workflow and update the tracking record.\n *\n * @param workflowName - Name of the workflow binding in env (e.g., 'MY_WORKFLOW')\n * @param workflowId - ID of the workflow instance\n * @returns The workflow status\n */\n async getWorkflowStatus(\n workflowName: WorkflowName<Env>,\n workflowId: string\n ): Promise<InstanceStatus> {\n const workflow = this._findWorkflowBindingByName(workflowName);\n if (!workflow) {\n throw new Error(\n `Workflow binding '${workflowName}' not found in environment`\n );\n }\n\n const instance = await workflow.get(workflowId);\n const status = await instance.status();\n\n // Update the tracking record\n this._updateWorkflowTracking(workflowId, status);\n\n return status;\n }\n\n /**\n * Get a tracked workflow by ID.\n *\n * @param workflowId - Workflow instance ID\n * @returns Workflow info or undefined if not found\n */\n getWorkflow(workflowId: string): WorkflowInfo | undefined {\n const rows = this.sql<WorkflowTrackingRow>`\n SELECT * FROM cf_agents_workflows WHERE workflow_id = ${workflowId}\n `;\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n return this._rowToWorkflowInfo(rows[0]);\n }\n\n /**\n * Query tracked workflows with cursor-based pagination.\n *\n * @param criteria - Query criteria including optional cursor for pagination\n * @returns WorkflowPage with workflows, total count, and next cursor\n *\n * @example\n * ```typescript\n * // First page\n * const page1 = this.getWorkflows({ status: 'running', limit: 20 });\n *\n * // Next page\n * if (page1.nextCursor) {\n * const page2 = this.getWorkflows({\n * status: 'running',\n * limit: 20,\n * cursor: page1.nextCursor\n * });\n * }\n * ```\n */\n getWorkflows(criteria: WorkflowQueryCriteria = {}): WorkflowPage {\n const limit = Math.min(criteria.limit ?? 50, 100);\n const isAsc = criteria.orderBy === \"asc\";\n\n // Get total count (ignores cursor and limit)\n const total = this._countWorkflows(criteria);\n\n // Build base query\n let query = \"SELECT * FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n // Apply cursor for keyset pagination\n if (criteria.cursor) {\n const cursor = this._decodeCursor(criteria.cursor);\n if (isAsc) {\n // ASC: get items after cursor\n query +=\n \" AND (created_at > ? OR (created_at = ? AND workflow_id > ?))\";\n } else {\n // DESC: get items before cursor\n query +=\n \" AND (created_at < ? OR (created_at = ? AND workflow_id < ?))\";\n }\n params.push(cursor.createdAt, cursor.createdAt, cursor.workflowId);\n }\n\n // Order by created_at and workflow_id for consistent keyset pagination\n query += ` ORDER BY created_at ${isAsc ? \"ASC\" : \"DESC\"}, workflow_id ${isAsc ? \"ASC\" : \"DESC\"}`;\n\n // Fetch limit + 1 to detect if there are more pages\n query += \" LIMIT ?\";\n params.push(limit + 1);\n\n const rows = this.ctx.storage.sql\n .exec(query, ...params)\n .toArray() as WorkflowTrackingRow[];\n\n const hasMore = rows.length > limit;\n const resultRows = hasMore ? rows.slice(0, limit) : rows;\n const workflows = resultRows.map((row) => this._rowToWorkflowInfo(row));\n\n // Build next cursor from last item\n const nextCursor =\n hasMore && workflows.length > 0\n ? this._encodeCursor(workflows[workflows.length - 1])\n : null;\n\n return { workflows, total, nextCursor };\n }\n\n /**\n * Count workflows matching criteria (for pagination total).\n */\n private _countWorkflows(\n criteria: Omit<WorkflowQueryCriteria, \"limit\" | \"cursor\" | \"orderBy\"> & {\n createdBefore?: Date;\n }\n ): number {\n let query = \"SELECT COUNT(*) as count FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n if (criteria.createdBefore) {\n query += \" AND created_at < ?\";\n params.push(Math.floor(criteria.createdBefore.getTime() / 1000));\n }\n\n const result = this.ctx.storage.sql.exec(query, ...params).toArray() as {\n count: number;\n }[];\n\n return result[0]?.count ?? 0;\n }\n\n /**\n * Encode a cursor from workflow info for pagination.\n * Stores createdAt as Unix timestamp in seconds (matching DB storage).\n */\n private _encodeCursor(workflow: WorkflowInfo): string {\n return btoa(\n JSON.stringify({\n c: Math.floor(workflow.createdAt.getTime() / 1000),\n i: workflow.workflowId\n })\n );\n }\n\n /**\n * Decode a pagination cursor.\n * Returns createdAt as Unix timestamp in seconds (matching DB storage).\n */\n private _decodeCursor(cursor: string): {\n createdAt: number;\n workflowId: string;\n } {\n try {\n const data = JSON.parse(atob(cursor));\n if (typeof data.c !== \"number\" || typeof data.i !== \"string\") {\n throw new Error(\"Invalid cursor structure\");\n }\n return { createdAt: data.c, workflowId: data.i };\n } catch {\n throw new Error(\n \"Invalid pagination cursor. The cursor may be malformed or corrupted.\"\n );\n }\n }\n\n /**\n * Delete a workflow tracking record.\n *\n * @param workflowId - ID of the workflow to delete\n * @returns true if a record was deleted, false if not found\n */\n deleteWorkflow(workflowId: string): boolean {\n // First check if workflow exists\n const existing = this.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_workflows WHERE workflow_id = ${workflowId}\n `;\n if (!existing[0] || existing[0].count === 0) {\n return false;\n }\n this.sql`DELETE FROM cf_agents_workflows WHERE workflow_id = ${workflowId}`;\n return true;\n }\n\n /**\n * Delete workflow tracking records matching criteria.\n * Useful for cleaning up old completed/errored workflows.\n *\n * @param criteria - Criteria for which workflows to delete\n * @returns Number of records matching criteria (expected deleted count)\n *\n * @example\n * ```typescript\n * // Delete all completed workflows created more than 7 days ago\n * const deleted = this.deleteWorkflows({\n * status: 'complete',\n * createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)\n * });\n *\n * // Delete all errored and terminated workflows\n * const deleted = this.deleteWorkflows({\n * status: ['errored', 'terminated']\n * });\n * ```\n */\n deleteWorkflows(\n criteria: Omit<WorkflowQueryCriteria, \"limit\" | \"orderBy\"> & {\n createdBefore?: Date;\n } = {}\n ): number {\n let query = \"DELETE FROM cf_agents_workflows WHERE 1=1\";\n const params: (string | number | boolean)[] = [];\n\n if (criteria.status) {\n const statuses = Array.isArray(criteria.status)\n ? criteria.status\n : [criteria.status];\n const placeholders = statuses.map(() => \"?\").join(\", \");\n query += ` AND status IN (${placeholders})`;\n params.push(...statuses);\n }\n\n if (criteria.workflowName) {\n query += \" AND workflow_name = ?\";\n params.push(criteria.workflowName);\n }\n\n if (criteria.metadata) {\n for (const [key, value] of Object.entries(criteria.metadata)) {\n query += ` AND json_extract(metadata, '$.' || ?) = ?`;\n params.push(key, value);\n }\n }\n\n if (criteria.createdBefore) {\n query += \" AND created_at < ?\";\n params.push(Math.floor(criteria.createdBefore.getTime() / 1000));\n }\n\n const cursor = this.ctx.storage.sql.exec(query, ...params);\n return cursor.rowsWritten;\n }\n\n /**\n * Migrate workflow tracking records from an old binding name to a new one.\n * Use this after renaming a workflow binding in wrangler.toml.\n *\n * @param oldName - Previous workflow binding name\n * @param newName - New workflow binding name\n * @returns Number of records migrated\n *\n * @example\n * ```typescript\n * // After renaming OLD_WORKFLOW to NEW_WORKFLOW in wrangler.toml\n * async onStart() {\n * const migrated = this.migrateWorkflowBinding('OLD_WORKFLOW', 'NEW_WORKFLOW');\n * }\n * ```\n */\n migrateWorkflowBinding(oldName: string, newName: string): number {\n // Validate new binding exists\n if (!this._findWorkflowBindingByName(newName)) {\n throw new Error(`Workflow binding '${newName}' not found in environment`);\n }\n\n const result = this.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_workflows WHERE workflow_name = ${oldName}\n `;\n const count = result[0]?.count ?? 0;\n\n if (count > 0) {\n this\n .sql`UPDATE cf_agents_workflows SET workflow_name = ${newName} WHERE workflow_name = ${oldName}`;\n console.log(\n `[Agent] Migrated ${count} workflow(s) from '${oldName}' to '${newName}'`\n );\n }\n\n return count;\n }\n\n /**\n * Update workflow tracking record from InstanceStatus\n */\n private _updateWorkflowTracking(\n workflowId: string,\n status: InstanceStatus\n ): void {\n const statusName = status.status;\n const now = Math.floor(Date.now() / 1000);\n\n // Determine if workflow is complete\n const completedStatuses: WorkflowStatus[] = [\n \"complete\",\n \"errored\",\n \"terminated\"\n ];\n const completedAt = completedStatuses.includes(statusName) ? now : null;\n\n // Extract error info if present\n const errorName = status.error?.name ?? null;\n const errorMessage = status.error?.message ?? null;\n\n this.sql`\n UPDATE cf_agents_workflows\n SET status = ${statusName},\n error_name = ${errorName},\n error_message = ${errorMessage},\n updated_at = ${now},\n completed_at = ${completedAt}\n WHERE workflow_id = ${workflowId}\n `;\n }\n\n /**\n * Convert a database row to WorkflowInfo\n */\n private _rowToWorkflowInfo(row: WorkflowTrackingRow): WorkflowInfo {\n return {\n id: row.id,\n workflowId: row.workflow_id,\n workflowName: row.workflow_name,\n status: row.status,\n metadata: row.metadata ? JSON.parse(row.metadata) : null,\n error: row.error_name\n ? { name: row.error_name, message: row.error_message ?? \"\" }\n : null,\n createdAt: new Date(row.created_at * 1000),\n updatedAt: new Date(row.updated_at * 1000),\n completedAt: row.completed_at ? new Date(row.completed_at * 1000) : null\n };\n }\n\n /**\n * Find the binding name for this Agent's namespace by matching class name.\n * Returns undefined if no match found - use options.agentBinding as fallback.\n */\n private _findAgentBindingName(): string | undefined {\n const className = this._ParentClass.name;\n for (const [key, value] of Object.entries(\n this.env as Record<string, unknown>\n )) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n // Check if this namespace's binding name matches our class name\n if (\n key === className ||\n camelCaseToKebabCase(key) === camelCaseToKebabCase(className)\n ) {\n return key;\n }\n }\n }\n return undefined;\n }\n\n // ==========================================\n // Workflow Lifecycle Callbacks\n // ==========================================\n\n /**\n * Handle a callback from a workflow.\n * Called when the Agent receives a callback at /_workflow/callback.\n * Override this to handle all callback types in one place.\n *\n * @param callback - The callback payload\n */\n async onWorkflowCallback(callback: WorkflowCallback): Promise<void> {\n const now = Math.floor(Date.now() / 1000);\n\n switch (callback.type) {\n case \"progress\":\n // Update tracking status to \"running\" when receiving progress\n // Only transition from queued/waiting to avoid overwriting terminal states\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'running', updated_at = ${now}\n WHERE workflow_id = ${callback.workflowId} AND status IN ('queued', 'waiting')\n `;\n await this.onWorkflowProgress(\n callback.workflowName,\n callback.workflowId,\n callback.progress\n );\n break;\n case \"complete\":\n // Update tracking status to \"complete\"\n // Don't overwrite if already terminated/paused (race condition protection)\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'complete', updated_at = ${now}, completed_at = ${now}\n WHERE workflow_id = ${callback.workflowId}\n AND status NOT IN ('terminated', 'paused')\n `;\n await this.onWorkflowComplete(\n callback.workflowName,\n callback.workflowId,\n callback.result\n );\n break;\n case \"error\":\n // Update tracking status to \"errored\"\n // Don't overwrite if already terminated/paused (race condition protection)\n this.sql`\n UPDATE cf_agents_workflows\n SET status = 'errored', updated_at = ${now}, completed_at = ${now},\n error_name = 'WorkflowError', error_message = ${callback.error}\n WHERE workflow_id = ${callback.workflowId}\n AND status NOT IN ('terminated', 'paused')\n `;\n await this.onWorkflowError(\n callback.workflowName,\n callback.workflowId,\n callback.error\n );\n break;\n case \"event\":\n // No status change for events - they can occur at any stage\n await this.onWorkflowEvent(\n callback.workflowName,\n callback.workflowId,\n callback.event\n );\n break;\n }\n }\n\n /**\n * Called when a workflow reports progress.\n * Override to handle progress updates.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param progress - Typed progress data (default: DefaultProgress)\n */\n async onWorkflowProgress(\n _workflowName: string,\n _workflowId: string,\n _progress: unknown\n ): Promise<void> {\n // Override to handle progress updates\n }\n\n /**\n * Called when a workflow completes successfully.\n * Override to handle completion.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param result - Optional result data\n */\n async onWorkflowComplete(\n _workflowName: string,\n _workflowId: string,\n _result?: unknown\n ): Promise<void> {\n // Override to handle completion\n }\n\n /**\n * Called when a workflow encounters an error.\n * Override to handle errors.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param error - Error message\n */\n async onWorkflowError(\n _workflowName: string,\n _workflowId: string,\n _error: string\n ): Promise<void> {\n // Override to handle errors\n }\n\n /**\n * Called when a workflow sends a custom event.\n * Override to handle custom events.\n *\n * @param workflowName - Workflow binding name\n * @param workflowId - ID of the workflow\n * @param event - Custom event payload\n */\n async onWorkflowEvent(\n _workflowName: string,\n _workflowId: string,\n _event: unknown\n ): Promise<void> {\n // Override to handle custom events\n }\n\n // ============================================================\n // Internal RPC methods for AgentWorkflow communication\n // These are called via DO RPC, not exposed via HTTP\n // ============================================================\n\n /**\n * Handle a workflow callback via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n async _workflow_handleCallback(callback: WorkflowCallback): Promise<void> {\n await this.onWorkflowCallback(callback);\n }\n\n /**\n * Broadcast a message to all connected clients via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n _workflow_broadcast(message: unknown): void {\n this.broadcast(JSON.stringify(message));\n }\n\n /**\n * Update agent state via RPC.\n * @internal - Called by AgentWorkflow, do not call directly\n */\n _workflow_updateState(\n action: \"set\" | \"merge\" | \"reset\",\n state?: unknown\n ): void {\n if (action === \"set\") {\n this.setState(state as State);\n } else if (action === \"merge\") {\n const currentState = this.state ?? ({} as State);\n this.setState({\n ...currentState,\n ...(state as Record<string, unknown>)\n } as State);\n } else if (action === \"reset\") {\n this.setState(this.initialState);\n }\n }\n\n /**\n * Connect to a new MCP Server\n *\n * @example\n * // Simple usage\n * await this.addMcpServer(\"github\", \"https://mcp.github.com\");\n *\n * @example\n * // With options (preferred for custom headers, transport, etc.)\n * await this.addMcpServer(\"github\", \"https://mcp.github.com\", {\n * transport: { headers: { \"Authorization\": \"Bearer ...\" } }\n * });\n *\n * @example\n * // Legacy 5-parameter signature (still supported)\n * await this.addMcpServer(\"github\", url, callbackHost, agentsPrefix, options);\n *\n * @param serverName Name of the MCP server\n * @param url MCP Server URL\n * @param callbackHostOrOptions Options object, or callback host string (legacy)\n * @param agentsPrefix agents routing prefix if not using `agents` (legacy)\n * @param options MCP client and transport options (legacy)\n * @returns Server id and state - either \"authenticating\" with authUrl, or \"ready\"\n * @throws If connection or discovery fails\n */\n async addMcpServer(\n serverName: string,\n url: string,\n callbackHostOrOptions?: string | AddMcpServerOptions,\n agentsPrefix?: string,\n options?: {\n client?: ConstructorParameters<typeof Client>[1];\n transport?: {\n headers?: HeadersInit;\n type?: TransportType;\n };\n }\n ): Promise<\n | {\n id: string;\n state: typeof MCPConnectionState.AUTHENTICATING;\n authUrl: string;\n }\n | {\n id: string;\n state: typeof MCPConnectionState.READY;\n authUrl?: undefined;\n }\n > {\n // Normalize arguments - support both new options API and legacy positional API\n let resolvedCallbackHost: string | undefined;\n let resolvedAgentsPrefix: string;\n let resolvedOptions:\n | {\n client?: ConstructorParameters<typeof Client>[1];\n transport?: {\n headers?: HeadersInit;\n type?: TransportType;\n };\n }\n | undefined;\n\n let resolvedCallbackPath: string | undefined;\n\n if (\n typeof callbackHostOrOptions === \"object\" &&\n callbackHostOrOptions !== null\n ) {\n // New API: options object as third parameter\n resolvedCallbackHost = callbackHostOrOptions.callbackHost;\n resolvedCallbackPath = callbackHostOrOptions.callbackPath;\n resolvedAgentsPrefix = callbackHostOrOptions.agentsPrefix ?? \"agents\";\n resolvedOptions = {\n client: callbackHostOrOptions.client,\n transport: callbackHostOrOptions.transport\n };\n } else {\n // Legacy API: positional parameters\n resolvedCallbackHost = callbackHostOrOptions;\n resolvedAgentsPrefix = agentsPrefix ?? \"agents\";\n resolvedOptions = options;\n }\n\n // Enforce callbackPath when sendIdentityOnConnect is false\n if (!this._resolvedOptions.sendIdentityOnConnect && !resolvedCallbackPath) {\n throw new Error(\n \"callbackPath is required in addMcpServer options when sendIdentityOnConnect is false — \" +\n \"the default callback URL would expose the instance name. \" +\n \"Provide a callbackPath and route the callback request to this agent via getAgentByName.\"\n );\n }\n\n // If callbackHost is not provided, derive it from the current request\n if (!resolvedCallbackHost) {\n const { request } = getCurrentAgent();\n if (!request) {\n throw new Error(\n \"callbackHost is required when not called within a request context\"\n );\n }\n\n // Extract the origin from the request\n const requestUrl = new URL(request.url);\n resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;\n }\n\n // Build the callback URL: use callbackPath if provided, otherwise default to /agents/{class}/{name}/callback\n const normalizedHost = resolvedCallbackHost.replace(/\\/$/, \"\");\n const callbackUrl = resolvedCallbackPath\n ? `${normalizedHost}/${resolvedCallbackPath.replace(/^\\//, \"\")}`\n : `${normalizedHost}/${resolvedAgentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;\n\n // TODO: make zod/ai sdk more performant and remove this\n // Late initialization of jsonSchemaFn (needed for getAITools)\n await this.mcp.ensureJsonSchema();\n\n const id = nanoid(8);\n\n const authProvider = this.createMcpOAuthProvider(callbackUrl);\n authProvider.serverId = id;\n\n // Use the transport type specified in options, or default to \"auto\"\n const transportType: TransportType =\n resolvedOptions?.transport?.type ?? \"auto\";\n\n // allows passing through transport headers if necessary\n // this handles some non-standard bearer auth setups (i.e. MCP server behind CF access instead of OAuth)\n let headerTransportOpts: SSEClientTransportOptions = {};\n if (resolvedOptions?.transport?.headers) {\n headerTransportOpts = {\n eventSourceInit: {\n fetch: (url, init) =>\n fetch(url, {\n ...init,\n headers: resolvedOptions?.transport?.headers\n })\n },\n requestInit: {\n headers: resolvedOptions?.transport?.headers\n }\n };\n }\n\n // Register server (also saves to storage)\n await this.mcp.registerServer(id, {\n url,\n name: serverName,\n callbackUrl,\n client: resolvedOptions?.client,\n transport: {\n ...headerTransportOpts,\n authProvider,\n type: transportType\n }\n });\n\n const result = await this.mcp.connectToServer(id);\n\n if (result.state === MCPConnectionState.FAILED) {\n // Server stays in storage so user can retry via connectToServer(id)\n throw new Error(\n `Failed to connect to MCP server at ${url}: ${result.error}`\n );\n }\n\n if (result.state === MCPConnectionState.AUTHENTICATING) {\n return { id, state: result.state, authUrl: result.authUrl };\n }\n\n // State is CONNECTED - discover capabilities\n const discoverResult = await this.mcp.discoverIfConnected(id);\n\n if (discoverResult && !discoverResult.success) {\n // Server stays in storage - connection is still valid, user can retry discovery\n throw new Error(\n `Failed to discover MCP server capabilities: ${discoverResult.error}`\n );\n }\n\n return { id, state: MCPConnectionState.READY };\n }\n\n async removeMcpServer(id: string) {\n await this.mcp.removeServer(id);\n }\n\n getMcpServers(): MCPServersState {\n const mcpState: MCPServersState = {\n prompts: this.mcp.listPrompts(),\n resources: this.mcp.listResources(),\n servers: {},\n tools: this.mcp.listTools()\n };\n\n const servers = this.mcp.listServers();\n\n if (servers && Array.isArray(servers) && servers.length > 0) {\n for (const server of servers) {\n const serverConn = this.mcp.mcpConnections[server.id];\n\n // Determine the default state when no connection exists\n let defaultState: \"authenticating\" | \"not-connected\" = \"not-connected\";\n if (!serverConn && server.auth_url) {\n // If there's an auth_url but no connection, it's waiting for OAuth\n defaultState = \"authenticating\";\n }\n\n mcpState.servers[server.id] = {\n auth_url: server.auth_url,\n capabilities: serverConn?.serverCapabilities ?? null,\n error: serverConn?.connectionError ?? null,\n instructions: serverConn?.instructions ?? null,\n name: server.name,\n server_url: server.server_url,\n state: serverConn?.connectionState ?? defaultState\n };\n }\n }\n\n return mcpState;\n }\n\n /**\n * Create the OAuth provider used when connecting to MCP servers that require authentication.\n *\n * Override this method in a subclass to supply a custom OAuth provider implementation,\n * for example to use pre-registered client credentials, mTLS-based authentication,\n * or any other OAuth flow beyond dynamic client registration.\n *\n * @example\n * // Custom OAuth provider\n * class MyAgent extends Agent {\n * createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {\n * return new MyCustomOAuthProvider(\n * this.ctx.storage,\n * this.name,\n * callbackUrl\n * );\n * }\n * }\n *\n * @param callbackUrl The OAuth callback URL for the authorization flow\n * @returns An {@link AgentMcpOAuthProvider} instance used by {@link addMcpServer}\n */\n createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {\n return new DurableObjectOAuthClientProvider(\n this.ctx.storage,\n this.name,\n callbackUrl\n );\n }\n\n private broadcastMcpServers() {\n this.broadcast(\n JSON.stringify({\n mcp: this.getMcpServers(),\n type: MessageType.CF_AGENT_MCP_SERVERS\n })\n );\n }\n\n /**\n * Handle MCP OAuth callback request if it's an OAuth callback.\n *\n * This method encapsulates the entire OAuth callback flow:\n * 1. Checks if the request is an MCP OAuth callback\n * 2. Processes the OAuth code exchange\n * 3. Establishes the connection if successful\n * 4. Broadcasts MCP server state updates\n * 5. Returns the appropriate HTTP response\n *\n * @param request The incoming HTTP request\n * @returns Response if this was an OAuth callback, null otherwise\n */\n private async handleMcpOAuthCallback(\n request: Request\n ): Promise<Response | null> {\n // Check if this is an OAuth callback request\n const isCallback = this.mcp.isCallbackRequest(request);\n if (!isCallback) {\n return null;\n }\n\n // Handle the OAuth callback (exchanges code for token, clears OAuth credentials from storage)\n // This fires onServerStateChanged event which triggers broadcast\n const result = await this.mcp.handleCallbackRequest(request);\n\n // If auth was successful, establish the connection in the background\n if (result.authSuccess) {\n this.mcp.establishConnection(result.serverId).catch((error) => {\n console.error(\n \"[Agent handleMcpOAuthCallback] Connection establishment failed:\",\n error\n );\n });\n }\n\n this.broadcastMcpServers();\n\n // Return the HTTP response for the OAuth callback\n return this.handleOAuthCallbackResponse(result, request);\n }\n\n /**\n * Handle OAuth callback response using MCPClientManager configuration\n * @param result OAuth callback result\n * @param request The original request (needed for base URL)\n * @returns Response for the OAuth callback\n */\n private handleOAuthCallbackResponse(\n result: MCPClientOAuthResult,\n request: Request\n ): Response {\n const config = this.mcp.getOAuthCallbackConfig();\n\n // Use custom handler if configured\n if (config?.customHandler) {\n return config.customHandler(result);\n }\n\n const baseOrigin = new URL(request.url).origin;\n\n // Redirect to success URL if configured\n if (config?.successRedirect && result.authSuccess) {\n try {\n return Response.redirect(\n new URL(config.successRedirect, baseOrigin).href\n );\n } catch (e) {\n console.error(\n \"Invalid successRedirect URL:\",\n config.successRedirect,\n e\n );\n return Response.redirect(baseOrigin);\n }\n }\n\n // Redirect to error URL if configured\n if (config?.errorRedirect && !result.authSuccess) {\n try {\n const errorUrl = `${config.errorRedirect}?error=${encodeURIComponent(\n result.authError || \"Unknown error\"\n )}`;\n return Response.redirect(new URL(errorUrl, baseOrigin).href);\n } catch (e) {\n console.error(\"Invalid errorRedirect URL:\", config.errorRedirect, e);\n return Response.redirect(baseOrigin);\n }\n }\n\n // Default: redirect to base URL\n return Response.redirect(baseOrigin);\n }\n}\n\n// A set of classes that have been wrapped with agent context\nconst wrappedClasses = new Set<typeof Agent.prototype.constructor>();\n\n/**\n * Namespace for creating Agent instances\n * @template Agentic Type of the Agent class\n * @deprecated Use DurableObjectNamespace instead\n */\nexport type AgentNamespace<Agentic extends Agent<Cloudflare.Env>> =\n DurableObjectNamespace<Agentic>;\n\n/**\n * Agent's durable context\n */\nexport type AgentContext = DurableObjectState;\n\n/**\n * Configuration options for Agent routing\n */\nexport type AgentOptions<Env> = PartyServerOptions<Env>;\n\n/**\n * Route a request to the appropriate Agent\n * @param request Request to route\n * @param env Environment containing Agent bindings\n * @param options Routing options\n * @returns Response from the Agent or undefined if no route matched\n */\nexport async function routeAgentRequest<Env>(\n request: Request,\n env: Env,\n options?: AgentOptions<Env>\n) {\n return routePartykitRequest(request, env as Record<string, unknown>, {\n prefix: \"agents\",\n ...(options as PartyServerOptions<Record<string, unknown>>)\n });\n}\n\n// Email routing - deprecated resolver kept in root for upgrade discoverability\n// Other email utilities moved to agents/email subpath\nexport { createHeaderBasedEmailResolver } from \"./email\";\n\nimport type { EmailResolver } from \"./email\";\n\nexport type EmailRoutingOptions<Env> = AgentOptions<Env> & {\n resolver: EmailResolver<Env>;\n /**\n * Callback invoked when no routing information is found for an email.\n * Use this to reject the email or perform custom handling.\n * If not provided, a warning is logged and the email is dropped.\n */\n onNoRoute?: (email: ForwardableEmailMessage) => void | Promise<void>;\n};\n\n// Cache the agent namespace map for email routing\n// This maps both kebab-case and original names to namespaces\nconst agentMapCache = new WeakMap<\n Record<string, unknown>,\n Record<string, unknown>\n>();\n\n/**\n * Route an email to the appropriate Agent\n * @param email The email to route\n * @param env The environment containing the Agent bindings\n * @param options The options for routing the email\n * @returns A promise that resolves when the email has been routed\n */\nexport async function routeAgentEmail<\n Env extends Cloudflare.Env = Cloudflare.Env\n>(\n email: ForwardableEmailMessage,\n env: Env,\n options: EmailRoutingOptions<Env>\n): Promise<void> {\n const routingInfo = await options.resolver(email, env);\n\n if (!routingInfo) {\n if (options.onNoRoute) {\n await options.onNoRoute(email);\n } else {\n console.warn(\"No routing information found for email, dropping message\");\n }\n return;\n }\n\n // Build a map that includes both original names and kebab-case versions\n if (!agentMapCache.has(env as Record<string, unknown>)) {\n const map: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(env as Record<string, unknown>)) {\n if (\n value &&\n typeof value === \"object\" &&\n \"idFromName\" in value &&\n typeof value.idFromName === \"function\"\n ) {\n // Add both the original name and kebab-case version\n map[key] = value;\n map[camelCaseToKebabCase(key)] = value;\n }\n }\n agentMapCache.set(env as Record<string, unknown>, map);\n }\n\n const agentMap = agentMapCache.get(env as Record<string, unknown>)!;\n const namespace = agentMap[routingInfo.agentName];\n\n if (!namespace) {\n // Provide helpful error message listing available agents\n const availableAgents = Object.keys(agentMap)\n .filter((key) => !key.includes(\"-\")) // Show only original names, not kebab-case duplicates\n .join(\", \");\n throw new Error(\n `Agent namespace '${routingInfo.agentName}' not found in environment. Available agents: ${availableAgents}`\n );\n }\n\n const agent = await getAgentByName(\n namespace as unknown as DurableObjectNamespace<Agent<Env>>,\n routingInfo.agentId\n );\n\n // let's make a serialisable version of the email\n const serialisableEmail: AgentEmail = {\n getRaw: async () => {\n const reader = email.raw.getReader();\n const chunks: Uint8Array[] = [];\n\n let done = false;\n while (!done) {\n const { value, done: readerDone } = await reader.read();\n done = readerDone;\n if (value) {\n chunks.push(value);\n }\n }\n\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const combined = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.length;\n }\n\n return combined;\n },\n headers: email.headers,\n rawSize: email.rawSize,\n setReject: (reason: string) => {\n email.setReject(reason);\n },\n forward: (rcptTo: string, headers?: Headers) => {\n return email.forward(rcptTo, headers);\n },\n reply: (replyOptions: { from: string; to: string; raw: string }) => {\n return email.reply(\n new EmailMessage(replyOptions.from, replyOptions.to, replyOptions.raw)\n );\n },\n from: email.from,\n to: email.to,\n _secureRouted: routingInfo._secureRouted\n };\n\n await agent._onEmail(serialisableEmail);\n}\n\n/**\n * Get or create an Agent by name\n * @template Env Environment type containing bindings\n * @template T Type of the Agent class\n * @param namespace Agent namespace\n * @param name Name of the Agent instance\n * @param options Options for Agent creation\n * @returns Promise resolving to an Agent instance stub\n */\nexport async function getAgentByName<\n Env extends Cloudflare.Env = Cloudflare.Env,\n T extends Agent<Env> = Agent<Env>,\n Props extends Record<string, unknown> = Record<string, unknown>\n>(\n namespace: DurableObjectNamespace<T>,\n name: string,\n options?: {\n jurisdiction?: DurableObjectJurisdiction;\n locationHint?: DurableObjectLocationHint;\n props?: Props;\n }\n) {\n return getServerByName<Env, T>(namespace, name, options);\n}\n\n/**\n * A wrapper for streaming responses in callable methods\n */\nexport class StreamingResponse {\n private _connection: Connection;\n private _id: string;\n private _closed = false;\n\n constructor(connection: Connection, id: string) {\n this._connection = connection;\n this._id = id;\n }\n\n /**\n * Whether the stream has been closed (via end() or error())\n */\n get isClosed(): boolean {\n return this._closed;\n }\n\n /**\n * Send a chunk of data to the client\n * @param chunk The data to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n send(chunk: unknown): boolean {\n if (this._closed) {\n console.warn(\n \"StreamingResponse.send() called after stream was closed - data not sent\"\n );\n return false;\n }\n const response: RPCResponse = {\n done: false,\n id: this._id,\n result: chunk,\n success: true,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n\n /**\n * End the stream and send the final chunk (if any)\n * @param finalChunk Optional final chunk of data to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n end(finalChunk?: unknown): boolean {\n if (this._closed) {\n return false;\n }\n this._closed = true;\n const response: RPCResponse = {\n done: true,\n id: this._id,\n result: finalChunk,\n success: true,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n\n /**\n * Send an error to the client and close the stream\n * @param message Error message to send\n * @returns false if stream is already closed (no-op), true if sent\n */\n error(message: string): boolean {\n if (this._closed) {\n return false;\n }\n this._closed = true;\n const response: RPCResponse = {\n error: message,\n id: this._id,\n success: false,\n type: MessageType.RPC\n };\n this._connection.send(JSON.stringify(response));\n return true;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA+FA,SAAS,aAAa,KAAiC;AACrD,QACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,OACV,IAAI,SAAS,YAAY,OACzB,QAAQ,OACR,OAAO,IAAI,OAAO,YAClB,YAAY,OACZ,OAAO,IAAI,WAAW,YACtB,UAAU,OACV,MAAM,QAAS,IAAmB,KAAK;;;;;AAO3C,SAAS,qBAAqB,KAAyC;AACrE,QACE,OAAO,QAAQ,YACf,QAAQ,QACR,UAAU,OACV,IAAI,SAAS,YAAY,kBACzB,WAAW;;AAcf,MAAM,mCAAmB,IAAI,SAAqC;;;;AAKlE,IAAa,WAAb,cAA8B,MAAM;CAIlC,YAAY,OAAe,OAAgB;EACzC,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,QAAM,qBAAqB,WAAW,EAAE,OAAO,CAAC;AAChD,OAAK,OAAO;AACZ,OAAK,QAAQ;;;;;;;AAQjB,SAAgB,SAAS,WAA6B,EAAE,EAAE;AACxD,QAAO,SAAS,kBACd,QACA,UACA;AACA,MAAI,CAAC,iBAAiB,IAAI,OAAO,CAC/B,kBAAiB,IAAI,QAAQ,SAAS;AAGxC,SAAO;;;AAIX,IAAI,+BAA+B;;;;;;AAOnC,MAAa,qBAAqB,WAA6B,EAAE,KAAK;AACpE,KAAI,CAAC,8BAA8B;AACjC,iCAA+B;AAC/B,UAAQ,KACN,sHACD;;AAEH,QAAO,SAAS,SAAS;;AAsD3B,SAAS,gBAAgB,MAAc;AAErC,QADiB,oBAAoB,KAAK,CAC1B,aAAa;;AAmE/B,MAAM,eAAe;AACrB,MAAM,oBAAoB;AAE1B,MAAM,gBAAgB,EAAE;;;;;AAMxB,MAAM,kBAAkB;;;;;AAMxB,MAAM,8CAA8B,IAAI,SAAmB;;;;;AAM3D,MAAa,+BAA+B;CAE1C,WAAW;CAEX,uBAAuB;CAMvB,4BAA4B;CAC7B;AAYD,SAAgB,kBAOd;CACA,MAAM,QAAQA,sCAAa,UAAU;AAQrC,KAAI,CAAC,MACH,QAAO;EACL,OAAO;EACP,YAAY;EACZ,SAAS;EACT,OAAO;EACR;AAEH,QAAO;;;;;;;;AAWT,SAAS,iBACP,QAIiB;AACjB,QAAO,SAAU,GAAG,MAAoC;EACtD,MAAM,EAAE,YAAY,SAAS,OAAO,UAAU,iBAAiB;AAE/D,MAAI,UAAU,KAEZ,QAAO,OAAO,MAAM,MAAM,KAAK;AAGjC,SAAOA,sCAAa,IAAI;GAAE,OAAO;GAAM;GAAY;GAAS;GAAO,QAAQ;AACzE,UAAO,OAAO,MAAM,MAAM,KAAK;IAC/B;;;;;;;;AAwBN,IAAa,QAAb,MAAa,cAIH,OAAmB;;;;CAwC3B,IAAI,QAAe;AACjB,MAAI,KAAK,WAAW,cAElB,QAAO,KAAK;EAId,MAAM,aAAa,KAAK,GAAkC;uDACP,kBAAkB;;EAIrE,MAAM,SAAS,KAAK,GAAiC;qDACJ,aAAa;;AAG9D,MACE,WAAW,IAAI,UAAU,UAEzB,OAAO,IAAI,OACX;GACA,MAAM,QAAQ,OAAO,IAAI;AAEzB,OAAI;AACF,SAAK,SAAS,KAAK,MAAM,MAAM;YACxB,GAAG;AACV,YAAQ,MACN,+DACA,EACD;AACD,QAAI,KAAK,iBAAiB,eAAe;AACvC,UAAK,SAAS,KAAK;AAEnB,UAAK,kBAAkB,KAAK,aAAa;WACpC;AAEL,UAAK,GAAG,0CAA0C;AAClD,UAAK,GAAG,0CAA0C;AAClD;;;AAGJ,UAAO,KAAK;;AAMd,MAAI,KAAK,iBAAiB,cAExB;AAIF,OAAK,kBAAkB,KAAK,aAAa;AACzC,SAAO,KAAK;;;iBAWuB,EAAE,WAAW,MAAM;;;;;CAKxD,IAAY,mBAAyC;EACnD,MAAM,OAAO,KAAK;AAClB,SAAO;GACL,WACE,KAAK,SAAS,aAAa,6BAA6B;GAC1D,uBACE,KAAK,SAAS,yBACd,6BAA6B;GAC/B,4BACE,KAAK,SAAS,8BACd,6BAA6B;GAChC;;;;;;;;;CAeH,IACE,SACA,GAAG,QACH;EACA,IAAI,QAAQ;AACZ,MAAI;AAEF,WAAQ,QAAQ,QACb,KAAK,KAAK,MAAM,MAAM,OAAO,IAAI,OAAO,SAAS,MAAM,KACxD,GACD;AAGD,UAAO,CAAC,GAAG,KAAK,IAAI,QAAQ,IAAI,KAAK,OAAO,GAAG,OAAO,CAAC;WAChD,GAAG;AACV,SAAM,KAAK,QAAQ,IAAI,SAAS,OAAO,EAAE,CAAC;;;CAG9C,YAAY,KAAmB,KAAU;AACvC,QAAM,KAAK,IAAI;gBA1JA;sBACM,IAAI,iBAAiB;oBACvB;4CAOQ,IAAI,SAM9B;8BAQoD;sBAGrD,OAAO,eAAe,KAAK,CAAC;sBAQR;uBA4FU;wBA0+BP;eAiaD,YAAY;GAClC,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;GAGzC,MAAM,SAAS,KAAK,GAEnB;wDACmD,IAAI;;AAGxD,OAAI,UAAU,MAAM,QAAQ,OAAO,CACjC,MAAK,MAAM,OAAO,QAAQ;IACxB,MAAM,WAAW,KAAK,IAAI;AAC1B,QAAI,CAAC,UAAU;AACb,aAAQ,MAAM,YAAY,IAAI,SAAS,YAAY;AACnD;;AAIF,QAAI,IAAI,SAAS,cAAc,IAAI,YAAY,GAAG;KAChD,MAAM,qBACH,IAA0C,wBAC3C;KACF,MAAM,qBACJ,KAAK,iBAAiB;KACxB,MAAM,iBAAiB,MAAM;AAE7B,SAAI,iBAAiB,oBAAoB;AACvC,cAAQ,KACN,8BAA8B,IAAI,GAAG,oCACtC;AACD;;AAGF,aAAQ,KACN,2CAA2C,IAAI,GAAG,YAAY,eAAe,QAC9E;;AAIH,QAAI,IAAI,SAAS,WACf,MACG,GAAG,sEAAsE,IAAI,cAAc,IAAI;AAGpG,UAAMA,sCAAa,IACjB;KACE,OAAO;KACP,YAAY;KACZ,SAAS;KACT,OAAO;KACR,EACD,YAAY;AACV,SAAI;AACF,WAAK,eAAe,KAClB;OACE,gBAAgB,YAAY,IAAI,GAAG;OACnC,IAAI,QAAQ;OACZ,SAAS;QACP,UAAU,IAAI;QACd,IAAI,IAAI;QACT;OACD,WAAW,KAAK,KAAK;OACrB,MAAM;OACP,EACD,KAAK,IACN;AAED,YACE,SAIA,KAAK,KAAK,CAAC,KAAK,MAAM,IAAI,QAAkB,EAAE,IAAI;cAC7C,GAAG;AACV,cAAQ,MAAM,6BAA6B,IAAI,SAAS,IAAI,EAAE;AAE9D,UAAI;AACF,aAAM,KAAK,QAAQ,EAAE;cACf;;MAKb;AAED,QAAI,KAAK,WAAY;AAErB,QAAI,IAAI,SAAS,QAAQ;KAEvB,MAAM,oBAAoB,gBAAgB,IAAI,KAAK;KACnD,MAAM,gBAAgB,KAAK,MAAM,kBAAkB,SAAS,GAAG,IAAK;AAEpE,UAAK,GAAG;oDACkC,cAAc,cAAc,IAAI,GAAG;;eAEpE,IAAI,SAAS,YAAY;KAElC,MAAM,gBACJ,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,IAAI,IAAI,mBAAmB;AAE1D,UAAK,GAAG;iEAC+C,cAAc,cAAc,IAAI,GAAG;;UAI1F,MAAK,GAAG;yDACuC,IAAI,GAAG;;;AAK5D,OAAI,KAAK,WAAY;AAGrB,SAAM,KAAK,oBAAoB;;AAh+C/B,MAAI,CAAC,eAAe,IAAI,KAAK,YAAY,EAAE;AAEzC,QAAK,wBAAwB;AAC7B,kBAAe,IAAI,KAAK,YAAY;;AAGtC,OAAK,GAAG;;;;;;;;;;;AAYR,OAAK,GAAG;;;;;;AAOR,OAAK,GAAG;;;;;;;;AASR,OAAK,GAAG;;;;;;;;;;;;;;EAiBR,MAAM,wBAAwB,QAAgB;AAC5C,OAAI;AACF,SAAK,IAAI,QAAQ,IAAI,KAAK,IAAI;YACvB,GAAG;AAGV,QAAI,EADY,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,EAC7C,aAAa,CAAC,SAAS,mBAAmB,CACrD,OAAM;;;AAKZ,uBACE,qEACD;AACD,uBACE,uEACD;AACD,uBACE,0EACD;AAGD,OAAK,GAAG;;;;;;;;;;;;;;;;;;AAmBR,OAAK,GAAG;;;AAIR,OAAK,GAAG;;;AAKR,OAAK,MAAM,IAAI,iBAAiB,KAAK,aAAa,MAAM,SAAS,EAC/D,SAAS,KAAK,IAAI,SACnB,CAAC;AAGF,OAAK,aAAa,IAChB,KAAK,IAAI,qBAAqB,YAAY;AACxC,QAAK,qBAAqB;IAC1B,CACH;AAGD,OAAK,aAAa,IAChB,KAAK,IAAI,sBAAsB,UAAU;AACvC,QAAK,eAAe,KAAK,MAAM;IAC/B,CACH;EAGD;GACE,MAAM,QAAQ,OAAO,eAAe,KAAK;GACzC,MAAM,YAAY,OAAO,UAAU,eAAe,KAChD,OACA,iBACD;GACD,MAAM,YAAY,OAAO,UAAU,eAAe,KAChD,OACA,gBACD;AAED,OAAI,aAAa,UACf,OAAM,IAAI,MACR,+HAED;AAGH,OAAI,WAAW;IACb,MAAM,OAAO,KAAK;AAClB,QAAI,CAAC,4BAA4B,IAAI,KAAK,EAAE;AAC1C,iCAA4B,IAAI,KAAK;AACrC,aAAQ,KACN,6FACD;;;GAIL,MAAM,OAAO,MAAM;AACnB,OAAI,MAAM,mBAAmB,KAAK,eAChC,MAAK,uBAAuB;YACnB,MAAM,kBAAkB,KAAK,cACtC,MAAK,uBAAuB;;EAKhC,MAAM,aAAa,KAAK,UAAU,KAAK,KAAK;AAC5C,OAAK,aAAa,YAAqB;AACrC,UAAOA,sCAAa,IAClB;IAAE,OAAO;IAAM,YAAY;IAAW;IAAS,OAAO;IAAW,EACjE,YAAY;AAGV,UAAM,KAAK,IAAI,kBAAkB;IAGjC,MAAM,gBAAgB,MAAM,KAAK,uBAAuB,QAAQ;AAChE,QAAI,cACF,QAAO;AAGT,WAAO,KAAK,gBAAgB,WAAW,QAAQ,CAAC;KAEnD;;EAGH,MAAM,aAAa,KAAK,UAAU,KAAK,KAAK;AAC5C,OAAK,YAAY,OAAO,YAAwB,YAAuB;AACrE,QAAK,yBAAyB,WAAW;AACzC,UAAOA,sCAAa,IAClB;IAAE,OAAO;IAAM;IAAY,SAAS;IAAW,OAAO;IAAW,EACjE,YAAY;AAGV,UAAM,KAAK,IAAI,kBAAkB;AACjC,QAAI,OAAO,YAAY,SACrB,QAAO,KAAK,gBAAgB,WAAW,YAAY,QAAQ,CAAC;IAG9D,IAAI;AACJ,QAAI;AACF,cAAS,KAAK,MAAM,QAAQ;aACrB,IAAI;AAEX,YAAO,KAAK,gBAAgB,WAAW,YAAY,QAAQ,CAAC;;AAG9D,QAAI,qBAAqB,OAAO,EAAE;AAEhC,SAAI,KAAK,qBAAqB,WAAW,EAAE;AAEzC,iBAAW,KACT,KAAK,UAAU;OACb,MAAM,YAAY;OAClB,OAAO;OACR,CAAC,CACH;AACD;;AAEF,SAAI;AACF,WAAK,kBAAkB,OAAO,OAAgB,WAAW;cAClD,GAAG;AAGV,cAAQ,MAAM,kCAAkC,EAAE;AAClD,iBAAW,KACT,KAAK,UAAU;OACb,MAAM,YAAY;OAClB,OAAO;OACR,CAAC,CACH;;AAEH;;AAGF,QAAI,aAAa,OAAO,EAAE;AACxB,SAAI;MACF,MAAM,EAAE,IAAI,QAAQ,SAAS;MAG7B,MAAM,WAAW,KAAK;AACtB,UAAI,OAAO,aAAa,WACtB,OAAM,IAAI,MAAM,UAAU,OAAO,iBAAiB;AAGpD,UAAI,CAAC,KAAK,YAAY,OAAO,CAC3B,OAAM,IAAI,MAAM,UAAU,OAAO,kBAAkB;MAGrD,MAAM,WAAW,iBAAiB,IAAI,SAAqB;AAG3D,UAAI,UAAU,WAAW;OACvB,MAAM,SAAS,IAAI,kBAAkB,YAAY,GAAG;AAEpD,YAAK,eAAe,KAClB;QACE,gBAAgB,yBAAyB;QACzC,IAAI,QAAQ;QACZ,SAAS;SACP;SACA,WAAW;SACZ;QACD,WAAW,KAAK,KAAK;QACrB,MAAM;QACP,EACD,KAAK,IACN;AAED,WAAI;AACF,cAAM,SAAS,MAAM,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACtC,KAAK;AAEZ,gBAAQ,MAAM,8BAA8B,OAAO,KAAK,IAAI;AAE5D,YAAI,CAAC,OAAO,SACV,QAAO,MACL,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CACjD;;AAGL;;MAIF,MAAM,SAAS,MAAM,SAAS,MAAM,MAAM,KAAK;AAE/C,WAAK,eAAe,KAClB;OACE,gBAAgB,eAAe;OAC/B,IAAI,QAAQ;OACZ,SAAS;QACP;QACA,WAAW,UAAU;QACtB;OACD,WAAW,KAAK,KAAK;OACrB,MAAM;OACP,EACD,KAAK,IACN;MAED,MAAM,WAAwB;OAC5B,MAAM;OACN;OACA;OACA,SAAS;OACT,MAAM,YAAY;OACnB;AACD,iBAAW,KAAK,KAAK,UAAU,SAAS,CAAC;cAClC,GAAG;MAEV,MAAM,WAAwB;OAC5B,OACE,aAAa,QAAQ,EAAE,UAAU;OACnC,IAAI,OAAO;OACX,SAAS;OACT,MAAM,YAAY;OACnB;AACD,iBAAW,KAAK,KAAK,UAAU,SAAS,CAAC;AACzC,cAAQ,MAAM,cAAc,EAAE;;AAEhC;;AAGF,WAAO,KAAK,gBAAgB,WAAW,YAAY,QAAQ,CAAC;KAE/D;;EAGH,MAAM,aAAa,KAAK,UAAU,KAAK,KAAK;AAC5C,OAAK,aAAa,YAAwB,QAA2B;AACnE,QAAK,yBAAyB,WAAW;AAGzC,UAAOA,sCAAa,IAClB;IAAE,OAAO;IAAM;IAAY,SAAS,IAAI;IAAS,OAAO;IAAW,EACnE,YAAY;AAGV,QAAI,KAAK,2BAA2B,YAAY,IAAI,CAClD,MAAK,sBAAsB,YAAY,KAAK;AAK9C,QAAI,KAAK,iBAAiB,sBACxB,YAAW,KACT,KAAK,UAAU;KACb,MAAM,KAAK;KACX,OAAO,qBAAqB,KAAK,aAAa,KAAK;KACnD,MAAM,YAAY;KACnB,CAAC,CACH;AAGH,QAAI,KAAK,MACP,YAAW,KACT,KAAK,UAAU;KACb,OAAO,KAAK;KACZ,MAAM,YAAY;KACnB,CAAC,CACH;AAGH,eAAW,KACT,KAAK,UAAU;KACb,KAAK,KAAK,eAAe;KACzB,MAAM,YAAY;KACnB,CAAC,CACH;AAED,SAAK,eAAe,KAClB;KACE,gBAAgB;KAChB,IAAI,QAAQ;KACZ,SAAS,EACP,cAAc,WAAW,IAC1B;KACD,WAAW,KAAK,KAAK;KACrB,MAAM;KACP,EACD,KAAK,IACN;AACD,WAAO,KAAK,gBAAgB,WAAW,YAAY,IAAI,CAAC;KAE3D;;EAGH,MAAM,WAAW,KAAK,QAAQ,KAAK,KAAK;AACxC,OAAK,UAAU,OAAO,UAAkB;AACtC,UAAOA,sCAAa,IAClB;IACE,OAAO;IACP,YAAY;IACZ,SAAS;IACT,OAAO;IACR,EACD,YAAY;AACV,UAAM,KAAK,UAAU,YAAY;AAC/B,WAAM,KAAK,IAAI,8BAA8B,KAAK,KAAK;AACvD,UAAK,qBAAqB;AAG1B,UAAK,yBAAyB;AAE9B,YAAO,SAAS,MAAM;MACtB;KAEL;;;;;;CAOL,AAAQ,0BAAgC;EAiBtC,MAAM,WAfgB,KAAK,GAKzB;;;;;;;;MAU6B,QAC5B,QAAQ,CAAC,KAAK,2BAA2B,IAAI,cAAc,CAC7D;AAED,MAAI,SAAS,SAAS,GAAG;GACvB,MAAM,kBAAkB,KAAK,0BAA0B;AACvD,QAAK,MAAM,EACT,eAAe,SACf,OACA,QACA,eACG,UAAU;IACb,MAAM,aACJ,gBAAgB,WAAW,IACvB,gCAAgC,QAAQ,MAAM,gBAAgB,GAAG,MACjE,gCAAgC,QAAQ;IAC9C,MAAM,YACJ,SAAS,KAAK,YAAY,IACtB,KAAK,OAAO,WAAW,UAAU,eACjC,SAAS,IACP,KAAK,OAAO,YACZ,KAAK,UAAU;AACvB,YAAQ,KACN,iBAAiB,MAAM,4CAA4C,QAAQ,GAAG,UAAU,sCACjD,aACxC;;;;CAKP,AAAQ,kBACN,WACA,SAAgC,UAC1B;AAEN,OAAK,oBAAoB,WAAW,OAAO;AAG3C,OAAK,SAAS;AACd,OAAK,GAAG;;gBAEI,aAAa,IAAI,KAAK,UAAU,UAAU,CAAC;;AAEvD,OAAK,GAAG;;gBAEI,kBAAkB,IAAI,KAAK,UAAU,KAAK,CAAC;;AAIvD,OAAK,UACH,KAAK,UAAU;GACb,OAAO;GACP,MAAM,YAAY;GACnB,CAAC,EACF,WAAW,WAAW,CAAC,OAAO,GAAG,GAAG,EAAE,CACvC;EAID,MAAM,EAAE,YAAY,SAAS,UAAUA,sCAAa,UAAU,IAAI,EAAE;AACpE,OAAK,IAAI,WACN,YAAY;AACX,OAAI;AACF,UAAMA,sCAAa,IACjB;KAAE,OAAO;KAAM;KAAY;KAAS;KAAO,EAC3C,YAAY;AACV,UAAK,eAAe,KAClB;MACE,gBAAgB;MAChB,IAAI,QAAQ;MACZ,SAAS,EAAE;MACX,WAAW,KAAK,KAAK;MACrB,MAAM;MACP,EACD,KAAK,IACN;AACD,WAAM,KAAK,0BAA0B,WAAW,OAAO;MAE1D;YACM,GAAG;AAEV,QAAI;AACF,WAAM,KAAK,QAAQ,EAAE;YACf;;MAIR,CACL;;;;;;;CAQH,SAAS,OAAoB;EAE3B,MAAM,QAAQA,sCAAa,UAAU;AACrC,MAAI,OAAO,cAAc,KAAK,qBAAqB,MAAM,WAAW,CAClE,OAAM,IAAI,MAAM,yBAAyB;AAE3C,OAAK,kBAAkB,OAAO,SAAS;;;;;;;;;CAUzC,AAAQ,yBAAyB,YAAwB;AACvD,MAAI,KAAK,mBAAmB,IAAI,WAAW,CAAE;EAM7C,MAAM,aAAa,OAAO,yBAAyB,YAAY,QAAQ;EAEvE,IAAI;EACJ,IAAI;AAEJ,MAAI,YAAY,KAAK;AAInB,YAAS,WAAW,IAAI,KAAK,WAAW;AAIxC,YAAS,WAAW,SAAS,KAAK,WAAW;SACxC;GAIL,IAAI,WAAY,WAAW,SAAS;AAIpC,kBAAe;AACf,aAAU,UAAmB;AAC3B,eAAW;AACX,WAAO;;;AAIX,OAAK,mBAAmB,IAAI,YAAY;GAAE;GAAQ;GAAQ,CAAC;EAE3D,MAAM,SAAS;AAGf,SAAO,eAAe,YAAY,SAAS;GACzC,cAAc;GACd,YAAY;GACZ,MAAM;IACJ,MAAM,MAAM,QAAQ;AACpB,QAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,UAAU,KAAK;KAC3D,MAAM,GAAG,SAAS,GAAG,GAAG,cAAc;AACtC,YAAO,OAAO,KAAK,UAAU,CAAC,SAAS,IAAI,YAAY;;AAEzD,WAAO;;GAEV,CAAC;AAGF,SAAO,eAAe,YAAY,YAAY;GAC5C,cAAc;GACd,UAAU;GACV,MAAM,WAAmD;IACvD,MAAM,MAAM,QAAQ;IACpB,MAAM,eACJ,OAAO,QAAQ,OAAO,QAAQ,WACzB,IAAgC,UACjC;IAEN,IAAI;AACJ,QAAI,OAAO,cAAc,YAAY;KAEnC,IAAI,cAAuB;AAC3B,SAAI,OAAO,QAAQ,OAAO,QAAQ,YAAY,UAAU,KAAK;MAC3D,MAAM,GAAG,SAAS,GAAG,GAAG,SAAS;AACjC,oBAAc,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO;;AAEtD,oBAAgB,UAAyC,YAAY;UAErE,gBAAe;AAIjB,QAAI,iBAAiB,QAAW;AAC9B,SAAI,gBAAgB,QAAQ,OAAO,iBAAiB,SAClD,QAAO,OAAO;MACZ,GAAI;OACH,SAAS;MACX,CAAC;AAGJ,YAAO,OAAO,GAAG,SAAS,cAAc,CAAC;;AAE3C,WAAO,OAAO,aAAa;;GAE9B,CAAC;;;;;;;CAQJ,sBAAsB,YAAwB,WAAW,MAAM;AAC7D,OAAK,yBAAyB,WAAW;EACzC,MAAM,YAAY,KAAK,mBAAmB,IAAI,WAAW;EACzD,MAAM,MAAO,UAAU,QAAQ,IAAuC,EAAE;AACxE,MAAI,SACF,WAAU,OAAO;GAAE,GAAG;IAAM,kBAAkB;GAAM,CAAC;OAChD;GAGL,MAAM,GAAG,kBAAkB,GAAG,GAAG,SAAS;AAC1C,aAAU,OAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO,KAAK;;;;;;;;CAShE,qBAAqB,YAAiC;EACpD,MAAM,YAAY,KAAK,mBAAmB,IAAI,WAAW;AACzD,MAAI,UACF,QAAO,CAAC,CAAE,UAAU,QAAQ,GAC1B;AAKJ,SAAO;;;;;;;;CAST,2BACE,aACA,MACS;AACT,SAAO;;;;;;;;CAUT,oBAAoB,WAAkB,QAA+B;;;;;;;;;CAarE,eAAe,OAA0B,QAA+B;;;;;;;;;;;;CAgBxE,cAAc,OAA0B,QAA+B;;;;;CAQvE,MAAc,0BACZ,OACA,QACe;AACf,UAAQ,KAAK,sBAAb;GACE,KAAK;AACH,UAAM,KAAK,eAAe,OAAO,OAAO;AACxC;GACF,KAAK;AACH,UAAM,KAAK,cAAc,OAAO,OAAO;AACvC;;;;;;;;CAUN,MAAM,SAAS,OAAmB;AAGhC,SAAOA,sCAAa,IAClB;GAAE,OAAO;GAAM,YAAY;GAAW,SAAS;GAAkB;GAAO,EACxE,YAAY;AACV,OAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,WAC/C,QAAO,KAAK,gBACT,KAAK,QAAiD,MAAM,CAC9D;QACI;AACL,YAAQ,IAAI,wBAAwB,MAAM,MAAM,OAAO,MAAM,GAAG;AAChE,YAAQ,IAAI,YAAY,MAAM,QAAQ,IAAI,UAAU,CAAC;AACrD,YAAQ,IACN,sFACD;;IAGN;;;;;;;;;;;CAYH,MAAM,aACJ,OACA,SAQe;AACf,SAAO,KAAK,UAAU,YAAY;AAEhC,OAAI,MAAM,iBAAiB,QAAQ,WAAW,OAC5C,OAAM,IAAI,MACR,0KAGD;GAGH,MAAM,YAAY,qBAAqB,KAAK,aAAa,KAAK;GAC9D,MAAM,UAAU,KAAK;GAErB,MAAM,EAAE,sBAAsB,MAAM,OAAO;GAC3C,MAAM,MAAM,mBAAmB;AAC/B,OAAI,UAAU;IAAE,MAAM,MAAM;IAAI,MAAM,QAAQ;IAAU,CAAC;AACzD,OAAI,aAAa,MAAM,KAAK;AAC5B,OAAI,WACF,QAAQ,WAAW,OAAO,MAAM,QAAQ,IAAI,UAAU,MAAM,aAC7D;AACD,OAAI,WAAW;IACb,aAAa,QAAQ,eAAe;IACpC,MAAM,QAAQ;IACf,CAAC;GAGF,MAAM,YAAY,IAAI,QAAQ,GADf,MAAM,KAAK,MAAM,IAAI,CAAC,GACG;AACxC,OAAI,UAAU,eAAe,MAAM,QAAQ,IAAI,aAAa,CAAE;AAC9D,OAAI,UAAU,cAAc,UAAU;AACtC,OAAI,UAAU,gBAAgB,UAAU;AACxC,OAAI,UAAU,cAAc,QAAQ;AAGpC,OAAI,OAAO,QAAQ,WAAW,UAAU;IACtC,MAAM,gBAAgB,MAAM,iBAC1B,QAAQ,QACR,WACA,QACD;AACD,QAAI,UAAU,eAAe,cAAc,eAAe;AAC1D,QAAI,UAAU,kBAAkB,cAAc,kBAAkB;;AAGlE,OAAI,QAAQ,QACV,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,QAAQ,CACxD,KAAI,UAAU,KAAK,MAAM;AAG7B,SAAM,MAAM,MAAM;IAChB,MAAM,MAAM;IACZ,KAAK,IAAI,OAAO;IAChB,IAAI,MAAM;IACX,CAAC;IACF;;CAGJ,MAAc,UAAa,IAA0B;AACnD,MAAI;AACF,UAAO,MAAM,IAAI;WACV,GAAG;AACV,SAAM,KAAK,QAAQ,EAAE;;;;;;;CAQzB,AAAQ,yBAAyB;EAE/B,MAAM,iBAAiB,CAAC,MAAM,WAAW,OAAO,UAAU;EAC1D,MAAM,8BAAc,IAAI,KAAa;AACrC,OAAK,MAAM,aAAa,gBAAgB;GACtC,IAAI,QAAQ;AACZ,UAAO,SAAS,UAAU,OAAO,WAAW;IAC1C,MAAM,cAAc,OAAO,oBAAoB,MAAM;AACrD,SAAK,MAAM,cAAc,YACvB,aAAY,IAAI,WAAW;AAE7B,YAAQ,OAAO,eAAe,MAAM;;;EAIxC,IAAI,QAAQ,OAAO,eAAe,KAAK;EACvC,IAAI,QAAQ;AACZ,SAAO,SAAS,UAAU,OAAO,aAAa,QAAQ,IAAI;GACxD,MAAM,cAAc,OAAO,oBAAoB,MAAM;AACrD,QAAK,MAAM,cAAc,aAAa;IACpC,MAAM,aAAa,OAAO,yBAAyB,OAAO,WAAW;AAGrE,QACE,YAAY,IAAI,WAAW,IAC3B,WAAW,WAAW,IAAI,IAC1B,CAAC,cACD,CAAC,CAAC,WAAW,OACb,OAAO,WAAW,UAAU,WAE5B;IAMF,MAAM,kBAAkB,iBACtB,KAAK,YACN;AAID,QAAI,KAAK,YAAY,WAAW,CAC9B,kBAAiB,IACf,iBACA,iBAAiB,IAAI,KAAK,YAAsC,CACjE;AAIH,SAAK,YAAY,UAAU,cAA4B;;AAGzD,WAAQ,OAAO,eAAe,MAAM;AACpC;;;CASJ,AAAS,QAAQ,mBAAyC,OAAiB;EACzE,IAAI;AACJ,MAAI,qBAAqB,OAAO;AAC9B,cAAW;AAEX,WAAQ,MACN,kCACC,kBAAiC,IAClC,SACD;AACD,WAAQ,MACN,4EACD;SACI;AACL,cAAW;AAEX,WAAQ,MAAM,oBAAoB,SAAS;AAC3C,WAAQ,MAAM,kDAAkD;;AAElE,QAAM;;;;;CAMR,SAAS;AACP,QAAM,IAAI,MAAM,kBAAkB;;;;;;;;CASpC,MAAM,MAAmB,UAAsB,SAA6B;EAC1E,MAAM,KAAK,OAAO,EAAE;AACpB,MAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MAAM,4BAA4B;AAG9C,MAAI,OAAO,KAAK,cAAc,WAC5B,OAAM,IAAI,MAAM,QAAQ,SAAS,oBAAoB;AAGvD,OAAK,GAAG;;gBAEI,GAAG,IAAI,KAAK,UAAU,QAAQ,CAAC,IAAI,SAAS;;AAGxD,EAAK,KAAK,aAAa,CAAC,OAAO,MAAM;AACnC,WAAQ,MAAM,yBAAyB,EAAE;IACzC;AAEF,SAAO;;CAKT,MAAc,cAAc;AAC1B,MAAI,KAAK,eACP;AAEF,OAAK,iBAAiB;AACtB,MAAI;AACF,UAAO,MAAM;IACX,MAAM,SAAS,KAAK,GAAsB;;;;AAK1C,QAAI,CAAC,UAAU,OAAO,WAAW,EAC/B;AAGF,SAAK,MAAM,OAAO,UAAU,EAAE,EAAE;KAC9B,MAAM,WAAW,KAAK,IAAI;AAC1B,SAAI,CAAC,UAAU;AACb,cAAQ,MAAM,YAAY,IAAI,SAAS,YAAY;AACnD,YAAM,KAAK,QAAQ,IAAI,GAAG;AAC1B;;KAEF,MAAM,EAAE,YAAY,SAAS,UAAUA,sCAAa,UAAU,IAAI,EAAE;AACpE,SAAI;AACF,YAAMA,sCAAa,IACjB;OACE,OAAO;OACP;OACA;OACA;OACD,EACD,YAAY;AAEV,aACE,SAIA,KAAK,KAAK,CAAC,KAAK,MAAM,IAAI,QAAkB,EAAE,IAAI;QAEvD;cACM,GAAG;AACV,cAAQ,MACN,kBAAkB,OAAO,IAAI,SAAS,CAAC,kBAAkB,IAAI,GAAG,IAChE,EACD;eACO;AACR,YAAM,KAAK,QAAQ,IAAI,GAAG;;;;YAIxB;AACR,QAAK,iBAAiB;;;;;;;CAQ1B,MAAM,QAAQ,IAAY;AACxB,OAAK,GAAG,2CAA2C;;;;;CAMrD,MAAM,aAAa;AACjB,OAAK,GAAG;;;;;;CAOV,MAAM,qBAAqB,UAAkB;AAC3C,OAAK,GAAG,iDAAiD;;;;;;;CAQ3D,MAAM,SAAS,IAAoD;EACjE,MAAM,SAAS,KAAK,GAAsB;kDACI,GAAG;;AAEjD,SAAO,SACH;GAAE,GAAG,OAAO;GAAI,SAAS,KAAK,MAAM,OAAO,GAAG,QAAQ;GAAE,GACxD;;;;;;;;CASN,MAAM,UAAU,KAAa,OAA6C;AAIxE,SAHe,KAAK,GAAsB;;MAG5B,QAAQ,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,SAAS,MAAM;;;;;;;;;;CAWvE,MAAM,SACJ,MACA,UACA,SACsB;EACtB,MAAM,KAAK,OAAO,EAAE;EAEpB,MAAM,sBAAsB,aAC1B,KAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,SAAS,GAAG;GACxC,IAAI,QAAQ;GACZ,SAAS;IACG;IACN;IACL;GACD,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;AAEH,MAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MAAM,4BAA4B;AAG9C,MAAI,OAAO,KAAK,cAAc,WAC5B,OAAM,IAAI,MAAM,QAAQ,SAAS,oBAAoB;AAGvD,MAAI,gBAAgB,MAAM;GACxB,MAAM,YAAY,KAAK,MAAM,KAAK,SAAS,GAAG,IAAK;AACnD,QAAK,GAAG;;kBAEI,GAAG,IAAI,SAAS,IAAI,KAAK,UACjC,QACD,CAAC,iBAAiB,UAAU;;AAG/B,SAAM,KAAK,oBAAoB;GAE/B,MAAM,WAAwB;IAClB;IACV;IACS;IACT,MAAM;IACN,MAAM;IACP;AAED,sBAAmB,SAAS;AAE5B,UAAO;;AAET,MAAI,OAAO,SAAS,UAAU;GAC5B,MAAM,OAAO,IAAI,KAAK,KAAK,KAAK,GAAG,OAAO,IAAK;GAC/C,MAAM,YAAY,KAAK,MAAM,KAAK,SAAS,GAAG,IAAK;AAEnD,QAAK,GAAG;;kBAEI,GAAG,IAAI,SAAS,IAAI,KAAK,UACjC,QACD,CAAC,eAAe,KAAK,IAAI,UAAU;;AAGtC,SAAM,KAAK,oBAAoB;GAE/B,MAAM,WAAwB;IAClB;IACV,gBAAgB;IAChB;IACS;IACT,MAAM;IACN,MAAM;IACP;AAED,sBAAmB,SAAS;AAE5B,UAAO;;AAET,MAAI,OAAO,SAAS,UAAU;GAC5B,MAAM,oBAAoB,gBAAgB,KAAK;GAC/C,MAAM,YAAY,KAAK,MAAM,kBAAkB,SAAS,GAAG,IAAK;AAEhE,QAAK,GAAG;;kBAEI,GAAG,IAAI,SAAS,IAAI,KAAK,UACjC,QACD,CAAC,YAAY,KAAK,IAAI,UAAU;;AAGnC,SAAM,KAAK,oBAAoB;GAE/B,MAAM,WAAwB;IAClB;IACV,MAAM;IACN;IACS;IACT,MAAM;IACN,MAAM;IACP;AAED,sBAAmB,SAAS;AAE5B,UAAO;;AAET,QAAM,IAAI,MACR,0BAA0B,KAAK,UAAU,KAAK,CAAC,GAAG,OAAO,KAAK,uBAAuB,WACtF;;;;;;;;;;CAWH,MAAM,cACJ,iBACA,UACA,SACsB;EAEtB,MAAM,uBAAuB,MAAU,KAAK;AAE5C,MAAI,OAAO,oBAAoB,YAAY,mBAAmB,EAC5D,OAAM,IAAI,MAAM,4CAA4C;AAG9D,MAAI,kBAAkB,qBACpB,OAAM,IAAI,MACR,iCAAiC,qBAAqB,oBACvD;AAGH,MAAI,OAAO,aAAa,SACtB,OAAM,IAAI,MAAM,4BAA4B;AAG9C,MAAI,OAAO,KAAK,cAAc,WAC5B,OAAM,IAAI,MAAM,QAAQ,SAAS,oBAAoB;EAGvD,MAAM,KAAK,OAAO,EAAE;EACpB,MAAM,OAAO,IAAI,KAAK,KAAK,KAAK,GAAG,kBAAkB,IAAK;EAC1D,MAAM,YAAY,KAAK,MAAM,KAAK,SAAS,GAAG,IAAK;AAEnD,OAAK,GAAG;;gBAEI,GAAG,IAAI,SAAS,IAAI,KAAK,UAAU,QAAQ,CAAC,gBAAgB,gBAAgB,IAAI,UAAU;;AAGtG,QAAM,KAAK,oBAAoB;EAE/B,MAAM,WAAwB;GAClB;GACV;GACA;GACS;GACT,MAAM;GACN,MAAM;GACP;AAED,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,SAAS,GAAG;GACxC,IAAI,QAAQ;GACZ,SAAS;IACG;IACN;IACL;GACD,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;AAED,SAAO;;;;;;;;CAST,MAAM,YAAwB,IAA8C;EAC1E,MAAM,SAAS,KAAK,GAAqB;qDACQ,GAAG;;AAEpD,MAAI,CAAC,UAAU,OAAO,WAAW,EAC/B;AAGF,SAAO;GAAE,GAAG,OAAO;GAAI,SAAS,KAAK,MAAM,OAAO,GAAG,QAAQ;GAAO;;;;;;;;CAStE,aACE,WAII,EAAE,EACS;EACf,IAAI,QAAQ;EACZ,MAAM,SAAS,EAAE;AAEjB,MAAI,SAAS,IAAI;AACf,YAAS;AACT,UAAO,KAAK,SAAS,GAAG;;AAG1B,MAAI,SAAS,MAAM;AACjB,YAAS;AACT,UAAO,KAAK,SAAS,KAAK;;AAG5B,MAAI,SAAS,WAAW;AACtB,YAAS;GACT,MAAM,QAAQ,SAAS,UAAU,yBAAS,IAAI,KAAK,EAAE;GACrD,MAAM,MAAM,SAAS,UAAU,uBAAO,IAAI,KAAK,gBAAgB;AAC/D,UAAO,KACL,KAAK,MAAM,MAAM,SAAS,GAAG,IAAK,EAClC,KAAK,MAAM,IAAI,SAAS,GAAG,IAAK,CACjC;;AAWH,SARe,KAAK,IAAI,QAAQ,IAC7B,KAAK,OAAO,GAAG,OAAO,CACtB,SAAS,CACT,KAAK,SAAS;GACb,GAAG;GACH,SAAS,KAAK,MAAM,IAAI,QAAkB;GAC3C,EAAE;;;;;;;CAUP,MAAM,eAAe,IAA8B;EACjD,MAAM,WAAW,MAAM,KAAK,YAAY,GAAG;AAC3C,MAAI,CAAC,SACH,QAAO;AAGT,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,GAAG;GAC/B,IAAI,QAAQ;GACZ,SAAS;IACP,UAAU,SAAS;IACnB,IAAI,SAAS;IACd;GACD,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;AAED,OAAK,GAAG,8CAA8C;AAEtD,QAAM,KAAK,oBAAoB;AAC/B,SAAO;;CAGT,MAAc,qBAAqB;EAEjC,MAAM,SAAS,KAAK,GAAG;;sBAEL,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK,CAAC;;;;AAIhD,MAAI,CAAC,OAAQ;AAEb,MAAI,OAAO,SAAS,KAAK,UAAU,OAAO,IAAI;GAC5C,MAAM,WAAY,OAAO,GAAG,OAAkB;AAC9C,SAAM,KAAK,IAAI,QAAQ,SAAS,SAAS;;;;;;CAqI7C,MAAM,UAAU;AAEd,OAAK,GAAG;AACR,OAAK,GAAG;AACR,OAAK,GAAG;AACR,OAAK,GAAG;AACR,OAAK,GAAG;AAGR,QAAM,KAAK,IAAI,QAAQ,aAAa;AACpC,QAAM,KAAK,IAAI,QAAQ,WAAW;AAElC,OAAK,aAAa,SAAS;AAC3B,QAAM,KAAK,IAAI,SAAS;AAExB,OAAK,aAAa;AAIlB,mBAAiB;AACf,QAAK,IAAI,MAAM,YAAY;KAC1B,EAAE;AAEL,OAAK,eAAe,KAClB;GACE,gBAAgB;GAChB,IAAI,QAAQ;GACZ,SAAS,EAAE;GACX,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;CAQH,AAAQ,YAAY,QAAyB;AAC3C,SAAO,iBAAiB,IAAI,KAAK,QAAkC;;;;;;CAOrE,qBAAoD;EAClD,MAAM,yBAAS,IAAI,KAA+B;EAGlD,IAAI,YAAY,OAAO,eAAe,KAAK;AAC3C,SAAO,aAAa,cAAc,OAAO,WAAW;AAClD,QAAK,MAAM,QAAQ,OAAO,oBAAoB,UAAU,EAAE;AACxD,QAAI,SAAS,cAAe;AAE5B,QAAI,OAAO,IAAI,KAAK,CAAE;AAEtB,QAAI;KACF,MAAM,KAAK,UAAU;AACrB,SAAI,OAAO,OAAO,YAAY;MAC5B,MAAM,OAAO,iBAAiB,IAAI,GAAe;AACjD,UAAI,KACF,QAAO,IAAI,MAAM,KAAK;;aAGnB,GAAG;AAGV,SAAI,EAAE,aAAa,WACjB,OAAM;;;AAIZ,eAAY,OAAO,eAAe,UAAU;;AAG9C,SAAO;;;;;;;;;;;;;;;;;;;;CAyBT,MAAM,YACJ,cACA,QACA,SACiB;EAEjB,MAAM,WAAW,KAAK,2BAA2B,aAAa;AAC9D,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,4BACnC;EAIH,MAAM,mBACJ,SAAS,gBAAgB,KAAK,uBAAuB;AACvD,MAAI,CAAC,iBACH,OAAM,IAAI,MACR,mGAED;EAIH,MAAM,aAAa,SAAS,MAAM,QAAQ;EAG1C,MAAM,kBAAkB;GACtB,GAAG;GACH,aAAa,KAAK;GAClB,gBAAgB;GAChB,gBAAgB;GACjB;EAGD,MAAM,WAAW,MAAM,SAAS,OAAO;GACrC,IAAI;GACJ,QAAQ;GACT,CAAC;EAGF,MAAM,KAAK,QAAQ;EACnB,MAAM,eAAe,SAAS,WAC1B,KAAK,UAAU,QAAQ,SAAS,GAChC;AACJ,MAAI;AACF,QAAK,GAAG;;kBAEI,GAAG,IAAI,SAAS,GAAG,IAAI,aAAa,cAAc,aAAa;;WAEpE,GAAG;AACV,OACE,aAAa,SACb,EAAE,QAAQ,SAAS,2BAA2B,CAE9C,OAAM,IAAI,MACR,qBAAqB,WAAW,4BACjC;AAEH,SAAM;;AAGR,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,SAAS,GAAG;GACxC,IAAI,QAAQ;GACZ,SAAS;IACP,YAAY,SAAS;IACP;IACf;GACD,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;AAED,SAAO,SAAS;;;;;;;;;;;;;;;;;;;CAoBlB,MAAM,kBACJ,cACA,YACA,OACe;EACf,MAAM,WAAW,KAAK,2BAA2B,aAAa;AAC9D,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,4BACnC;AAIH,SADiB,MAAM,SAAS,IAAI,WAAW,EAChC,UAAU,MAAM;AAE/B,OAAK,eAAe,KAClB;GACE,gBAAgB,0BAA0B;GAC1C,IAAI,QAAQ;GACZ,SAAS;IACP;IACA,WAAW,MAAM;IAClB;GACD,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;;CAkBH,MAAM,gBACJ,YACA,MACe;EACf,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;AAGvE,QAAM,KAAK,kBACT,aAAa,cACb,YACA;GACE,MAAM;GACN,SAAS;IACP,UAAU;IACV,QAAQ,MAAM;IACd,UAAU,MAAM;IACjB;GACF,CACF;AAED,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,QAAQ,MAAM;IAAQ;GAC7C,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;CAiBH,MAAM,eACJ,YACA,MACe;EACf,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;AAGvE,QAAM,KAAK,kBACT,aAAa,cACb,YACA;GACE,MAAM;GACN,SAAS;IACP,UAAU;IACV,QAAQ,MAAM;IACf;GACF,CACF;AAED,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,QAAQ,MAAM;IAAQ;GAC7C,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;;;;CAoBH,MAAM,kBAAkB,YAAmC;EACzD,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;EAGvE,MAAM,WAAW,KAAK,2BACpB,aAAa,aACd;AACD,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,aAAa,4BAChD;EAGH,MAAM,WAAW,MAAM,SAAS,IAAI,WAAW;AAC/C,MAAI;AACF,SAAM,SAAS,WAAW;WACnB,KAAK;AACZ,OAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,kBAAkB,CACjE,OAAM,IAAI,MACR,uLAGD;AAEH,SAAM;;EAIR,MAAM,SAAS,MAAM,SAAS,QAAQ;AACtC,OAAK,wBAAwB,YAAY,OAAO;AAEhD,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,cAAc,aAAa;IAAc;GAChE,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;;;;CAoBH,MAAM,cAAc,YAAmC;EACrD,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;EAGvE,MAAM,WAAW,KAAK,2BACpB,aAAa,aACd;AACD,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,aAAa,4BAChD;EAGH,MAAM,WAAW,MAAM,SAAS,IAAI,WAAW;AAC/C,MAAI;AACF,SAAM,SAAS,OAAO;WACf,KAAK;AACZ,OAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,kBAAkB,CACjE,OAAM,IAAI,MACR,mLAGD;AAEH,SAAM;;EAGR,MAAM,SAAS,MAAM,SAAS,QAAQ;AACtC,OAAK,wBAAwB,YAAY,OAAO;AAEhD,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,cAAc,aAAa;IAAc;GAChE,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;;;CAmBH,MAAM,eAAe,YAAmC;EACtD,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;EAGvE,MAAM,WAAW,KAAK,2BACpB,aAAa,aACd;AACD,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,aAAa,4BAChD;EAGH,MAAM,WAAW,MAAM,SAAS,IAAI,WAAW;AAC/C,MAAI;AACF,SAAM,SAAS,QAAQ;WAChB,KAAK;AACZ,OAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,kBAAkB,CACjE,OAAM,IAAI,MACR,oLAGD;AAEH,SAAM;;EAGR,MAAM,SAAS,MAAM,SAAS,QAAQ;AACtC,OAAK,wBAAwB,YAAY,OAAO;AAEhD,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,cAAc,aAAa;IAAc;GAChE,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;;;;;;;;;;;;;;;;;;;;;CA0BH,MAAM,gBACJ,YACA,UAAuC,EAAE,EAC1B;EACf,MAAM,EAAE,gBAAgB,SAAS;EAEjC,MAAM,eAAe,KAAK,YAAY,WAAW;AACjD,MAAI,CAAC,aACH,OAAM,IAAI,MAAM,YAAY,WAAW,8BAA8B;EAGvE,MAAM,WAAW,KAAK,2BACpB,aAAa,aACd;AACD,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,aAAa,4BAChD;EAGH,MAAM,WAAW,MAAM,SAAS,IAAI,WAAW;AAC/C,MAAI;AACF,SAAM,SAAS,SAAS;WACjB,KAAK;AACZ,OAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,kBAAkB,CACjE,OAAM,IAAI,MACR,qLAGD;AAEH,SAAM;;AAGR,MAAI,eAAe;GAEjB,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AACzC,QAAK,GAAG;;;2BAGa,IAAI;2BACJ,IAAI;;;;8BAID,WAAW;;SAE9B;GAEL,MAAM,SAAS,MAAM,SAAS,QAAQ;AACtC,QAAK,wBAAwB,YAAY,OAAO;;AAGlD,OAAK,eAAe,KAClB;GACE,gBAAgB,YAAY,WAAW;GACvC,IAAI,QAAQ;GACZ,SAAS;IAAE;IAAY,cAAc,aAAa;IAAc;GAChE,WAAW,KAAK,KAAK;GACrB,MAAM;GACP,EACD,KAAK,IACN;;;;;CAMH,AAAQ,2BACN,cACsB;EACtB,MAAM,UAAW,KAAK,IAAgC;AACtD,MACE,WACA,OAAO,YAAY,YACnB,YAAY,WACZ,SAAS,QAET,QAAO;;;;;CAQX,AAAQ,2BAAqC;EAC3C,MAAM,QAAkB,EAAE;AAC1B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAChC,KAAK,IACN,CACC,KACE,SACA,OAAO,UAAU,YACjB,YAAY,SACZ,SAAS,MAET,OAAM,KAAK,IAAI;AAGnB,SAAO;;;;;;;;;CAUT,MAAM,kBACJ,cACA,YACyB;EACzB,MAAM,WAAW,KAAK,2BAA2B,aAAa;AAC9D,MAAI,CAAC,SACH,OAAM,IAAI,MACR,qBAAqB,aAAa,4BACnC;EAIH,MAAM,SAAS,OADE,MAAM,SAAS,IAAI,WAAW,EACjB,QAAQ;AAGtC,OAAK,wBAAwB,YAAY,OAAO;AAEhD,SAAO;;;;;;;;CAST,YAAY,YAA8C;EACxD,MAAM,OAAO,KAAK,GAAwB;8DACgB,WAAW;;AAGrE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAC3B;AAGF,SAAO,KAAK,mBAAmB,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAwBzC,aAAa,WAAkC,EAAE,EAAgB;EAC/D,MAAM,QAAQ,KAAK,IAAI,SAAS,SAAS,IAAI,IAAI;EACjD,MAAM,QAAQ,SAAS,YAAY;EAGnC,MAAM,QAAQ,KAAK,gBAAgB,SAAS;EAG5C,IAAI,QAAQ;EACZ,MAAM,SAAwC,EAAE;AAEhD,MAAI,SAAS,QAAQ;GACnB,MAAM,WAAW,MAAM,QAAQ,SAAS,OAAO,GAC3C,SAAS,SACT,CAAC,SAAS,OAAO;GACrB,MAAM,eAAe,SAAS,UAAU,IAAI,CAAC,KAAK,KAAK;AACvD,YAAS,mBAAmB,aAAa;AACzC,UAAO,KAAK,GAAG,SAAS;;AAG1B,MAAI,SAAS,cAAc;AACzB,YAAS;AACT,UAAO,KAAK,SAAS,aAAa;;AAGpC,MAAI,SAAS,SACX,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,SAAS,EAAE;AAC5D,YAAS;AACT,UAAO,KAAK,KAAK,MAAM;;AAK3B,MAAI,SAAS,QAAQ;GACnB,MAAM,SAAS,KAAK,cAAc,SAAS,OAAO;AAClD,OAAI,MAEF,UACE;OAGF,UACE;AAEJ,UAAO,KAAK,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW;;AAIpE,WAAS,wBAAwB,QAAQ,QAAQ,OAAO,gBAAgB,QAAQ,QAAQ;AAGxF,WAAS;AACT,SAAO,KAAK,QAAQ,EAAE;EAEtB,MAAM,OAAO,KAAK,IAAI,QAAQ,IAC3B,KAAK,OAAO,GAAG,OAAO,CACtB,SAAS;EAEZ,MAAM,UAAU,KAAK,SAAS;EAE9B,MAAM,aADa,UAAU,KAAK,MAAM,GAAG,MAAM,GAAG,MACvB,KAAK,QAAQ,KAAK,mBAAmB,IAAI,CAAC;AAQvE,SAAO;GAAE;GAAW;GAAO,YAJzB,WAAW,UAAU,SAAS,IAC1B,KAAK,cAAc,UAAU,UAAU,SAAS,GAAG,GACnD;GAEiC;;;;;CAMzC,AAAQ,gBACN,UAGQ;EACR,IAAI,QAAQ;EACZ,MAAM,SAAwC,EAAE;AAEhD,MAAI,SAAS,QAAQ;GACnB,MAAM,WAAW,MAAM,QAAQ,SAAS,OAAO,GAC3C,SAAS,SACT,CAAC,SAAS,OAAO;GACrB,MAAM,eAAe,SAAS,UAAU,IAAI,CAAC,KAAK,KAAK;AACvD,YAAS,mBAAmB,aAAa;AACzC,UAAO,KAAK,GAAG,SAAS;;AAG1B,MAAI,SAAS,cAAc;AACzB,YAAS;AACT,UAAO,KAAK,SAAS,aAAa;;AAGpC,MAAI,SAAS,SACX,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,SAAS,EAAE;AAC5D,YAAS;AACT,UAAO,KAAK,KAAK,MAAM;;AAI3B,MAAI,SAAS,eAAe;AAC1B,YAAS;AACT,UAAO,KAAK,KAAK,MAAM,SAAS,cAAc,SAAS,GAAG,IAAK,CAAC;;AAOlE,SAJe,KAAK,IAAI,QAAQ,IAAI,KAAK,OAAO,GAAG,OAAO,CAAC,SAAS,CAItD,IAAI,SAAS;;;;;;CAO7B,AAAQ,cAAc,UAAgC;AACpD,SAAO,KACL,KAAK,UAAU;GACb,GAAG,KAAK,MAAM,SAAS,UAAU,SAAS,GAAG,IAAK;GAClD,GAAG,SAAS;GACb,CAAC,CACH;;;;;;CAOH,AAAQ,cAAc,QAGpB;AACA,MAAI;GACF,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,CAAC;AACrC,OAAI,OAAO,KAAK,MAAM,YAAY,OAAO,KAAK,MAAM,SAClD,OAAM,IAAI,MAAM,2BAA2B;AAE7C,UAAO;IAAE,WAAW,KAAK;IAAG,YAAY,KAAK;IAAG;UAC1C;AACN,SAAM,IAAI,MACR,uEACD;;;;;;;;;CAUL,eAAe,YAA6B;EAE1C,MAAM,WAAW,KAAK,GAAsB;8EAC8B,WAAW;;AAErF,MAAI,CAAC,SAAS,MAAM,SAAS,GAAG,UAAU,EACxC,QAAO;AAET,OAAK,GAAG,uDAAuD;AAC/D,SAAO;;;;;;;;;;;;;;;;;;;;;;;CAwBT,gBACE,WAEI,EAAE,EACE;EACR,IAAI,QAAQ;EACZ,MAAM,SAAwC,EAAE;AAEhD,MAAI,SAAS,QAAQ;GACnB,MAAM,WAAW,MAAM,QAAQ,SAAS,OAAO,GAC3C,SAAS,SACT,CAAC,SAAS,OAAO;GACrB,MAAM,eAAe,SAAS,UAAU,IAAI,CAAC,KAAK,KAAK;AACvD,YAAS,mBAAmB,aAAa;AACzC,UAAO,KAAK,GAAG,SAAS;;AAG1B,MAAI,SAAS,cAAc;AACzB,YAAS;AACT,UAAO,KAAK,SAAS,aAAa;;AAGpC,MAAI,SAAS,SACX,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,SAAS,EAAE;AAC5D,YAAS;AACT,UAAO,KAAK,KAAK,MAAM;;AAI3B,MAAI,SAAS,eAAe;AAC1B,YAAS;AACT,UAAO,KAAK,KAAK,MAAM,SAAS,cAAc,SAAS,GAAG,IAAK,CAAC;;AAIlE,SADe,KAAK,IAAI,QAAQ,IAAI,KAAK,OAAO,GAAG,OAAO,CAC5C;;;;;;;;;;;;;;;;;;CAmBhB,uBAAuB,SAAiB,SAAyB;AAE/D,MAAI,CAAC,KAAK,2BAA2B,QAAQ,CAC3C,OAAM,IAAI,MAAM,qBAAqB,QAAQ,4BAA4B;EAM3E,MAAM,QAHS,KAAK,GAAsB;gFACkC,QAAQ;MAE/D,IAAI,SAAS;AAElC,MAAI,QAAQ,GAAG;AACb,QACG,GAAG,kDAAkD,QAAQ,yBAAyB;AACzF,WAAQ,IACN,oBAAoB,MAAM,qBAAqB,QAAQ,QAAQ,QAAQ,GACxE;;AAGH,SAAO;;;;;CAMT,AAAQ,wBACN,YACA,QACM;EACN,MAAM,aAAa,OAAO;EAC1B,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;EAQzC,MAAM,cALsC;GAC1C;GACA;GACA;GACD,CACqC,SAAS,WAAW,GAAG,MAAM;EAGnE,MAAM,YAAY,OAAO,OAAO,QAAQ;EACxC,MAAM,eAAe,OAAO,OAAO,WAAW;AAE9C,OAAK,GAAG;;qBAES,WAAW;yBACP,UAAU;4BACP,aAAa;yBAChB,IAAI;2BACF,YAAY;4BACX,WAAW;;;;;;CAOrC,AAAQ,mBAAmB,KAAwC;AACjE,SAAO;GACL,IAAI,IAAI;GACR,YAAY,IAAI;GAChB,cAAc,IAAI;GAClB,QAAQ,IAAI;GACZ,UAAU,IAAI,WAAW,KAAK,MAAM,IAAI,SAAS,GAAG;GACpD,OAAO,IAAI,aACP;IAAE,MAAM,IAAI;IAAY,SAAS,IAAI,iBAAiB;IAAI,GAC1D;GACJ,2BAAW,IAAI,KAAK,IAAI,aAAa,IAAK;GAC1C,2BAAW,IAAI,KAAK,IAAI,aAAa,IAAK;GAC1C,aAAa,IAAI,+BAAe,IAAI,KAAK,IAAI,eAAe,IAAK,GAAG;GACrE;;;;;;CAOH,AAAQ,wBAA4C;EAClD,MAAM,YAAY,KAAK,aAAa;AACpC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAChC,KAAK,IACN,CACC,KACE,SACA,OAAO,UAAU,YACjB,gBAAgB,SAChB,OAAO,MAAM,eAAe,YAG5B;OACE,QAAQ,aACR,qBAAqB,IAAI,KAAK,qBAAqB,UAAU,CAE7D,QAAO;;;;;;;;;;CAkBf,MAAM,mBAAmB,UAA2C;EAClE,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK,GAAG,IAAK;AAEzC,UAAQ,SAAS,MAAjB;GACE,KAAK;AAGH,SAAK,GAAG;;iDAEiC,IAAI;gCACrB,SAAS,WAAW;;AAE5C,UAAM,KAAK,mBACT,SAAS,cACT,SAAS,YACT,SAAS,SACV;AACD;GACF,KAAK;AAGH,SAAK,GAAG;;kDAEkC,IAAI,mBAAmB,IAAI;gCAC7C,SAAS,WAAW;;;AAG5C,UAAM,KAAK,mBACT,SAAS,cACT,SAAS,YACT,SAAS,OACV;AACD;GACF,KAAK;AAGH,SAAK,GAAG;;iDAEiC,IAAI,mBAAmB,IAAI;8DACd,SAAS,MAAM;gCAC7C,SAAS,WAAW;;;AAG5C,UAAM,KAAK,gBACT,SAAS,cACT,SAAS,YACT,SAAS,MACV;AACD;GACF,KAAK;AAEH,UAAM,KAAK,gBACT,SAAS,cACT,SAAS,YACT,SAAS,MACV;AACD;;;;;;;;;;;CAYN,MAAM,mBACJ,eACA,aACA,WACe;;;;;;;;;CAYjB,MAAM,mBACJ,eACA,aACA,SACe;;;;;;;;;CAYjB,MAAM,gBACJ,eACA,aACA,QACe;;;;;;;;;CAYjB,MAAM,gBACJ,eACA,aACA,QACe;;;;;CAajB,MAAM,yBAAyB,UAA2C;AACxE,QAAM,KAAK,mBAAmB,SAAS;;;;;;CAOzC,oBAAoB,SAAwB;AAC1C,OAAK,UAAU,KAAK,UAAU,QAAQ,CAAC;;;;;;CAOzC,sBACE,QACA,OACM;AACN,MAAI,WAAW,MACb,MAAK,SAAS,MAAe;WACpB,WAAW,SAAS;GAC7B,MAAM,eAAe,KAAK,SAAU,EAAE;AACtC,QAAK,SAAS;IACZ,GAAG;IACH,GAAI;IACL,CAAU;aACF,WAAW,QACpB,MAAK,SAAS,KAAK,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BpC,MAAM,aACJ,YACA,KACA,uBACA,cACA,SAkBA;EAEA,IAAI;EACJ,IAAI;EACJ,IAAI;EAUJ,IAAI;AAEJ,MACE,OAAO,0BAA0B,YACjC,0BAA0B,MAC1B;AAEA,0BAAuB,sBAAsB;AAC7C,0BAAuB,sBAAsB;AAC7C,0BAAuB,sBAAsB,gBAAgB;AAC7D,qBAAkB;IAChB,QAAQ,sBAAsB;IAC9B,WAAW,sBAAsB;IAClC;SACI;AAEL,0BAAuB;AACvB,0BAAuB,gBAAgB;AACvC,qBAAkB;;AAIpB,MAAI,CAAC,KAAK,iBAAiB,yBAAyB,CAAC,qBACnD,OAAM,IAAI,MACR,0OAGD;AAIH,MAAI,CAAC,sBAAsB;GACzB,MAAM,EAAE,YAAY,iBAAiB;AACrC,OAAI,CAAC,QACH,OAAM,IAAI,MACR,oEACD;GAIH,MAAM,aAAa,IAAI,IAAI,QAAQ,IAAI;AACvC,0BAAuB,GAAG,WAAW,SAAS,IAAI,WAAW;;EAI/D,MAAM,iBAAiB,qBAAqB,QAAQ,OAAO,GAAG;EAC9D,MAAM,cAAc,uBAChB,GAAG,eAAe,GAAG,qBAAqB,QAAQ,OAAO,GAAG,KAC5D,GAAG,eAAe,GAAG,qBAAqB,GAAG,qBAAqB,KAAK,aAAa,KAAK,CAAC,GAAG,KAAK,KAAK;AAI3G,QAAM,KAAK,IAAI,kBAAkB;EAEjC,MAAM,KAAK,OAAO,EAAE;EAEpB,MAAM,eAAe,KAAK,uBAAuB,YAAY;AAC7D,eAAa,WAAW;EAGxB,MAAM,gBACJ,iBAAiB,WAAW,QAAQ;EAItC,IAAI,sBAAiD,EAAE;AACvD,MAAI,iBAAiB,WAAW,QAC9B,uBAAsB;GACpB,iBAAiB,EACf,QAAQ,KAAK,SACX,MAAM,KAAK;IACT,GAAG;IACH,SAAS,iBAAiB,WAAW;IACtC,CAAC,EACL;GACD,aAAa,EACX,SAAS,iBAAiB,WAAW,SACtC;GACF;AAIH,QAAM,KAAK,IAAI,eAAe,IAAI;GAChC;GACA,MAAM;GACN;GACA,QAAQ,iBAAiB;GACzB,WAAW;IACT,GAAG;IACH;IACA,MAAM;IACP;GACF,CAAC;EAEF,MAAM,SAAS,MAAM,KAAK,IAAI,gBAAgB,GAAG;AAEjD,MAAI,OAAO,UAAU,mBAAmB,OAEtC,OAAM,IAAI,MACR,sCAAsC,IAAI,IAAI,OAAO,QACtD;AAGH,MAAI,OAAO,UAAU,mBAAmB,eACtC,QAAO;GAAE;GAAI,OAAO,OAAO;GAAO,SAAS,OAAO;GAAS;EAI7D,MAAM,iBAAiB,MAAM,KAAK,IAAI,oBAAoB,GAAG;AAE7D,MAAI,kBAAkB,CAAC,eAAe,QAEpC,OAAM,IAAI,MACR,+CAA+C,eAAe,QAC/D;AAGH,SAAO;GAAE;GAAI,OAAO,mBAAmB;GAAO;;CAGhD,MAAM,gBAAgB,IAAY;AAChC,QAAM,KAAK,IAAI,aAAa,GAAG;;CAGjC,gBAAiC;EAC/B,MAAM,WAA4B;GAChC,SAAS,KAAK,IAAI,aAAa;GAC/B,WAAW,KAAK,IAAI,eAAe;GACnC,SAAS,EAAE;GACX,OAAO,KAAK,IAAI,WAAW;GAC5B;EAED,MAAM,UAAU,KAAK,IAAI,aAAa;AAEtC,MAAI,WAAW,MAAM,QAAQ,QAAQ,IAAI,QAAQ,SAAS,EACxD,MAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,aAAa,KAAK,IAAI,eAAe,OAAO;GAGlD,IAAI,eAAmD;AACvD,OAAI,CAAC,cAAc,OAAO,SAExB,gBAAe;AAGjB,YAAS,QAAQ,OAAO,MAAM;IAC5B,UAAU,OAAO;IACjB,cAAc,YAAY,sBAAsB;IAChD,OAAO,YAAY,mBAAmB;IACtC,cAAc,YAAY,gBAAgB;IAC1C,MAAM,OAAO;IACb,YAAY,OAAO;IACnB,OAAO,YAAY,mBAAmB;IACvC;;AAIL,SAAO;;;;;;;;;;;;;;;;;;;;;;;;CAyBT,uBAAuB,aAA4C;AACjE,SAAO,IAAI,iCACT,KAAK,IAAI,SACT,KAAK,MACL,YACD;;CAGH,AAAQ,sBAAsB;AAC5B,OAAK,UACH,KAAK,UAAU;GACb,KAAK,KAAK,eAAe;GACzB,MAAM,YAAY;GACnB,CAAC,CACH;;;;;;;;;;;;;;;CAgBH,MAAc,uBACZ,SAC0B;AAG1B,MAAI,CADe,KAAK,IAAI,kBAAkB,QAAQ,CAEpD,QAAO;EAKT,MAAM,SAAS,MAAM,KAAK,IAAI,sBAAsB,QAAQ;AAG5D,MAAI,OAAO,YACT,MAAK,IAAI,oBAAoB,OAAO,SAAS,CAAC,OAAO,UAAU;AAC7D,WAAQ,MACN,mEACA,MACD;IACD;AAGJ,OAAK,qBAAqB;AAG1B,SAAO,KAAK,4BAA4B,QAAQ,QAAQ;;;;;;;;CAS1D,AAAQ,4BACN,QACA,SACU;EACV,MAAM,SAAS,KAAK,IAAI,wBAAwB;AAGhD,MAAI,QAAQ,cACV,QAAO,OAAO,cAAc,OAAO;EAGrC,MAAM,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC;AAGxC,MAAI,QAAQ,mBAAmB,OAAO,YACpC,KAAI;AACF,UAAO,SAAS,SACd,IAAI,IAAI,OAAO,iBAAiB,WAAW,CAAC,KAC7C;WACM,GAAG;AACV,WAAQ,MACN,gCACA,OAAO,iBACP,EACD;AACD,UAAO,SAAS,SAAS,WAAW;;AAKxC,MAAI,QAAQ,iBAAiB,CAAC,OAAO,YACnC,KAAI;GACF,MAAM,WAAW,GAAG,OAAO,cAAc,SAAS,mBAChD,OAAO,aAAa,gBACrB;AACD,UAAO,SAAS,SAAS,IAAI,IAAI,UAAU,WAAW,CAAC,KAAK;WACrD,GAAG;AACV,WAAQ,MAAM,8BAA8B,OAAO,eAAe,EAAE;AACpE,UAAO,SAAS,SAAS,WAAW;;AAKxC,SAAO,SAAS,SAAS,WAAW;;;AAKxC,MAAM,iCAAiB,IAAI,KAAyC;;;;;;;;AA2BpE,eAAsB,kBACpB,SACA,KACA,SACA;AACA,QAAO,qBAAqB,SAAS,KAAgC;EACnE,QAAQ;EACR,GAAI;EACL,CAAC;;AAqBJ,MAAM,gCAAgB,IAAI,SAGvB;;;;;;;;AASH,eAAsB,gBAGpB,OACA,KACA,SACe;CACf,MAAM,cAAc,MAAM,QAAQ,SAAS,OAAO,IAAI;AAEtD,KAAI,CAAC,aAAa;AAChB,MAAI,QAAQ,UACV,OAAM,QAAQ,UAAU,MAAM;MAE9B,SAAQ,KAAK,2DAA2D;AAE1E;;AAIF,KAAI,CAAC,cAAc,IAAI,IAA+B,EAAE;EACtD,MAAM,MAA+B,EAAE;AACvC,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAA+B,CACvE,KACE,SACA,OAAO,UAAU,YACjB,gBAAgB,SAChB,OAAO,MAAM,eAAe,YAC5B;AAEA,OAAI,OAAO;AACX,OAAI,qBAAqB,IAAI,IAAI;;AAGrC,gBAAc,IAAI,KAAgC,IAAI;;CAGxD,MAAM,WAAW,cAAc,IAAI,IAA+B;CAClE,MAAM,YAAY,SAAS,YAAY;AAEvC,KAAI,CAAC,WAAW;EAEd,MAAM,kBAAkB,OAAO,KAAK,SAAS,CAC1C,QAAQ,QAAQ,CAAC,IAAI,SAAS,IAAI,CAAC,CACnC,KAAK,KAAK;AACb,QAAM,IAAI,MACR,oBAAoB,YAAY,UAAU,gDAAgD,kBAC3F;;CAGH,MAAM,QAAQ,MAAM,eAClB,WACA,YAAY,QACb;CAGD,MAAM,oBAAgC;EACpC,QAAQ,YAAY;GAClB,MAAM,SAAS,MAAM,IAAI,WAAW;GACpC,MAAM,SAAuB,EAAE;GAE/B,IAAI,OAAO;AACX,UAAO,CAAC,MAAM;IACZ,MAAM,EAAE,OAAO,MAAM,eAAe,MAAM,OAAO,MAAM;AACvD,WAAO;AACP,QAAI,MACF,QAAO,KAAK,MAAM;;GAItB,MAAM,cAAc,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM,QAAQ,EAAE;GACxE,MAAM,WAAW,IAAI,WAAW,YAAY;GAC5C,IAAI,SAAS;AACb,QAAK,MAAM,SAAS,QAAQ;AAC1B,aAAS,IAAI,OAAO,OAAO;AAC3B,cAAU,MAAM;;AAGlB,UAAO;;EAET,SAAS,MAAM;EACf,SAAS,MAAM;EACf,YAAY,WAAmB;AAC7B,SAAM,UAAU,OAAO;;EAEzB,UAAU,QAAgB,YAAsB;AAC9C,UAAO,MAAM,QAAQ,QAAQ,QAAQ;;EAEvC,QAAQ,iBAA4D;AAClE,UAAO,MAAM,MACX,IAAI,aAAa,aAAa,MAAM,aAAa,IAAI,aAAa,IAAI,CACvE;;EAEH,MAAM,MAAM;EACZ,IAAI,MAAM;EACV,eAAe,YAAY;EAC5B;AAED,OAAM,MAAM,SAAS,kBAAkB;;;;;;;;;;;AAYzC,eAAsB,eAKpB,WACA,MACA,SAKA;AACA,QAAO,gBAAwB,WAAW,MAAM,QAAQ;;;;;AAM1D,IAAa,oBAAb,MAA+B;CAK7B,YAAY,YAAwB,IAAY;iBAF9B;AAGhB,OAAK,cAAc;AACnB,OAAK,MAAM;;;;;CAMb,IAAI,WAAoB;AACtB,SAAO,KAAK;;;;;;;CAQd,KAAK,OAAyB;AAC5B,MAAI,KAAK,SAAS;AAChB,WAAQ,KACN,0EACD;AACD,UAAO;;EAET,MAAM,WAAwB;GAC5B,MAAM;GACN,IAAI,KAAK;GACT,QAAQ;GACR,SAAS;GACT,MAAM,YAAY;GACnB;AACD,OAAK,YAAY,KAAK,KAAK,UAAU,SAAS,CAAC;AAC/C,SAAO;;;;;;;CAQT,IAAI,YAA+B;AACjC,MAAI,KAAK,QACP,QAAO;AAET,OAAK,UAAU;EACf,MAAM,WAAwB;GAC5B,MAAM;GACN,IAAI,KAAK;GACT,QAAQ;GACR,SAAS;GACT,MAAM,YAAY;GACnB;AACD,OAAK,YAAY,KAAK,KAAK,UAAU,SAAS,CAAC;AAC/C,SAAO;;;;;;;CAQT,MAAM,SAA0B;AAC9B,MAAI,KAAK,QACP,QAAO;AAET,OAAK,UAAU;EACf,MAAM,WAAwB;GAC5B,OAAO;GACP,IAAI,KAAK;GACT,SAAS;GACT,MAAM,YAAY;GACnB;AACD,OAAK,YAAY,KAAK,KAAK,UAAU,SAAS,CAAC;AAC/C,SAAO"}
|
|
@@ -23,7 +23,11 @@ type AgentContextStore = {
|
|
|
23
23
|
request: Request | undefined;
|
|
24
24
|
email: AgentEmail | undefined;
|
|
25
25
|
};
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @internal — This is an internal implementation detail.
|
|
28
|
+
* Importing or relying on this symbol **will** break your code in a future release.
|
|
29
|
+
*/
|
|
30
|
+
declare const __DO_NOT_USE_WILL_BREAK__agentContext: AsyncLocalStorage<AgentContextStore>;
|
|
27
31
|
//#endregion
|
|
28
|
-
export { AgentContextStore, AgentEmail,
|
|
32
|
+
export { AgentContextStore, AgentEmail, __DO_NOT_USE_WILL_BREAK__agentContext };
|
|
29
33
|
//# sourceMappingURL=internal_context.d.ts.map
|
package/dist/internal_context.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
|
|
3
3
|
//#region src/internal_context.ts
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* @internal — This is an internal implementation detail.
|
|
6
|
+
* Importing or relying on this symbol **will** break your code in a future release.
|
|
7
|
+
*/
|
|
8
|
+
const __DO_NOT_USE_WILL_BREAK__agentContext = new AsyncLocalStorage();
|
|
5
9
|
|
|
6
10
|
//#endregion
|
|
7
|
-
export {
|
|
11
|
+
export { __DO_NOT_USE_WILL_BREAK__agentContext };
|
|
8
12
|
//# sourceMappingURL=internal_context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal_context.js","names":[],"sources":["../src/internal_context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { Connection } from \"partyserver\";\n\nexport type AgentEmail = {\n from: string;\n to: string;\n getRaw: () => Promise<Uint8Array>;\n headers: Headers;\n rawSize: number;\n setReject: (reason: string) => void;\n forward: (rcptTo: string, headers?: Headers) => Promise<EmailSendResult>;\n reply: (options: {\n from: string;\n to: string;\n raw: string;\n }) => Promise<EmailSendResult>;\n /** @internal Indicates email was routed via createSecureReplyEmailResolver */\n _secureRouted?: boolean;\n};\n\nexport type AgentContextStore = {\n // Using unknown to avoid circular dependency with Agent\n agent: unknown;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n};\n\nexport const
|
|
1
|
+
{"version":3,"file":"internal_context.js","names":[],"sources":["../src/internal_context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { Connection } from \"partyserver\";\n\nexport type AgentEmail = {\n from: string;\n to: string;\n getRaw: () => Promise<Uint8Array>;\n headers: Headers;\n rawSize: number;\n setReject: (reason: string) => void;\n forward: (rcptTo: string, headers?: Headers) => Promise<EmailSendResult>;\n reply: (options: {\n from: string;\n to: string;\n raw: string;\n }) => Promise<EmailSendResult>;\n /** @internal Indicates email was routed via createSecureReplyEmailResolver */\n _secureRouted?: boolean;\n};\n\nexport type AgentContextStore = {\n // Using unknown to avoid circular dependency with Agent\n agent: unknown;\n connection: Connection | undefined;\n request: Request | undefined;\n email: AgentEmail | undefined;\n};\n\n/**\n * @internal — This is an internal implementation detail.\n * Importing or relying on this symbol **will** break your code in a future release.\n */\nexport const __DO_NOT_USE_WILL_BREAK__agentContext =\n new AsyncLocalStorage<AgentContextStore>();\n"],"mappings":";;;;;;;AAgCA,MAAa,wCACX,IAAI,mBAAsC"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"durable objects"
|
|
10
10
|
],
|
|
11
11
|
"type": "module",
|
|
12
|
-
"version": "0.4.
|
|
12
|
+
"version": "0.4.1",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
15
15
|
"directory": "packages/agents",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@ai-sdk/openai": "^3.0.0",
|
|
55
55
|
"@ai-sdk/react": "^3.0.0",
|
|
56
|
-
"@cloudflare/ai-chat": "^0.0.
|
|
56
|
+
"@cloudflare/ai-chat": "^0.0.8",
|
|
57
57
|
"@cloudflare/codemode": "^0.0.7",
|
|
58
58
|
"@x402/core": "^2.0.0",
|
|
59
59
|
"@x402/evm": "^2.0.0",
|
|
@@ -136,11 +136,6 @@
|
|
|
136
136
|
"import": "./dist/workflows.js",
|
|
137
137
|
"require": "./dist/workflows.js"
|
|
138
138
|
},
|
|
139
|
-
"./internal_context": {
|
|
140
|
-
"types": "./dist/internal_context.d.ts",
|
|
141
|
-
"import": "./dist/internal_context.js",
|
|
142
|
-
"require": "./dist/internal_context.js"
|
|
143
|
-
},
|
|
144
139
|
"./x402": {
|
|
145
140
|
"types": "./dist/mcp/x402.d.ts",
|
|
146
141
|
"import": "./dist/mcp/x402.js",
|