agents 0.12.1 → 0.12.3

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.
@@ -846,7 +846,7 @@ declare class MCPClientConnection {
846
846
  */
847
847
  getTransport(
848
848
  transportType: BaseTransportType
849
- ): RPCClientTransport | SSEClientTransport | StreamableHTTPClientTransport;
849
+ ): StreamableHTTPClientTransport | SSEClientTransport | RPCClientTransport;
850
850
  private tryConnect;
851
851
  private _capabilityErrorHandler;
852
852
  }
@@ -4071,4 +4071,4 @@ export {
4071
4071
  createMcpHandler as yt,
4072
4072
  SendEmailOptions as z
4073
4073
  };
4074
- //# sourceMappingURL=agent-tool-types-CB7nISDE.d.ts.map
4074
+ //# sourceMappingURL=agent-tool-types-DSteYkkS.d.ts.map
@@ -14,7 +14,7 @@ import {
14
14
  s as AgentToolRunInfo,
15
15
  t as AgentToolChildAdapter,
16
16
  u as AgentToolRunStatus
17
- } from "./agent-tool-types-CB7nISDE.js";
17
+ } from "./agent-tool-types-DSteYkkS.js";
18
18
  export {
19
19
  AgentToolChildAdapter,
20
20
  AgentToolDisplayMetadata,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  a as AgentToolEventState,
3
3
  i as AgentToolEventMessage
4
- } from "./agent-tool-types-CB7nISDE.js";
4
+ } from "./agent-tool-types-DSteYkkS.js";
5
5
 
6
6
  //#region src/chat/agent-tools.d.ts
7
7
  declare function createAgentToolEventState(): AgentToolEventState;
@@ -11,4 +11,4 @@ declare function applyAgentToolEvent(
11
11
  ): AgentToolEventState;
12
12
  //#endregion
13
13
  export { createAgentToolEventState as n, applyAgentToolEvent as t };
14
- //# sourceMappingURL=agent-tools-Bb1O8blK.d.ts.map
14
+ //# sourceMappingURL=agent-tools-eGTCdVZX.d.ts.map
@@ -14,7 +14,7 @@ import {
14
14
  s as AgentToolRunInfo,
15
15
  t as AgentToolChildAdapter,
16
16
  u as AgentToolRunStatus
17
- } from "./agent-tool-types-CB7nISDE.js";
17
+ } from "./agent-tool-types-DSteYkkS.js";
18
18
  import { Tool } from "ai";
19
19
 
20
20
  //#region src/agent-tools.d.ts
@@ -1,5 +1,5 @@
1
- import { a as AgentToolEventState, i as AgentToolEventMessage, l as AgentToolRunState, r as AgentToolEvent } from "../agent-tool-types-CB7nISDE.js";
2
- import { n as createAgentToolEventState, t as applyAgentToolEvent } from "../agent-tools-Bb1O8blK.js";
1
+ import { a as AgentToolEventState, i as AgentToolEventMessage, l as AgentToolRunState, r as AgentToolEvent } from "../agent-tool-types-DSteYkkS.js";
2
+ import { n as createAgentToolEventState, t as applyAgentToolEvent } from "../agent-tools-eGTCdVZX.js";
3
3
  import { JSONSchema7, Tool, ToolSet, UIMessage } from "ai";
4
4
  import { Connection } from "agents";
5
5
 
