@langchain/langgraph-sdk 1.9.20 → 1.9.21
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/client/index.cjs +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/stream/error.cjs +21 -0
- package/dist/client/stream/error.cjs.map +1 -1
- package/dist/client/stream/error.js +21 -1
- package/dist/client/stream/error.js.map +1 -1
- package/dist/client/stream/index.cjs +24 -1
- package/dist/client/stream/index.cjs.map +1 -1
- package/dist/client/stream/index.d.cts.map +1 -1
- package/dist/client/stream/index.d.ts.map +1 -1
- package/dist/client/stream/index.js +24 -1
- package/dist/client/stream/index.js.map +1 -1
- package/dist/client/stream/transport/agent-server.cjs +2 -1
- package/dist/client/stream/transport/agent-server.cjs.map +1 -1
- package/dist/client/stream/transport/agent-server.d.cts +7 -0
- package/dist/client/stream/transport/agent-server.d.cts.map +1 -1
- package/dist/client/stream/transport/agent-server.d.ts +7 -0
- package/dist/client/stream/transport/agent-server.d.ts.map +1 -1
- package/dist/client/stream/transport/agent-server.js +2 -1
- package/dist/client/stream/transport/agent-server.js.map +1 -1
- package/dist/client/stream/transport/http.cjs +48 -9
- package/dist/client/stream/transport/http.cjs.map +1 -1
- package/dist/client/stream/transport/http.d.cts +4 -0
- package/dist/client/stream/transport/http.d.cts.map +1 -1
- package/dist/client/stream/transport/http.d.ts +4 -0
- package/dist/client/stream/transport/http.d.ts.map +1 -1
- package/dist/client/stream/transport/http.js +48 -9
- package/dist/client/stream/transport/http.js.map +1 -1
- package/dist/client/stream/transport/index.cjs +2 -1
- package/dist/client/stream/transport/index.js +2 -1
- package/dist/client/stream/transport/types.d.cts +44 -0
- package/dist/client/stream/transport/types.d.cts.map +1 -1
- package/dist/client/stream/transport/types.d.ts +44 -0
- package/dist/client/stream/transport/types.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.cjs +105 -16
- package/dist/client/stream/transport/websocket.cjs.map +1 -1
- package/dist/client/stream/transport/websocket.d.cts +19 -0
- package/dist/client/stream/transport/websocket.d.cts.map +1 -1
- package/dist/client/stream/transport/websocket.d.ts +19 -0
- package/dist/client/stream/transport/websocket.d.ts.map +1 -1
- package/dist/client/stream/transport/websocket.js +105 -17
- package/dist/client/stream/transport/websocket.js.map +1 -1
- package/dist/client/stream/types.d.cts +17 -0
- package/dist/client/stream/types.d.cts.map +1 -1
- package/dist/client/stream/types.d.ts +17 -0
- package/dist/client/stream/types.d.ts.map +1 -1
- package/dist/client/threads/index.cjs +30 -14
- package/dist/client/threads/index.cjs.map +1 -1
- package/dist/client/threads/index.js +30 -14
- package/dist/client/threads/index.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/stream/controller.cjs +19 -1
- package/dist/stream/controller.cjs.map +1 -1
- package/dist/stream/controller.d.cts.map +1 -1
- package/dist/stream/controller.d.ts.map +1 -1
- package/dist/stream/controller.js +19 -1
- package/dist/stream/controller.js.map +1 -1
- package/dist/stream/index.cjs +2 -0
- package/dist/stream/index.d.cts +2 -1
- package/dist/stream/index.d.ts +2 -1
- package/dist/stream/index.js +2 -1
- package/dist/stream/projections/channel-effect.cjs +52 -0
- package/dist/stream/projections/channel-effect.cjs.map +1 -0
- package/dist/stream/projections/channel-effect.d.cts +35 -0
- package/dist/stream/projections/channel-effect.d.cts.map +1 -0
- package/dist/stream/projections/channel-effect.d.ts +35 -0
- package/dist/stream/projections/channel-effect.d.ts.map +1 -0
- package/dist/stream/projections/channel-effect.js +52 -0
- package/dist/stream/projections/channel-effect.js.map +1 -0
- package/dist/stream/projections/index.cjs +1 -0
- package/dist/stream/projections/index.d.ts +1 -0
- package/dist/stream/projections/index.js +1 -0
- package/dist/stream/root-message-projection.cjs +55 -0
- package/dist/stream/root-message-projection.cjs.map +1 -1
- package/dist/stream/root-message-projection.js +55 -0
- package/dist/stream/root-message-projection.js.map +1 -1
- package/dist/ui/branching.d.cts +1 -1
- package/dist/ui/branching.d.ts +1 -1
- package/dist/ui/orchestrator.d.cts +1 -1
- package/dist/ui/orchestrator.d.cts.map +1 -1
- package/dist/ui/orchestrator.d.ts +1 -1
- package/dist/ui/orchestrator.d.ts.map +1 -1
- package/dist/utils/stream.d.cts +1 -1
- package/dist/utils/stream.d.cts.map +1 -1
- package/dist/utils/stream.d.ts +1 -1
- package/dist/utils/stream.d.ts.map +1 -1
- package/package.json +5 -2
|
@@ -1,10 +1,28 @@
|
|
|
1
|
+
import { MaxWebSocketReconnectAttemptsError } from "../error.js";
|
|
1
2
|
import { AsyncQueue } from "./queue.js";
|
|
2
3
|
import { hasHeaders, isRecord, toAbsoluteUrl, toError, toWebSocketUrl } from "./utils.js";
|
|
3
4
|
//#region src/client/stream/transport/websocket.ts
|
|
5
|
+
const WEB_SOCKET_CONNECTING = 0;
|
|
6
|
+
const WEB_SOCKET_OPEN = 1;
|
|
7
|
+
const WEB_SOCKET_CLOSED = 3;
|
|
8
|
+
/**
|
|
9
|
+
* Exponential backoff with jitter for WebSocket reconnect. Mirrors
|
|
10
|
+
* {@link streamWithRetry} in `utils/stream.ts` (capped at 5s + 1s jitter).
|
|
11
|
+
*/
|
|
12
|
+
function webSocketReconnectDelayMs(attempt) {
|
|
13
|
+
return Math.min(1e3 * 2 ** (attempt - 1), 5e3) + Math.random() * 1e3;
|
|
14
|
+
}
|
|
4
15
|
/**
|
|
5
16
|
* Transport adapter that speaks the thread-centric protocol over a
|
|
6
17
|
* bidirectional WebSocket. Bound to a specific `threadId` — the socket
|
|
7
18
|
* connects to `ws://.../threads/:thread_id/stream/events`.
|
|
19
|
+
*
|
|
20
|
+
* On unexpected disconnect the adapter reconnects with exponential
|
|
21
|
+
* backoff (see {@link ProtocolWebSocketTransportOptions.maxReconnectAttempts}).
|
|
22
|
+
* The server replays buffered events on the new socket; the SDK
|
|
23
|
+
* deduplicates by `event_id`. {@link ProtocolWebSocketTransportOptions.onReconnected}
|
|
24
|
+
* runs after each successful reconnect so `ThreadStream` can re-issue
|
|
25
|
+
* `subscription.subscribe` commands.
|
|
8
26
|
*/
|
|
9
27
|
var ProtocolWebSocketTransportAdapter = class {
|
|
10
28
|
threadId;
|
|
@@ -14,10 +32,15 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
14
32
|
onRequest;
|
|
15
33
|
webSocketFactory;
|
|
16
34
|
streamUrl;
|
|
35
|
+
maxReconnectAttempts;
|
|
36
|
+
onReconnect;
|
|
37
|
+
reconnectDelayMs;
|
|
38
|
+
onReconnected;
|
|
17
39
|
pending = /* @__PURE__ */ new Map();
|
|
18
40
|
socket = null;
|
|
19
41
|
closed = false;
|
|
20
42
|
intentionalClose = false;
|
|
43
|
+
reconnectInFlight = null;
|
|
21
44
|
constructor(options) {
|
|
22
45
|
this.apiUrl = options.apiUrl;
|
|
23
46
|
this.threadId = options.threadId;
|
|
@@ -25,18 +48,32 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
25
48
|
this.onRequest = options.onRequest;
|
|
26
49
|
this.webSocketFactory = options.webSocketFactory ?? ((url) => new WebSocket(url));
|
|
27
50
|
this.streamUrl = options.paths?.stream ?? `/threads/${this.threadId}/stream/events`;
|
|
51
|
+
this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
|
|
52
|
+
this.onReconnect = options.onReconnect;
|
|
53
|
+
this.onReconnected = options.onReconnected;
|
|
54
|
+
this.reconnectDelayMs = options.reconnectDelayMs ?? webSocketReconnectDelayMs;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Register a callback invoked after each successful reconnect. Used
|
|
58
|
+
* by {@link ThreadStream} to re-send active `subscription.subscribe`
|
|
59
|
+
* commands.
|
|
60
|
+
*/
|
|
61
|
+
setOnReconnected(handler) {
|
|
62
|
+
this.onReconnected = handler;
|
|
28
63
|
}
|
|
29
64
|
async open() {
|
|
30
|
-
if (this.
|
|
65
|
+
if (this.closed) throw new Error("Protocol WebSocket transport is closed.");
|
|
66
|
+
if (this.socket?.readyState === WEB_SOCKET_OPEN) return;
|
|
67
|
+
if (this.socket != null) {
|
|
68
|
+
this.#detachSocket(this.socket);
|
|
69
|
+
this.socket = null;
|
|
70
|
+
}
|
|
31
71
|
this.assertBrowserSafeTransportConfig();
|
|
32
72
|
const wsUrl = toWebSocketUrl(toAbsoluteUrl(this.apiUrl, this.streamUrl).toString());
|
|
33
73
|
const socket = this.webSocketFactory(wsUrl);
|
|
34
74
|
this.socket = socket;
|
|
35
|
-
this.closed = false;
|
|
36
75
|
this.intentionalClose = false;
|
|
37
|
-
socket
|
|
38
|
-
socket.addEventListener("close", this.handleClose);
|
|
39
|
-
socket.addEventListener("error", this.handleSocketError);
|
|
76
|
+
this.#attachSocket(socket);
|
|
40
77
|
await new Promise((resolve, reject) => {
|
|
41
78
|
const onOpen = () => {
|
|
42
79
|
cleanup();
|
|
@@ -80,8 +117,9 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
80
117
|
const socket = this.socket;
|
|
81
118
|
this.socket = null;
|
|
82
119
|
if (!socket) return;
|
|
120
|
+
this.#detachSocket(socket);
|
|
83
121
|
await new Promise((resolve) => {
|
|
84
|
-
if (socket.readyState ===
|
|
122
|
+
if (socket.readyState === WEB_SOCKET_CLOSED) {
|
|
85
123
|
resolve();
|
|
86
124
|
return;
|
|
87
125
|
}
|
|
@@ -90,7 +128,7 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
90
128
|
resolve();
|
|
91
129
|
};
|
|
92
130
|
socket.addEventListener("close", onClose, { once: true });
|
|
93
|
-
if (socket.readyState ===
|
|
131
|
+
if (socket.readyState === WEB_SOCKET_OPEN || socket.readyState === WEB_SOCKET_CONNECTING) socket.close();
|
|
94
132
|
else resolve();
|
|
95
133
|
});
|
|
96
134
|
}
|
|
@@ -98,8 +136,12 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
98
136
|
if (hasHeaders(this.defaultHeaders) || this.onRequest != null) throw new Error("Browser WebSocket protocol transport does not support defaultHeaders or onRequest hooks. Supply a custom protocolWebSocketFactory if you need custom WebSocket setup.");
|
|
99
137
|
}
|
|
100
138
|
async sendCommand(command) {
|
|
101
|
-
|
|
102
|
-
if (socket == null || socket.readyState !==
|
|
139
|
+
let socket = this.socket;
|
|
140
|
+
if (this.reconnectInFlight != null && (socket == null || socket.readyState !== WEB_SOCKET_OPEN)) {
|
|
141
|
+
await this.reconnectInFlight.catch(() => void 0);
|
|
142
|
+
socket = this.socket;
|
|
143
|
+
}
|
|
144
|
+
if (socket == null || socket.readyState !== WEB_SOCKET_OPEN) throw new Error("Protocol WebSocket is not open.");
|
|
103
145
|
return await new Promise((resolve, reject) => {
|
|
104
146
|
this.pending.set(command.id, {
|
|
105
147
|
resolve,
|
|
@@ -113,6 +155,16 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
113
155
|
}
|
|
114
156
|
});
|
|
115
157
|
}
|
|
158
|
+
#attachSocket(socket) {
|
|
159
|
+
socket.addEventListener("message", this.handleMessage);
|
|
160
|
+
socket.addEventListener("close", this.handleClose);
|
|
161
|
+
socket.addEventListener("error", this.handleSocketError);
|
|
162
|
+
}
|
|
163
|
+
#detachSocket(socket) {
|
|
164
|
+
socket.removeEventListener("message", this.handleMessage);
|
|
165
|
+
socket.removeEventListener("close", this.handleClose);
|
|
166
|
+
socket.removeEventListener("error", this.handleSocketError);
|
|
167
|
+
}
|
|
116
168
|
handleMessage = (event) => {
|
|
117
169
|
let payload;
|
|
118
170
|
try {
|
|
@@ -131,25 +183,61 @@ var ProtocolWebSocketTransportAdapter = class {
|
|
|
131
183
|
if (isRecord(payload) && payload.type === "event") this.queue.push(payload);
|
|
132
184
|
};
|
|
133
185
|
handleClose = () => {
|
|
186
|
+
const socket = this.socket;
|
|
187
|
+
if (socket != null) this.#detachSocket(socket);
|
|
134
188
|
this.socket = null;
|
|
135
189
|
if (this.intentionalClose || this.closed) {
|
|
136
190
|
this.queue.close();
|
|
137
191
|
return;
|
|
138
192
|
}
|
|
139
|
-
|
|
140
|
-
for (const { reject } of this.pending.values()) reject(error);
|
|
141
|
-
this.pending.clear();
|
|
142
|
-
this.queue.close(error);
|
|
193
|
+
this.#handleUnexpectedDisconnect(/* @__PURE__ */ new Error("Protocol WebSocket closed unexpectedly."));
|
|
143
194
|
};
|
|
144
195
|
handleSocketError = () => {
|
|
145
196
|
if (this.closed || this.intentionalClose) return;
|
|
146
|
-
|
|
197
|
+
this.#handleUnexpectedDisconnect(/* @__PURE__ */ new Error("Protocol WebSocket encountered an error."));
|
|
198
|
+
};
|
|
199
|
+
#handleUnexpectedDisconnect(cause) {
|
|
200
|
+
const error = toError(cause);
|
|
147
201
|
for (const { reject } of this.pending.values()) reject(error);
|
|
148
202
|
this.pending.clear();
|
|
149
|
-
this.
|
|
150
|
-
|
|
203
|
+
if (this.maxReconnectAttempts <= 0) {
|
|
204
|
+
this.queue.close(error);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.#scheduleReconnect(cause);
|
|
208
|
+
}
|
|
209
|
+
#scheduleReconnect(cause) {
|
|
210
|
+
if (this.closed || this.intentionalClose) return;
|
|
211
|
+
if (this.reconnectInFlight != null) return;
|
|
212
|
+
this.reconnectInFlight = this.#runReconnectLoop(cause).finally(() => {
|
|
213
|
+
this.reconnectInFlight = null;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
async #runReconnectLoop(initialCause) {
|
|
217
|
+
let lastError = initialCause;
|
|
218
|
+
for (let attempt = 1; attempt <= this.maxReconnectAttempts; attempt += 1) {
|
|
219
|
+
if (this.closed || this.intentionalClose) return;
|
|
220
|
+
this.onReconnect?.({
|
|
221
|
+
attempt,
|
|
222
|
+
cause: lastError
|
|
223
|
+
});
|
|
224
|
+
const delay = this.reconnectDelayMs(attempt);
|
|
225
|
+
if (delay > 0) await new Promise((resolve) => {
|
|
226
|
+
setTimeout(resolve, delay);
|
|
227
|
+
});
|
|
228
|
+
if (this.closed || this.intentionalClose) return;
|
|
229
|
+
try {
|
|
230
|
+
await this.open();
|
|
231
|
+
if (this.onReconnected) await this.onReconnected();
|
|
232
|
+
return;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
lastError = error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
this.queue.close(new MaxWebSocketReconnectAttemptsError(this.maxReconnectAttempts, lastError));
|
|
238
|
+
}
|
|
151
239
|
};
|
|
152
240
|
//#endregion
|
|
153
|
-
export { ProtocolWebSocketTransportAdapter };
|
|
241
|
+
export { ProtocolWebSocketTransportAdapter, webSocketReconnectDelayMs };
|
|
154
242
|
|
|
155
243
|
//# sourceMappingURL=websocket.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket.js","names":[],"sources":["../../../../src/client/stream/transport/websocket.ts"],"sourcesContent":["import { AsyncQueue } from \"./queue.js\";\nimport type {\n Message,\n Command,\n CommandResponse,\n ErrorResponse,\n} from \"@langchain/protocol\";\n\nimport {\n toAbsoluteUrl,\n toWebSocketUrl,\n isRecord,\n hasHeaders,\n toError,\n} from \"./utils.js\";\nimport type {\n HeaderValue,\n ProtocolRequestHook,\n PendingResponse,\n ProtocolWebSocketTransportOptions,\n} from \"./types.js\";\nimport type { TransportAdapter } from \"../transport.js\";\n\n/**\n * Transport adapter that speaks the thread-centric protocol over a\n * bidirectional WebSocket. Bound to a specific `threadId` — the socket\n * connects to `ws://.../threads/:thread_id/stream/events`.\n */\nexport class ProtocolWebSocketTransportAdapter implements TransportAdapter {\n readonly threadId: string;\n\n private readonly queue = new AsyncQueue<Message>();\n\n private readonly apiUrl: string;\n\n private readonly defaultHeaders?: Record<string, HeaderValue>;\n\n private readonly onRequest?: ProtocolRequestHook;\n\n private readonly webSocketFactory: (url: string) => WebSocket;\n\n private readonly streamUrl: string;\n\n private readonly pending = new Map<number, PendingResponse>();\n\n private socket: WebSocket | null = null;\n\n private closed = false;\n\n private intentionalClose = false;\n\n constructor(options: ProtocolWebSocketTransportOptions) {\n this.apiUrl = options.apiUrl;\n this.threadId = options.threadId;\n this.defaultHeaders = options.defaultHeaders;\n this.onRequest = options.onRequest;\n this.webSocketFactory =\n options.webSocketFactory ?? ((url) => new WebSocket(url));\n this.streamUrl =\n options.paths?.stream ?? `/threads/${this.threadId}/stream/events`;\n }\n\n async open(): Promise<void> {\n if (this.socket != null) return;\n this.assertBrowserSafeTransportConfig();\n\n const wsUrl = toWebSocketUrl(\n toAbsoluteUrl(this.apiUrl, this.streamUrl).toString()\n );\n const socket = this.webSocketFactory(wsUrl);\n this.socket = socket;\n this.closed = false;\n this.intentionalClose = false;\n\n socket.addEventListener(\"message\", this.handleMessage);\n socket.addEventListener(\"close\", this.handleClose);\n socket.addEventListener(\"error\", this.handleSocketError);\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n cleanup();\n resolve();\n };\n const onError = () => {\n cleanup();\n reject(new Error(\"Failed to open protocol WebSocket.\"));\n };\n const cleanup = () => {\n socket.removeEventListener(\"open\", onOpen);\n socket.removeEventListener(\"error\", onError);\n };\n socket.addEventListener(\"open\", onOpen, { once: true });\n socket.addEventListener(\"error\", onError, { once: true });\n });\n }\n\n async send(\n command: Command\n ): Promise<CommandResponse | ErrorResponse | void> {\n return await this.sendCommand(command);\n }\n\n events(): AsyncIterable<Message> {\n const queue = this.queue;\n return {\n [Symbol.asyncIterator]: () => ({\n next: async () => await queue.shift(),\n return: async () => {\n queue.close();\n return { done: true, value: undefined };\n },\n }),\n };\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n this.intentionalClose = true;\n\n for (const { reject } of this.pending.values()) {\n reject(new Error(\"Protocol WebSocket connection closed.\"));\n }\n this.pending.clear();\n this.queue.close();\n\n const socket = this.socket;\n this.socket = null;\n if (!socket) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n if (socket.readyState === WebSocket.CLOSED) {\n resolve();\n return;\n }\n\n const onClose = () => {\n socket.removeEventListener(\"close\", onClose);\n resolve();\n };\n\n socket.addEventListener(\"close\", onClose, { once: true });\n if (\n socket.readyState === WebSocket.OPEN ||\n socket.readyState === WebSocket.CONNECTING\n ) {\n socket.close();\n } else {\n resolve();\n }\n });\n }\n\n private assertBrowserSafeTransportConfig(): void {\n if (hasHeaders(this.defaultHeaders) || this.onRequest != null) {\n throw new Error(\n \"Browser WebSocket protocol transport does not support defaultHeaders or onRequest hooks. Supply a custom protocolWebSocketFactory if you need custom WebSocket setup.\"\n );\n }\n }\n\n private async sendCommand(\n command: Command\n ): Promise<CommandResponse | ErrorResponse> {\n const socket = this.socket;\n if (socket == null || socket.readyState !== WebSocket.OPEN) {\n throw new Error(\"Protocol WebSocket is not open.\");\n }\n\n return await new Promise<CommandResponse | ErrorResponse>(\n (resolve, reject) => {\n this.pending.set(command.id, { resolve, reject });\n\n try {\n socket.send(JSON.stringify(command));\n } catch (error) {\n this.pending.delete(command.id);\n reject(toError(error));\n }\n }\n );\n }\n\n private readonly handleMessage = (event: MessageEvent): void => {\n let payload: unknown;\n try {\n payload = JSON.parse(String(event.data));\n } catch {\n return;\n }\n\n if (\n isRecord(payload) &&\n typeof payload.id === \"number\" &&\n (payload.type === \"success\" || payload.type === \"error\")\n ) {\n const pending = this.pending.get(payload.id);\n if (pending) {\n this.pending.delete(payload.id);\n pending.resolve(payload as CommandResponse | ErrorResponse);\n }\n return;\n }\n\n if (isRecord(payload) && payload.type === \"event\") {\n this.queue.push(payload as Message);\n }\n };\n\n private readonly handleClose = (): void => {\n this.socket = null;\n\n if (this.intentionalClose || this.closed) {\n this.queue.close();\n return;\n }\n\n const error = new Error(\"Protocol WebSocket closed unexpectedly.\");\n for (const { reject } of this.pending.values()) {\n reject(error);\n }\n this.pending.clear();\n this.queue.close(error);\n };\n\n private readonly handleSocketError = (): void => {\n if (this.closed || this.intentionalClose) {\n return;\n }\n\n const error = new Error(\"Protocol WebSocket encountered an error.\");\n for (const { reject } of this.pending.values()) {\n reject(error);\n }\n this.pending.clear();\n this.queue.close(error);\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"websocket.js","names":["#detachSocket","#attachSocket","#handleUnexpectedDisconnect","#scheduleReconnect","#runReconnectLoop"],"sources":["../../../../src/client/stream/transport/websocket.ts"],"sourcesContent":["import { AsyncQueue } from \"./queue.js\";\nimport type {\n Message,\n Command,\n CommandResponse,\n ErrorResponse,\n} from \"@langchain/protocol\";\n\nimport {\n toAbsoluteUrl,\n toWebSocketUrl,\n isRecord,\n hasHeaders,\n toError,\n} from \"./utils.js\";\nimport type {\n HeaderValue,\n ProtocolRequestHook,\n PendingResponse,\n ProtocolWebSocketTransportOptions,\n} from \"./types.js\";\nimport type { TransportAdapter } from \"../transport.js\";\nimport { MaxWebSocketReconnectAttemptsError } from \"../error.js\";\n\nconst WEB_SOCKET_CONNECTING = 0;\nconst WEB_SOCKET_OPEN = 1;\nconst WEB_SOCKET_CLOSED = 3;\n\n/**\n * Reconnect tuning for {@link ProtocolWebSocketTransportAdapter}. A subset\n * of {@link ProtocolWebSocketTransportOptions}.\n */\nexport interface WebSocketReconnectOptions {\n /**\n * Maximum reconnection attempts after an unexpected disconnect.\n * Defaults to 5.\n */\n maxReconnectAttempts?: number;\n\n /**\n * Invoked before each reconnect attempt (after backoff).\n */\n onReconnect?: (options: { attempt: number; cause: unknown }) => void;\n}\n\n/**\n * Exponential backoff with jitter for WebSocket reconnect. Mirrors\n * {@link streamWithRetry} in `utils/stream.ts` (capped at 5s + 1s jitter).\n */\nexport function webSocketReconnectDelayMs(attempt: number): number {\n const baseDelay = Math.min(1000 * 2 ** (attempt - 1), 5000);\n const jitter = Math.random() * 1000;\n return baseDelay + jitter;\n}\n\n/**\n * Transport adapter that speaks the thread-centric protocol over a\n * bidirectional WebSocket. Bound to a specific `threadId` — the socket\n * connects to `ws://.../threads/:thread_id/stream/events`.\n *\n * On unexpected disconnect the adapter reconnects with exponential\n * backoff (see {@link ProtocolWebSocketTransportOptions.maxReconnectAttempts}).\n * The server replays buffered events on the new socket; the SDK\n * deduplicates by `event_id`. {@link ProtocolWebSocketTransportOptions.onReconnected}\n * runs after each successful reconnect so `ThreadStream` can re-issue\n * `subscription.subscribe` commands.\n */\nexport class ProtocolWebSocketTransportAdapter implements TransportAdapter {\n readonly threadId: string;\n\n private readonly queue = new AsyncQueue<Message>();\n\n private readonly apiUrl: string;\n\n private readonly defaultHeaders?: Record<string, HeaderValue>;\n\n private readonly onRequest?: ProtocolRequestHook;\n\n private readonly webSocketFactory: (url: string) => WebSocket;\n\n private readonly streamUrl: string;\n\n private readonly maxReconnectAttempts: number;\n\n private readonly onReconnect?: ProtocolWebSocketTransportOptions[\"onReconnect\"];\n\n private readonly reconnectDelayMs: (attempt: number) => number;\n\n private onReconnected?: () => void | Promise<void>;\n\n private readonly pending = new Map<number, PendingResponse>();\n\n private socket: WebSocket | null = null;\n\n private closed = false;\n\n private intentionalClose = false;\n\n private reconnectInFlight: Promise<void> | null = null;\n\n constructor(options: ProtocolWebSocketTransportOptions) {\n this.apiUrl = options.apiUrl;\n this.threadId = options.threadId;\n this.defaultHeaders = options.defaultHeaders;\n this.onRequest = options.onRequest;\n this.webSocketFactory =\n options.webSocketFactory ?? ((url) => new WebSocket(url));\n this.streamUrl =\n options.paths?.stream ?? `/threads/${this.threadId}/stream/events`;\n this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\n this.onReconnect = options.onReconnect;\n this.onReconnected = options.onReconnected;\n this.reconnectDelayMs =\n options.reconnectDelayMs ?? webSocketReconnectDelayMs;\n }\n\n /**\n * Register a callback invoked after each successful reconnect. Used\n * by {@link ThreadStream} to re-send active `subscription.subscribe`\n * commands.\n */\n setOnReconnected(handler: () => void | Promise<void>): void {\n this.onReconnected = handler;\n }\n\n async open(): Promise<void> {\n if (this.closed) {\n throw new Error(\"Protocol WebSocket transport is closed.\");\n }\n if (this.socket?.readyState === WEB_SOCKET_OPEN) {\n return;\n }\n if (this.socket != null) {\n this.#detachSocket(this.socket);\n this.socket = null;\n }\n\n this.assertBrowserSafeTransportConfig();\n\n const wsUrl = toWebSocketUrl(\n toAbsoluteUrl(this.apiUrl, this.streamUrl).toString()\n );\n const socket = this.webSocketFactory(wsUrl);\n this.socket = socket;\n this.intentionalClose = false;\n\n this.#attachSocket(socket);\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n cleanup();\n resolve();\n };\n const onError = () => {\n cleanup();\n reject(new Error(\"Failed to open protocol WebSocket.\"));\n };\n const cleanup = () => {\n socket.removeEventListener(\"open\", onOpen);\n socket.removeEventListener(\"error\", onError);\n };\n socket.addEventListener(\"open\", onOpen, { once: true });\n socket.addEventListener(\"error\", onError, { once: true });\n });\n }\n\n async send(\n command: Command\n ): Promise<CommandResponse | ErrorResponse | void> {\n return await this.sendCommand(command);\n }\n\n events(): AsyncIterable<Message> {\n const queue = this.queue;\n return {\n [Symbol.asyncIterator]: () => ({\n next: async () => await queue.shift(),\n return: async () => {\n queue.close();\n return { done: true, value: undefined };\n },\n }),\n };\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n\n this.closed = true;\n this.intentionalClose = true;\n\n for (const { reject } of this.pending.values()) {\n reject(new Error(\"Protocol WebSocket connection closed.\"));\n }\n this.pending.clear();\n this.queue.close();\n\n const socket = this.socket;\n this.socket = null;\n if (!socket) {\n return;\n }\n\n this.#detachSocket(socket);\n\n await new Promise<void>((resolve) => {\n if (socket.readyState === WEB_SOCKET_CLOSED) {\n resolve();\n return;\n }\n\n const onClose = () => {\n socket.removeEventListener(\"close\", onClose);\n resolve();\n };\n\n socket.addEventListener(\"close\", onClose, { once: true });\n if (\n socket.readyState === WEB_SOCKET_OPEN ||\n socket.readyState === WEB_SOCKET_CONNECTING\n ) {\n socket.close();\n } else {\n resolve();\n }\n });\n }\n\n private assertBrowserSafeTransportConfig(): void {\n if (hasHeaders(this.defaultHeaders) || this.onRequest != null) {\n throw new Error(\n \"Browser WebSocket protocol transport does not support defaultHeaders or onRequest hooks. Supply a custom protocolWebSocketFactory if you need custom WebSocket setup.\"\n );\n }\n }\n\n private async sendCommand(\n command: Command\n ): Promise<CommandResponse | ErrorResponse> {\n // Wait for an in-flight reconnect only when the socket is not usable.\n // After `open()` succeeds, `#runReconnectLoop` may still be awaiting\n // `onReconnected` (e.g. ThreadStream resubscribe). Those callbacks call\n // `sendCommand` and must not await the same `reconnectInFlight` promise.\n let socket = this.socket;\n if (\n this.reconnectInFlight != null &&\n (socket == null || socket.readyState !== WEB_SOCKET_OPEN)\n ) {\n await this.reconnectInFlight.catch(() => undefined);\n socket = this.socket;\n }\n\n if (socket == null || socket.readyState !== WEB_SOCKET_OPEN) {\n throw new Error(\"Protocol WebSocket is not open.\");\n }\n\n return await new Promise<CommandResponse | ErrorResponse>(\n (resolve, reject) => {\n this.pending.set(command.id, { resolve, reject });\n\n try {\n socket.send(JSON.stringify(command));\n } catch (error) {\n this.pending.delete(command.id);\n reject(toError(error));\n }\n }\n );\n }\n\n #attachSocket(socket: WebSocket): void {\n socket.addEventListener(\"message\", this.handleMessage);\n socket.addEventListener(\"close\", this.handleClose);\n socket.addEventListener(\"error\", this.handleSocketError);\n }\n\n #detachSocket(socket: WebSocket): void {\n socket.removeEventListener(\"message\", this.handleMessage);\n socket.removeEventListener(\"close\", this.handleClose);\n socket.removeEventListener(\"error\", this.handleSocketError);\n }\n\n private readonly handleMessage = (event: MessageEvent): void => {\n let payload: unknown;\n try {\n payload = JSON.parse(String(event.data));\n } catch {\n return;\n }\n\n if (\n isRecord(payload) &&\n typeof payload.id === \"number\" &&\n (payload.type === \"success\" || payload.type === \"error\")\n ) {\n const pending = this.pending.get(payload.id);\n if (pending) {\n this.pending.delete(payload.id);\n pending.resolve(payload as CommandResponse | ErrorResponse);\n }\n return;\n }\n\n if (isRecord(payload) && payload.type === \"event\") {\n this.queue.push(payload as Message);\n }\n };\n\n private readonly handleClose = (): void => {\n const socket = this.socket;\n if (socket != null) {\n this.#detachSocket(socket);\n }\n this.socket = null;\n\n if (this.intentionalClose || this.closed) {\n this.queue.close();\n return;\n }\n\n this.#handleUnexpectedDisconnect(\n new Error(\"Protocol WebSocket closed unexpectedly.\")\n );\n };\n\n private readonly handleSocketError = (): void => {\n if (this.closed || this.intentionalClose) {\n return;\n }\n\n this.#handleUnexpectedDisconnect(\n new Error(\"Protocol WebSocket encountered an error.\")\n );\n };\n\n #handleUnexpectedDisconnect(cause: unknown): void {\n const error = toError(cause);\n for (const { reject } of this.pending.values()) {\n reject(error);\n }\n this.pending.clear();\n\n if (this.maxReconnectAttempts <= 0) {\n this.queue.close(error);\n return;\n }\n\n this.#scheduleReconnect(cause);\n }\n\n #scheduleReconnect(cause: unknown): void {\n if (this.closed || this.intentionalClose) {\n return;\n }\n if (this.reconnectInFlight != null) {\n return;\n }\n\n this.reconnectInFlight = this.#runReconnectLoop(cause).finally(() => {\n this.reconnectInFlight = null;\n });\n }\n\n async #runReconnectLoop(initialCause: unknown): Promise<void> {\n let lastError: unknown = initialCause;\n\n for (let attempt = 1; attempt <= this.maxReconnectAttempts; attempt += 1) {\n if (this.closed || this.intentionalClose) {\n return;\n }\n\n this.onReconnect?.({ attempt, cause: lastError });\n\n const delay = this.reconnectDelayMs(attempt);\n if (delay > 0) {\n await new Promise<void>((resolve) => {\n setTimeout(resolve, delay);\n });\n }\n\n if (this.closed || this.intentionalClose) {\n return;\n }\n\n try {\n await this.open();\n if (this.onReconnected) {\n await this.onReconnected();\n }\n return;\n } catch (error) {\n lastError = error;\n }\n }\n\n this.queue.close(\n new MaxWebSocketReconnectAttemptsError(\n this.maxReconnectAttempts,\n lastError\n )\n );\n }\n}\n"],"mappings":";;;;AAwBA,MAAM,wBAAwB;AAC9B,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;;;;;AAuB1B,SAAgB,0BAA0B,SAAyB;AAGjE,QAFkB,KAAK,IAAI,MAAO,MAAM,UAAU,IAAI,IAAK,GAC5C,KAAK,QAAQ,GAAG;;;;;;;;;;;;;;AAgBjC,IAAa,oCAAb,MAA2E;CACzE;CAEA,QAAyB,IAAI,YAAqB;CAElD;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA,0BAA2B,IAAI,KAA8B;CAE7D,SAAmC;CAEnC,SAAiB;CAEjB,mBAA2B;CAE3B,oBAAkD;CAElD,YAAY,SAA4C;AACtD,OAAK,SAAS,QAAQ;AACtB,OAAK,WAAW,QAAQ;AACxB,OAAK,iBAAiB,QAAQ;AAC9B,OAAK,YAAY,QAAQ;AACzB,OAAK,mBACH,QAAQ,sBAAsB,QAAQ,IAAI,UAAU,IAAI;AAC1D,OAAK,YACH,QAAQ,OAAO,UAAU,YAAY,KAAK,SAAS;AACrD,OAAK,uBAAuB,QAAQ,wBAAwB;AAC5D,OAAK,cAAc,QAAQ;AAC3B,OAAK,gBAAgB,QAAQ;AAC7B,OAAK,mBACH,QAAQ,oBAAoB;;;;;;;CAQhC,iBAAiB,SAA2C;AAC1D,OAAK,gBAAgB;;CAGvB,MAAM,OAAsB;AAC1B,MAAI,KAAK,OACP,OAAM,IAAI,MAAM,0CAA0C;AAE5D,MAAI,KAAK,QAAQ,eAAe,gBAC9B;AAEF,MAAI,KAAK,UAAU,MAAM;AACvB,SAAA,aAAmB,KAAK,OAAO;AAC/B,QAAK,SAAS;;AAGhB,OAAK,kCAAkC;EAEvC,MAAM,QAAQ,eACZ,cAAc,KAAK,QAAQ,KAAK,UAAU,CAAC,UAAU,CACtD;EACD,MAAM,SAAS,KAAK,iBAAiB,MAAM;AAC3C,OAAK,SAAS;AACd,OAAK,mBAAmB;AAExB,QAAA,aAAmB,OAAO;AAE1B,QAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,MAAM,eAAe;AACnB,aAAS;AACT,aAAS;;GAEX,MAAM,gBAAgB;AACpB,aAAS;AACT,2BAAO,IAAI,MAAM,qCAAqC,CAAC;;GAEzD,MAAM,gBAAgB;AACpB,WAAO,oBAAoB,QAAQ,OAAO;AAC1C,WAAO,oBAAoB,SAAS,QAAQ;;AAE9C,UAAO,iBAAiB,QAAQ,QAAQ,EAAE,MAAM,MAAM,CAAC;AACvD,UAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;IACzD;;CAGJ,MAAM,KACJ,SACiD;AACjD,SAAO,MAAM,KAAK,YAAY,QAAQ;;CAGxC,SAAiC;EAC/B,MAAM,QAAQ,KAAK;AACnB,SAAO,GACJ,OAAO,uBAAuB;GAC7B,MAAM,YAAY,MAAM,MAAM,OAAO;GACrC,QAAQ,YAAY;AAClB,UAAM,OAAO;AACb,WAAO;KAAE,MAAM;KAAM,OAAO,KAAA;KAAW;;GAE1C,GACF;;CAGH,MAAM,QAAuB;AAC3B,MAAI,KAAK,OACP;AAGF,OAAK,SAAS;AACd,OAAK,mBAAmB;AAExB,OAAK,MAAM,EAAE,YAAY,KAAK,QAAQ,QAAQ,CAC5C,wBAAO,IAAI,MAAM,wCAAwC,CAAC;AAE5D,OAAK,QAAQ,OAAO;AACpB,OAAK,MAAM,OAAO;EAElB,MAAM,SAAS,KAAK;AACpB,OAAK,SAAS;AACd,MAAI,CAAC,OACH;AAGF,QAAA,aAAmB,OAAO;AAE1B,QAAM,IAAI,SAAe,YAAY;AACnC,OAAI,OAAO,eAAe,mBAAmB;AAC3C,aAAS;AACT;;GAGF,MAAM,gBAAgB;AACpB,WAAO,oBAAoB,SAAS,QAAQ;AAC5C,aAAS;;AAGX,UAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AACzD,OACE,OAAO,eAAe,mBACtB,OAAO,eAAe,sBAEtB,QAAO,OAAO;OAEd,UAAS;IAEX;;CAGJ,mCAAiD;AAC/C,MAAI,WAAW,KAAK,eAAe,IAAI,KAAK,aAAa,KACvD,OAAM,IAAI,MACR,wKACD;;CAIL,MAAc,YACZ,SAC0C;EAK1C,IAAI,SAAS,KAAK;AAClB,MACE,KAAK,qBAAqB,SACzB,UAAU,QAAQ,OAAO,eAAe,kBACzC;AACA,SAAM,KAAK,kBAAkB,YAAY,KAAA,EAAU;AACnD,YAAS,KAAK;;AAGhB,MAAI,UAAU,QAAQ,OAAO,eAAe,gBAC1C,OAAM,IAAI,MAAM,kCAAkC;AAGpD,SAAO,MAAM,IAAI,SACd,SAAS,WAAW;AACnB,QAAK,QAAQ,IAAI,QAAQ,IAAI;IAAE;IAAS;IAAQ,CAAC;AAEjD,OAAI;AACF,WAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;YAC7B,OAAO;AACd,SAAK,QAAQ,OAAO,QAAQ,GAAG;AAC/B,WAAO,QAAQ,MAAM,CAAC;;IAG3B;;CAGH,cAAc,QAAyB;AACrC,SAAO,iBAAiB,WAAW,KAAK,cAAc;AACtD,SAAO,iBAAiB,SAAS,KAAK,YAAY;AAClD,SAAO,iBAAiB,SAAS,KAAK,kBAAkB;;CAG1D,cAAc,QAAyB;AACrC,SAAO,oBAAoB,WAAW,KAAK,cAAc;AACzD,SAAO,oBAAoB,SAAS,KAAK,YAAY;AACrD,SAAO,oBAAoB,SAAS,KAAK,kBAAkB;;CAG7D,iBAAkC,UAA8B;EAC9D,IAAI;AACJ,MAAI;AACF,aAAU,KAAK,MAAM,OAAO,MAAM,KAAK,CAAC;UAClC;AACN;;AAGF,MACE,SAAS,QAAQ,IACjB,OAAO,QAAQ,OAAO,aACrB,QAAQ,SAAS,aAAa,QAAQ,SAAS,UAChD;GACA,MAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAC5C,OAAI,SAAS;AACX,SAAK,QAAQ,OAAO,QAAQ,GAAG;AAC/B,YAAQ,QAAQ,QAA2C;;AAE7D;;AAGF,MAAI,SAAS,QAAQ,IAAI,QAAQ,SAAS,QACxC,MAAK,MAAM,KAAK,QAAmB;;CAIvC,oBAA2C;EACzC,MAAM,SAAS,KAAK;AACpB,MAAI,UAAU,KACZ,OAAA,aAAmB,OAAO;AAE5B,OAAK,SAAS;AAEd,MAAI,KAAK,oBAAoB,KAAK,QAAQ;AACxC,QAAK,MAAM,OAAO;AAClB;;AAGF,QAAA,2CACE,IAAI,MAAM,0CAA0C,CACrD;;CAGH,0BAAiD;AAC/C,MAAI,KAAK,UAAU,KAAK,iBACtB;AAGF,QAAA,2CACE,IAAI,MAAM,2CAA2C,CACtD;;CAGH,4BAA4B,OAAsB;EAChD,MAAM,QAAQ,QAAQ,MAAM;AAC5B,OAAK,MAAM,EAAE,YAAY,KAAK,QAAQ,QAAQ,CAC5C,QAAO,MAAM;AAEf,OAAK,QAAQ,OAAO;AAEpB,MAAI,KAAK,wBAAwB,GAAG;AAClC,QAAK,MAAM,MAAM,MAAM;AACvB;;AAGF,QAAA,kBAAwB,MAAM;;CAGhC,mBAAmB,OAAsB;AACvC,MAAI,KAAK,UAAU,KAAK,iBACtB;AAEF,MAAI,KAAK,qBAAqB,KAC5B;AAGF,OAAK,oBAAoB,MAAA,iBAAuB,MAAM,CAAC,cAAc;AACnE,QAAK,oBAAoB;IACzB;;CAGJ,OAAA,iBAAwB,cAAsC;EAC5D,IAAI,YAAqB;AAEzB,OAAK,IAAI,UAAU,GAAG,WAAW,KAAK,sBAAsB,WAAW,GAAG;AACxE,OAAI,KAAK,UAAU,KAAK,iBACtB;AAGF,QAAK,cAAc;IAAE;IAAS,OAAO;IAAW,CAAC;GAEjD,MAAM,QAAQ,KAAK,iBAAiB,QAAQ;AAC5C,OAAI,QAAQ,EACV,OAAM,IAAI,SAAe,YAAY;AACnC,eAAW,SAAS,MAAM;KAC1B;AAGJ,OAAI,KAAK,UAAU,KAAK,iBACtB;AAGF,OAAI;AACF,UAAM,KAAK,MAAM;AACjB,QAAI,KAAK,cACP,OAAM,KAAK,eAAe;AAE5B;YACO,OAAO;AACd,gBAAY;;;AAIhB,OAAK,MAAM,MACT,IAAI,mCACF,KAAK,sBACL,UACD,CACF"}
|
|
@@ -96,6 +96,23 @@ interface ThreadStreamOptions {
|
|
|
96
96
|
* for the SSE transport and for custom {@link AgentServerAdapter}s.
|
|
97
97
|
*/
|
|
98
98
|
webSocketFactory?: (url: string) => WebSocket;
|
|
99
|
+
/**
|
|
100
|
+
* Built-in `"sse"` / `"websocket"` transports only: max reconnect
|
|
101
|
+
* attempts after an unexpected disconnect. Defaults to 5.
|
|
102
|
+
*/
|
|
103
|
+
maxReconnectAttempts?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Built-in transports only: delay before each reconnect attempt.
|
|
106
|
+
* Defaults to exponential backoff with jitter.
|
|
107
|
+
*/
|
|
108
|
+
reconnectDelayMs?: (attempt: number) => number;
|
|
109
|
+
/**
|
|
110
|
+
* Built-in transports only: invoked before each reconnect attempt.
|
|
111
|
+
*/
|
|
112
|
+
onReconnect?: (options: {
|
|
113
|
+
attempt: number;
|
|
114
|
+
cause: unknown;
|
|
115
|
+
}) => void;
|
|
99
116
|
}
|
|
100
117
|
interface SessionOrderingState {
|
|
101
118
|
lastSeenSeq?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.cts","names":[],"sources":["../../../src/client/stream/types.ts"],"mappings":";;;;;UAoBiB,sBAAA,SAA+B,cAAA;EAC9C,QAAA;EACA,iBAAA;AAAA;AAAA,KAGU,gBAAA,GAAmB,IAAA,CAAK,eAAA;AAAA,KAExB,oBAAA;EACV,MAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,KAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA;AAAA;AAAA,KAGU,eAAA,kBAAiC,OAAA,IAC3C,QAAA,eAAuB,oBAAA,GACnB,OAAA,CAAQ,KAAA;EAAS,MAAA,EAAQ,oBAAA,CAAqB,QAAA;AAAA,KAC9C,QAAA,8BACE,OAAA,CAAQ,KAAA;EAAS,MAAA;AAAA;AAAA,KAGb,gBAAA,4BAA4C,OAAA,MACtD,eAAA,CAAgB,SAAA;;;;;;;KAQN,eAAA,kBAAiC,OAAA,IAC3C,QAAA,wCAAgD,eAAA,CAAgB,QAAA;AAAA,KAEtD,gBAAA,4BAA4C,OAAA,MACtD,eAAA,CAAgB,SAAA;;AApBlB;;;;;;;KA8BY,yBAAA;;;;;;;;;KAUA,qBAAA,GACR,yBAAA,GACA,kBAAA;;;;UAKa,mBAAA;EA7CM;;;;;EAmDrB,WAAA;EAjDuB;;;AAGzB;;;;;;;;;;EA4DE,SAAA,GAAY,qBAAA;EA3DI;;;AAQlB;EAwDE,iBAAA;EAxDyB;;;;;;;EAgEzB,KAAA,UAAe,KAAA;EAhE4B;;;;;;EAuE3C,gBAAA,IAAoB,GAAA,aAAgB,SAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../../../src/client/stream/types.ts"],"mappings":"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"}
|
|
@@ -96,6 +96,23 @@ interface ThreadStreamOptions {
|
|
|
96
96
|
* for the SSE transport and for custom {@link AgentServerAdapter}s.
|
|
97
97
|
*/
|
|
98
98
|
webSocketFactory?: (url: string) => WebSocket;
|
|
99
|
+
/**
|
|
100
|
+
* Built-in `"sse"` / `"websocket"` transports only: max reconnect
|
|
101
|
+
* attempts after an unexpected disconnect. Defaults to 5.
|
|
102
|
+
*/
|
|
103
|
+
maxReconnectAttempts?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Built-in transports only: delay before each reconnect attempt.
|
|
106
|
+
* Defaults to exponential backoff with jitter.
|
|
107
|
+
*/
|
|
108
|
+
reconnectDelayMs?: (attempt: number) => number;
|
|
109
|
+
/**
|
|
110
|
+
* Built-in transports only: invoked before each reconnect attempt.
|
|
111
|
+
*/
|
|
112
|
+
onReconnect?: (options: {
|
|
113
|
+
attempt: number;
|
|
114
|
+
cause: unknown;
|
|
115
|
+
}) => void;
|
|
99
116
|
}
|
|
100
117
|
interface SessionOrderingState {
|
|
101
118
|
lastSeenSeq?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/client/stream/types.ts"],"mappings":";;;;;UAoBiB,sBAAA,SAA+B,cAAA;EAC9C,QAAA;EACA,iBAAA;AAAA;AAAA,KAGU,gBAAA,GAAmB,IAAA,CAAK,eAAA;AAAA,KAExB,oBAAA;EACV,MAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,KAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA;AAAA;AAAA,KAGU,eAAA,kBAAiC,OAAA,IAC3C,QAAA,eAAuB,oBAAA,GACnB,OAAA,CAAQ,KAAA;EAAS,MAAA,EAAQ,oBAAA,CAAqB,QAAA;AAAA,KAC9C,QAAA,8BACE,OAAA,CAAQ,KAAA;EAAS,MAAA;AAAA;AAAA,KAGb,gBAAA,4BAA4C,OAAA,MACtD,eAAA,CAAgB,SAAA;;;;;;;KAQN,eAAA,kBAAiC,OAAA,IAC3C,QAAA,wCAAgD,eAAA,CAAgB,QAAA;AAAA,KAEtD,gBAAA,4BAA4C,OAAA,MACtD,eAAA,CAAgB,SAAA;;AApBlB;;;;;;;KA8BY,yBAAA;;;;;;;;;KAUA,qBAAA,GACR,yBAAA,GACA,kBAAA;;;;UAKa,mBAAA;EA7CM;;;;;EAmDrB,WAAA;EAjDuB;;;AAGzB;;;;;;;;;;EA4DE,SAAA,GAAY,qBAAA;EA3DI;;;AAQlB;EAwDE,iBAAA;EAxDyB;;;;;;;EAgEzB,KAAA,UAAe,KAAA;EAhE4B;;;;;;EAuE3C,gBAAA,IAAoB,GAAA,aAAgB,SAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/client/stream/types.ts"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require("../../_virtual/_rolldown/runtime.cjs");
|
|
2
2
|
const require_base = require("../base.cjs");
|
|
3
3
|
const require_index = require("../stream/index.cjs");
|
|
4
|
-
const require_http = require("../stream/transport/http.cjs");
|
|
5
4
|
const require_websocket = require("../stream/transport/websocket.cjs");
|
|
5
|
+
const require_http = require("../stream/transport/http.cjs");
|
|
6
6
|
let uuid = require("uuid");
|
|
7
7
|
//#region src/client/threads/index.ts
|
|
8
8
|
var ThreadsClient = class extends require_base.BaseClient {
|
|
@@ -249,22 +249,38 @@ var ThreadsClient = class extends require_base.BaseClient {
|
|
|
249
249
|
threadId: (0, uuid.v7)(),
|
|
250
250
|
options: threadIdOrOptions
|
|
251
251
|
};
|
|
252
|
+
const userFetch = options.fetch;
|
|
253
|
+
const protocolFetch = userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller);
|
|
252
254
|
let transport;
|
|
253
255
|
if (options.transport != null && typeof options.transport !== "string") transport = options.transport;
|
|
254
|
-
else
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
256
|
+
else {
|
|
257
|
+
const transportKind = options.transport ?? (this.streamProtocol === "v2-websocket" ? "websocket" : "sse");
|
|
258
|
+
const maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
|
|
259
|
+
/**
|
|
260
|
+
* Common options for both transports.
|
|
261
|
+
*/
|
|
262
|
+
const commonOpts = {
|
|
263
|
+
apiUrl: this.apiUrl,
|
|
264
|
+
threadId,
|
|
265
|
+
defaultHeaders: this.defaultHeaders,
|
|
266
|
+
onRequest: this.onRequest,
|
|
267
|
+
maxReconnectAttempts,
|
|
268
|
+
reconnectDelayMs: options.reconnectDelayMs,
|
|
269
|
+
onReconnect: options.onReconnect
|
|
270
|
+
};
|
|
271
|
+
transport = transportKind === "websocket" ? new require_websocket.ProtocolWebSocketTransportAdapter({
|
|
272
|
+
...commonOpts,
|
|
273
|
+
webSocketFactory: options.webSocketFactory
|
|
274
|
+
}) : new require_http.ProtocolSseTransportAdapter({
|
|
275
|
+
...commonOpts,
|
|
276
|
+
fetch: userFetch,
|
|
277
|
+
asyncCaller: userFetch ? void 0 : this.asyncCaller
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return new require_index.ThreadStream(transport, {
|
|
281
|
+
...options,
|
|
282
|
+
fetch: protocolFetch
|
|
266
283
|
});
|
|
267
|
-
return new require_index.ThreadStream(transport, options);
|
|
268
284
|
}
|
|
269
285
|
};
|
|
270
286
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["BaseClient","ProtocolWebSocketTransportAdapter","ProtocolSseTransportAdapter","ThreadStream"],"sources":["../../../src/client/threads/index.ts"],"sourcesContent":["import { v7 as uuidv7 } from \"uuid\";\n\nimport {\n Checkpoint,\n Config,\n DefaultValues,\n Metadata,\n SortOrder,\n Thread,\n ThreadSelectField,\n ThreadSortBy,\n ThreadState,\n ThreadStatus,\n ThreadValuesFilter,\n} from \"../../schema.js\";\nimport type { Command, OnConflictBehavior, StreamEvent } from \"../../types.js\";\nimport type { ThreadStreamMode } from \"../../types.stream.js\";\nimport { BaseClient } from \"../base.js\";\nimport { ThreadStream } from \"../stream/index.js\";\nimport type {\n ThreadStreamOptions,\n ThreadStreamTransportKind,\n} from \"../stream/types.js\";\nimport { ProtocolSseTransportAdapter } from \"../stream/transport/http.js\";\nimport { ProtocolWebSocketTransportAdapter } from \"../stream/transport/websocket.js\";\nimport type { TransportAdapter } from \"../stream/transport.js\";\n\nexport class ThreadsClient<\n TStateType = DefaultValues,\n TUpdateType = TStateType,\n> extends BaseClient {\n /**\n * Get a thread by ID.\n *\n * @param threadId ID of the thread.\n * @returns The thread.\n */\n async get<ValuesType = TStateType>(\n threadId: string,\n options?: { signal?: AbortSignal; include?: string[] }\n ): Promise<Thread<ValuesType>> {\n return this.fetch<Thread<ValuesType>>(`/threads/${threadId}`, {\n params: {\n include: options?.include ?? undefined,\n },\n signal: options?.signal,\n });\n }\n\n /**\n * Create a new thread.\n *\n * @param payload Payload for creating a thread.\n * @returns The created thread.\n */\n async create(payload?: {\n metadata?: Metadata;\n threadId?: string;\n ifExists?: OnConflictBehavior;\n graphId?: string;\n supersteps?: Array<{\n updates: Array<{ values: unknown; command?: Command; asNode: string }>;\n }>;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n signal?: AbortSignal;\n }): Promise<Thread<TStateType>> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread<TStateType>>(`/threads`, {\n method: \"POST\",\n json: {\n metadata: {\n ...payload?.metadata,\n graph_id: payload?.graphId,\n },\n thread_id: payload?.threadId,\n if_exists: payload?.ifExists,\n supersteps: payload?.supersteps?.map((s) => ({\n updates: s.updates.map((u) => ({\n values: u.values,\n command: u.command,\n as_node: u.asNode,\n })),\n })),\n ttl: ttlPayload,\n },\n signal: payload?.signal,\n });\n }\n\n /**\n * Copy an existing thread\n * @param threadId ID of the thread to be copied\n * @returns Newly copied thread\n */\n async copy(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<Thread<TStateType>> {\n return this.fetch<Thread<TStateType>>(`/threads/${threadId}/copy`, {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n /**\n * Update a thread.\n *\n * @param threadId ID of the thread.\n * @param payload Payload for updating the thread.\n * @returns The updated thread.\n */\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: false;\n signal?: AbortSignal;\n }\n ): Promise<Thread>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: true;\n signal?: AbortSignal;\n }\n ): Promise<void>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void>;\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread | void>(`/threads/${threadId}`, {\n method: \"PATCH\",\n headers: payload?.returnMinimal\n ? { Prefer: \"return=minimal\" }\n : undefined,\n json: { metadata: payload?.metadata, ttl: ttlPayload },\n signal: payload?.signal,\n });\n }\n\n /**\n * Delete a thread.\n *\n * @param threadId ID of the thread.\n */\n async delete(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n return this.fetch<void>(`/threads/${threadId}`, {\n method: \"DELETE\",\n signal: options?.signal,\n });\n }\n\n /**\n * Prune threads by ID. The 'delete' strategy removes threads entirely.\n * The 'keep_latest' strategy prunes old checkpoints but keeps threads\n * and their latest state.\n *\n * @param threadIds List of thread IDs to prune.\n * @param options Additional options for pruning.\n * @param options.strategy The prune strategy. Defaults to 'delete'.\n * @param options.signal Signal to abort the request.\n * @returns An object containing `pruned_count`.\n */\n async prune(\n threadIds: string[],\n options?: {\n strategy?: \"delete\" | \"keep_latest\";\n signal?: AbortSignal;\n }\n ): Promise<{ pruned_count: number }> {\n return this.fetch<{ pruned_count: number }>(\"/threads/prune\", {\n method: \"POST\",\n json: {\n thread_ids: threadIds,\n strategy: options?.strategy ?? \"delete\",\n },\n signal: options?.signal,\n });\n }\n\n /**\n * List threads\n *\n * @param query Query options\n * @returns List of threads\n */\n async search<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n ids?: string[];\n limit?: number;\n offset?: number;\n status?: ThreadStatus;\n sortBy?: ThreadSortBy;\n sortOrder?: SortOrder;\n select?: ThreadSelectField[];\n values?: ThreadValuesFilter;\n extract?: Record<string, string>;\n signal?: AbortSignal;\n }): Promise<Thread<ValuesType>[]> {\n return this.fetch<Thread<ValuesType>[]>(\"/threads/search\", {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n ids: query?.ids ?? undefined,\n limit: query?.limit ?? 10,\n offset: query?.offset ?? 0,\n status: query?.status,\n sort_by: query?.sortBy,\n sort_order: query?.sortOrder,\n select: query?.select ?? undefined,\n values: query?.values ?? undefined,\n extract: query?.extract ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Count threads matching filters.\n *\n * @param query.metadata Thread metadata to filter on.\n * @param query.values State values to filter on.\n * @param query.status Thread status to filter on.\n * @returns Number of threads matching the criteria.\n */\n async count<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n values?: ValuesType;\n status?: ThreadStatus;\n signal?: AbortSignal;\n }): Promise<number> {\n return this.fetch<number>(`/threads/count`, {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n values: query?.values ?? undefined,\n status: query?.status ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Get state for a thread.\n *\n * @param threadId ID of the thread.\n * @returns Thread state.\n */\n async getState<ValuesType = TStateType>(\n threadId: string,\n checkpoint?: Checkpoint | string,\n options?: { subgraphs?: boolean; signal?: AbortSignal }\n ): Promise<ThreadState<ValuesType>> {\n if (checkpoint != null) {\n if (typeof checkpoint !== \"string\") {\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/checkpoint`,\n {\n method: \"POST\",\n json: { checkpoint, subgraphs: options?.subgraphs },\n signal: options?.signal,\n }\n );\n }\n\n // deprecated\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/${checkpoint}`,\n { params: { subgraphs: options?.subgraphs }, signal: options?.signal }\n );\n }\n\n return this.fetch<ThreadState<ValuesType>>(`/threads/${threadId}/state`, {\n params: { subgraphs: options?.subgraphs },\n signal: options?.signal,\n // Coalesce concurrent identical reads (e.g. two controllers\n // hydrating the same thread on reconnect). Skipped automatically\n // when a caller supplies its own `signal`.\n dedupe: true,\n });\n }\n\n /**\n * Add state to a thread.\n *\n * @param threadId The ID of the thread.\n * @returns\n */\n async updateState<ValuesType = TUpdateType>(\n threadId: string,\n options: {\n values: ValuesType;\n checkpoint?: Checkpoint;\n checkpointId?: string;\n asNode?: string;\n signal?: AbortSignal;\n }\n ): Promise<Pick<Config, \"configurable\">> {\n return this.fetch<Pick<Config, \"configurable\">>(\n `/threads/${threadId}/state`,\n {\n method: \"POST\",\n json: {\n values: options.values,\n checkpoint: options.checkpoint,\n checkpoint_id: options.checkpointId,\n as_node: options?.asNode,\n },\n signal: options?.signal,\n }\n );\n }\n\n /**\n * Patch the metadata of a thread.\n *\n * @param threadIdOrConfig Thread ID or config to patch the state of.\n * @param metadata Metadata to patch the state with.\n */\n async patchState(\n threadIdOrConfig: string | Config,\n metadata: Metadata,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n let threadId: string;\n\n if (typeof threadIdOrConfig !== \"string\") {\n if (typeof threadIdOrConfig.configurable?.thread_id !== \"string\") {\n throw new Error(\n \"Thread ID is required when updating state with a config.\"\n );\n }\n threadId = threadIdOrConfig.configurable.thread_id;\n } else {\n threadId = threadIdOrConfig;\n }\n\n return this.fetch<void>(`/threads/${threadId}/state`, {\n method: \"PATCH\",\n json: { metadata },\n signal: options?.signal,\n });\n }\n\n /**\n * Get all past states for a thread.\n *\n * @param threadId ID of the thread.\n * @param options Additional options.\n * @returns List of thread states.\n */\n async getHistory<ValuesType = TStateType>(\n threadId: string,\n options?: {\n limit?: number;\n before?: Config;\n checkpoint?: Partial<Omit<Checkpoint, \"thread_id\">>;\n metadata?: Metadata;\n signal?: AbortSignal;\n }\n ): Promise<ThreadState<ValuesType>[]> {\n return this.fetch<ThreadState<ValuesType>[]>(\n `/threads/${threadId}/history`,\n {\n method: \"POST\",\n json: {\n limit: options?.limit ?? 10,\n before: options?.before,\n metadata: options?.metadata,\n checkpoint: options?.checkpoint,\n },\n signal: options?.signal,\n // `getHistory` is a read despite using POST — coalesce the\n // hydrate-time discovery seed when two controllers reconnect to\n // the same thread concurrently. Skipped when `signal` is set.\n dedupe: true,\n }\n );\n }\n\n async *joinStream(\n threadId: string,\n options?: {\n lastEventId?: string;\n streamMode?: ThreadStreamMode | ThreadStreamMode[];\n signal?: AbortSignal;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): AsyncGenerator<{ id?: string; event: StreamEvent; data: any }> {\n yield* this.streamWithRetry({\n endpoint: `/threads/${threadId}/stream`,\n method: \"GET\",\n signal: options?.signal,\n headers: options?.lastEventId\n ? { \"Last-Event-ID\": options.lastEventId }\n : undefined,\n params: options?.streamMode\n ? { stream_mode: options.streamMode }\n : undefined,\n });\n }\n\n /**\n * Open a protocol stream over the thread-centric v2 protocol.\n *\n * Returns a {@link ThreadStream} with lazy getters\n * (`.messages`, `.values`, `.toolCalls`, `.subgraphs`, `.subagents`,\n * `.output`) and `thread.run.start({ input, ... })` for starting runs.\n * Mirrors the in-process `graph.streamEvents(..., { version: \"v3\" })` API.\n *\n * The thread is bound to `options.assistantId` for its lifetime.\n * The wire transport defaults to SSE; pass `transport: \"websocket\"`\n * in options (or configure `streamProtocol: \"v2-websocket\"` on the\n * client) to use a WebSocket instead.\n *\n * @example New thread (UUID generated client-side)\n * ```ts\n * const thread = client.threads.stream({ assistantId: \"my-agent\" });\n * ```\n *\n * @example Attach to an existing thread\n * ```ts\n * const thread = client.threads.stream(threadId, { assistantId: \"my-agent\" });\n * ```\n *\n * @example WebSocket transport\n * ```ts\n * const thread = client.threads.stream({\n * assistantId: \"my-agent\",\n * transport: \"websocket\",\n * });\n * ```\n */\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadId: string,\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadIdOrOptions: string | ThreadStreamOptions,\n maybeOptions?: ThreadStreamOptions\n ): ThreadStream<TExtensions> {\n const { threadId, options } =\n typeof threadIdOrOptions === \"string\"\n ? {\n threadId: threadIdOrOptions,\n options: maybeOptions as ThreadStreamOptions,\n }\n : { threadId: uuidv7(), options: threadIdOrOptions };\n\n // `transport` accepts either a preset string (`\"sse\"` / `\"websocket\"`)\n // or a custom {@link AgentServerAdapter}. A custom adapter replaces\n // the built-in factories entirely — this is the seam that lets users\n // point `useStream` at any agent server (including the thin wrappers\n // produced by `HttpAgentServerAdapter`).\n let transport: TransportAdapter;\n if (options.transport != null && typeof options.transport !== \"string\") {\n transport = options.transport;\n } else {\n const transportKind: ThreadStreamTransportKind =\n options.transport ??\n (this.streamProtocol === \"v2-websocket\" ? \"websocket\" : \"sse\");\n transport =\n transportKind === \"websocket\"\n ? new ProtocolWebSocketTransportAdapter({\n apiUrl: this.apiUrl,\n threadId,\n defaultHeaders: this.defaultHeaders,\n onRequest: this.onRequest,\n webSocketFactory: options.webSocketFactory,\n })\n : new ProtocolSseTransportAdapter({\n apiUrl: this.apiUrl,\n threadId,\n defaultHeaders: this.defaultHeaders,\n onRequest: this.onRequest,\n fetch: options.fetch,\n });\n }\n\n return new ThreadStream<TExtensions>(transport, options);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["BaseClient","ProtocolWebSocketTransportAdapter","ProtocolSseTransportAdapter","ThreadStream"],"sources":["../../../src/client/threads/index.ts"],"sourcesContent":["import { v7 as uuidv7 } from \"uuid\";\n\nimport {\n Checkpoint,\n Config,\n DefaultValues,\n Metadata,\n SortOrder,\n Thread,\n ThreadSelectField,\n ThreadSortBy,\n ThreadState,\n ThreadStatus,\n ThreadValuesFilter,\n} from \"../../schema.js\";\nimport type { Command, OnConflictBehavior, StreamEvent } from \"../../types.js\";\nimport type { ThreadStreamMode } from \"../../types.stream.js\";\nimport { BaseClient } from \"../base.js\";\nimport { ThreadStream } from \"../stream/index.js\";\nimport type {\n ThreadStreamOptions,\n ThreadStreamTransportKind,\n} from \"../stream/types.js\";\nimport { ProtocolSseTransportAdapter } from \"../stream/transport/http.js\";\nimport { ProtocolWebSocketTransportAdapter } from \"../stream/transport/websocket.js\";\nimport type { TransportAdapter } from \"../stream/transport.js\";\n\nexport class ThreadsClient<\n TStateType = DefaultValues,\n TUpdateType = TStateType,\n> extends BaseClient {\n /**\n * Get a thread by ID.\n *\n * @param threadId ID of the thread.\n * @returns The thread.\n */\n async get<ValuesType = TStateType>(\n threadId: string,\n options?: { signal?: AbortSignal; include?: string[] }\n ): Promise<Thread<ValuesType>> {\n return this.fetch<Thread<ValuesType>>(`/threads/${threadId}`, {\n params: {\n include: options?.include ?? undefined,\n },\n signal: options?.signal,\n });\n }\n\n /**\n * Create a new thread.\n *\n * @param payload Payload for creating a thread.\n * @returns The created thread.\n */\n async create(payload?: {\n metadata?: Metadata;\n threadId?: string;\n ifExists?: OnConflictBehavior;\n graphId?: string;\n supersteps?: Array<{\n updates: Array<{ values: unknown; command?: Command; asNode: string }>;\n }>;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n signal?: AbortSignal;\n }): Promise<Thread<TStateType>> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread<TStateType>>(`/threads`, {\n method: \"POST\",\n json: {\n metadata: {\n ...payload?.metadata,\n graph_id: payload?.graphId,\n },\n thread_id: payload?.threadId,\n if_exists: payload?.ifExists,\n supersteps: payload?.supersteps?.map((s) => ({\n updates: s.updates.map((u) => ({\n values: u.values,\n command: u.command,\n as_node: u.asNode,\n })),\n })),\n ttl: ttlPayload,\n },\n signal: payload?.signal,\n });\n }\n\n /**\n * Copy an existing thread\n * @param threadId ID of the thread to be copied\n * @returns Newly copied thread\n */\n async copy(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<Thread<TStateType>> {\n return this.fetch<Thread<TStateType>>(`/threads/${threadId}/copy`, {\n method: \"POST\",\n signal: options?.signal,\n });\n }\n\n /**\n * Update a thread.\n *\n * @param threadId ID of the thread.\n * @param payload Payload for updating the thread.\n * @returns The updated thread.\n */\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: false;\n signal?: AbortSignal;\n }\n ): Promise<Thread>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: true;\n signal?: AbortSignal;\n }\n ): Promise<void>;\n async update(\n threadId: string,\n payload: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void>;\n async update(\n threadId: string,\n payload?: {\n metadata?: Metadata;\n ttl?: number | { ttl: number; strategy?: \"delete\" };\n returnMinimal?: boolean;\n signal?: AbortSignal;\n }\n ): Promise<Thread | void> {\n const ttlPayload =\n typeof payload?.ttl === \"number\"\n ? { ttl: payload.ttl, strategy: \"delete\" as const }\n : payload?.ttl;\n\n return this.fetch<Thread | void>(`/threads/${threadId}`, {\n method: \"PATCH\",\n headers: payload?.returnMinimal\n ? { Prefer: \"return=minimal\" }\n : undefined,\n json: { metadata: payload?.metadata, ttl: ttlPayload },\n signal: payload?.signal,\n });\n }\n\n /**\n * Delete a thread.\n *\n * @param threadId ID of the thread.\n */\n async delete(\n threadId: string,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n return this.fetch<void>(`/threads/${threadId}`, {\n method: \"DELETE\",\n signal: options?.signal,\n });\n }\n\n /**\n * Prune threads by ID. The 'delete' strategy removes threads entirely.\n * The 'keep_latest' strategy prunes old checkpoints but keeps threads\n * and their latest state.\n *\n * @param threadIds List of thread IDs to prune.\n * @param options Additional options for pruning.\n * @param options.strategy The prune strategy. Defaults to 'delete'.\n * @param options.signal Signal to abort the request.\n * @returns An object containing `pruned_count`.\n */\n async prune(\n threadIds: string[],\n options?: {\n strategy?: \"delete\" | \"keep_latest\";\n signal?: AbortSignal;\n }\n ): Promise<{ pruned_count: number }> {\n return this.fetch<{ pruned_count: number }>(\"/threads/prune\", {\n method: \"POST\",\n json: {\n thread_ids: threadIds,\n strategy: options?.strategy ?? \"delete\",\n },\n signal: options?.signal,\n });\n }\n\n /**\n * List threads\n *\n * @param query Query options\n * @returns List of threads\n */\n async search<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n ids?: string[];\n limit?: number;\n offset?: number;\n status?: ThreadStatus;\n sortBy?: ThreadSortBy;\n sortOrder?: SortOrder;\n select?: ThreadSelectField[];\n values?: ThreadValuesFilter;\n extract?: Record<string, string>;\n signal?: AbortSignal;\n }): Promise<Thread<ValuesType>[]> {\n return this.fetch<Thread<ValuesType>[]>(\"/threads/search\", {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n ids: query?.ids ?? undefined,\n limit: query?.limit ?? 10,\n offset: query?.offset ?? 0,\n status: query?.status,\n sort_by: query?.sortBy,\n sort_order: query?.sortOrder,\n select: query?.select ?? undefined,\n values: query?.values ?? undefined,\n extract: query?.extract ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Count threads matching filters.\n *\n * @param query.metadata Thread metadata to filter on.\n * @param query.values State values to filter on.\n * @param query.status Thread status to filter on.\n * @returns Number of threads matching the criteria.\n */\n async count<ValuesType = TStateType>(query?: {\n metadata?: Metadata;\n values?: ValuesType;\n status?: ThreadStatus;\n signal?: AbortSignal;\n }): Promise<number> {\n return this.fetch<number>(`/threads/count`, {\n method: \"POST\",\n json: {\n metadata: query?.metadata ?? undefined,\n values: query?.values ?? undefined,\n status: query?.status ?? undefined,\n },\n signal: query?.signal,\n });\n }\n\n /**\n * Get state for a thread.\n *\n * @param threadId ID of the thread.\n * @returns Thread state.\n */\n async getState<ValuesType = TStateType>(\n threadId: string,\n checkpoint?: Checkpoint | string,\n options?: { subgraphs?: boolean; signal?: AbortSignal }\n ): Promise<ThreadState<ValuesType>> {\n if (checkpoint != null) {\n if (typeof checkpoint !== \"string\") {\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/checkpoint`,\n {\n method: \"POST\",\n json: { checkpoint, subgraphs: options?.subgraphs },\n signal: options?.signal,\n }\n );\n }\n\n // deprecated\n return this.fetch<ThreadState<ValuesType>>(\n `/threads/${threadId}/state/${checkpoint}`,\n { params: { subgraphs: options?.subgraphs }, signal: options?.signal }\n );\n }\n\n return this.fetch<ThreadState<ValuesType>>(`/threads/${threadId}/state`, {\n params: { subgraphs: options?.subgraphs },\n signal: options?.signal,\n // Coalesce concurrent identical reads (e.g. two controllers\n // hydrating the same thread on reconnect). Skipped automatically\n // when a caller supplies its own `signal`.\n dedupe: true,\n });\n }\n\n /**\n * Add state to a thread.\n *\n * @param threadId The ID of the thread.\n * @returns\n */\n async updateState<ValuesType = TUpdateType>(\n threadId: string,\n options: {\n values: ValuesType;\n checkpoint?: Checkpoint;\n checkpointId?: string;\n asNode?: string;\n signal?: AbortSignal;\n }\n ): Promise<Pick<Config, \"configurable\">> {\n return this.fetch<Pick<Config, \"configurable\">>(\n `/threads/${threadId}/state`,\n {\n method: \"POST\",\n json: {\n values: options.values,\n checkpoint: options.checkpoint,\n checkpoint_id: options.checkpointId,\n as_node: options?.asNode,\n },\n signal: options?.signal,\n }\n );\n }\n\n /**\n * Patch the metadata of a thread.\n *\n * @param threadIdOrConfig Thread ID or config to patch the state of.\n * @param metadata Metadata to patch the state with.\n */\n async patchState(\n threadIdOrConfig: string | Config,\n metadata: Metadata,\n options?: { signal?: AbortSignal }\n ): Promise<void> {\n let threadId: string;\n\n if (typeof threadIdOrConfig !== \"string\") {\n if (typeof threadIdOrConfig.configurable?.thread_id !== \"string\") {\n throw new Error(\n \"Thread ID is required when updating state with a config.\"\n );\n }\n threadId = threadIdOrConfig.configurable.thread_id;\n } else {\n threadId = threadIdOrConfig;\n }\n\n return this.fetch<void>(`/threads/${threadId}/state`, {\n method: \"PATCH\",\n json: { metadata },\n signal: options?.signal,\n });\n }\n\n /**\n * Get all past states for a thread.\n *\n * @param threadId ID of the thread.\n * @param options Additional options.\n * @returns List of thread states.\n */\n async getHistory<ValuesType = TStateType>(\n threadId: string,\n options?: {\n limit?: number;\n before?: Config;\n checkpoint?: Partial<Omit<Checkpoint, \"thread_id\">>;\n metadata?: Metadata;\n signal?: AbortSignal;\n }\n ): Promise<ThreadState<ValuesType>[]> {\n return this.fetch<ThreadState<ValuesType>[]>(\n `/threads/${threadId}/history`,\n {\n method: \"POST\",\n json: {\n limit: options?.limit ?? 10,\n before: options?.before,\n metadata: options?.metadata,\n checkpoint: options?.checkpoint,\n },\n signal: options?.signal,\n // `getHistory` is a read despite using POST — coalesce the\n // hydrate-time discovery seed when two controllers reconnect to\n // the same thread concurrently. Skipped when `signal` is set.\n dedupe: true,\n }\n );\n }\n\n async *joinStream(\n threadId: string,\n options?: {\n lastEventId?: string;\n streamMode?: ThreadStreamMode | ThreadStreamMode[];\n signal?: AbortSignal;\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): AsyncGenerator<{ id?: string; event: StreamEvent; data: any }> {\n yield* this.streamWithRetry({\n endpoint: `/threads/${threadId}/stream`,\n method: \"GET\",\n signal: options?.signal,\n headers: options?.lastEventId\n ? { \"Last-Event-ID\": options.lastEventId }\n : undefined,\n params: options?.streamMode\n ? { stream_mode: options.streamMode }\n : undefined,\n });\n }\n\n /**\n * Open a protocol stream over the thread-centric v2 protocol.\n *\n * Returns a {@link ThreadStream} with lazy getters\n * (`.messages`, `.values`, `.toolCalls`, `.subgraphs`, `.subagents`,\n * `.output`) and `thread.run.start({ input, ... })` for starting runs.\n * Mirrors the in-process `graph.streamEvents(..., { version: \"v3\" })` API.\n *\n * The thread is bound to `options.assistantId` for its lifetime.\n * The wire transport defaults to SSE; pass `transport: \"websocket\"`\n * in options (or configure `streamProtocol: \"v2-websocket\"` on the\n * client) to use a WebSocket instead.\n *\n * @example New thread (UUID generated client-side)\n * ```ts\n * const thread = client.threads.stream({ assistantId: \"my-agent\" });\n * ```\n *\n * @example Attach to an existing thread\n * ```ts\n * const thread = client.threads.stream(threadId, { assistantId: \"my-agent\" });\n * ```\n *\n * @example WebSocket transport\n * ```ts\n * const thread = client.threads.stream({\n * assistantId: \"my-agent\",\n * transport: \"websocket\",\n * });\n * ```\n */\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadId: string,\n options: ThreadStreamOptions\n ): ThreadStream<TExtensions>;\n stream<TExtensions extends Record<string, unknown> = Record<string, unknown>>(\n threadIdOrOptions: string | ThreadStreamOptions,\n maybeOptions?: ThreadStreamOptions\n ): ThreadStream<TExtensions> {\n const { threadId, options } =\n typeof threadIdOrOptions === \"string\"\n ? {\n threadId: threadIdOrOptions,\n options: maybeOptions as ThreadStreamOptions,\n }\n : { threadId: uuidv7(), options: threadIdOrOptions };\n\n // `transport` accepts either a preset string (`\"sse\"` / `\"websocket\"`)\n // or a custom {@link AgentServerAdapter}. A custom adapter replaces\n // the built-in factories entirely — this is the seam that lets users\n // point `useStream` at any agent server (including the thin wrappers\n // produced by `HttpAgentServerAdapter`).\n // When callers supply `fetch`, use it verbatim (tests, auth shims). Otherwise\n // route protocol HTTP and media URL fetches through AsyncCaller like REST.\n const userFetch = options.fetch;\n const protocolFetch =\n userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller);\n\n let transport: TransportAdapter;\n if (options.transport != null && typeof options.transport !== \"string\") {\n transport = options.transport;\n } else {\n const transportKind: ThreadStreamTransportKind =\n options.transport ??\n (this.streamProtocol === \"v2-websocket\" ? \"websocket\" : \"sse\");\n const maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\n\n /**\n * Common options for both transports.\n */\n const commonOpts = {\n apiUrl: this.apiUrl,\n threadId,\n defaultHeaders: this.defaultHeaders,\n onRequest: this.onRequest,\n maxReconnectAttempts,\n reconnectDelayMs: options.reconnectDelayMs,\n onReconnect: options.onReconnect,\n };\n\n transport =\n transportKind === \"websocket\"\n ? new ProtocolWebSocketTransportAdapter({\n ...commonOpts,\n webSocketFactory: options.webSocketFactory,\n })\n : new ProtocolSseTransportAdapter({\n ...commonOpts,\n fetch: userFetch,\n asyncCaller: userFetch ? undefined : this.asyncCaller,\n });\n }\n\n return new ThreadStream<TExtensions>(transport, {\n ...options,\n fetch: protocolFetch,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BaseClient } from "../base.js";
|
|
2
2
|
import { ThreadStream } from "../stream/index.js";
|
|
3
|
-
import { ProtocolSseTransportAdapter } from "../stream/transport/http.js";
|
|
4
3
|
import { ProtocolWebSocketTransportAdapter } from "../stream/transport/websocket.js";
|
|
4
|
+
import { ProtocolSseTransportAdapter } from "../stream/transport/http.js";
|
|
5
5
|
import { v7 } from "uuid";
|
|
6
6
|
//#region src/client/threads/index.ts
|
|
7
7
|
var ThreadsClient = class extends BaseClient {
|
|
@@ -248,22 +248,38 @@ var ThreadsClient = class extends BaseClient {
|
|
|
248
248
|
threadId: v7(),
|
|
249
249
|
options: threadIdOrOptions
|
|
250
250
|
};
|
|
251
|
+
const userFetch = options.fetch;
|
|
252
|
+
const protocolFetch = userFetch ?? this.asyncCaller.fetch.bind(this.asyncCaller);
|
|
251
253
|
let transport;
|
|
252
254
|
if (options.transport != null && typeof options.transport !== "string") transport = options.transport;
|
|
253
|
-
else
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
255
|
+
else {
|
|
256
|
+
const transportKind = options.transport ?? (this.streamProtocol === "v2-websocket" ? "websocket" : "sse");
|
|
257
|
+
const maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
|
|
258
|
+
/**
|
|
259
|
+
* Common options for both transports.
|
|
260
|
+
*/
|
|
261
|
+
const commonOpts = {
|
|
262
|
+
apiUrl: this.apiUrl,
|
|
263
|
+
threadId,
|
|
264
|
+
defaultHeaders: this.defaultHeaders,
|
|
265
|
+
onRequest: this.onRequest,
|
|
266
|
+
maxReconnectAttempts,
|
|
267
|
+
reconnectDelayMs: options.reconnectDelayMs,
|
|
268
|
+
onReconnect: options.onReconnect
|
|
269
|
+
};
|
|
270
|
+
transport = transportKind === "websocket" ? new ProtocolWebSocketTransportAdapter({
|
|
271
|
+
...commonOpts,
|
|
272
|
+
webSocketFactory: options.webSocketFactory
|
|
273
|
+
}) : new ProtocolSseTransportAdapter({
|
|
274
|
+
...commonOpts,
|
|
275
|
+
fetch: userFetch,
|
|
276
|
+
asyncCaller: userFetch ? void 0 : this.asyncCaller
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
return new ThreadStream(transport, {
|
|
280
|
+
...options,
|
|
281
|
+
fetch: protocolFetch
|
|
265
282
|
});
|
|
266
|
-
return new ThreadStream(transport, options);
|
|
267
283
|
}
|
|
268
284
|
};
|
|
269
285
|
//#endregion
|