agents 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-tool-types-VPsjVYL0.d.ts → agent-tool-types-NofdbL9X.d.ts} +57 -4
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-BGpgfpJT.d.ts → agent-tools-DLquv-dp.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/browser/ai.d.ts +126 -7
- package/dist/browser/ai.js +73 -29
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/index.d.ts +81 -69
- package/dist/browser/index.js +3 -2
- package/dist/browser/tanstack-ai.d.ts +13 -7
- package/dist/browser/tanstack-ai.js +18 -19
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/chat/index.d.ts +111 -5
- package/dist/chat/index.js +207 -35
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/{classPrivateFieldGet2-Beqsfu2Z.js → classPrivateFieldGet2-CZ7QjTXN.js} +5 -5
- package/dist/{classPrivateMethodInitSpec-B5ko1s2R.js → classPrivateMethodInitSpec-D-0__zd9.js} +2 -2
- package/dist/client.d.ts +19 -2
- package/dist/client.js +31 -11
- package/dist/client.js.map +1 -1
- package/dist/{compaction-helpers-BEUILPss.d.ts → compaction-helpers-DVcu5lPN.d.ts} +91 -12
- package/dist/connector-D6yYzYHg.js +1080 -0
- package/dist/connector-D6yYzYHg.js.map +1 -0
- package/dist/connector-DXursxV5.d.ts +340 -0
- package/dist/experimental/memory/session/index.d.ts +75 -12
- package/dist/experimental/memory/session/index.js +226 -21
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/experimental/memory/utils/index.d.ts +2 -2
- package/dist/{index-CPe1OtI0.d.ts → index-B7IbEeze.d.ts} +32 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +116 -45
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/react.d.ts +12 -1
- package/dist/react.js +101 -30
- package/dist/react.js.map +1 -1
- package/dist/{retries-CF_HKSlJ.d.ts → retries-CwlpAGet.d.ts} +35 -5
- package/dist/retries.d.ts +9 -5
- package/dist/retries.js +87 -1
- package/dist/retries.js.map +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/skills/index.js +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +10 -10
- package/dist/shared-4CAYLCTO.d.ts +0 -34
- package/dist/shared-wyII629d.js +0 -432
- package/dist/shared-wyII629d.js.map +0 -1
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/checkPrivateRedeclaration.js
|
|
2
2
|
function _checkPrivateRedeclaration(e, t) {
|
|
3
3
|
if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
4
4
|
}
|
|
5
5
|
//#endregion
|
|
6
|
-
//#region \0@oxc-project+runtime@0.
|
|
6
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/classPrivateFieldInitSpec.js
|
|
7
7
|
function _classPrivateFieldInitSpec(e, t, a) {
|
|
8
8
|
_checkPrivateRedeclaration(e, t), t.set(e, a);
|
|
9
9
|
}
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region \0@oxc-project+runtime@0.
|
|
11
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/assertClassBrand.js
|
|
12
12
|
function _assertClassBrand(e, t, n) {
|
|
13
13
|
if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
|
|
14
14
|
throw new TypeError("Private element is not present on this object");
|
|
15
15
|
}
|
|
16
16
|
//#endregion
|
|
17
|
-
//#region \0@oxc-project+runtime@0.
|
|
17
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/classPrivateFieldSet2.js
|
|
18
18
|
function _classPrivateFieldSet2(s, a, r) {
|
|
19
19
|
return s.set(_assertClassBrand(s, a), r), r;
|
|
20
20
|
}
|
|
21
21
|
//#endregion
|
|
22
|
-
//#region \0@oxc-project+runtime@0.
|
|
22
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/classPrivateFieldGet2.js
|
|
23
23
|
function _classPrivateFieldGet2(s, a) {
|
|
24
24
|
return s.get(_assertClassBrand(s, a));
|
|
25
25
|
}
|
package/dist/{classPrivateMethodInitSpec-B5ko1s2R.js → classPrivateMethodInitSpec-D-0__zd9.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as _checkPrivateRedeclaration } from "./classPrivateFieldGet2-
|
|
2
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
import { a as _checkPrivateRedeclaration } from "./classPrivateFieldGet2-CZ7QjTXN.js";
|
|
2
|
+
//#region \0@oxc-project+runtime@0.135.0/helpers/esm/classPrivateMethodInitSpec.js
|
|
3
3
|
function _classPrivateMethodInitSpec(e, a) {
|
|
4
4
|
_checkPrivateRedeclaration(e, a), a.add(e);
|
|
5
5
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as Agent } from "./agent-tool-types-
|
|
1
|
+
import { b as Agent } from "./agent-tool-types-NofdbL9X.js";
|
|
2
2
|
import {
|
|
3
3
|
ClientParameters,
|
|
4
4
|
Method,
|
|
@@ -67,7 +67,21 @@ type AgentClientOptions<State = unknown> = Omit<
|
|
|
67
67
|
* { agent: "MyAgent", name: "room", path: "settings" }
|
|
68
68
|
*/
|
|
69
69
|
path?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Default timeout (in milliseconds) applied to non-streaming `call()`s
|
|
72
|
+
* that don't pass an explicit `timeout`. Defaults to 30 000 ms.
|
|
73
|
+
* Set to `0` to disable. Streaming calls never get a default timeout.
|
|
74
|
+
*/
|
|
75
|
+
defaultCallTimeout?: number;
|
|
70
76
|
};
|
|
77
|
+
/**
|
|
78
|
+
* Default timeout (in milliseconds) applied to non-streaming RPC calls
|
|
79
|
+
* that don't pass an explicit `timeout`. Acts as a backstop so calls
|
|
80
|
+
* whose response is lost (e.g. the connection drops mid-flight) reject
|
|
81
|
+
* instead of hanging forever. Override per client via
|
|
82
|
+
* `defaultCallTimeout`, or per call via `timeout` (0 disables).
|
|
83
|
+
*/
|
|
84
|
+
declare const DEFAULT_CALL_TIMEOUT_MS = 30000;
|
|
71
85
|
/**
|
|
72
86
|
* Options for streaming RPC calls
|
|
73
87
|
*/
|
|
@@ -216,7 +230,9 @@ declare class AgentClient<
|
|
|
216
230
|
private _resetReady;
|
|
217
231
|
constructor(options: AgentClientOptions<State>);
|
|
218
232
|
/**
|
|
219
|
-
* Reject
|
|
233
|
+
* Reject pending RPC calls with the given reason.
|
|
234
|
+
* With `onlyTransmitted`, calls still sitting in the send buffer are
|
|
235
|
+
* kept pending (they'll be flushed on reconnect).
|
|
220
236
|
*/
|
|
221
237
|
private _rejectPendingCalls;
|
|
222
238
|
setState(state: State): void;
|
|
@@ -255,6 +271,7 @@ export {
|
|
|
255
271
|
AgentPromiseReturnType,
|
|
256
272
|
AgentStub,
|
|
257
273
|
CallOptions,
|
|
274
|
+
DEFAULT_CALL_TIMEOUT_MS,
|
|
258
275
|
OptionalAgentMethods,
|
|
259
276
|
RPCMethods,
|
|
260
277
|
RequiredAgentMethods,
|
package/dist/client.js
CHANGED
|
@@ -3,6 +3,14 @@ import { camelCaseToKebabCase, isInternalJsStubProp } from "./utils.js";
|
|
|
3
3
|
import { PartySocket } from "partysocket";
|
|
4
4
|
//#region src/client.ts
|
|
5
5
|
/**
|
|
6
|
+
* Default timeout (in milliseconds) applied to non-streaming RPC calls
|
|
7
|
+
* that don't pass an explicit `timeout`. Acts as a backstop so calls
|
|
8
|
+
* whose response is lost (e.g. the connection drops mid-flight) reject
|
|
9
|
+
* instead of hanging forever. Override per client via
|
|
10
|
+
* `defaultCallTimeout`, or per call via `timeout` (0 disables).
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_CALL_TIMEOUT_MS = 3e4;
|
|
13
|
+
/**
|
|
6
14
|
* Creates a proxy that wraps RPC method calls.
|
|
7
15
|
* Internal JS methods (toJSON, then, etc.) return undefined to avoid
|
|
8
16
|
* triggering RPC calls during serialization (e.g., console.log)
|
|
@@ -103,7 +111,10 @@ var AgentClient = class extends PartySocket {
|
|
|
103
111
|
if (parsedMessage.type === "rpc") {
|
|
104
112
|
const response = parsedMessage;
|
|
105
113
|
const pending = this._pendingCalls.get(response.id);
|
|
106
|
-
if (!pending)
|
|
114
|
+
if (!pending) {
|
|
115
|
+
console.warn(`[AgentClient] Discarded an RPC response with no matching pending call (id "${response.id}"). The call likely timed out or was rejected when its connection closed before the response arrived.`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
107
118
|
if (!response.success) {
|
|
108
119
|
pending.reject(new Error(response.error));
|
|
109
120
|
this._pendingCalls.delete(response.id);
|
|
@@ -122,24 +133,31 @@ var AgentClient = class extends PartySocket {
|
|
|
122
133
|
}
|
|
123
134
|
}
|
|
124
135
|
});
|
|
136
|
+
this.addEventListener("open", () => {
|
|
137
|
+
for (const pending of this._pendingCalls.values()) pending.transmitted = true;
|
|
138
|
+
});
|
|
125
139
|
this.addEventListener("close", () => {
|
|
126
140
|
this.identified = false;
|
|
127
141
|
this._resetReady();
|
|
128
|
-
this._rejectPendingCalls("Connection closed");
|
|
142
|
+
if (this.shouldReconnect) this._rejectPendingCalls("Connection closed", { onlyTransmitted: true });
|
|
143
|
+
else this._rejectPendingCalls("Connection closed");
|
|
129
144
|
});
|
|
130
145
|
this.call = this._callImpl.bind(this);
|
|
131
146
|
this.stub = createStubProxy((method, args) => this._callImpl(method, args));
|
|
132
147
|
}
|
|
133
148
|
/**
|
|
134
|
-
* Reject
|
|
149
|
+
* Reject pending RPC calls with the given reason.
|
|
150
|
+
* With `onlyTransmitted`, calls still sitting in the send buffer are
|
|
151
|
+
* kept pending (they'll be flushed on reconnect).
|
|
135
152
|
*/
|
|
136
|
-
_rejectPendingCalls(reason) {
|
|
153
|
+
_rejectPendingCalls(reason, { onlyTransmitted = false } = {}) {
|
|
137
154
|
const error = new Error(reason);
|
|
138
|
-
for (const pending of this._pendingCalls
|
|
155
|
+
for (const [id, pending] of this._pendingCalls) {
|
|
156
|
+
if (onlyTransmitted && !pending.transmitted) continue;
|
|
157
|
+
this._pendingCalls.delete(id);
|
|
139
158
|
pending.reject(error);
|
|
140
159
|
pending.stream?.onError?.(reason);
|
|
141
160
|
}
|
|
142
|
-
this._pendingCalls.clear();
|
|
143
161
|
}
|
|
144
162
|
setState(state) {
|
|
145
163
|
this.send(JSON.stringify({
|
|
@@ -173,13 +191,14 @@ var AgentClient = class extends PartySocket {
|
|
|
173
191
|
const isLegacyFormat = options && ("onChunk" in options || "onDone" in options || "onError" in options);
|
|
174
192
|
const streamOptions = isLegacyFormat ? options : options?.stream;
|
|
175
193
|
const timeout = isLegacyFormat ? void 0 : options?.timeout;
|
|
176
|
-
|
|
194
|
+
const effectiveTimeout = timeout !== void 0 ? timeout : streamOptions ? void 0 : this.options.defaultCallTimeout ?? 3e4;
|
|
195
|
+
if (effectiveTimeout) timeoutId = setTimeout(() => {
|
|
177
196
|
const pending = this._pendingCalls.get(id);
|
|
178
197
|
this._pendingCalls.delete(id);
|
|
179
|
-
const errorMessage = `RPC call to ${method} timed out after ${
|
|
198
|
+
const errorMessage = `RPC call to ${method} timed out after ${effectiveTimeout}ms`;
|
|
180
199
|
pending?.stream?.onError?.(errorMessage);
|
|
181
200
|
reject(new Error(errorMessage));
|
|
182
|
-
},
|
|
201
|
+
}, effectiveTimeout);
|
|
183
202
|
this._pendingCalls.set(id, {
|
|
184
203
|
reject: (e) => {
|
|
185
204
|
if (timeoutId) clearTimeout(timeoutId);
|
|
@@ -189,7 +208,8 @@ var AgentClient = class extends PartySocket {
|
|
|
189
208
|
if (timeoutId) clearTimeout(timeoutId);
|
|
190
209
|
resolve(value);
|
|
191
210
|
},
|
|
192
|
-
stream: streamOptions
|
|
211
|
+
stream: streamOptions,
|
|
212
|
+
transmitted: this.readyState === this.OPEN
|
|
193
213
|
});
|
|
194
214
|
const request = {
|
|
195
215
|
args,
|
|
@@ -221,6 +241,6 @@ function agentFetch(opts, init) {
|
|
|
221
241
|
}, init);
|
|
222
242
|
}
|
|
223
243
|
//#endregion
|
|
224
|
-
export { AgentClient, agentFetch, createStubProxy };
|
|
244
|
+
export { AgentClient, DEFAULT_CALL_TIMEOUT_MS, agentFetch, createStubProxy };
|
|
225
245
|
|
|
226
246
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/client.ts"],"sourcesContent":["import {\n type PartyFetchOptions,\n PartySocket,\n type PartySocketOptions\n} from \"partysocket\";\nimport type { Agent, RPCRequest, RPCResponse } from \"./\";\nimport type {\n 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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"}
|
|
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 * Default timeout (in milliseconds) applied to non-streaming `call()`s\n * that don't pass an explicit `timeout`. Defaults to 30 000 ms.\n * Set to `0` to disable. Streaming calls never get a default timeout.\n */\n defaultCallTimeout?: number;\n};\n\n/**\n * Default timeout (in milliseconds) applied to non-streaming RPC calls\n * that don't pass an explicit `timeout`. Acts as a backstop so calls\n * whose response is lost (e.g. the connection drops mid-flight) reject\n * instead of hanging forever. Override per client via\n * `defaultCallTimeout`, or per call via `timeout` (0 disables).\n */\nexport const DEFAULT_CALL_TIMEOUT_MS = 30_000;\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 * Whether the request was actually transmitted to the server.\n * Requests issued while disconnected sit in PartySocket's internal\n * buffer (transmitted: false) and are flushed on the next open —\n * they survive a transient close instead of being rejected, since\n * the server never saw them and re-delivery can't double-execute.\n */\n transmitted: boolean;\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) {\n console.warn(\n `[AgentClient] Discarded an RPC response with no matching pending call (id \"${response.id}\"). ` +\n \"The call likely timed out or was rejected when its connection closed before the response arrived.\"\n );\n return;\n }\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 // PartySocket flushes its internal message buffer right before\n // dispatching \"open\" — anything queued has now been transmitted.\n this.addEventListener(\"open\", () => {\n for (const pending of this._pendingCalls.values()) {\n pending.transmitted = true;\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 if (this.shouldReconnect) {\n // Transient disconnect: reject calls whose request was already\n // transmitted — their response can never arrive. Buffered calls\n // stay pending; PartySocket re-sends them on reconnect.\n this._rejectPendingCalls(\"Connection closed\", {\n onlyTransmitted: true\n });\n } else {\n // Permanent close (close() called or retries exhausted): nothing\n // will ever flush the buffer, so reject everything.\n this._rejectPendingCalls(\"Connection closed\");\n }\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 pending RPC calls with the given reason.\n * With `onlyTransmitted`, calls still sitting in the send buffer are\n * kept pending (they'll be flushed on reconnect).\n */\n private _rejectPendingCalls(\n reason: string,\n { onlyTransmitted = false }: { onlyTransmitted?: boolean } = {}\n ) {\n const error = new Error(reason);\n for (const [id, pending] of this._pendingCalls) {\n if (onlyTransmitted && !pending.transmitted) continue;\n this._pendingCalls.delete(id);\n pending.reject(error);\n pending.stream?.onError?.(reason);\n }\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 // Apply the default timeout as a backstop for non-streaming calls\n // so a lost response rejects instead of hanging forever. An\n // explicit `timeout` (including 0 = disabled) always wins.\n const effectiveTimeout =\n timeout !== undefined\n ? timeout\n : streamOptions\n ? undefined\n : (this.options.defaultCallTimeout ?? DEFAULT_CALL_TIMEOUT_MS);\n\n if (effectiveTimeout) {\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 ${effectiveTimeout}ms`;\n pending?.stream?.onError?.(errorMessage);\n reject(new Error(errorMessage));\n }, effectiveTimeout);\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 // If the socket is open, send() below transmits synchronously;\n // otherwise the request is buffered until the next open event\n // (the \"open\" listener then marks it transmitted).\n transmitted: this.readyState === this.OPEN\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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"}
|
|
@@ -90,6 +90,30 @@ interface StoredCompaction {
|
|
|
90
90
|
toMessageId: string;
|
|
91
91
|
createdAt: string;
|
|
92
92
|
}
|
|
93
|
+
/** Per-row info for the active branch path, root → leaf order. */
|
|
94
|
+
interface HistoryRowStat {
|
|
95
|
+
id: string;
|
|
96
|
+
/** Stored message role (e.g. "user" / "assistant"). */
|
|
97
|
+
role: string;
|
|
98
|
+
/** Serialized content size of the stored row in bytes. */
|
|
99
|
+
bytes: number;
|
|
100
|
+
}
|
|
101
|
+
/** Result of a byte-budgeted history read. */
|
|
102
|
+
interface RecentHistoryResult {
|
|
103
|
+
/**
|
|
104
|
+
* The most recent messages on the active branch path whose summed stored
|
|
105
|
+
* content size fits `maxContentBytes`, root → leaf order, with compaction
|
|
106
|
+
* overlays applied within the window. The window always covers at least
|
|
107
|
+
* the leaf row (and `minRecentMessages` rows when requested), but rows
|
|
108
|
+
* whose stored content fails to parse are skipped — so a corrupt leaf can
|
|
109
|
+
* yield fewer messages than the window covers.
|
|
110
|
+
*/
|
|
111
|
+
messages: SessionMessage[];
|
|
112
|
+
/** True when older messages were left out to satisfy the byte budget. */
|
|
113
|
+
truncated: boolean;
|
|
114
|
+
/** Summed stored content size of the FULL path, in bytes. */
|
|
115
|
+
totalContentBytes: number;
|
|
116
|
+
}
|
|
93
117
|
/**
|
|
94
118
|
* Session storage provider.
|
|
95
119
|
* Messages are tree-structured via parentId for branching.
|
|
@@ -108,6 +132,32 @@ interface SessionProvider {
|
|
|
108
132
|
getLatestLeaf(): SessionMessage | null | Promise<SessionMessage | null>;
|
|
109
133
|
getBranches(messageId: string): SessionMessage[] | Promise<SessionMessage[]>;
|
|
110
134
|
getPathLength(leafId?: string | null): number | Promise<number>;
|
|
135
|
+
/**
|
|
136
|
+
* Optional: byte-budgeted read of the most recent messages on the active
|
|
137
|
+
* branch path. Lets hosts hydrate a bounded window instead of the full
|
|
138
|
+
* transcript, so wake-time memory scales with the budget rather than total
|
|
139
|
+
* session history (#1710). Providers that don't implement it fall back to
|
|
140
|
+
* a full `getHistory()` read in `Session.getRecentHistory()`.
|
|
141
|
+
*
|
|
142
|
+
* `minRecentMessages` (default 1) is a floor on the window size: the most
|
|
143
|
+
* recent N rows are always included even when they exceed the byte budget.
|
|
144
|
+
* Hosts use this to guarantee the window never shrinks below the recent
|
|
145
|
+
* span their model context assembly expects (rows are individually capped
|
|
146
|
+
* at write time, so the floor keeps memory bounded).
|
|
147
|
+
*/
|
|
148
|
+
getRecentHistory?(
|
|
149
|
+
leafId: string | null | undefined,
|
|
150
|
+
maxContentBytes: number,
|
|
151
|
+
minRecentMessages?: number
|
|
152
|
+
): RecentHistoryResult | Promise<RecentHistoryResult>;
|
|
153
|
+
/**
|
|
154
|
+
* Optional: per-row stored sizes for the active branch path (root → leaf),
|
|
155
|
+
* WITHOUT loading message content. Lets hosts find oversized rows (e.g.
|
|
156
|
+
* inline base64 media) and process them one at a time with bounded memory.
|
|
157
|
+
*/
|
|
158
|
+
getHistoryRowStats?(
|
|
159
|
+
leafId?: string | null
|
|
160
|
+
): HistoryRowStat[] | Promise<HistoryRowStat[]>;
|
|
111
161
|
/**
|
|
112
162
|
* Append a message.
|
|
113
163
|
*
|
|
@@ -159,6 +209,12 @@ declare class AgentSessionProvider implements SessionProvider {
|
|
|
159
209
|
private ensureTable;
|
|
160
210
|
getMessage(id: string): SessionMessage | null;
|
|
161
211
|
getHistory(leafId?: string | null): SessionMessage[];
|
|
212
|
+
getRecentHistory(
|
|
213
|
+
leafId: string | null | undefined,
|
|
214
|
+
maxContentBytes: number,
|
|
215
|
+
minRecentMessages?: number
|
|
216
|
+
): RecentHistoryResult;
|
|
217
|
+
getHistoryRowStats(leafId?: string | null): HistoryRowStat[];
|
|
162
218
|
getLatestLeaf(): SessionMessage | null;
|
|
163
219
|
getBranches(messageId: string): SessionMessage[];
|
|
164
220
|
getPathLength(leafId?: string | null): number;
|
|
@@ -174,6 +230,27 @@ declare class AgentSessionProvider implements SessionProvider {
|
|
|
174
230
|
getCompactions(): StoredCompaction[];
|
|
175
231
|
searchMessages(query: string, limit?: number): SearchResult[];
|
|
176
232
|
private latestLeafRow;
|
|
233
|
+
private leafRowById;
|
|
234
|
+
/**
|
|
235
|
+
* The active branch path as (id, role, content size) rows, root → leaf.
|
|
236
|
+
*
|
|
237
|
+
* Recurses over (id, parent_id) only. Carrying `content` through the
|
|
238
|
+
* recursive queue AND the ORDER BY sorter materializes the entire
|
|
239
|
+
* transcript several times over inside SQLite's allocator, which in
|
|
240
|
+
* workerd shares the isolate's memory budget with the JS heap — large
|
|
241
|
+
* media-heavy sessions then fail with SQLITE_NOMEM on wake (#1710).
|
|
242
|
+
* Content is fetched separately in bounded chunks (`messagesByPathStats`).
|
|
243
|
+
*/
|
|
244
|
+
private pathRowStats;
|
|
245
|
+
/**
|
|
246
|
+
* Fetch and parse message content for an ordered list of path rows.
|
|
247
|
+
*
|
|
248
|
+
* Content is read in chunks bounded by both row count and cumulative
|
|
249
|
+
* stored bytes (no ORDER BY — SQLite streams rows without materializing
|
|
250
|
+
* the result set) and reassembled in path order. Rows that fail to parse
|
|
251
|
+
* are skipped, matching previous behavior.
|
|
252
|
+
*/
|
|
253
|
+
private messagesByPathStats;
|
|
177
254
|
private indexFTS;
|
|
178
255
|
private deleteFTS;
|
|
179
256
|
private applyCompactions;
|
|
@@ -483,16 +560,18 @@ declare function createCompactFunction(
|
|
|
483
560
|
) => Promise<CompactResult | null>;
|
|
484
561
|
//#endregion
|
|
485
562
|
export {
|
|
486
|
-
|
|
563
|
+
StoredCompaction as A,
|
|
487
564
|
isSearchProvider as C,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
565
|
+
RecentHistoryResult as D,
|
|
566
|
+
HistoryRowStat as E,
|
|
567
|
+
SessionMessagePart as F,
|
|
568
|
+
SessionOptions as I,
|
|
569
|
+
SessionTokenCounter as L,
|
|
570
|
+
CompactContext as M,
|
|
571
|
+
CompactionErrorHandler as N,
|
|
572
|
+
SearchResult as O,
|
|
573
|
+
SessionMessage as P,
|
|
574
|
+
SessionTokenCounterInput as R,
|
|
496
575
|
SearchProvider as S,
|
|
497
576
|
SqlProvider as T,
|
|
498
577
|
isWritableProvider as _,
|
|
@@ -504,8 +583,8 @@ export {
|
|
|
504
583
|
WritableContextProvider as g,
|
|
505
584
|
ContextProvider as h,
|
|
506
585
|
CompactTokenCounter as i,
|
|
507
|
-
|
|
508
|
-
|
|
586
|
+
CompactAfterOptions as j,
|
|
587
|
+
SessionProvider as k,
|
|
509
588
|
createCompactFunction as l,
|
|
510
589
|
ContextConfig as m,
|
|
511
590
|
CompactOptions as n,
|
|
@@ -520,4 +599,4 @@ export {
|
|
|
520
599
|
AgentSearchProvider as x,
|
|
521
600
|
SkillProvider as y
|
|
522
601
|
};
|
|
523
|
-
//# sourceMappingURL=compaction-helpers-
|
|
602
|
+
//# sourceMappingURL=compaction-helpers-DVcu5lPN.d.ts.map
|