package/dist/client.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import { v as Agent } from "./agent-tool-types-CB7nISDE.js";
1
+ import { v as Agent } from "./agent-tool-types-DSteYkkS.js";
2
2
  import {
3
- i as SerializableValue,
4
- n as RPCMethod,
5
- r as SerializableReturnValue,
6
- t as Method
7
- } from "./serializable-Brg7fRds.js";
3
+ ClientParameters,
4
+ Method,
5
+ RPCMethod,
6
+ SerializableReturnValue,
7
+ SerializableValue
8
+ } from "./serializable.js";
8
9
  import {
9
10
  PartyFetchOptions,
10
11
  PartySocket,
@@ -105,7 +106,7 @@ type RPCMethods<T> = {
105
106
  [K in keyof T as T[K] extends RPCMethod<T[K]> ? K : never]: RPCMethod<T[K]>;
106
107
  };
107
108
  type OptionalParametersMethod<T extends RPCMethod> =
108
- AllOptional<Parameters<T>> extends true ? T : never;
109
+ AllOptional<ClientParameters<T>> extends true ? T : never;
109
110
  type AgentMethods<T> = Omit<RPCMethods<T>, keyof Agent<any, any>>;
110
111
  type OptionalAgentMethods<T> = {
111
112
  [K in keyof AgentMethods<T> as AgentMethods<T>[K] extends OptionalParametersMethod<
@@ -124,7 +125,7 @@ type AgentPromiseReturnType<T, K extends keyof AgentMethods<T>> =
124
125
  : Promise<ReturnType<AgentMethods<T>[K]>>;
125
126
  type AgentStub<T> = {
126
127
  [K in keyof AgentMethods<T>]: (
127
- ...args: Parameters<AgentMethods<T>[K]>
128
+ ...args: ClientParameters<AgentMethods<T>[K]>
128
129
  ) => AgentPromiseReturnType<AgentMethods<T>, K>;
129
130
  };
130
131
  type UntypedAgentStub = Record<string, Method>;
@@ -135,14 +136,14 @@ type OptionalArgsAgentClientCall<AgentT> = <
135
136
  K extends keyof OptionalAgentMethods<AgentT>
136
137
  >(
137
138
  method: K,
138
- args?: Parameters<OptionalAgentMethods<AgentT>[K]>,
139
+ args?: ClientParameters<OptionalAgentMethods<AgentT>[K]>,
139
140
  options?: CallOptions | StreamOptions
140
141
  ) => AgentPromiseReturnType<AgentT, K>;
141
142
  type RequiredArgsAgentClientCall<AgentT> = <
142
143
  K extends keyof RequiredAgentMethods<AgentT>
143
144
  >(
144
145
  method: K,
145
- args: Parameters<RequiredAgentMethods<AgentT>[K]>,
146
+ args: ClientParameters<RequiredAgentMethods<AgentT>[K]>,
146
147
  options?: CallOptions | StreamOptions
147
148
  ) => AgentPromiseReturnType<AgentT, K>;
148
149
  type TypedAgentClientCall<AgentT> = OptionalArgsAgentClientCall<AgentT> &
@@ -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, 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
+ {"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 ClientParameters,\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<ClientParameters<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: ClientParameters<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?: ClientParameters<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: ClientParameters<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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"}
@@ -438,4 +438,4 @@ export {
438
438
  SearchProvider as x,
439
439
  isSkillProvider as y
440
440
  };
441
- //# sourceMappingURL=compaction-helpers-D92Ipstp.d.ts.map
441
+ //# sourceMappingURL=compaction-helpers-CzCq1-fF.d.ts.map
@@ -1,4 +1,4 @@
1
- import { A as SessionOptions, C as AgentSessionProvider, D as StoredCompaction, E as SessionProvider, O as SessionMessage, S as isSearchProvider, T as SearchResult, _ as R2SkillProvider, b as AgentSearchProvider, f as ContextBlock, g as isWritableProvider, h as WritableContextProvider, k as SessionMessagePart, m as ContextProvider, p as ContextConfig, r as CompactResult, v as SkillProvider, w as SqlProvider, x as SearchProvider, y as isSkillProvider } from "../../../compaction-helpers-D92Ipstp.js";
1
+ import { A as SessionOptions, C as AgentSessionProvider, D as StoredCompaction, E as SessionProvider, O as SessionMessage, S as isSearchProvider, T as SearchResult, _ as R2SkillProvider, b as AgentSearchProvider, f as ContextBlock, g as isWritableProvider, h as WritableContextProvider, k as SessionMessagePart, m as ContextProvider, p as ContextConfig, r as CompactResult, v as SkillProvider, w as SqlProvider, x as SearchProvider, y as isSkillProvider } from "../../../compaction-helpers-CzCq1-fF.js";
2
2
  import { ToolSet } from "ai";
3
3
 
4
4
  //#region src/experimental/memory/session/session.d.ts
@@ -1,4 +1,4 @@
1
- import { O as SessionMessage, a as alignBoundaryForward, c as createCompactFunction, d as sanitizeToolPairs, i as alignBoundaryBackward, l as findTailCutByTokens, n as CompactOptions, o as buildSummaryPrompt, r as CompactResult, s as computeSummaryBudget, t as COMPACTION_PREFIX, u as isCompactionMessage } from "../../../compaction-helpers-D92Ipstp.js";
1
+ import { O as SessionMessage, a as alignBoundaryForward, c as createCompactFunction, d as sanitizeToolPairs, i as alignBoundaryBackward, l as findTailCutByTokens, n as CompactOptions, o as buildSummaryPrompt, r as CompactResult, s as computeSummaryBudget, t as COMPACTION_PREFIX, u as isCompactionMessage } from "../../../compaction-helpers-CzCq1-fF.js";
2
2
 
3
3
  //#region src/experimental/memory/utils/tokens.d.ts
4
4
  /** Approximate characters per token for English text */
package/dist/index.d.ts CHANGED
@@ -57,7 +57,7 @@ import {
57
57
  x as AgentOptions,
58
58
  y as AgentContext,
59
59
  z as SendEmailOptions
60
- } from "./agent-tool-types-CB7nISDE.js";
60
+ } from "./agent-tool-types-DSteYkkS.js";
61
61
  import { t as RetryOptions } from "./retries-fLD8cGNf.js";
62
62
  import {
63
63
  n as AgentsOAuthProvider,
@@ -1,2 +1,2 @@
1
- import { $ as MCPClientManagerOptions, Q as MCPClientManager, at as MCPServerFilter, ct as getNamespacedData, et as MCPClientOAuthCallbackConfig, it as MCPOAuthCallbackResult, nt as MCPConnectionResult, ot as MCPServerOptions, rt as MCPDiscoverResult, st as RegisterServerOptions, tt as MCPClientOAuthResult } from "../agent-tool-types-CB7nISDE.js";
1
+ import { $ as MCPClientManagerOptions, Q as MCPClientManager, at as MCPServerFilter, ct as getNamespacedData, et as MCPClientOAuthCallbackConfig, it as MCPOAuthCallbackResult, nt as MCPConnectionResult, ot as MCPServerOptions, rt as MCPDiscoverResult, st as RegisterServerOptions, tt as MCPClientOAuthResult } from "../agent-tool-types-DSteYkkS.js";
2
2
  export { MCPClientManager, MCPClientManagerOptions, MCPClientOAuthCallbackConfig, MCPClientOAuthResult, MCPConnectionResult, MCPDiscoverResult, MCPOAuthCallbackResult, MCPServerFilter, MCPServerOptions, RegisterServerOptions, getNamespacedData };
@@ -1,2 +1,2 @@
1
- import { Ct as TransportState, Dt as StreamableHTTPEdgeClientTransport, Et as SSEEdgeClientTransport, Ot as McpClientOptions, St as getMcpAuthContext, Tt as WorkerTransportOptions, _t as McpAgent, bt as experimental_createMcpHandler, dt as RPCServerTransport, et as MCPClientOAuthCallbackConfig, ft as RPCServerTransportOptions, gt as ElicitResult, ht as ElicitRequestSchema, lt as RPCClientTransport, mt as ElicitRequest, nt as MCPConnectionResult, ot as MCPServerOptions, pt as RPC_DO_PREFIX, rt as MCPDiscoverResult, tt as MCPClientOAuthResult, ut as RPCClientTransportOptions, vt as CreateMcpHandlerOptions, wt as WorkerTransport, xt as McpAuthContext, yt as createMcpHandler } from "../agent-tool-types-CB7nISDE.js";
1
+ import { Ct as TransportState, Dt as StreamableHTTPEdgeClientTransport, Et as SSEEdgeClientTransport, Ot as McpClientOptions, St as getMcpAuthContext, Tt as WorkerTransportOptions, _t as McpAgent, bt as experimental_createMcpHandler, dt as RPCServerTransport, et as MCPClientOAuthCallbackConfig, ft as RPCServerTransportOptions, gt as ElicitResult, ht as ElicitRequestSchema, lt as RPCClientTransport, mt as ElicitRequest, nt as MCPConnectionResult, ot as MCPServerOptions, pt as RPC_DO_PREFIX, rt as MCPDiscoverResult, tt as MCPClientOAuthResult, ut as RPCClientTransportOptions, vt as CreateMcpHandlerOptions, wt as WorkerTransport, xt as McpAuthContext, yt as createMcpHandler } from "../agent-tool-types-DSteYkkS.js";
2
2
  export { CreateMcpHandlerOptions, ElicitRequest, ElicitRequestSchema, ElicitResult, MCPClientOAuthCallbackConfig, MCPClientOAuthResult, MCPConnectionResult, MCPDiscoverResult, MCPServerOptions, McpAgent, McpAuthContext, McpClientOptions, RPCClientTransport, RPCClientTransportOptions, RPCServerTransport, RPCServerTransportOptions, RPC_DO_PREFIX, SSEEdgeClientTransport, StreamableHTTPEdgeClientTransport, TransportState, WorkerTransport, WorkerTransportOptions, createMcpHandler, experimental_createMcpHandler, getMcpAuthContext };
package/dist/react.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  N as MCPServersState,
3
3
  l as AgentToolRunState
4
- } from "./agent-tool-types-CB7nISDE.js";
4
+ } from "./agent-tool-types-DSteYkkS.js";
5
+ import { ClientParameters } from "./serializable.js";
5
6
  import {
6
7
  AgentPromiseReturnType,
7
8
  AgentStub,
9
+ CallOptions,
8
10
  OptionalAgentMethods,
9
11
  RequiredAgentMethods,
10
12
  StreamOptions,
@@ -149,22 +151,22 @@ type OptionalArgsAgentMethodCall<AgentT> = <
149
151
  K extends keyof OptionalAgentMethods<AgentT>
150
152
  >(
151
153
  method: K,
152
- args?: Parameters<OptionalAgentMethods<AgentT>[K]>,
153
- streamOptions?: StreamOptions
154
+ args?: ClientParameters<OptionalAgentMethods<AgentT>[K]>,
155
+ options?: CallOptions | StreamOptions
154
156
  ) => AgentPromiseReturnType<AgentT, K>;
155
157
  type RequiredArgsAgentMethodCall<AgentT> = <
156
158
  K extends keyof RequiredAgentMethods<AgentT>
157
159
  >(
158
160
  method: K,
159
- args: Parameters<RequiredAgentMethods<AgentT>[K]>,
160
- streamOptions?: StreamOptions
161
+ args: ClientParameters<RequiredAgentMethods<AgentT>[K]>,
162
+ options?: CallOptions | StreamOptions
161
163
  ) => AgentPromiseReturnType<AgentT, K>;
162
164
  type AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &
163
165
  RequiredArgsAgentMethodCall<AgentT>;
164
166
  type UntypedAgentMethodCall = <T = unknown>(
165
167
  method: string,
166
168
  args?: unknown[],
167
- streamOptions?: StreamOptions
169
+ options?: CallOptions | StreamOptions
168
170
  ) => Promise<T>;
169
171
  /**
170
172
  * React hook for connecting to an Agent
package/dist/react.js CHANGED
@@ -239,17 +239,20 @@ function useAgent(options) {
239
239
  const pending = pendingCallsRef.current.get(response.id);
240
240
  if (!pending) return;
241
241
  if (!response.success) {
242
+ if (pending.timeoutId) clearTimeout(pending.timeoutId);
242
243
  pending.reject(new Error(response.error));
243
244
  pendingCallsRef.current.delete(response.id);
244
245
  pending.stream?.onError?.(response.error);
245
246
  return;
246
247
  }
247
248
  if ("done" in response) if (response.done) {
249
+ if (pending.timeoutId) clearTimeout(pending.timeoutId);
248
250
  pending.resolve(response.result);
249
251
  pendingCallsRef.current.delete(response.id);
250
252
  pending.stream?.onDone?.(response.result);
251
253
  } else pending.stream?.onChunk?.(response.result);
252
254
  else {
255
+ if (pending.timeoutId) clearTimeout(pending.timeoutId);
253
256
  pending.resolve(response.result);
254
257
  pendingCallsRef.current.delete(response.id);
255
258
  }
@@ -270,6 +273,7 @@ function useAgent(options) {
270
273
  setCacheInvalidatedAt(Date.now());
271
274
  const error = /* @__PURE__ */ new Error("Connection closed");
272
275
  for (const pending of pendingCallsRef.current.values()) {
276
+ if (pending.timeoutId) clearTimeout(pending.timeoutId);
273
277
  pending.reject(error);
274
278
  pending.stream?.onError?.("Connection closed");
275
279
  }
@@ -277,13 +281,25 @@ function useAgent(options) {
277
281
  options.onClose?.(event);
278
282
  }
279
283
  });
