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.
- package/README.md +44 -1
- package/dist/chat/index.d.ts +73 -1
- package/dist/{client-B_xdiZbn.js → client-BYF13FDD.js} +3 -1
- package/dist/{client-B_xdiZbn.js.map → client-BYF13FDD.js.map} +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +2 -2
- package/dist/client.js.map +1 -1
- package/dist/{index-D9qo_Inc.d.ts → index-DabjI66m.d.ts} +364 -19
- package/dist/index.d.ts +12 -2
- package/dist/index.js +296 -28
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/react.d.ts +53 -5
- package/dist/react.js +47 -7
- package/dist/react.js.map +1 -1
- package/dist/{retries-JlwH9mnV.d.ts → retries-fLD8cGNf.d.ts} +1 -1
- package/dist/retries.d.ts +1 -1
- package/dist/sub-routing.d.ts +14 -0
- package/dist/sub-routing.js +171 -0
- package/dist/sub-routing.js.map +1 -0
- package/dist/utils.d.ts +21 -1
- package/dist/utils.js +36 -1
- package/dist/utils.js.map +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +4 -17
package/dist/client.js.map
CHANGED
|
@@ -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-
|
|
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
|
-
*
|
|
2399
|
-
*
|
|
2400
|
-
*
|
|
2401
|
-
*
|
|
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(
|
|
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-
|
|
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-
|
|
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
|
};
|