agents 0.11.4 → 0.11.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n type PartyFetchOptions,\n PartySocket,\n type PartySocketOptions\n} from \"partysocket\";\nimport type { Agent, RPCRequest, RPCResponse } from \"./\";\nimport type {\n Method,\n RPCMethod,\n SerializableReturnValue,\n SerializableValue\n} from \"./serializable\";\nimport { MessageType } from \"./types\";\nimport { camelCaseToKebabCase } from \"./utils\";\n\n/**\n * Options for creating an AgentClient\n */\nexport type AgentClientOptions<State = unknown> = Omit<\n PartySocketOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the client connects to this path directly.\n * Server must handle routing manually (e.g., with getAgentByName + fetch).\n * @example\n * // Client connects to /user, server routes based on session\n * useAgent({ agent: \"UserAgent\", basePath: \"user\" })\n */\n basePath?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n /** Called when a state update fails (e.g., connection is readonly) */\n onStateUpdateError?: (error: string) => void;\n /**\n * Called when the server sends the agent's identity on connect.\n * Useful when using basePath, as the actual instance name is determined server-side.\n * @param name The actual agent instance name\n * @param agent The agent class name (kebab-case)\n */\n onIdentity?: (name: string, agent: string) => void;\n /**\n * Called when identity changes on reconnect (different instance than before).\n * If not provided and identity changes, a warning will be logged.\n * @param oldName Previous instance name\n * @param newName New instance name\n * @param oldAgent Previous agent class name\n * @param newAgent New agent class name\n */\n onIdentityChange?: (\n oldName: string,\n newName: string,\n oldAgent: string,\n newAgent: string\n ) => void;\n /**\n * Additional path to append to the URL.\n * Works with both standard routing and basePath.\n * @example\n * // With basePath: /user/settings\n * { basePath: \"user\", path: \"settings\" }\n * // Standard: /agents/my-agent/room/settings\n * { agent: \"MyAgent\", name: \"room\", path: \"settings\" }\n */\n path?: string;\n};\n\n/**\n * Options for streaming RPC calls\n */\nexport type StreamOptions = {\n /** Called when a chunk of data is received */\n onChunk?: (chunk: unknown) => void;\n /** Called when the stream ends */\n onDone?: (finalChunk: unknown) => void;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n};\n\n/**\n * Options for RPC calls\n */\nexport type CallOptions = {\n /** Timeout in milliseconds. If the call doesn't complete within this time, it will be rejected. */\n timeout?: number;\n /** Streaming options for handling streaming responses */\n stream?: StreamOptions;\n};\n\n/**\n * Options for the agentFetch function\n */\nexport type AgentClientFetchOptions = Omit<\n PartyFetchOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the request is made to this path directly.\n */\n basePath?: string;\n};\n\n// ---- Shared RPC Type Utilities ----\n\ntype AllOptional<T> = T extends [infer A, ...infer R]\n ? undefined extends A\n ? AllOptional<R>\n : false\n : true;\n\nexport type RPCMethods<T> = {\n [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;\n};\n\ntype OptionalParametersMethod<T extends RPCMethod> =\n AllOptional<Parameters<T>> extends true ? T : never;\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic agent type constraint\nexport type AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;\n\nexport type OptionalAgentMethods<T> = {\n [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<\n AgentMethods<T>[K]\n >\n ? K\n : never]: OptionalParametersMethod<AgentMethods<T>[K]>;\n};\n\nexport type RequiredAgentMethods<T> = Omit<\n AgentMethods<T>,\n keyof OptionalAgentMethods<T>\n>;\n\nexport type AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic promise return type\n ReturnType<AgentMethods<T>[K]> extends Promise<any>\n ? ReturnType<AgentMethods<T>[K]>\n : Promise<ReturnType<AgentMethods<T>[K]>>;\n\nexport type AgentStub<T> = {\n [K in keyof AgentMethods<T>]: (\n ...args: Parameters<AgentMethods<T>[K]>\n ) => AgentPromiseReturnType<AgentMethods<T>, K>;\n};\n\nexport type UntypedAgentStub = Record<string, Method>;\n\ntype AgentClientStub<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentStub\n : AgentStub<AgentT>;\n\ntype OptionalArgsAgentClientCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: Parameters<OptionalAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentClientCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: Parameters<RequiredAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype TypedAgentClientCall<AgentT> = OptionalArgsAgentClientCall<AgentT> &\n RequiredArgsAgentClientCall<AgentT>;\n\ntype UntypedAgentClientCall = {\n <T extends SerializableReturnValue>(\n method: string,\n args?: SerializableValue[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n <T = unknown>(\n method: string,\n args?: unknown[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n};\n\ntype AgentClientCall<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentClientCall\n : TypedAgentClientCall<AgentT>;\n\n/**\n * Creates a proxy that wraps RPC method calls.\n * Internal JS methods (toJSON, then, etc.) return undefined to avoid\n * triggering RPC calls during serialization (e.g., console.log)\n */\nexport function createStubProxy<T = Record<string, Method>>(\n call: (method: string, args: unknown[]) => unknown\n): T {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- proxy needs any for dynamic method access\n return new Proxy<any>(\n {},\n {\n get: (_target, method) => {\n if (\n typeof method === \"symbol\" ||\n method === \"toJSON\" ||\n method === \"then\" ||\n method === \"catch\" ||\n method === \"finally\" ||\n method === \"valueOf\" ||\n method === \"toString\" ||\n method === \"constructor\" ||\n method === \"prototype\" ||\n method === \"$$typeof\" ||\n method === \"@@toStringTag\" ||\n method === \"asymmetricMatch\" ||\n method === \"nodeType\"\n ) {\n return undefined;\n }\n return (...args: unknown[]) => call(method as string, args);\n }\n }\n );\n}\n\n/**\n * WebSocket client for connecting to an Agent\n */\nexport class AgentClient<\n AgentT = unknown,\n State = AgentT extends { get state(): infer S } ? S : AgentT\n> extends PartySocket {\n /**\n * @deprecated Use agentFetch instead\n */\n static fetch(_opts: PartyFetchOptions): Promise<Response> {\n throw new Error(\n \"AgentClient.fetch is not implemented, use agentFetch instead\"\n );\n }\n agent: string;\n name: string;\n call: AgentClientCall<AgentT>;\n stub: AgentClientStub<AgentT>;\n\n /**\n * The current agent state, updated on server broadcasts and client setState calls.\n * Starts as undefined until the first state message is received from the server.\n */\n state: State | undefined = undefined;\n\n /**\n * Whether the client has received identity from the server.\n * Becomes true after the first identity message is received.\n * Resets to false on connection close.\n */\n identified = false;\n\n /**\n * Promise that resolves when identity has been received from the server.\n * Useful for waiting before making calls that depend on knowing the instance.\n * Resets on connection close so it can be awaited again after reconnect.\n */\n get ready(): Promise<void> {\n return this._readyPromise;\n }\n\n private options: AgentClientOptions<State>;\n private _pendingCalls = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >();\n private _readyPromise!: Promise<void>;\n private _resolveReady!: () => void;\n private _previousName: string | null = null;\n private _previousAgent: string | null = null;\n\n private _resetReady() {\n this._readyPromise = new Promise((resolve) => {\n this._resolveReady = resolve;\n });\n }\n\n constructor(options: AgentClientOptions<State>) {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? { basePath: options.basePath, path: options.path, ...options }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: options.path,\n ...options\n };\n\n super(socketOptions);\n this.agent = agentNamespace;\n this.name = options.name || \"default\";\n this.options = options;\n\n // Initialize ready promise\n this._resetReady();\n\n this.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(event.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = this._previousName;\n const oldAgent = this._previousAgent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n // Resolve ready/identified\n this.identified = true;\n this._resolveReady();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (this.options.onIdentityChange) {\n this.options.onIdentityChange(\n oldName,\n newName,\n oldAgent,\n newAgent\n );\n } else {\n const agentChanged = oldAgent !== newAgent;\n const nameChanged = oldName !== newName;\n let changeDescription = \"\";\n if (agentChanged && nameChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\", instance \"${oldName}\" → \"${newName}\"`;\n } else if (agentChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\"`;\n } else {\n changeDescription = `instance \"${oldName}\" → \"${newName}\"`;\n }\n console.warn(\n `[agents] Identity changed on reconnect: ${changeDescription}. ` +\n \"This can happen with server-side routing (e.g., basePath with getAgentByName) \" +\n \"where the instance is determined by auth/session. \" +\n \"Provide onIdentityChange callback to handle this explicitly, \" +\n \"or ignore if this is expected for your routing pattern.\"\n );\n }\n }\n\n // Always update from server identity (server is authoritative)\n this._previousName = newName;\n this._previousAgent = newAgent;\n this.name = newName;\n this.agent = newAgent;\n\n // Call onIdentity callback\n this.options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n this.state = parsedMessage.state as State;\n this.options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE_ERROR) {\n this.options.onStateUpdateError?.(parsedMessage.error as string);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = this._pendingCalls.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n this._pendingCalls.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n }\n }\n }\n });\n\n // Clean up pending calls and reset ready state when connection closes\n this.addEventListener(\"close\", () => {\n // Reset ready state for next connection\n this.identified = false;\n this._resetReady();\n\n // Reject any remaining pending calls (e.g., from unexpected disconnect)\n this._rejectPendingCalls(\"Connection closed\");\n });\n\n this.call = this._callImpl.bind(this) as AgentClientCall<AgentT>;\n this.stub = createStubProxy((method, args) =>\n this._callImpl(method, args)\n ) as AgentClientStub<AgentT>;\n }\n\n /**\n * Reject all pending RPC calls with the given reason.\n */\n private _rejectPendingCalls(reason: string) {\n const error = new Error(reason);\n for (const pending of this._pendingCalls.values()) {\n pending.reject(error);\n pending.stream?.onError?.(reason);\n }\n this._pendingCalls.clear();\n }\n\n setState(state: State) {\n this.send(JSON.stringify({ state, type: MessageType.CF_AGENT_STATE }));\n this.state = state;\n this.options.onStateUpdate?.(state, \"client\");\n }\n\n /**\n * Close the connection and immediately reject all pending RPC calls.\n * This provides immediate feedback on intentional close rather than\n * waiting for the WebSocket close handshake to complete.\n *\n * Note: Any calls made after `close()` will be rejected when the\n * underlying WebSocket close event fires.\n */\n close(code?: number, reason?: string) {\n // Immediately reject all pending calls on intentional close\n this._rejectPendingCalls(\"Connection closed\");\n\n // Then close the underlying socket\n super.close(code, reason);\n }\n\n /**\n * Call a method on the Agent.\n * When AgentT is provided, method names are inferred from the agent's methods.\n * Falls back to untyped string-based calls when AgentT is not provided.\n */\n private async _callImpl(\n method: string,\n args: unknown[] = [],\n options?: CallOptions | StreamOptions\n ): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const id = crypto.randomUUID();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n // Detect legacy format: { onChunk?, onDone?, onError? } vs new format: { timeout?, stream? }\n const isLegacyFormat =\n options &&\n (\"onChunk\" in options || \"onDone\" in options || \"onError\" in options);\n const streamOptions = isLegacyFormat\n ? (options as StreamOptions)\n : (options as CallOptions | undefined)?.stream;\n const timeout = isLegacyFormat\n ? undefined\n : (options as CallOptions | undefined)?.timeout;\n\n // Set up timeout if specified\n if (timeout) {\n timeoutId = setTimeout(() => {\n const pending = this._pendingCalls.get(id);\n this._pendingCalls.delete(id);\n const errorMessage = `RPC call to ${method} timed out after ${timeout}ms`;\n pending?.stream?.onError?.(errorMessage);\n reject(new Error(errorMessage));\n }, timeout);\n }\n\n this._pendingCalls.set(id, {\n reject: (e: Error) => {\n if (timeoutId) clearTimeout(timeoutId);\n reject(e);\n },\n resolve: (value: unknown) => {\n if (timeoutId) clearTimeout(timeoutId);\n resolve(value);\n },\n stream: streamOptions\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n this.send(JSON.stringify(request));\n });\n }\n}\n\n/**\n * Make an HTTP request to an Agent\n * @param opts Connection options\n * @param init Request initialization options\n * @returns Promise resolving to a Response\n */\nexport function agentFetch(opts: AgentClientFetchOptions, init?: RequestInit) {\n const agentNamespace = camelCaseToKebabCase(opts.agent);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n // When basePath is set, room/party aren't used by PartySocket (basePath replaces the URL)\n if (opts.basePath) {\n return PartySocket.fetch(\n { basePath: opts.basePath, ...opts } as unknown as PartyFetchOptions,\n init\n );\n }\n\n return PartySocket.fetch(\n {\n party: agentNamespace,\n prefix: \"agents\",\n room: opts.name || \"default\",\n ...opts\n },\n init\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n type PartyFetchOptions,\n PartySocket,\n type PartySocketOptions\n} from \"partysocket\";\nimport type { Agent, RPCRequest, RPCResponse } from \"./\";\nimport type {\n Method,\n RPCMethod,\n SerializableReturnValue,\n SerializableValue\n} from \"./serializable\";\nimport { MessageType } from \"./types\";\nimport { camelCaseToKebabCase, isInternalJsStubProp } from \"./utils\";\n\n/**\n * Options for creating an AgentClient\n */\nexport type AgentClientOptions<State = unknown> = Omit<\n PartySocketOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the client connects to this path directly.\n * Server must handle routing manually (e.g., with getAgentByName + fetch).\n * @example\n * // Client connects to /user, server routes based on session\n * useAgent({ agent: \"UserAgent\", basePath: \"user\" })\n */\n basePath?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n /** Called when a state update fails (e.g., connection is readonly) */\n onStateUpdateError?: (error: string) => void;\n /**\n * Called when the server sends the agent's identity on connect.\n * Useful when using basePath, as the actual instance name is determined server-side.\n * @param name The actual agent instance name\n * @param agent The agent class name (kebab-case)\n */\n onIdentity?: (name: string, agent: string) => void;\n /**\n * Called when identity changes on reconnect (different instance than before).\n * If not provided and identity changes, a warning will be logged.\n * @param oldName Previous instance name\n * @param newName New instance name\n * @param oldAgent Previous agent class name\n * @param newAgent New agent class name\n */\n onIdentityChange?: (\n oldName: string,\n newName: string,\n oldAgent: string,\n newAgent: string\n ) => void;\n /**\n * Additional path to append to the URL.\n * Works with both standard routing and basePath.\n * @example\n * // With basePath: /user/settings\n * { basePath: \"user\", path: \"settings\" }\n * // Standard: /agents/my-agent/room/settings\n * { agent: \"MyAgent\", name: \"room\", path: \"settings\" }\n */\n path?: string;\n};\n\n/**\n * Options for streaming RPC calls\n */\nexport type StreamOptions = {\n /** Called when a chunk of data is received */\n onChunk?: (chunk: unknown) => void;\n /** Called when the stream ends */\n onDone?: (finalChunk: unknown) => void;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n};\n\n/**\n * Options for RPC calls\n */\nexport type CallOptions = {\n /** Timeout in milliseconds. If the call doesn't complete within this time, it will be rejected. */\n timeout?: number;\n /** Streaming options for handling streaming responses */\n stream?: StreamOptions;\n};\n\n/**\n * Options for the agentFetch function\n */\nexport type AgentClientFetchOptions = Omit<\n PartyFetchOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to (ignored if basePath is set) */\n agent: string;\n /** Name of the specific Agent instance (ignored if basePath is set) */\n name?: string;\n /**\n * Full URL path - bypasses agent/name URL construction.\n * When set, the request is made to this path directly.\n */\n basePath?: string;\n};\n\n// ---- Shared RPC Type Utilities ----\n\ntype AllOptional<T> = T extends [infer A, ...infer R]\n ? undefined extends A\n ? AllOptional<R>\n : false\n : true;\n\nexport type RPCMethods<T> = {\n [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;\n};\n\ntype OptionalParametersMethod<T extends RPCMethod> =\n AllOptional<Parameters<T>> extends true ? T : never;\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic agent type constraint\nexport type AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;\n\nexport type OptionalAgentMethods<T> = {\n [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<\n AgentMethods<T>[K]\n >\n ? K\n : never]: OptionalParametersMethod<AgentMethods<T>[K]>;\n};\n\nexport type RequiredAgentMethods<T> = Omit<\n AgentMethods<T>,\n keyof OptionalAgentMethods<T>\n>;\n\nexport type AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- generic promise return type\n ReturnType<AgentMethods<T>[K]> extends Promise<any>\n ? ReturnType<AgentMethods<T>[K]>\n : Promise<ReturnType<AgentMethods<T>[K]>>;\n\nexport type AgentStub<T> = {\n [K in keyof AgentMethods<T>]: (\n ...args: Parameters<AgentMethods<T>[K]>\n ) => AgentPromiseReturnType<AgentMethods<T>, K>;\n};\n\nexport type UntypedAgentStub = Record<string, Method>;\n\ntype AgentClientStub<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentStub\n : AgentStub<AgentT>;\n\ntype OptionalArgsAgentClientCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: Parameters<OptionalAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentClientCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: Parameters<RequiredAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype TypedAgentClientCall<AgentT> = OptionalArgsAgentClientCall<AgentT> &\n RequiredArgsAgentClientCall<AgentT>;\n\ntype UntypedAgentClientCall = {\n <T extends SerializableReturnValue>(\n method: string,\n args?: SerializableValue[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n <T = unknown>(\n method: string,\n args?: unknown[],\n options?: CallOptions | StreamOptions\n ): Promise<T>;\n};\n\ntype AgentClientCall<AgentT> = keyof AgentMethods<AgentT> extends never\n ? UntypedAgentClientCall\n : TypedAgentClientCall<AgentT>;\n\n/**\n * Creates a proxy that wraps RPC method calls.\n * Internal JS methods (toJSON, then, etc.) return undefined to avoid\n * triggering RPC calls during serialization (e.g., console.log)\n */\nexport function createStubProxy<T = Record<string, Method>>(\n call: (method: string, args: unknown[]) => unknown\n): T {\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- proxy needs any for dynamic method access\n return new Proxy<any>(\n {},\n {\n get: (_target, method) => {\n if (isInternalJsStubProp(method)) {\n return undefined;\n }\n return (...args: unknown[]) => call(method as string, args);\n }\n }\n );\n}\n\n/**\n * WebSocket client for connecting to an Agent\n */\nexport class AgentClient<\n AgentT = unknown,\n State = AgentT extends { get state(): infer S } ? S : AgentT\n> extends PartySocket {\n /**\n * @deprecated Use agentFetch instead\n */\n static fetch(_opts: PartyFetchOptions): Promise<Response> {\n throw new Error(\n \"AgentClient.fetch is not implemented, use agentFetch instead\"\n );\n }\n agent: string;\n name: string;\n call: AgentClientCall<AgentT>;\n stub: AgentClientStub<AgentT>;\n\n /**\n * The current agent state, updated on server broadcasts and client setState calls.\n * Starts as undefined until the first state message is received from the server.\n */\n state: State | undefined = undefined;\n\n /**\n * Whether the client has received identity from the server.\n * Becomes true after the first identity message is received.\n * Resets to false on connection close.\n */\n identified = false;\n\n /**\n * Promise that resolves when identity has been received from the server.\n * Useful for waiting before making calls that depend on knowing the instance.\n * Resets on connection close so it can be awaited again after reconnect.\n */\n get ready(): Promise<void> {\n return this._readyPromise;\n }\n\n private options: AgentClientOptions<State>;\n private _pendingCalls = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >();\n private _readyPromise!: Promise<void>;\n private _resolveReady!: () => void;\n private _previousName: string | null = null;\n private _previousAgent: string | null = null;\n\n private _resetReady() {\n this._readyPromise = new Promise((resolve) => {\n this._resolveReady = resolve;\n });\n }\n\n constructor(options: AgentClientOptions<State>) {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? { basePath: options.basePath, path: options.path, ...options }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: options.path,\n ...options\n };\n\n super(socketOptions);\n this.agent = agentNamespace;\n this.name = options.name || \"default\";\n this.options = options;\n\n // Initialize ready promise\n this._resetReady();\n\n this.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(event.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = this._previousName;\n const oldAgent = this._previousAgent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n // Resolve ready/identified\n this.identified = true;\n this._resolveReady();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (this.options.onIdentityChange) {\n this.options.onIdentityChange(\n oldName,\n newName,\n oldAgent,\n newAgent\n );\n } else {\n const agentChanged = oldAgent !== newAgent;\n const nameChanged = oldName !== newName;\n let changeDescription = \"\";\n if (agentChanged && nameChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\", instance \"${oldName}\" → \"${newName}\"`;\n } else if (agentChanged) {\n changeDescription = `agent \"${oldAgent}\" → \"${newAgent}\"`;\n } else {\n changeDescription = `instance \"${oldName}\" → \"${newName}\"`;\n }\n console.warn(\n `[agents] Identity changed on reconnect: ${changeDescription}. ` +\n \"This can happen with server-side routing (e.g., basePath with getAgentByName) \" +\n \"where the instance is determined by auth/session. \" +\n \"Provide onIdentityChange callback to handle this explicitly, \" +\n \"or ignore if this is expected for your routing pattern.\"\n );\n }\n }\n\n // Always update from server identity (server is authoritative)\n this._previousName = newName;\n this._previousAgent = newAgent;\n this.name = newName;\n this.agent = newAgent;\n\n // Call onIdentity callback\n this.options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n this.state = parsedMessage.state as State;\n this.options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE_ERROR) {\n this.options.onStateUpdateError?.(parsedMessage.error as string);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = this._pendingCalls.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n this._pendingCalls.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n this._pendingCalls.delete(response.id);\n }\n }\n }\n });\n\n // Clean up pending calls and reset ready state when connection closes\n this.addEventListener(\"close\", () => {\n // Reset ready state for next connection\n this.identified = false;\n this._resetReady();\n\n // Reject any remaining pending calls (e.g., from unexpected disconnect)\n this._rejectPendingCalls(\"Connection closed\");\n });\n\n this.call = this._callImpl.bind(this) as AgentClientCall<AgentT>;\n this.stub = createStubProxy((method, args) =>\n this._callImpl(method, args)\n ) as AgentClientStub<AgentT>;\n }\n\n /**\n * Reject all pending RPC calls with the given reason.\n */\n private _rejectPendingCalls(reason: string) {\n const error = new Error(reason);\n for (const pending of this._pendingCalls.values()) {\n pending.reject(error);\n pending.stream?.onError?.(reason);\n }\n this._pendingCalls.clear();\n }\n\n setState(state: State) {\n this.send(JSON.stringify({ state, type: MessageType.CF_AGENT_STATE }));\n this.state = state;\n this.options.onStateUpdate?.(state, \"client\");\n }\n\n /**\n * Close the connection and immediately reject all pending RPC calls.\n * This provides immediate feedback on intentional close rather than\n * waiting for the WebSocket close handshake to complete.\n *\n * Note: Any calls made after `close()` will be rejected when the\n * underlying WebSocket close event fires.\n */\n close(code?: number, reason?: string) {\n // Immediately reject all pending calls on intentional close\n this._rejectPendingCalls(\"Connection closed\");\n\n // Then close the underlying socket\n super.close(code, reason);\n }\n\n /**\n * Call a method on the Agent.\n * When AgentT is provided, method names are inferred from the agent's methods.\n * Falls back to untyped string-based calls when AgentT is not provided.\n */\n private async _callImpl(\n method: string,\n args: unknown[] = [],\n options?: CallOptions | StreamOptions\n ): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const id = crypto.randomUUID();\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n // Detect legacy format: { onChunk?, onDone?, onError? } vs new format: { timeout?, stream? }\n const isLegacyFormat =\n options &&\n (\"onChunk\" in options || \"onDone\" in options || \"onError\" in options);\n const streamOptions = isLegacyFormat\n ? (options as StreamOptions)\n : (options as CallOptions | undefined)?.stream;\n const timeout = isLegacyFormat\n ? undefined\n : (options as CallOptions | undefined)?.timeout;\n\n // Set up timeout if specified\n if (timeout) {\n timeoutId = setTimeout(() => {\n const pending = this._pendingCalls.get(id);\n this._pendingCalls.delete(id);\n const errorMessage = `RPC call to ${method} timed out after ${timeout}ms`;\n pending?.stream?.onError?.(errorMessage);\n reject(new Error(errorMessage));\n }, timeout);\n }\n\n this._pendingCalls.set(id, {\n reject: (e: Error) => {\n if (timeoutId) clearTimeout(timeoutId);\n reject(e);\n },\n resolve: (value: unknown) => {\n if (timeoutId) clearTimeout(timeoutId);\n resolve(value);\n },\n stream: streamOptions\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n this.send(JSON.stringify(request));\n });\n }\n}\n\n/**\n * Make an HTTP request to an Agent\n * @param opts Connection options\n * @param init Request initialization options\n * @returns Promise resolving to a Response\n */\nexport function agentFetch(opts: AgentClientFetchOptions, init?: RequestInit) {\n const agentNamespace = camelCaseToKebabCase(opts.agent);\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n // When basePath is set, room/party aren't used by PartySocket (basePath replaces the URL)\n if (opts.basePath) {\n return PartySocket.fetch(\n { basePath: opts.basePath, ...opts } as unknown as PartyFetchOptions,\n init\n );\n }\n\n return PartySocket.fetch(\n {\n party: agentNamespace,\n prefix: \"agents\",\n room: opts.name || \"default\",\n ...opts\n },\n init\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { n as AgentEmail } from "./internal_context-BvuGZieY.js";
2
- import { t as RetryOptions } from "./retries-JlwH9mnV.js";
2
+ import { t as RetryOptions } from "./retries-fLD8cGNf.js";
3
3
  import {
4
4
  n as Observability,
5
5
  r as ObservabilityEvent,
@@ -67,6 +67,122 @@ import { Server as Server$1 } from "@modelcontextprotocol/sdk/server/index.js";
67
67
  import { Client as Client$1 } from "@modelcontextprotocol/sdk/client";
68
68
  import { EventStore } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
69
69
 
70
+ //#region src/sub-routing.d.ts
71
+ /**
72
+ * URL segment marking a parent↔child boundary.
73
+ *
74
+ * Exposed as a constant so callers can build URLs symbolically, but
75
+ * not configurable — the routing layer matches on the literal `sub`
76
+ * token everywhere (parent fetch, client, helpers).
77
+ */
78
+ declare const SUB_PREFIX = "sub";
79
+ interface SubAgentPathMatch {
80
+ /** CamelCase class name of the child, as it appears in `ctx.exports`. */
81
+ childClass: string;
82
+ /** URL-decoded child name. */
83
+ childName: string;
84
+ /**
85
+ * Request path to forward to the child, with the
86
+ * `/sub/{class}/{name}` segment stripped. Always begins with `/`;
87
+ * may itself contain further `/sub/...` markers when a
88
+ * recursively nested sub-agent is being routed.
89
+ */
90
+ remainingPath: string;
91
+ }
92
+ /**
93
+ * Parse a URL and extract the first `/sub/{class}/{name}` segment,
94
+ * if any. Recursive nesting is handled naturally: callers parse one
95
+ * level at a time; the child then parses its own URL (which still
96
+ * contains any deeper `/sub/...` markers).
97
+ *
98
+ * Names are URL-decoded. Classes are kebab-to-CamelCase converted
99
+ * via a best-effort match against a provided lookup — pass
100
+ * `ctx.exports` keys to get exact CamelCase; pass `undefined` for
101
+ * a tolerant conversion without validation.
102
+ *
103
+ * Returns `null` when the URL doesn't contain the marker at a
104
+ * recognized position, or when the marker has no following
105
+ * class+name pair.
106
+ */
107
+ declare function parseSubAgentPath(
108
+ url: string,
109
+ options?: {
110
+ /** CamelCase class names to match against (usually `ctx.exports` keys). */ knownClasses?: readonly string[];
111
+ }
112
+ ): SubAgentPathMatch | null;
113
+ /**
114
+ * Route a request into a sub-agent via its parent DO.
115
+ *
116
+ * Use this in a custom fetch handler when your URL shape doesn't
117
+ * match the `/agents/{class}/{name}` default — you identify and
118
+ * fetch the parent yourself, then let this helper parse the
119
+ * `/sub/{child}/...` tail and forward it.
120
+ *
121
+ * Runs `onBeforeSubAgent` on the parent DO (authorization / request
122
+ * mutation / short-circuit response).
123
+ *
124
+ * For the default `/agents/...` URL shape, use `routeAgentRequest`
125
+ * instead — it handles the parent lookup and this dispatch in one
126
+ * call.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * export default {
131
+ * async fetch(req, env) {
132
+ * const { parentName, rest } = myCustomParse(req.url);
133
+ * const parent = await getAgentByName(env.Inbox, parentName);
134
+ * return routeSubAgentRequest(req, parent, { fromPath: rest });
135
+ * }
136
+ * };
137
+ * ```
138
+ *
139
+ * @experimental The API surface may change before stabilizing.
140
+ */
141
+ declare function routeSubAgentRequest(
142
+ req: Request,
143
+ parent: unknown,
144
+ options?: {
145
+ /**
146
+ * Path to route on. Defaults to `req.url`'s pathname. Useful
147
+ * when your outer URL is custom (e.g. `/api/v1/...`) and you
148
+ * want to route the sub-agent tail without rewriting the
149
+ * Request first.
150
+ */
151
+ fromPath?: string;
152
+ }
153
+ ): Promise<Response>;
154
+ /**
155
+ * Get a typed RPC stub for a sub-agent from outside the parent DO.
156
+ *
157
+ * The returned stub proxies method calls through the parent via a
158
+ * stateless per-call bridge (caller → parent → facet), so each
159
+ * method invocation costs one extra RPC hop. Works across parent
160
+ * hibernation — no cached references to go stale.
161
+ *
162
+ * Limitations:
163
+ * - RPC methods only. `.fetch()` is not supported (will throw).
164
+ * Use `routeSubAgentRequest` for external HTTP/WS.
165
+ * - Arguments and return values must be structured-cloneable,
166
+ * same as any DO RPC call.
167
+ * - Does not run `onBeforeSubAgent` on the parent — analogous to
168
+ * `getAgentByName` not running `onBeforeConnect`. The caller is
169
+ * assumed to have performed whatever access checks are needed.
170
+ *
171
+ * @example
172
+ * ```ts
173
+ * const inbox = await getAgentByName(env.MyInbox, userId);
174
+ * const chat = await getSubAgentByName(inbox, MyChat, chatId);
175
+ * await chat.addMessage({ role: "user", content: "hi" });
176
+ * ```
177
+ *
178
+ * @experimental The API surface may change before stabilizing.
179
+ */
180
+ declare function getSubAgentByName<T extends Agent>(
181
+ parent: unknown,
182
+ cls: SubAgentClass<T>,
183
+ name: string
184
+ ): Promise<SubAgentStub<T>>;
185
+ //#endregion
70
186
  //#region src/core/events.d.ts
71
187
  interface Disposable {
72
188
  dispose(): void;
@@ -1796,6 +1912,13 @@ declare class Agent<
1796
1912
  private _persistenceHookMode;
1797
1913
  /** True when this agent runs as a facet (sub-agent) inside a parent. */
1798
1914
  private _isFacet;
1915
+ /**
1916
+ * Ancestor chain, root-first. Empty for top-level DOs; populated at
1917
+ * facet init time from the parent's own `selfPath`. Exposed publicly
1918
+ * via the `parentPath` getter.
1919
+ * @internal
1920
+ */
1921
+ private _parentPath;
1799
1922
  /** True while user's onStart() is executing. Used to warn about non-idempotent schedule() calls. */
1800
1923
  private _insideOnStart;
1801
1924
  /** Tracks callbacks already warned about during this onStart() to avoid log spam. */
@@ -1903,18 +2026,6 @@ declare class Agent<
1903
2026
  * @param excludeIds Additional connection IDs to exclude (e.g. the source)
1904
2027
  */
1905
2028
  private _broadcastProtocol;
1906
- /**
1907
- * When running as a facet, the parent DO owns the WebSocket registry
1908
- * (`ctx.getWebSockets()`). Iterating from the child isolate throws
1909
- * "Cannot perform I/O on behalf of a different Durable Object".
1910
- * Downstream callers (e.g. chat-streaming paths) invoke
1911
- * `this.broadcast()` directly, bypassing `_broadcastProtocol`'s
1912
- * guard, so override at the base to catch every path.
1913
- */
1914
- broadcast(
1915
- msg: string | ArrayBuffer | ArrayBufferView,
1916
- without?: string[]
1917
- ): void;
1918
2029
  private _setStateInternal;
1919
2030
  /**
1920
2031
  * Update the Agent's state
@@ -2293,6 +2404,12 @@ declare class Agent<
2293
2404
  * alarm system, without creating schedule rows or emitting observability
2294
2405
  * events. Configure via `static options = { keepAliveIntervalMs: 5000 }`.
2295
2406
  *
2407
+ * No-op on facets. Facets share the parent's isolate and don't
2408
+ * need a separate alarm heartbeat — the parent's own activity,
2409
+ * any open WebSocket to the facet, and any in-flight Promise
2410
+ * already keep the shared machine alive for the duration of
2411
+ * real work.
2412
+ *
2296
2413
  * @example
2297
2414
  * ```ts
2298
2415
  * const dispose = await this.keepAlive();
@@ -2385,6 +2502,90 @@ declare class Agent<
2385
2502
  * See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
2386
2503
  */
2387
2504
  alarm(): Promise<void>;
2505
+ /**
2506
+ * Intercept incoming HTTP/WS requests whose URL contains a
2507
+ * `/sub/{child-class}/{child-name}` marker and forward them to
2508
+ * the facet. The `onBeforeSubAgent` hook fires first (authorize,
2509
+ * mutate, or short-circuit). If the hook doesn't return a
2510
+ * Response, the framework resolves the facet and hands the
2511
+ * request off.
2512
+ *
2513
+ * After a WebSocket upgrade completes, subsequent frames route
2514
+ * directly to the child — the parent is only on the path for the
2515
+ * initial request.
2516
+ *
2517
+ * @experimental The API surface may change before stabilizing.
2518
+ */
2519
+ fetch(request: Request): Promise<Response>;
2520
+ /**
2521
+ * Parent-side middleware hook. Fires before a request is
2522
+ * forwarded into a facet sub-agent. Mirrors `onBeforeConnect` /
2523
+ * `onBeforeRequest`.
2524
+ *
2525
+ * - return `void` (default) → forward the original request
2526
+ * - return `Request` → forward this (modified) request
2527
+ * - return `Response` → return this response to the
2528
+ * client; do not wake the child
2529
+ *
2530
+ * Default implementation: return void (permissive).
2531
+ *
2532
+ * The hook receives the **original** request with its URL intact —
2533
+ * including the `/sub/{class}/{name}` segment. The routing
2534
+ * decision for which facet to wake is fixed at parse time, so if
2535
+ * you return a modified `Request`, its headers, body, method, and
2536
+ * query string flow through to the child, but the **pathname**
2537
+ * the child sees is always the tail after `/sub/{class}/{name}`.
2538
+ * Customize via headers/body rather than URL-rewriting.
2539
+ *
2540
+ * WebSocket upgrade requests flow through this hook the same way as
2541
+ * plain HTTP. If you return a mutated `Request`, make sure it still
2542
+ * carries the original `Upgrade: websocket` and `Sec-WebSocket-*`
2543
+ * headers — the simplest safe recipe is to clone the incoming
2544
+ * request's headers (via `new Headers(req.headers)`) and only add
2545
+ * or replace entries, rather than constructing a fresh `Headers`
2546
+ * object from scratch.
2547
+ *
2548
+ * @experimental The API surface may change before stabilizing.
2549
+ *
2550
+ * @example
2551
+ * ```ts
2552
+ * class Inbox extends Agent {
2553
+ * override async onBeforeSubAgent(req, { className, name }) {
2554
+ * // Strict registry gate
2555
+ * if (!this.hasSubAgent(className, name)) {
2556
+ * return new Response("Not found", { status: 404 });
2557
+ * }
2558
+ * }
2559
+ * }
2560
+ * ```
2561
+ */
2562
+ onBeforeSubAgent(
2563
+ _request: Request,
2564
+ _child: {
2565
+ className: string;
2566
+ name: string;
2567
+ }
2568
+ ): Promise<Request | Response | void>;
2569
+ /**
2570
+ * Resolve the facet Fetcher for the match and forward the
2571
+ * request to it with `/sub/{class}/{name}` stripped.
2572
+ *
2573
+ * @internal
2574
+ */
2575
+ private _cf_forwardToFacet;
2576
+ /**
2577
+ * Bridge method used by `getSubAgentByName`. Resolves the facet
2578
+ * on each call (idempotent via `subAgent`) and dispatches one
2579
+ * RPC method. Stateless — no cached references.
2580
+ *
2581
+ * @internal
2582
+ */
2583
+ _cf_invokeSubAgent(
2584
+ className: string,
2585
+ name: string,
2586
+ method: string,
2587
+ args: unknown[]
2588
+ ): Promise<unknown>;
2388
2589
  /**
2389
2590
  * Initialize this agent as a facet in a single RPC.
2390
2591
  *
@@ -2395,14 +2596,95 @@ declare class Agent<
2395
2596
  * parent and triggered "Cannot perform I/O on behalf of a different
2396
2597
  * Durable Object" on the child.
2397
2598
  *
2398
- * Order matters: set `_isFacet` BEFORE triggering initialization, so
2399
- * the first `onStart()` run (which calls `broadcastMcpServers`) sees
2400
- * the flag and skips broadcasts that would touch the parent DO's
2401
- * WebSocket registry.
2599
+ * We still set `_isFacet` eagerly (before `__unsafe_ensureInitialized`)
2600
+ * so any code that legitimately branches on it — e.g. skipping
2601
+ * parent-owned alarms in schedule guards sees the flag during
2602
+ * the first `onStart()` run. Broadcast paths no longer special-case
2603
+ * facets, since facets can be directly addressed via sub-agent
2604
+ * routing and have their own WebSocket connections.
2402
2605
  *
2403
2606
  * @internal Called by {@link subAgent}.
2404
2607
  */
2405
- _cf_initAsFacet(name: string): Promise<void>;
2608
+ _cf_initAsFacet(
2609
+ name: string,
2610
+ parentPath?: ReadonlyArray<{
2611
+ className: string;
2612
+ name: string;
2613
+ }>
2614
+ ): Promise<void>;
2615
+ /**
2616
+ * Ancestor chain for this agent, root-first. Empty for top-level
2617
+ * DOs. Populated at facet init time; survives hibernation.
2618
+ *
2619
+ * @example
2620
+ * ```ts
2621
+ * class Chat extends Agent {
2622
+ * onStart() {
2623
+ * console.log("chat started under:", this.parentPath);
2624
+ * // → [{ className: "Tenant", name: "acme" }, { className: "Inbox", name: "alice" }]
2625
+ * }
2626
+ * }
2627
+ * ```
2628
+ *
2629
+ * @experimental The API surface may change before stabilizing.
2630
+ */
2631
+ get parentPath(): ReadonlyArray<{
2632
+ className: string;
2633
+ name: string;
2634
+ }>;
2635
+ /**
2636
+ * Ancestor chain + self, root-first. Convenient for logging.
2637
+ *
2638
+ * @experimental The API surface may change before stabilizing.
2639
+ */
2640
+ get selfPath(): ReadonlyArray<{
2641
+ className: string;
2642
+ name: string;
2643
+ }>;
2644
+ /**
2645
+ * Resolve a typed RPC stub for this facet's **immediate** parent
2646
+ * agent.
2647
+ *
2648
+ * Symmetric with `subAgent(Cls, name)`: while `subAgent` opens a
2649
+ * stub from parent to child, `parentAgent` opens one from child
2650
+ * to parent. Pass the direct parent's class reference — the
2651
+ * framework verifies it matches the last entry of
2652
+ * `this.parentPath` at runtime, then looks up `env[Cls.name]` to
2653
+ * find the namespace binding.
2654
+ *
2655
+ * `this.parentPath` is root-first, so the direct parent is the
2656
+ * **last** entry: `this.parentPath.at(-1)`. For grandparents and
2657
+ * further ancestors, iterate `this.parentPath` and use
2658
+ * `getAgentByName(env.X, this.parentPath[i].name)` directly.
2659
+ *
2660
+ * Assumes the standard "binding name matches class name" convention.
2661
+ * If your `wrangler.jsonc` binds the parent under a different name
2662
+ * (e.g. `{ class_name: "Inbox", name: "MY_INBOX" }`), call
2663
+ * `getAgentByName(env.MY_INBOX, this.parentPath.at(-1)!.name)`
2664
+ * directly instead.
2665
+ *
2666
+ * @experimental The API surface may change before stabilizing.
2667
+ *
2668
+ * @throws If this agent is not a facet (no parent).
2669
+ * @throws If `Cls.name` doesn't match the recorded direct-parent
2670
+ * class (guards against accidentally reaching the wrong
2671
+ * DO, especially in nested Root → Mid → Leaf chains).
2672
+ * @throws If no env binding named `Cls.name` is found.
2673
+ *
2674
+ * @example
2675
+ * ```ts
2676
+ * class Chat extends AIChatAgent<Env> {
2677
+ * async onChatMessage(...) {
2678
+ * const inbox = await this.parentAgent(Inbox);
2679
+ * const memory = await inbox.getSharedMemory("facts");
2680
+ * // ...
2681
+ * }
2682
+ * }
2683
+ * ```
2684
+ */
2685
+ parentAgent<T extends Agent>(
2686
+ cls: SubAgentClass<T>
2687
+ ): Promise<DurableObjectStub<T>>;
2406
2688
  /**
2407
2689
  * Get or create a named sub-agent — a child Durable Object (facet)
2408
2690
  * with its own isolated SQLite storage running on the same machine.
@@ -2427,6 +2709,16 @@ declare class Agent<
2427
2709
  cls: SubAgentClass<T>,
2428
2710
  name: string
2429
2711
  ): Promise<SubAgentStub<T>>;
2712
+ /**
2713
+ * Shared facet resolution — takes a CamelCase class name string
2714
+ * (matching `ctx.exports`) rather than a class reference. Both
2715
+ * `subAgent(cls, name)` and `_cf_invokeSubAgent(className, ...)`
2716
+ * funnel through here so registry bookkeeping and the
2717
+ * `_cf_initAsFacet` handshake are consistent.
2718
+ *
2719
+ * @internal
2720
+ */
2721
+ private _cf_resolveSubAgent;
2430
2722
  /**
2431
2723
  * Forcefully abort a running sub-agent. The child stops executing
2432
2724
  * immediately and will be restarted on next {@link subAgent} call.
@@ -2450,6 +2742,54 @@ declare class Agent<
2450
2742
  * @param name Name of the child to delete
2451
2743
  */
2452
2744
  deleteSubAgent(cls: SubAgentClass, name: string): void;
2745
+ /** @internal */
2746
+ private _subAgentRegistryReady;
2747
+ /** @internal */
2748
+ private _ensureSubAgentRegistry;
2749
+ /** @internal */
2750
+ private _recordSubAgent;
2751
+ /** @internal */
2752
+ private _forgetSubAgent;
2753
+ /**
2754
+ * Whether this agent has previously spawned (and not deleted) a
2755
+ * sub-agent of the given class and name. Backed by an
2756
+ * auto-maintained SQLite registry in the parent's storage.
2757
+ *
2758
+ * Intended for strict-registry access patterns in
2759
+ * `onBeforeSubAgent` or similar gating logic.
2760
+ *
2761
+ * @experimental The API surface may change before stabilizing.
2762
+ *
2763
+ * @example
2764
+ * ```ts
2765
+ * async onBeforeSubAgent(req, { className, name }) {
2766
+ * if (!this.hasSubAgent(className, name)) {
2767
+ * return new Response("Not found", { status: 404 });
2768
+ * }
2769
+ * }
2770
+ * ```
2771
+ */
2772
+ hasSubAgent<T extends Agent>(cls: SubAgentClass<T>, name: string): boolean;
2773
+ hasSubAgent(className: string, name: string): boolean;
2774
+ /**
2775
+ * List known sub-agents, optionally filtered by class. Reflects
2776
+ * the registry rows written by {@link subAgent} and removed by
2777
+ * {@link deleteSubAgent}.
2778
+ *
2779
+ * @experimental The API surface may change before stabilizing.
2780
+ */
2781
+ listSubAgents<T extends Agent>(
2782
+ cls: SubAgentClass<T>
2783
+ ): Array<{
2784
+ className: string;
2785
+ name: string;
2786
+ createdAt: number;
2787
+ }>;
2788
+ listSubAgents(className?: string): Array<{
2789
+ className: string;
2790
+ name: string;
2791
+ createdAt: number;
2792
+ }>;
2453
2793
  /**
2454
2794
  * Destroy the Agent, removing all state and scheduled tasks
2455
2795
  */
@@ -3068,6 +3408,7 @@ export {
3068
3408
  RPCServerTransport as Y,
3069
3409
  RPC_DO_PREFIX as Z,
3070
3410
  MCPServerMessage as _,
3411
+ parseSubAgentPath as _t,
3071
3412
  AgentNamespace as a,
3072
3413
  McpAuthContext as at,
3073
3414
  RPCRequest as b,
@@ -3079,7 +3420,9 @@ export {
3079
3420
  EmailRoutingOptions as f,
3080
3421
  McpClientOptions as ft,
3081
3422
  MCPServer as g,
3423
+ getSubAgentByName as gt,
3082
3424
  FiberRecoveryContext as h,
3425
+ SubAgentPathMatch as ht,
3083
3426
  AgentContext as i,
3084
3427
  experimental_createMcpHandler as it,
3085
3428
  getAgentByName as j,
@@ -3087,6 +3430,7 @@ export {
3087
3430
  Connection$1 as l,
3088
3431
  WorkerTransportOptions as lt,
3089
3432
  FiberContext as m,
3433
+ SUB_PREFIX as mt,
3090
3434
  AddRpcMcpServerOptions as n,
3091
3435
  CreateMcpHandlerOptions as nt,
3092
3436
  AgentOptions as o,
@@ -3103,9 +3447,10 @@ export {
3103
3447
  ConnectionContext$1 as u,
3104
3448
  SSEEdgeClientTransport as ut,
3105
3449
  MCPServersState as v,
3450
+ routeSubAgentRequest as vt,
3106
3451
  SqlError as w,
3107
3452
  RPCResponse as x,
3108
3453
  QueueItem as y,
3109
3454
  MCPClientOAuthResult as z
3110
3455
  };
3111
- //# sourceMappingURL=index-D9qo_Inc.d.ts.map
3456
+ //# sourceMappingURL=index-DabjI66m.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { r as __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context-BvuGZieY.js";
2
- import { t as RetryOptions } from "./retries-JlwH9mnV.js";
3
2
  import {
4
3
  A as callable,
5
4
  C as SendEmailOptions,
@@ -13,18 +12,22 @@ import {
13
12
  S as Schedule,
14
13
  T as StateUpdateMessage,
15
14
  _ as MCPServerMessage,
15
+ _t as parseSubAgentPath,
16
16
  a as AgentNamespace,
17
17
  b as RPCRequest,
18
18
  c as CallableMetadata,
19
19
  d as DEFAULT_AGENT_STATIC_OPTIONS,
20
20
  f as EmailRoutingOptions,
21
21
  g as MCPServer,
22
+ gt as getSubAgentByName,
22
23
  h as FiberRecoveryContext,
24
+ ht as SubAgentPathMatch,
23
25
  i as AgentContext,
24
26
  j as getAgentByName,
25
27
  k as WSMessage,
26
28
  l as Connection,
27
29
  m as FiberContext,
30
+ mt as SUB_PREFIX,
28
31
  n as AddRpcMcpServerOptions,
29
32
  o as AgentOptions,
30
33
  p as EmailSendBinding,
@@ -34,10 +37,12 @@ import {
34
37
  t as AddMcpServerOptions,
35
38
  u as ConnectionContext,
36
39
  v as MCPServersState,
40
+ vt as routeSubAgentRequest,
37
41
  w as SqlError,
38
42
  x as RPCResponse,
39
43
  y as QueueItem
40
- } from "./index-D9qo_Inc.js";
44
+ } from "./index-DabjI66m.js";
45
+ import { t as RetryOptions } from "./retries-fLD8cGNf.js";
41
46
  import {
42
47
  n as AgentsOAuthProvider,
43
48
  r as DurableObjectOAuthClientProvider,
@@ -72,12 +77,14 @@ export {
72
77
  RPCRequest,
73
78
  RPCResponse,
74
79
  RetryOptions,
80
+ SUB_PREFIX,
75
81
  Schedule,
76
82
  SendEmailOptions,
77
83
  SqlError,
78
84
  StateUpdateMessage,
79
85
  StreamingResponse,
80
86
  SubAgentClass,
87
+ SubAgentPathMatch,
81
88
  SubAgentStub,
82
89
  TransportType,
83
90
  WSMessage,
@@ -86,7 +93,10 @@ export {
86
93
  createHeaderBasedEmailResolver,
87
94
  getAgentByName,
88
95
  getCurrentAgent,
96
+ getSubAgentByName,
97
+ parseSubAgentPath,
89
98
  routeAgentEmail,
90
99
  routeAgentRequest,
100
+ routeSubAgentRequest,
91
101
  unstable_callable
92
102
  };