280
- const call = useCallback((method, args = [], streamOptions) => {
284
+ const call = useCallback((method, args = [], options) => {
281
285
  return new Promise((resolve, reject) => {
282
286
  const id = crypto.randomUUID();
287
+ let timeoutId;
288
+ const isLegacyFormat = options && ("onChunk" in options || "onDone" in options || "onError" in options);
289
+ const streamOptions = isLegacyFormat ? options : options?.stream;
290
+ const timeout = isLegacyFormat ? void 0 : options?.timeout;
291
+ if (timeout) timeoutId = setTimeout(() => {
292
+ const pending = pendingCallsRef.current.get(id);
293
+ pendingCallsRef.current.delete(id);
294
+ const errorMessage = `RPC call to ${method} timed out after ${timeout}ms`;
295
+ pending?.stream?.onError?.(errorMessage);
296
+ reject(new Error(errorMessage));
297
+ }, timeout);
283
298
  pendingCallsRef.current.set(id, {
284
299
  reject,
285
300
  resolve,
286
- stream: streamOptions
301
+ stream: streamOptions,
302
+ timeoutId
287
303
  });
288
304
  const request = {
289
305
  args,
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef, use, useMemo, useState, useEffect } from \"react\";\nimport type { MCPServersState, RPCRequest, RPCResponse } from \"./\";\nimport type {\n AgentPromiseReturnType,\n AgentStub,\n OptionalAgentMethods,\n RequiredAgentMethods,\n StreamOptions,\n UntypedAgentStub\n} from \"./client\";\nimport { createStubProxy } from \"./client\";\nimport { camelCaseToKebabCase } from \"./utils\";\nimport { MessageType } from \"./types\";\nimport {\n applyAgentToolEvent,\n createAgentToolEventState,\n type AgentToolEventMessage,\n type AgentToolEventState,\n type AgentToolRunState\n} from \"./chat/agent-tools\";\n\ntype QueryObject = Record<string, string | null>;\n\ninterface CacheEntry {\n promise: Promise<QueryObject>;\n expiresAt: number;\n}\n\nconst queryCache = new Map<string, CacheEntry>();\n\nfunction createCacheKey(\n agentNamespace: string,\n name: string | undefined,\n subChainOrDeps: ReadonlyArray<{ agent: string; name: string }> | unknown[],\n deps?: unknown[]\n): string {\n // Backwards-compatible overload: if called with 3 args, the third\n // argument is `deps` and `subChain` defaults to empty. With 4 args,\n // the third is the sub-chain. This keeps existing callers (and\n // the `_testUtils` surface) working while letting new callers\n // include the nested chain in the cache key.\n //\n // Empty sub-chain must produce the same key as the old 3-arg\n // form, so nested-addressing code can opt-in without invalidating\n // existing caches.\n if (deps === undefined) {\n return JSON.stringify([\n agentNamespace,\n name || \"default\",\n ...(subChainOrDeps as unknown[])\n ]);\n }\n const subChain = subChainOrDeps as ReadonlyArray<{\n agent: string;\n name: string;\n }>;\n if (subChain.length === 0) {\n return JSON.stringify([agentNamespace, name || \"default\", ...deps]);\n }\n return JSON.stringify([\n agentNamespace,\n name || \"default\",\n subChain.map((s) => [s.agent, s.name]),\n ...deps\n ]);\n}\n\n/** Build a URL path tail `/sub/{agent-kebab}/{name}/...` from a sub chain. */\nfunction buildSubPath(\n subChain: ReadonlyArray<{ agent: string; name: string }>,\n extraPath?: string\n): string {\n if (subChain.length === 0) return extraPath ?? \"\";\n const parts = subChain.flatMap((step) => [\n \"sub\",\n camelCaseToKebabCase(step.agent),\n encodeURIComponent(step.name)\n ]);\n const combined = parts.join(\"/\");\n if (extraPath) {\n const trimmed = extraPath.startsWith(\"/\") ? extraPath.slice(1) : extraPath;\n return `${combined}/${trimmed}`;\n }\n return combined;\n}\n\nfunction getCacheEntry(key: string): CacheEntry | undefined {\n const entry = queryCache.get(key);\n if (!entry) return undefined;\n\n if (Date.now() >= entry.expiresAt) {\n queryCache.delete(key);\n return undefined;\n }\n\n return entry;\n}\n\nfunction setCacheEntry(\n key: string,\n promise: Promise<QueryObject>,\n cacheTtl: number\n): CacheEntry {\n const entry: CacheEntry = {\n promise,\n expiresAt: Date.now() + cacheTtl\n };\n queryCache.set(key, entry);\n return entry;\n}\n\nfunction deleteCacheEntry(key: string): void {\n queryCache.delete(key);\n}\n\n// Export for testing purposes\nexport const _testUtils = {\n queryCache,\n setCacheEntry,\n getCacheEntry,\n deleteCacheEntry,\n clearCache: () => queryCache.clear(),\n createStubProxy,\n createCacheKey\n};\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\" | \"query\"\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 /** Query parameters - can be static object or async function */\n query?: QueryObject | (() => Promise<QueryObject>);\n /** Dependencies for async query caching */\n queryDeps?: unknown[];\n /** Cache TTL in milliseconds for auth tokens/time-sensitive data */\n cacheTtl?: number;\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 /** Called when MCP server state is updated */\n onMcpUpdate?: (mcpServers: MCPServersState) => 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 * Connect to a sub-agent (facet) via its parent. Flat array,\n * root-first. Each step addresses one parent↔child hop.\n *\n * The hook's returned `.agent` / `.name` report the **leaf**\n * identity (the deepest entry in `sub`), so downstream hooks\n * like `useAgentChat` see the child they actually talk to.\n * `.path` exposes the full chain for observability, deep links,\n * and reconnect keying.\n *\n * @example\n * ```ts\n * // Two-level nesting: Inbox (Alice) → Chat (abc)\n * useAgent({\n * agent: \"inbox\", name: userId,\n * sub: [{ agent: \"chat\", name: chatId }]\n * });\n *\n * // Three-level: tenant → inbox → chat\n * useAgent({\n * agent: \"tenant\", name: tenantId,\n * sub: [\n * { agent: \"inbox\", name: userId },\n * { agent: \"chat\", name: chatId }\n * ]\n * });\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\n sub?: ReadonlyArray<{ agent: string; name: string }>;\n};\n\ntype OptionalArgsAgentMethodCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: Parameters<OptionalAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentMethodCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: Parameters<RequiredAgentMethods<AgentT>[K]>,\n streamOptions?: StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &\n RequiredArgsAgentMethodCall<AgentT>;\n\ntype UntypedAgentMethodCall = <T = unknown>(\n method: string,\n args?: unknown[],\n streamOptions?: StreamOptions\n) => Promise<T>;\n\n/**\n * React hook for connecting to an Agent\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): Omit<PartySocket, \"path\"> & {\n agent: string;\n name: string;\n /** Full root-first address chain, including leaf. Single entry when `sub` isn't set. */\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n};\nexport function useAgent<\n AgentT extends {\n get state(): State;\n },\n State\n>(\n options: UseAgentOptions<State>\n): Omit<PartySocket, \"path\"> & {\n agent: string;\n name: string;\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: AgentMethodCall<AgentT>;\n stub: AgentStub<AgentT>;\n getHttpUrl: () => string;\n};\nexport function useAgent<State>(options: UseAgentOptions<unknown>): Omit<\n PartySocket,\n \"path\"\n> & {\n agent: string;\n name: string;\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall | AgentMethodCall<unknown>;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n} {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n // NOTE: `path` is destructured out (as `userPath`) so it does NOT\n // end up in `restOptions`. Spreading `restOptions` after the\n // computed `path: combinedPath` would otherwise let the user's raw\n // `path` overwrite the combined sub-agent URL, dropping every\n // `/sub/{child}/{name}` segment on the way to the socket.\n const {\n query,\n queryDeps,\n cacheTtl,\n sub: subOption,\n path: userPath,\n ...restOptions\n } = options;\n\n const subChain = useMemo(\n () => (subOption ?? []).map((s) => ({ agent: s.agent, name: s.name })),\n // Stable serialization — deep changes re-memoize.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(subOption ?? [])]\n );\n\n // The \"leaf\" is the deepest entry in the chain; it's what\n // downstream code (useAgentChat etc.) should see as the\n // authoritative identity.\n const leafAgent =\n subChain.length > 0 ? subChain[subChain.length - 1].agent : options.agent;\n const leafName =\n subChain.length > 0\n ? subChain[subChain.length - 1].name\n : options.name || \"default\";\n\n // Full root-first chain, including the leaf. Exposed as `.path`\n // and used for cache keying so nested sessions with the same leaf\n // name don't collide.\n const fullPath = useMemo(\n () => [\n { agent: options.agent, name: options.name || \"default\" },\n ...subChain\n ],\n [options.agent, options.name, subChain]\n );\n\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n }\n >()\n );\n\n const cacheKey = useMemo(\n () =>\n createCacheKey(agentNamespace, options.name, subChain, queryDeps || []),\n [agentNamespace, options.name, subChain, queryDeps]\n );\n\n // Track current cache key in a ref for use in onClose handler.\n // This ensures we invalidate the correct cache entry when the connection closes,\n // even if the component re-renders with different props before onClose fires.\n // We update synchronously during render (not in useEffect) to avoid race\n // conditions where onClose could fire before the effect runs.\n const cacheKeyRef = useRef(cacheKey);\n cacheKeyRef.current = cacheKey;\n\n const ttl = cacheTtl ?? 5 * 60 * 1000;\n\n // Track cache invalidation to force re-render when TTL expires\n const [cacheInvalidatedAt, setCacheInvalidatedAt] = useState<number>(0);\n\n // Disable socket while waiting for async query to refresh after disconnect\n const isAsyncQuery = query && typeof query === \"function\";\n const [awaitingQueryRefresh, setAwaitingQueryRefresh] = useState(false);\n\n // Get or create the query promise\n const queryPromise = useMemo(() => {\n // Re-run when cache is invalidated after TTL expiry\n void cacheInvalidatedAt;\n\n if (!query || typeof query !== \"function\") {\n return null;\n }\n\n // Always check cache first to deduplicate concurrent requests\n const cached = getCacheEntry(cacheKey);\n if (cached) {\n return cached.promise;\n }\n\n // Create new promise\n const promise = query().catch((error) => {\n console.error(\n `[useAgent] Query failed for agent \"${options.agent}\":`,\n error\n );\n deleteCacheEntry(cacheKey);\n throw error;\n });\n\n // Always cache to deduplicate concurrent requests\n setCacheEntry(cacheKey, promise, ttl);\n\n return promise;\n }, [cacheKey, query, options.agent, ttl, cacheInvalidatedAt]);\n\n // Schedule cache invalidation when TTL expires\n useEffect(() => {\n if (!queryPromise || ttl <= 0) return;\n\n const entry = getCacheEntry(cacheKey);\n if (!entry) return;\n\n const timeUntilExpiry = entry.expiresAt - Date.now();\n\n // Always set a timer (with min 0ms) to ensure cleanup function is returned\n const timer = setTimeout(\n () => {\n deleteCacheEntry(cacheKey);\n setCacheInvalidatedAt(Date.now());\n },\n Math.max(0, timeUntilExpiry)\n );\n\n return () => clearTimeout(timer);\n }, [cacheKey, queryPromise, ttl]);\n\n let resolvedQuery: QueryObject | undefined;\n\n if (query) {\n if (typeof query === \"function\") {\n // Use React's use() to resolve the promise\n const queryResult = use(queryPromise!);\n\n // Check for non-primitive values and warn\n if (queryResult) {\n for (const [key, value] of Object.entries(queryResult)) {\n if (\n value !== null &&\n value !== undefined &&\n typeof value !== \"string\" &&\n typeof value !== \"number\" &&\n typeof value !== \"boolean\"\n ) {\n console.warn(\n `[useAgent] Query parameter \"${key}\" is an object and will be converted to \"[object Object]\". ` +\n \"Query parameters should be string, number, boolean, or null.\"\n );\n }\n }\n resolvedQuery = queryResult;\n }\n } else {\n // Sync query - use directly\n resolvedQuery = query;\n }\n }\n\n // Re-enable socket after async query resolves\n useEffect(() => {\n if (awaitingQueryRefresh && resolvedQuery !== undefined) {\n setAwaitingQueryRefresh(false);\n }\n }, [awaitingQueryRefresh, resolvedQuery]);\n\n // Track agent state for reactivity — updated on server broadcasts and client setState\n const [agentState, setAgentState] = useState<State | undefined>(undefined);\n\n // Store identity in React state for reactivity. Seed with the\n // leaf's address — what the server will echo back in\n // `cf_agent_identity`.\n const [identity, setIdentity] = useState({\n name: leafName,\n agent: camelCaseToKebabCase(leafAgent),\n identified: false\n });\n\n // Track previous identity for change detection\n const previousIdentityRef = useRef<{\n name: string | null;\n agent: string | null;\n }>({ name: null, agent: null });\n\n // Ready promise - resolves when identity is received, resets on close\n const readyRef = useRef<\n { promise: Promise<void>; resolve: () => void } | undefined\n >(undefined);\n\n const resetReady = () => {\n let resolve: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n readyRef.current = { promise, resolve: resolve! };\n };\n\n if (!readyRef.current) {\n resetReady();\n }\n\n const mutableAgentRef = useRef<{\n agent: string;\n name: string;\n identified: boolean;\n } | null>(null);\n\n // Combine the sub-agent chain with the user-provided `path`.\n // Order matters: `/sub/{child}/{name}/...` comes before `path` so\n // the server sees the hierarchy it expects.\n const combinedPath = useMemo(\n () => buildSubPath(subChain, userPath),\n [subChain, userPath]\n );\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? {\n basePath: options.basePath,\n path: combinedPath || undefined,\n query: resolvedQuery,\n ...restOptions\n }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: combinedPath || undefined,\n query: resolvedQuery,\n ...restOptions\n };\n\n const socketEnabled = !awaitingQueryRefresh && (restOptions.enabled ?? true);\n\n const agent = usePartySocket({\n ...socketOptions,\n enabled: socketEnabled,\n onMessage: (message) => {\n if (typeof message.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(message.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return options.onMessage?.(message);\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = previousIdentityRef.current.name;\n const oldAgent = previousIdentityRef.current.agent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n const currentAgent = mutableAgentRef.current;\n if (currentAgent) {\n currentAgent.name = newName;\n currentAgent.agent = newAgent;\n currentAgent.identified = true;\n }\n\n // Update reactive state (triggers re-render)\n setIdentity({ name: newName, agent: newAgent, identified: true });\n\n // Resolve ready promise\n readyRef.current?.resolve();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (options.onIdentityChange) {\n options.onIdentityChange(oldName, newName, oldAgent, newAgent);\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 // Track for next change detection\n previousIdentityRef.current = { name: newName, agent: newAgent };\n\n // Call onIdentity callback\n options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n setAgentState(parsedMessage.state as State);\n options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE_ERROR) {\n options.onStateUpdateError?.(parsedMessage.error as string);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_MCP_SERVERS) {\n options.onMcpUpdate?.(parsedMessage.mcp as MCPServersState);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = pendingCallsRef.current.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n pendingCallsRef.current.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 pendingCallsRef.current.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 pendingCallsRef.current.delete(response.id);\n }\n return;\n }\n }\n options.onMessage?.(message);\n },\n onClose: (event: CloseEvent) => {\n // Reset ready state for next connection\n resetReady();\n if (mutableAgentRef.current) {\n mutableAgentRef.current.identified = false;\n }\n setIdentity((prev) => ({ ...prev, identified: false }));\n\n // Pause reconnection for async queries until fresh query params are ready\n if (isAsyncQuery) {\n setAwaitingQueryRefresh(true);\n }\n\n // Invalidate cache and trigger re-render to fetch fresh query params\n deleteCacheEntry(cacheKeyRef.current);\n setCacheInvalidatedAt(Date.now());\n\n // Reject all pending calls (consistent with AgentClient behavior)\n const error = new Error(\"Connection closed\");\n for (const pending of pendingCallsRef.current.values()) {\n pending.reject(error);\n pending.stream?.onError?.(\"Connection closed\");\n }\n pendingCallsRef.current.clear();\n\n // Call user's onClose if provided\n options.onClose?.(event);\n }\n }) as PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n };\n // Create the call method\n const call = useCallback(\n <T = unknown,>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> => {\n return new Promise((resolve, reject) => {\n const id = crypto.randomUUID();\n pendingCallsRef.current.set(id, {\n reject,\n resolve: resolve as (value: unknown) => void,\n stream: streamOptions\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n agent.send(JSON.stringify(request));\n });\n },\n [agent]\n );\n\n agent.setState = (newState: State) => {\n agent.send(\n JSON.stringify({ state: newState, type: MessageType.CF_AGENT_STATE })\n );\n setAgentState(newState);\n options.onStateUpdate?.(newState, \"client\");\n };\n\n agent.call = call;\n // Use reactive identity state (updates on identity message)\n agent.agent = identity.agent;\n agent.name = identity.name;\n // Full root-first chain including the leaf. Computed from the\n // user-provided options — the server doesn't need to echo it\n // back because the client already knows. Write past the\n // PartySocket `.path: string` shape via an unknown cast — the\n // overload signatures expose this as `ReadonlyArray<...>`.\n (\n agent as unknown as { path: ReadonlyArray<{ agent: string; name: string }> }\n ).path = fullPath;\n agent.identified = identity.identified;\n agent.ready = readyRef.current!.promise;\n agent.state = agentState;\n mutableAgentRef.current = agent;\n // Memoize stub so it's referentially stable across renders\n // (call is already stable via useCallback)\n const stub = useMemo(() => createStubProxy(call), [call]);\n agent.stub = stub;\n agent.getHttpUrl = () => {\n // TODO: upstream to partysocket — expose an HTTP URL property\n // @ts-expect-error accessing protected PartySocket internals\n const wsUrl: string = (agent._url as string | null) || agent._pkurl || \"\";\n return wsUrl.replace(\"ws://\", \"http://\").replace(\"wss://\", \"https://\");\n };\n\n // warn if agent isn't in lowercase\n if (identity.agent !== identity.agent.toLowerCase()) {\n console.warn(\n \"Agent name: \" +\n identity.agent +\n \" should probably be in lowercase. Received: \" +\n identity.agent\n );\n }\n\n // The overload signatures return `Omit<PartySocket, \"path\"> & { path: ... }`,\n // but `agent` is inferred as the raw PartySocket. Cast to satisfy\n // the overload contract — the runtime override of `agent.path`\n // above ensures the shape matches.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return agent as any;\n}\n\ntype AgentToolEventAgent = Pick<\n PartySocket,\n \"addEventListener\" | \"removeEventListener\"\n>;\n\nfunction agentToolDedupeKey(message: AgentToolEventMessage): string {\n return [\n message.parentToolCallId ?? \"\",\n message.event.runId,\n String(message.sequence)\n ].join(\"\\0\");\n}\n\nexport function useAgentToolEvents(options: { agent: AgentToolEventAgent }): {\n runsById: Record<string, AgentToolRunState>;\n runsByToolCallId: Record<string, AgentToolRunState[]>;\n unboundRuns: AgentToolRunState[];\n getRunsForToolCall(toolCallId: string): AgentToolRunState[];\n resetLocalState(): void;\n} {\n const { agent } = options;\n const [state, setState] = useState<AgentToolEventState>(() =>\n createAgentToolEventState()\n );\n const seenRef = useRef(new Set<string>());\n\n useEffect(() => {\n const onMessage = (event: MessageEvent) => {\n if (typeof event.data !== \"string\") return;\n let message: AgentToolEventMessage;\n try {\n message = JSON.parse(event.data) as AgentToolEventMessage;\n } catch {\n return;\n }\n if (message.type !== \"agent-tool-event\") return;\n const key = agentToolDedupeKey(message);\n if (seenRef.current.has(key)) return;\n seenRef.current.add(key);\n setState((prev) => applyAgentToolEvent(prev, message));\n };\n\n agent.addEventListener(\"message\", onMessage);\n return () => agent.removeEventListener(\"message\", onMessage);\n }, [agent]);\n\n const resetLocalState = useCallback(() => {\n seenRef.current.clear();\n setState(createAgentToolEventState());\n }, []);\n\n const getRunsForToolCall = useCallback(\n (toolCallId: string) => state.runsByToolCallId[toolCallId] ?? [],\n [state.runsByToolCallId]\n );\n\n return {\n ...state,\n getRunsForToolCall,\n resetLocalState\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import type { PartySocket } from \"partysocket\";\nimport { usePartySocket } from \"partysocket/react\";\nimport { useCallback, useRef, use, useMemo, useState, useEffect } from \"react\";\nimport type { MCPServersState, RPCRequest, RPCResponse } from \"./\";\nimport type {\n AgentPromiseReturnType,\n AgentStub,\n CallOptions,\n OptionalAgentMethods,\n RequiredAgentMethods,\n StreamOptions,\n UntypedAgentStub\n} from \"./client\";\nimport type { ClientParameters } from \"./serializable\";\nimport { createStubProxy } from \"./client\";\nimport { camelCaseToKebabCase } from \"./utils\";\nimport { MessageType } from \"./types\";\nimport {\n applyAgentToolEvent,\n createAgentToolEventState,\n type AgentToolEventMessage,\n type AgentToolEventState,\n type AgentToolRunState\n} from \"./chat/agent-tools\";\n\ntype QueryObject = Record<string, string | null>;\n\ninterface CacheEntry {\n promise: Promise<QueryObject>;\n expiresAt: number;\n}\n\nconst queryCache = new Map<string, CacheEntry>();\n\nfunction createCacheKey(\n agentNamespace: string,\n name: string | undefined,\n subChainOrDeps: ReadonlyArray<{ agent: string; name: string }> | unknown[],\n deps?: unknown[]\n): string {\n // Backwards-compatible overload: if called with 3 args, the third\n // argument is `deps` and `subChain` defaults to empty. With 4 args,\n // the third is the sub-chain. This keeps existing callers (and\n // the `_testUtils` surface) working while letting new callers\n // include the nested chain in the cache key.\n //\n // Empty sub-chain must produce the same key as the old 3-arg\n // form, so nested-addressing code can opt-in without invalidating\n // existing caches.\n if (deps === undefined) {\n return JSON.stringify([\n agentNamespace,\n name || \"default\",\n ...(subChainOrDeps as unknown[])\n ]);\n }\n const subChain = subChainOrDeps as ReadonlyArray<{\n agent: string;\n name: string;\n }>;\n if (subChain.length === 0) {\n return JSON.stringify([agentNamespace, name || \"default\", ...deps]);\n }\n return JSON.stringify([\n agentNamespace,\n name || \"default\",\n subChain.map((s) => [s.agent, s.name]),\n ...deps\n ]);\n}\n\n/** Build a URL path tail `/sub/{agent-kebab}/{name}/...` from a sub chain. */\nfunction buildSubPath(\n subChain: ReadonlyArray<{ agent: string; name: string }>,\n extraPath?: string\n): string {\n if (subChain.length === 0) return extraPath ?? \"\";\n const parts = subChain.flatMap((step) => [\n \"sub\",\n camelCaseToKebabCase(step.agent),\n encodeURIComponent(step.name)\n ]);\n const combined = parts.join(\"/\");\n if (extraPath) {\n const trimmed = extraPath.startsWith(\"/\") ? extraPath.slice(1) : extraPath;\n return `${combined}/${trimmed}`;\n }\n return combined;\n}\n\nfunction getCacheEntry(key: string): CacheEntry | undefined {\n const entry = queryCache.get(key);\n if (!entry) return undefined;\n\n if (Date.now() >= entry.expiresAt) {\n queryCache.delete(key);\n return undefined;\n }\n\n return entry;\n}\n\nfunction setCacheEntry(\n key: string,\n promise: Promise<QueryObject>,\n cacheTtl: number\n): CacheEntry {\n const entry: CacheEntry = {\n promise,\n expiresAt: Date.now() + cacheTtl\n };\n queryCache.set(key, entry);\n return entry;\n}\n\nfunction deleteCacheEntry(key: string): void {\n queryCache.delete(key);\n}\n\n// Export for testing purposes\nexport const _testUtils = {\n queryCache,\n setCacheEntry,\n getCacheEntry,\n deleteCacheEntry,\n clearCache: () => queryCache.clear(),\n createStubProxy,\n createCacheKey\n};\n\n/**\n * Options for the useAgent hook\n * @template State Type of the Agent's state\n */\nexport type UseAgentOptions<State = unknown> = Omit<\n Parameters<typeof usePartySocket>[0],\n \"party\" | \"room\" | \"query\"\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 /** Query parameters - can be static object or async function */\n query?: QueryObject | (() => Promise<QueryObject>);\n /** Dependencies for async query caching */\n queryDeps?: unknown[];\n /** Cache TTL in milliseconds for auth tokens/time-sensitive data */\n cacheTtl?: number;\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 /** Called when MCP server state is updated */\n onMcpUpdate?: (mcpServers: MCPServersState) => 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 * Connect to a sub-agent (facet) via its parent. Flat array,\n * root-first. Each step addresses one parent↔child hop.\n *\n * The hook's returned `.agent` / `.name` report the **leaf**\n * identity (the deepest entry in `sub`), so downstream hooks\n * like `useAgentChat` see the child they actually talk to.\n * `.path` exposes the full chain for observability, deep links,\n * and reconnect keying.\n *\n * @example\n * ```ts\n * // Two-level nesting: Inbox (Alice) → Chat (abc)\n * useAgent({\n * agent: \"inbox\", name: userId,\n * sub: [{ agent: \"chat\", name: chatId }]\n * });\n *\n * // Three-level: tenant → inbox → chat\n * useAgent({\n * agent: \"tenant\", name: tenantId,\n * sub: [\n * { agent: \"inbox\", name: userId },\n * { agent: \"chat\", name: chatId }\n * ]\n * });\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\n sub?: ReadonlyArray<{ agent: string; name: string }>;\n};\n\ntype OptionalArgsAgentMethodCall<AgentT> = <\n K extends keyof OptionalAgentMethods<AgentT>\n>(\n method: K,\n args?: ClientParameters<OptionalAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype RequiredArgsAgentMethodCall<AgentT> = <\n K extends keyof RequiredAgentMethods<AgentT>\n>(\n method: K,\n args: ClientParameters<RequiredAgentMethods<AgentT>[K]>,\n options?: CallOptions | StreamOptions\n) => AgentPromiseReturnType<AgentT, K>;\n\ntype AgentMethodCall<AgentT> = OptionalArgsAgentMethodCall<AgentT> &\n RequiredArgsAgentMethodCall<AgentT>;\n\ntype UntypedAgentMethodCall = <T = unknown>(\n method: string,\n args?: unknown[],\n options?: CallOptions | StreamOptions\n) => Promise<T>;\n\n/**\n * React hook for connecting to an Agent\n */\nexport function useAgent<State = unknown>(\n options: UseAgentOptions<State>\n): Omit<PartySocket, \"path\"> & {\n agent: string;\n name: string;\n /** Full root-first address chain, including leaf. Single entry when `sub` isn't set. */\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n};\nexport function useAgent<\n AgentT extends {\n get state(): State;\n },\n State\n>(\n options: UseAgentOptions<State>\n): Omit<PartySocket, \"path\"> & {\n agent: string;\n name: string;\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: AgentMethodCall<AgentT>;\n stub: AgentStub<AgentT>;\n getHttpUrl: () => string;\n};\nexport function useAgent<State>(options: UseAgentOptions<unknown>): Omit<\n PartySocket,\n \"path\"\n> & {\n agent: string;\n name: string;\n path: ReadonlyArray<{ agent: string; name: string }>;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall | AgentMethodCall<unknown>;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n} {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n // NOTE: `path` is destructured out (as `userPath`) so it does NOT\n // end up in `restOptions`. Spreading `restOptions` after the\n // computed `path: combinedPath` would otherwise let the user's raw\n // `path` overwrite the combined sub-agent URL, dropping every\n // `/sub/{child}/{name}` segment on the way to the socket.\n const {\n query,\n queryDeps,\n cacheTtl,\n sub: subOption,\n path: userPath,\n ...restOptions\n } = options;\n\n const subChain = useMemo(\n () => (subOption ?? []).map((s) => ({ agent: s.agent, name: s.name })),\n // Stable serialization — deep changes re-memoize.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(subOption ?? [])]\n );\n\n // The \"leaf\" is the deepest entry in the chain; it's what\n // downstream code (useAgentChat etc.) should see as the\n // authoritative identity.\n const leafAgent =\n subChain.length > 0 ? subChain[subChain.length - 1].agent : options.agent;\n const leafName =\n subChain.length > 0\n ? subChain[subChain.length - 1].name\n : options.name || \"default\";\n\n // Full root-first chain, including the leaf. Exposed as `.path`\n // and used for cache keying so nested sessions with the same leaf\n // name don't collide.\n const fullPath = useMemo(\n () => [\n { agent: options.agent, name: options.name || \"default\" },\n ...subChain\n ],\n [options.agent, options.name, subChain]\n );\n\n // Keep track of pending RPC calls\n const pendingCallsRef = useRef(\n new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n timeoutId?: ReturnType<typeof setTimeout>;\n }\n >()\n );\n\n const cacheKey = useMemo(\n () =>\n createCacheKey(agentNamespace, options.name, subChain, queryDeps || []),\n [agentNamespace, options.name, subChain, queryDeps]\n );\n\n // Track current cache key in a ref for use in onClose handler.\n // This ensures we invalidate the correct cache entry when the connection closes,\n // even if the component re-renders with different props before onClose fires.\n // We update synchronously during render (not in useEffect) to avoid race\n // conditions where onClose could fire before the effect runs.\n const cacheKeyRef = useRef(cacheKey);\n cacheKeyRef.current = cacheKey;\n\n const ttl = cacheTtl ?? 5 * 60 * 1000;\n\n // Track cache invalidation to force re-render when TTL expires\n const [cacheInvalidatedAt, setCacheInvalidatedAt] = useState<number>(0);\n\n // Disable socket while waiting for async query to refresh after disconnect\n const isAsyncQuery = query && typeof query === \"function\";\n const [awaitingQueryRefresh, setAwaitingQueryRefresh] = useState(false);\n\n // Get or create the query promise\n const queryPromise = useMemo(() => {\n // Re-run when cache is invalidated after TTL expiry\n void cacheInvalidatedAt;\n\n if (!query || typeof query !== \"function\") {\n return null;\n }\n\n // Always check cache first to deduplicate concurrent requests\n const cached = getCacheEntry(cacheKey);\n if (cached) {\n return cached.promise;\n }\n\n // Create new promise\n const promise = query().catch((error) => {\n console.error(\n `[useAgent] Query failed for agent \"${options.agent}\":`,\n error\n );\n deleteCacheEntry(cacheKey);\n throw error;\n });\n\n // Always cache to deduplicate concurrent requests\n setCacheEntry(cacheKey, promise, ttl);\n\n return promise;\n }, [cacheKey, query, options.agent, ttl, cacheInvalidatedAt]);\n\n // Schedule cache invalidation when TTL expires\n useEffect(() => {\n if (!queryPromise || ttl <= 0) return;\n\n const entry = getCacheEntry(cacheKey);\n if (!entry) return;\n\n const timeUntilExpiry = entry.expiresAt - Date.now();\n\n // Always set a timer (with min 0ms) to ensure cleanup function is returned\n const timer = setTimeout(\n () => {\n deleteCacheEntry(cacheKey);\n setCacheInvalidatedAt(Date.now());\n },\n Math.max(0, timeUntilExpiry)\n );\n\n return () => clearTimeout(timer);\n }, [cacheKey, queryPromise, ttl]);\n\n let resolvedQuery: QueryObject | undefined;\n\n if (query) {\n if (typeof query === \"function\") {\n // Use React's use() to resolve the promise\n const queryResult = use(queryPromise!);\n\n // Check for non-primitive values and warn\n if (queryResult) {\n for (const [key, value] of Object.entries(queryResult)) {\n if (\n value !== null &&\n value !== undefined &&\n typeof value !== \"string\" &&\n typeof value !== \"number\" &&\n typeof value !== \"boolean\"\n ) {\n console.warn(\n `[useAgent] Query parameter \"${key}\" is an object and will be converted to \"[object Object]\". ` +\n \"Query parameters should be string, number, boolean, or null.\"\n );\n }\n }\n resolvedQuery = queryResult;\n }\n } else {\n // Sync query - use directly\n resolvedQuery = query;\n }\n }\n\n // Re-enable socket after async query resolves\n useEffect(() => {\n if (awaitingQueryRefresh && resolvedQuery !== undefined) {\n setAwaitingQueryRefresh(false);\n }\n }, [awaitingQueryRefresh, resolvedQuery]);\n\n // Track agent state for reactivity — updated on server broadcasts and client setState\n const [agentState, setAgentState] = useState<State | undefined>(undefined);\n\n // Store identity in React state for reactivity. Seed with the\n // leaf's address — what the server will echo back in\n // `cf_agent_identity`.\n const [identity, setIdentity] = useState({\n name: leafName,\n agent: camelCaseToKebabCase(leafAgent),\n identified: false\n });\n\n // Track previous identity for change detection\n const previousIdentityRef = useRef<{\n name: string | null;\n agent: string | null;\n }>({ name: null, agent: null });\n\n // Ready promise - resolves when identity is received, resets on close\n const readyRef = useRef<\n { promise: Promise<void>; resolve: () => void } | undefined\n >(undefined);\n\n const resetReady = () => {\n let resolve: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n readyRef.current = { promise, resolve: resolve! };\n };\n\n if (!readyRef.current) {\n resetReady();\n }\n\n const mutableAgentRef = useRef<{\n agent: string;\n name: string;\n identified: boolean;\n } | null>(null);\n\n // Combine the sub-agent chain with the user-provided `path`.\n // Order matters: `/sub/{child}/{name}/...` comes before `path` so\n // the server sees the hierarchy it expects.\n const combinedPath = useMemo(\n () => buildSubPath(subChain, userPath),\n [subChain, userPath]\n );\n\n // If basePath is provided, use it directly; otherwise construct from agent/name\n const socketOptions = options.basePath\n ? {\n basePath: options.basePath,\n path: combinedPath || undefined,\n query: resolvedQuery,\n ...restOptions\n }\n : {\n party: agentNamespace,\n prefix: \"agents\",\n room: options.name || \"default\",\n path: combinedPath || undefined,\n query: resolvedQuery,\n ...restOptions\n };\n\n const socketEnabled = !awaitingQueryRefresh && (restOptions.enabled ?? true);\n\n const agent = usePartySocket({\n ...socketOptions,\n enabled: socketEnabled,\n onMessage: (message) => {\n if (typeof message.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(message.data);\n } catch (_error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return options.onMessage?.(message);\n }\n if (parsedMessage.type === MessageType.CF_AGENT_IDENTITY) {\n const oldName = previousIdentityRef.current.name;\n const oldAgent = previousIdentityRef.current.agent;\n const newName = parsedMessage.name as string;\n const newAgent = parsedMessage.agent as string;\n\n const currentAgent = mutableAgentRef.current;\n if (currentAgent) {\n currentAgent.name = newName;\n currentAgent.agent = newAgent;\n currentAgent.identified = true;\n }\n\n // Update reactive state (triggers re-render)\n setIdentity({ name: newName, agent: newAgent, identified: true });\n\n // Resolve ready promise\n readyRef.current?.resolve();\n\n // Detect identity change on reconnect\n if (\n oldName !== null &&\n oldAgent !== null &&\n (oldName !== newName || oldAgent !== newAgent)\n ) {\n if (options.onIdentityChange) {\n options.onIdentityChange(oldName, newName, oldAgent, newAgent);\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 // Track for next change detection\n previousIdentityRef.current = { name: newName, agent: newAgent };\n\n // Call onIdentity callback\n options.onIdentity?.(newName, newAgent);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE) {\n setAgentState(parsedMessage.state as State);\n options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_STATE_ERROR) {\n options.onStateUpdateError?.(parsedMessage.error as string);\n return;\n }\n if (parsedMessage.type === MessageType.CF_AGENT_MCP_SERVERS) {\n options.onMcpUpdate?.(parsedMessage.mcp as MCPServersState);\n return;\n }\n if (parsedMessage.type === MessageType.RPC) {\n const response = parsedMessage as RPCResponse;\n const pending = pendingCallsRef.current.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n if (pending.timeoutId) clearTimeout(pending.timeoutId);\n pending.reject(new Error(response.error));\n pendingCallsRef.current.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 if (pending.timeoutId) clearTimeout(pending.timeoutId);\n pending.resolve(response.result);\n pendingCallsRef.current.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 if (pending.timeoutId) clearTimeout(pending.timeoutId);\n pending.resolve(response.result);\n pendingCallsRef.current.delete(response.id);\n }\n return;\n }\n }\n options.onMessage?.(message);\n },\n onClose: (event: CloseEvent) => {\n // Reset ready state for next connection\n resetReady();\n if (mutableAgentRef.current) {\n mutableAgentRef.current.identified = false;\n }\n setIdentity((prev) => ({ ...prev, identified: false }));\n\n // Pause reconnection for async queries until fresh query params are ready\n if (isAsyncQuery) {\n setAwaitingQueryRefresh(true);\n }\n\n // Invalidate cache and trigger re-render to fetch fresh query params\n deleteCacheEntry(cacheKeyRef.current);\n setCacheInvalidatedAt(Date.now());\n\n // Reject all pending calls (consistent with AgentClient behavior)\n const error = new Error(\"Connection closed\");\n for (const pending of pendingCallsRef.current.values()) {\n if (pending.timeoutId) clearTimeout(pending.timeoutId);\n pending.reject(error);\n pending.stream?.onError?.(\"Connection closed\");\n }\n pendingCallsRef.current.clear();\n\n // Call user's onClose if provided\n options.onClose?.(event);\n }\n }) as PartySocket & {\n agent: string;\n name: string;\n identified: boolean;\n ready: Promise<void>;\n state: State | undefined;\n setState: (state: State) => void;\n call: UntypedAgentMethodCall;\n stub: UntypedAgentStub;\n getHttpUrl: () => string;\n };\n // Create the call method\n const call = useCallback(\n <T = unknown,>(\n method: string,\n args: unknown[] = [],\n options?: CallOptions | StreamOptions\n ): Promise<T> => {\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 if (timeout) {\n timeoutId = setTimeout(() => {\n const pending = pendingCallsRef.current.get(id);\n pendingCallsRef.current.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 pendingCallsRef.current.set(id, {\n reject,\n resolve: resolve as (value: unknown) => void,\n stream: streamOptions,\n timeoutId\n });\n\n const request: RPCRequest = {\n args,\n id,\n method,\n type: MessageType.RPC\n };\n\n agent.send(JSON.stringify(request));\n });\n },\n [agent]\n );\n\n agent.setState = (newState: State) => {\n agent.send(\n JSON.stringify({ state: newState, type: MessageType.CF_AGENT_STATE })\n );\n setAgentState(newState);\n options.onStateUpdate?.(newState, \"client\");\n };\n\n agent.call = call;\n // Use reactive identity state (updates on identity message)\n agent.agent = identity.agent;\n agent.name = identity.name;\n // Full root-first chain including the leaf. Computed from the\n // user-provided options — the server doesn't need to echo it\n // back because the client already knows. Write past the\n // PartySocket `.path: string` shape via an unknown cast — the\n // overload signatures expose this as `ReadonlyArray<...>`.\n (\n agent as unknown as { path: ReadonlyArray<{ agent: string; name: string }> }\n ).path = fullPath;\n agent.identified = identity.identified;\n agent.ready = readyRef.current!.promise;\n agent.state = agentState;\n mutableAgentRef.current = agent;\n // Memoize stub so it's referentially stable across renders\n // (call is already stable via useCallback)\n const stub = useMemo(() => createStubProxy(call), [call]);\n agent.stub = stub;\n agent.getHttpUrl = () => {\n // TODO: upstream to partysocket — expose an HTTP URL property\n // @ts-expect-error accessing protected PartySocket internals\n const wsUrl: string = (agent._url as string | null) || agent._pkurl || \"\";\n return wsUrl.replace(\"ws://\", \"http://\").replace(\"wss://\", \"https://\");\n };\n\n // warn if agent isn't in lowercase\n if (identity.agent !== identity.agent.toLowerCase()) {\n console.warn(\n \"Agent name: \" +\n identity.agent +\n \" should probably be in lowercase. Received: \" +\n identity.agent\n );\n }\n\n // The overload signatures return `Omit<PartySocket, \"path\"> & { path: ... }`,\n // but `agent` is inferred as the raw PartySocket. Cast to satisfy\n // the overload contract — the runtime override of `agent.path`\n // above ensures the shape matches.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return agent as any;\n}\n\ntype AgentToolEventAgent = Pick<\n PartySocket,\n \"addEventListener\" | \"removeEventListener\"\n>;\n\nfunction agentToolDedupeKey(message: AgentToolEventMessage): string {\n return [\n message.parentToolCallId ?? \"\",\n message.event.runId,\n String(message.sequence)\n ].join(\"\\0\");\n}\n\nexport function useAgentToolEvents(options: { agent: AgentToolEventAgent }): {\n runsById: Record<string, AgentToolRunState>;\n runsByToolCallId: Record<string, AgentToolRunState[]>;\n unboundRuns: AgentToolRunState[];\n getRunsForToolCall(toolCallId: string): AgentToolRunState[];\n resetLocalState(): void;\n} {\n const { agent } = options;\n const [state, setState] = useState<AgentToolEventState>(() =>\n createAgentToolEventState()\n );\n const seenRef = useRef(new Set<string>());\n\n useEffect(() => {\n const onMessage = (event: MessageEvent) => {\n if (typeof event.data !== \"string\") return;\n let message: AgentToolEventMessage;\n try {\n message = JSON.parse(event.data) as AgentToolEventMessage;\n } catch {\n return;\n }\n if (message.type !== \"agent-tool-event\") return;\n const key = agentToolDedupeKey(message);\n if (seenRef.current.has(key)) return;\n seenRef.current.add(key);\n setState((prev) => applyAgentToolEvent(prev, message));\n };\n\n agent.addEventListener(\"message\", onMessage);\n return () => agent.removeEventListener(\"message\", onMessage);\n }, [agent]);\n\n const resetLocalState = useCallback(() => {\n seenRef.current.clear();\n setState(createAgentToolEventState());\n }, []);\n\n const getRunsForToolCall = useCallback(\n (toolCallId: string) => state.runsByToolCallId[toolCallId] ?? [],\n [state.runsByToolCallId]\n );\n\n return {\n ...state,\n getRunsForToolCall,\n resetLocalState\n };\n}\n"],"mappings":"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"}
@@ -1,7 +1,141 @@
1
- import {
2
- i as SerializableValue,
3
- n as RPCMethod,
4
- r as SerializableReturnValue,
5
- t as Method
6
- } from "./serializable-Brg7fRds.js";
7
- export { Method, RPCMethod, SerializableReturnValue, SerializableValue };
1
+ import { H as StreamingResponse } from "./agent-tool-types-DSteYkkS.js";
2
+
3
+ //#region src/serializable.d.ts
4
+ type SerializablePrimitive = undefined | null | string | number | boolean;
5
+ type NonSerializable =
6
+ | Function
7
+ | symbol
8
+ | bigint
9
+ | Date
10
+ | RegExp
11
+ | Map<unknown, unknown>
12
+ | Set<unknown>
13
+ | WeakMap<object, unknown>
14
+ | WeakSet<object>
15
+ | Error
16
+ | ArrayBuffer
17
+ | SharedArrayBuffer
18
+ | DataView
19
+ | Int8Array
20
+ | Uint8Array
21
+ | Uint8ClampedArray
22
+ | Int16Array
23
+ | Uint16Array
24
+ | Int32Array
25
+ | Uint32Array
26
+ | Float32Array
27
+ | Float64Array
28
+ | BigInt64Array
29
+ | BigUint64Array;
30
+ type MaxDepth = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
31
+ type Increment<D extends unknown[]> = [0, ...D];
32
+ type IsMaxDepth<D extends unknown[]> = D["length"] extends MaxDepth["length"]
33
+ ? true
34
+ : false;
35
+ type SerializableValue =
36
+ | undefined
37
+ | null
38
+ | string
39
+ | number
40
+ | boolean
41
+ | {
42
+ [key: string]: SerializableValue;
43
+ }
44
+ | SerializableValue[];
45
+ type CanSerialize<T, Seen = never, Depth extends unknown[] = []> =
46
+ IsMaxDepth<Depth> extends true
47
+ ? true
48
+ : T extends Seen
49
+ ? true
50
+ : T extends SerializablePrimitive
51
+ ? true
52
+ : T extends NonSerializable
53
+ ? false
54
+ : T extends readonly (infer U)[]
55
+ ? CanSerialize<U, Seen | T, Increment<Depth>>
56
+ : T extends object
57
+ ? unknown extends T
58
+ ? true
59
+ : {
60
+ [K in keyof T]: CanSerialize<
61
+ T[K],
62
+ Seen | T,
63
+ Increment<Depth>
64
+ >;
65
+ } extends { [K in keyof T]: true }
66
+ ? true
67
+ : false
68
+ : true;
69
+ type CanSerializeReturn<T> = T extends void
70
+ ? true
71
+ : T extends Promise<infer U>
72
+ ? CanSerialize<U>
73
+ : CanSerialize<T>;
74
+ type SerializableReturnValue =
75
+ | SerializableValue
76
+ | void
77
+ | Promise<SerializableValue>
78
+ | Promise<void>;
79
+ type IsSerializableParam<T, Seen = never, Depth extends unknown[] = []> =
80
+ IsMaxDepth<Depth> extends true
81
+ ? true
82
+ : T extends Seen
83
+ ? true
84
+ : T extends SerializablePrimitive
85
+ ? true
86
+ : T extends NonSerializable
87
+ ? false
88
+ : T extends readonly (infer U)[]
89
+ ? IsSerializableParam<U, Seen | T, Increment<Depth>>
90
+ : T extends object
91
+ ? unknown extends T
92
+ ? true
93
+ : {
94
+ [K in keyof T]: IsSerializableParam<
95
+ T[K],
96
+ Seen | T,
97
+ Increment<Depth>
98
+ >;
99
+ } extends { [K in keyof T]: true }
100
+ ? true
101
+ : false
102
+ : true;
103
+ type AllSerializableValues<A> = A extends [infer First, ...infer Rest]
104
+ ? IsSerializableParam<First> extends true
105
+ ? AllSerializableValues<Rest>
106
+ : false
107
+ : true;
108
+ type Method = (...args: any[]) => any;
109
+ type ClientParameters<T = Method> = T extends (...args: infer A) => unknown
110
+ ? A extends [StreamingResponse, ...infer Rest]
111
+ ? Rest
112
+ : A
113
+ : never;
114
+ type IsUnknown<T> = [unknown] extends [T]
115
+ ? [T] extends [unknown]
116
+ ? true
117
+ : false
118
+ : false;
119
+ type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
120
+ type RPCMethod<T = Method> = T extends Method
121
+ ? T extends (...arg: infer A) => infer R
122
+ ? AllSerializableValues<ClientParameters<T>> extends true
123
+ ? A extends [StreamingResponse, ...unknown[]]
124
+ ? T
125
+ : CanSerializeReturn<R> extends true
126
+ ? T
127
+ : IsUnknown<UnwrapPromise<R>> extends true
128
+ ? T
129
+ : never
130
+ : never
131
+ : never
132
+ : never;
133
+ //#endregion
134
+ export {
135
+ ClientParameters,
136
+ Method,
137
+ RPCMethod,
138
+ SerializableReturnValue,
139
+ SerializableValue
140
+ };
141
+ //# sourceMappingURL=serializable.d.ts.map
@@ -4,7 +4,7 @@ import {
4
4
  Nt as parseSubAgentPath,
5
5
  Pt as routeSubAgentRequest,
6
6
  jt as SubAgentPathMatch
7
- } from "./agent-tool-types-CB7nISDE.js";
7
+ } from "./agent-tool-types-DSteYkkS.js";
8
8
  export {
9
9
  SUB_PREFIX,
10
10
  SubAgentPathMatch,
@@ -1,4 +1,4 @@
1
- import { v as Agent } from "./agent-tool-types-CB7nISDE.js";
1
+ import { v as Agent } from "./agent-tool-types-DSteYkkS.js";
2
2
  import {
3
3
  S as WorkflowTrackingRow,
4
4
  _ as WorkflowPage,
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "durable objects"
10
10
  ],
11
11
  "type": "module",
12
- "version": "0.12.1",
12
+ "version": "0.12.3",
13
13
  "license": "MIT",
14
14
  "repository": {
15
15
  "directory": "packages/agents",
@@ -30,26 +30,26 @@
30
30
  "@rolldown/plugin-babel": "^0.2.3",
31
31
  "cron-schedule": "^6.0.0",
32
32
  "mimetext": "^3.0.28",
33
- "nanoid": "^5.1.10",
33
+ "nanoid": "^5.1.11",
34
34
  "partyserver": "^0.5.5",
35
35
  "partysocket": "1.1.18",
36
36
  "yargs": "^18.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@ai-sdk/react": "^3.0.174",
39
+ "@ai-sdk/react": "^3.0.176",
40
40
  "@tanstack/ai": "^0.14.0",
41
41
  "@types/react": "^19.2.14",
42
42
  "@types/yargs": "^17.0.35",
43
43
  "@vitest/browser-playwright": "^4.1.5",
44
44
  "@x402/core": "^2.11.0",
45
45
  "@x402/evm": "^2.11.0",
46
- "ai": "^6.0.172",
46
+ "ai": "^6.0.174",
47
47
  "react": "^19.2.5",
48
48
  "vitest-browser-react": "^2.2.0",
49
- "zod": "^4.4.1"
49
+ "zod": "^4.4.2"
50
50
  },
51
51
  "peerDependencies": {
52
- "@cloudflare/ai-chat": ">=0.5.2 <1.0.0",
52
+ "@cloudflare/ai-chat": ">=0.6.1 <1.0.0",
53
53
  "@cloudflare/codemode": ">=0.3.4 <1.0.0",
54
54
  "@tanstack/ai": ">=0.10.2 <1.0.0",
55
55
  "@x402/core": "^2.0.0",
@@ -1,131 +0,0 @@
1
- //#region src/serializable.d.ts
2
- type SerializablePrimitive = undefined | null | string | number | boolean;
3
- type NonSerializable =
4
- | Function
5
- | symbol
6
- | bigint
7
- | Date
8
- | RegExp
9
- | Map<unknown, unknown>
10
- | Set<unknown>
11
- | WeakMap<object, unknown>
12
- | WeakSet<object>
13
- | Error
14
- | ArrayBuffer
15
- | SharedArrayBuffer
16
- | DataView
17
- | Int8Array
18
- | Uint8Array
19
- | Uint8ClampedArray
20
- | Int16Array
21
- | Uint16Array
22
- | Int32Array
23
- | Uint32Array
24
- | Float32Array
25
- | Float64Array
26
- | BigInt64Array
27
- | BigUint64Array;
28
- type MaxDepth = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
29
- type Increment<D extends unknown[]> = [0, ...D];
30
- type IsMaxDepth<D extends unknown[]> = D["length"] extends MaxDepth["length"]
31
- ? true
32
- : false;
33
- type SerializableValue =
34
- | undefined
35
- | null
36
- | string
37
- | number
38
- | boolean
39
- | {
40
- [key: string]: SerializableValue;
41
- }
42
- | SerializableValue[];
43
- type CanSerialize<T, Seen = never, Depth extends unknown[] = []> =
44
- IsMaxDepth<Depth> extends true
45
- ? true
46
- : T extends Seen
47
- ? true
48
- : T extends SerializablePrimitive
49
- ? true
50
- : T extends NonSerializable
51
- ? false
52
- : T extends readonly (infer U)[]
53
- ? CanSerialize<U, Seen | T, Increment<Depth>>
54
- : T extends object
55
- ? unknown extends T
56
- ? true
57
- : {
58
- [K in keyof T]: CanSerialize<
59
- T[K],
60
- Seen | T,
61
- Increment<Depth>
62
- >;
63
- } extends { [K in keyof T]: true }
64
- ? true
65
- : false
66
- : true;
67
- type CanSerializeReturn<T> = T extends void
68
- ? true
69
- : T extends Promise<infer U>
70
- ? CanSerialize<U>
71
- : CanSerialize<T>;
72
- type SerializableReturnValue =
73
- | SerializableValue
74
- | void
75
- | Promise<SerializableValue>
76
- | Promise<void>;
77
- type IsSerializableParam<T, Seen = never, Depth extends unknown[] = []> =
78
- IsMaxDepth<Depth> extends true
79
- ? true
80
- : T extends Seen
81
- ? true
82
- : T extends SerializablePrimitive
83
- ? true
84
- : T extends NonSerializable
85
- ? false
86
- : T extends readonly (infer U)[]
87
- ? IsSerializableParam<U, Seen | T, Increment<Depth>>
88
- : T extends object
89
- ? unknown extends T
90
- ? true
91
- : {
92
- [K in keyof T]: IsSerializableParam<
93
- T[K],
94
- Seen | T,
95
- Increment<Depth>
96
- >;
97
- } extends { [K in keyof T]: true }
98
- ? true
99
- : false
100
- : true;
101
- type AllSerializableValues<A> = A extends [infer First, ...infer Rest]
102
- ? IsSerializableParam<First> extends true
103
- ? AllSerializableValues<Rest>
104
- : false
105
- : true;
106
- type Method = (...args: any[]) => any;
107
- type IsUnknown<T> = [unknown] extends [T]
108
- ? [T] extends [unknown]
109
- ? true
110
- : false
111
- : false;
112
- type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
113
- type RPCMethod<T = Method> = T extends Method
114
- ? T extends (...arg: infer A) => infer R
115
- ? AllSerializableValues<A> extends true
116
- ? CanSerializeReturn<R> extends true
117
- ? T
118
- : IsUnknown<UnwrapPromise<R>> extends true
119
- ? T
120
- : never
121
- : never
122
- : never
123
- : never;
124
- //#endregion
125
- export {
126
- SerializableValue as i,
127
- RPCMethod as n,
128
- SerializableReturnValue as r,
129
- Method as t
130
- };
131
- //# sourceMappingURL=serializable-Brg7fRds.d.ts.map