@langchain/langgraph-sdk 0.1.4 → 0.1.6
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/CHANGELOG.md +14 -0
- package/dist/react/index.cjs +3 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +1 -0
- package/dist/react/manager.cjs +12 -5
- package/dist/react/manager.d.ts +1 -0
- package/dist/react/manager.js +12 -5
- package/dist/react/stream.cjs +12 -460
- package/dist/react/stream.custom.cjs +148 -0
- package/dist/react/stream.custom.d.ts +41 -0
- package/dist/react/stream.custom.js +142 -0
- package/dist/react/stream.d.ts +61 -1
- package/dist/react/stream.js +13 -460
- package/dist/react/stream.lgp.cjs +485 -0
- package/dist/react/stream.lgp.d.ts +7 -0
- package/dist/react/stream.lgp.js +481 -0
- package/dist/react/thread.cjs +19 -0
- package/dist/react/thread.d.ts +4 -0
- package/dist/react/thread.js +15 -0
- package/dist/react/types.d.ts +24 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @langchain/langgraph-sdk
|
|
2
2
|
|
|
3
|
+
## 0.1.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5603276: Fix `useStream()` keeping stale thread history when switching threads mid-stream (#1632)
|
|
8
|
+
- b65c80b: Add `transport` option to useStream, allowing custom endpoints, that emit compatible Server-Sent Events to be used with `useStream`.
|
|
9
|
+
- 5603276: Fix `stop()` behavior when cancelling a resumable stream via `useStream()` (#1610)
|
|
10
|
+
|
|
11
|
+
## 0.1.5
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- f21fd04: Fix mutate function in `onCustomEvent` and in `onUpdateEvent` receiving incorrect previous value
|
|
16
|
+
|
|
3
17
|
## 0.1.4
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/react/index.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useStream = void 0;
|
|
3
|
+
exports.FetchStreamTransport = exports.useStream = void 0;
|
|
4
4
|
var stream_js_1 = require("./stream.cjs");
|
|
5
5
|
Object.defineProperty(exports, "useStream", { enumerable: true, get: function () { return stream_js_1.useStream; } });
|
|
6
|
+
var stream_custom_js_1 = require("./stream.custom.cjs");
|
|
7
|
+
Object.defineProperty(exports, "FetchStreamTransport", { enumerable: true, get: function () { return stream_custom_js_1.FetchStreamTransport; } });
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { useStream } from "./stream.js";
|
|
2
|
-
export
|
|
2
|
+
export { FetchStreamTransport } from "./stream.custom.js";
|
|
3
|
+
export type { MessageMetadata, UseStream, UseStreamOptions, UseStreamCustom, UseStreamCustomOptions, UseStreamTransport, } from "./types.js";
|
package/dist/react/index.js
CHANGED
package/dist/react/manager.cjs
CHANGED
|
@@ -83,7 +83,10 @@ class StreamManager {
|
|
|
83
83
|
writable: true,
|
|
84
84
|
value: (kind, historyValues) => {
|
|
85
85
|
return (update) => {
|
|
86
|
-
const prev = {
|
|
86
|
+
const prev = {
|
|
87
|
+
...historyValues,
|
|
88
|
+
...(this.state.values ?? [null, "stream"])[0],
|
|
89
|
+
};
|
|
87
90
|
const next = typeof update === "function" ? update(prev) : update;
|
|
88
91
|
this.setStreamValues({ ...prev, ...next }, kind);
|
|
89
92
|
};
|
|
@@ -186,6 +189,7 @@ class StreamManager {
|
|
|
186
189
|
finally {
|
|
187
190
|
this.setState({ isLoading: false });
|
|
188
191
|
this.abortRef = new AbortController();
|
|
192
|
+
options.onFinish?.();
|
|
189
193
|
}
|
|
190
194
|
}
|
|
191
195
|
});
|
|
@@ -194,10 +198,8 @@ class StreamManager {
|
|
|
194
198
|
configurable: true,
|
|
195
199
|
writable: true,
|
|
196
200
|
value: async (historyValues, options) => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.abortRef = new AbortController();
|
|
200
|
-
}
|
|
201
|
+
this.abortRef.abort();
|
|
202
|
+
this.abortRef = new AbortController();
|
|
201
203
|
options.onStop?.({ mutate: this.getMutateFn("stop", historyValues) });
|
|
202
204
|
}
|
|
203
205
|
});
|
|
@@ -206,7 +208,12 @@ class StreamManager {
|
|
|
206
208
|
configurable: true,
|
|
207
209
|
writable: true,
|
|
208
210
|
value: () => {
|
|
211
|
+
// Cancel any running streams
|
|
212
|
+
this.abortRef.abort();
|
|
213
|
+
this.abortRef = new AbortController();
|
|
214
|
+
// Set the stream state to null
|
|
209
215
|
this.setState({ error: undefined, values: null });
|
|
216
|
+
// Clear any pending messages
|
|
210
217
|
this.messages.clear();
|
|
211
218
|
}
|
|
212
219
|
});
|
package/dist/react/manager.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ export declare class StreamManager<StateType extends Record<string, unknown>, Ba
|
|
|
75
75
|
callbacks: StreamManagerEventCallbacks<StateType, Bag>;
|
|
76
76
|
onSuccess: () => StateType | null | undefined | void | Promise<StateType | null | undefined | void>;
|
|
77
77
|
onError: (error: unknown) => void | Promise<void>;
|
|
78
|
+
onFinish?: () => void;
|
|
78
79
|
}) => Promise<void>;
|
|
79
80
|
stop: (historyValues: StateType, options: {
|
|
80
81
|
onStop?: (options: {
|
package/dist/react/manager.js
CHANGED
|
@@ -80,7 +80,10 @@ export class StreamManager {
|
|
|
80
80
|
writable: true,
|
|
81
81
|
value: (kind, historyValues) => {
|
|
82
82
|
return (update) => {
|
|
83
|
-
const prev = {
|
|
83
|
+
const prev = {
|
|
84
|
+
...historyValues,
|
|
85
|
+
...(this.state.values ?? [null, "stream"])[0],
|
|
86
|
+
};
|
|
84
87
|
const next = typeof update === "function" ? update(prev) : update;
|
|
85
88
|
this.setStreamValues({ ...prev, ...next }, kind);
|
|
86
89
|
};
|
|
@@ -183,6 +186,7 @@ export class StreamManager {
|
|
|
183
186
|
finally {
|
|
184
187
|
this.setState({ isLoading: false });
|
|
185
188
|
this.abortRef = new AbortController();
|
|
189
|
+
options.onFinish?.();
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
192
|
});
|
|
@@ -191,10 +195,8 @@ export class StreamManager {
|
|
|
191
195
|
configurable: true,
|
|
192
196
|
writable: true,
|
|
193
197
|
value: async (historyValues, options) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.abortRef = new AbortController();
|
|
197
|
-
}
|
|
198
|
+
this.abortRef.abort();
|
|
199
|
+
this.abortRef = new AbortController();
|
|
198
200
|
options.onStop?.({ mutate: this.getMutateFn("stop", historyValues) });
|
|
199
201
|
}
|
|
200
202
|
});
|
|
@@ -203,7 +205,12 @@ export class StreamManager {
|
|
|
203
205
|
configurable: true,
|
|
204
206
|
writable: true,
|
|
205
207
|
value: () => {
|
|
208
|
+
// Cancel any running streams
|
|
209
|
+
this.abortRef.abort();
|
|
210
|
+
this.abortRef = new AbortController();
|
|
211
|
+
// Set the stream state to null
|
|
206
212
|
this.setState({ error: undefined, values: null });
|
|
213
|
+
// Clear any pending messages
|
|
207
214
|
this.messages.clear();
|
|
208
215
|
}
|
|
209
216
|
});
|
package/dist/react/stream.cjs
CHANGED
|
@@ -1,467 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */
|
|
3
|
-
"use client";
|
|
4
|
-
/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.useStream = useStream;
|
|
7
4
|
const react_1 = require("react");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const client_js_1 = require("../client.cjs");
|
|
13
|
-
const messages_js_1 = require("./messages.cjs");
|
|
14
|
-
function fetchHistory(client, threadId, options) {
|
|
15
|
-
if (options?.limit === false) {
|
|
16
|
-
return client.threads.getState(threadId).then((state) => {
|
|
17
|
-
if (state.checkpoint == null)
|
|
18
|
-
return [];
|
|
19
|
-
return [state];
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
const limit = typeof options?.limit === "number" ? options.limit : 10;
|
|
23
|
-
return client.threads.getHistory(threadId, { limit });
|
|
24
|
-
}
|
|
25
|
-
function useThreadHistory(threadId, client, limit, clearCallbackRef, submittingRef, onErrorRef) {
|
|
26
|
-
const [history, setHistory] = (0, react_1.useState)(undefined);
|
|
27
|
-
const [isLoading, setIsLoading] = (0, react_1.useState)(() => {
|
|
28
|
-
if (threadId == null)
|
|
29
|
-
return false;
|
|
30
|
-
return true;
|
|
31
|
-
});
|
|
32
|
-
const [error, setError] = (0, react_1.useState)(undefined);
|
|
33
|
-
const clientHash = (0, client_js_1.getClientConfigHash)(client);
|
|
34
|
-
const clientRef = (0, react_1.useRef)(client);
|
|
35
|
-
clientRef.current = client;
|
|
36
|
-
const fetcher = (0, react_1.useCallback)((threadId) => {
|
|
37
|
-
if (threadId != null) {
|
|
38
|
-
const client = clientRef.current;
|
|
39
|
-
setIsLoading(true);
|
|
40
|
-
return fetchHistory(client, threadId, {
|
|
41
|
-
limit,
|
|
42
|
-
})
|
|
43
|
-
.then((history) => {
|
|
44
|
-
setHistory(history);
|
|
45
|
-
return history;
|
|
46
|
-
}, (error) => {
|
|
47
|
-
setError(error);
|
|
48
|
-
onErrorRef.current?.(error);
|
|
49
|
-
return Promise.reject(error);
|
|
50
|
-
})
|
|
51
|
-
.finally(() => {
|
|
52
|
-
setIsLoading(false);
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
setHistory(undefined);
|
|
56
|
-
setError(undefined);
|
|
57
|
-
setIsLoading(false);
|
|
58
|
-
clearCallbackRef.current?.();
|
|
59
|
-
return Promise.resolve([]);
|
|
60
|
-
}, [clearCallbackRef, onErrorRef, limit]);
|
|
61
|
-
(0, react_1.useEffect)(() => {
|
|
62
|
-
if (submittingRef.current)
|
|
63
|
-
return;
|
|
64
|
-
void fetcher(threadId);
|
|
65
|
-
}, [fetcher, submittingRef, clientHash, limit, threadId]);
|
|
66
|
-
return {
|
|
67
|
-
data: history,
|
|
68
|
-
isLoading,
|
|
69
|
-
error,
|
|
70
|
-
mutate: (mutateId) => fetcher(mutateId ?? threadId),
|
|
71
|
-
};
|
|
5
|
+
const stream_lgp_js_1 = require("./stream.lgp.cjs");
|
|
6
|
+
const stream_custom_js_1 = require("./stream.custom.cjs");
|
|
7
|
+
function isCustomOptions(options) {
|
|
8
|
+
return "transport" in options;
|
|
72
9
|
}
|
|
73
|
-
const useControllableThreadId = (options) => {
|
|
74
|
-
const [localThreadId, _setLocalThreadId] = (0, react_1.useState)(options?.threadId ?? null);
|
|
75
|
-
const onThreadIdRef = (0, react_1.useRef)(options?.onThreadId);
|
|
76
|
-
onThreadIdRef.current = options?.onThreadId;
|
|
77
|
-
const onThreadId = (0, react_1.useCallback)((threadId) => {
|
|
78
|
-
_setLocalThreadId(threadId);
|
|
79
|
-
onThreadIdRef.current?.(threadId);
|
|
80
|
-
}, []);
|
|
81
|
-
if (!options || !("threadId" in options)) {
|
|
82
|
-
return [localThreadId, onThreadId];
|
|
83
|
-
}
|
|
84
|
-
return [options.threadId ?? null, onThreadId];
|
|
85
|
-
};
|
|
86
10
|
function useStream(options) {
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return storage();
|
|
96
|
-
return null;
|
|
97
|
-
}, []);
|
|
98
|
-
const client = (0, react_1.useMemo)(() => options.client ??
|
|
99
|
-
new client_js_1.Client({
|
|
100
|
-
apiUrl: options.apiUrl,
|
|
101
|
-
apiKey: options.apiKey,
|
|
102
|
-
callerOptions: options.callerOptions,
|
|
103
|
-
defaultHeaders: options.defaultHeaders,
|
|
104
|
-
}), [
|
|
105
|
-
options.client,
|
|
106
|
-
options.apiKey,
|
|
107
|
-
options.apiUrl,
|
|
108
|
-
options.callerOptions,
|
|
109
|
-
options.defaultHeaders,
|
|
110
|
-
]);
|
|
111
|
-
const [messageManager] = (0, react_1.useState)(() => new messages_js_1.MessageTupleManager());
|
|
112
|
-
const [stream] = (0, react_1.useState)(() => new manager_js_1.StreamManager(messageManager));
|
|
113
|
-
(0, react_1.useSyncExternalStore)(stream.subscribe, stream.getSnapshot, stream.getSnapshot);
|
|
114
|
-
const [threadId, onThreadId] = useControllableThreadId(options);
|
|
115
|
-
const trackStreamModeRef = (0, react_1.useRef)([]);
|
|
116
|
-
const trackStreamMode = (0, react_1.useCallback)((...mode) => {
|
|
117
|
-
const ref = trackStreamModeRef.current;
|
|
118
|
-
for (const m of mode) {
|
|
119
|
-
if (!ref.includes(m))
|
|
120
|
-
ref.push(m);
|
|
121
|
-
}
|
|
122
|
-
}, []);
|
|
123
|
-
const hasUpdateListener = options.onUpdateEvent != null;
|
|
124
|
-
const hasCustomListener = options.onCustomEvent != null;
|
|
125
|
-
const hasLangChainListener = options.onLangChainEvent != null;
|
|
126
|
-
const hasDebugListener = options.onDebugEvent != null;
|
|
127
|
-
const hasCheckpointListener = options.onCheckpointEvent != null;
|
|
128
|
-
const hasTaskListener = options.onTaskEvent != null;
|
|
129
|
-
const callbackStreamMode = (0, react_1.useMemo)(() => {
|
|
130
|
-
const modes = [];
|
|
131
|
-
if (hasUpdateListener)
|
|
132
|
-
modes.push("updates");
|
|
133
|
-
if (hasCustomListener)
|
|
134
|
-
modes.push("custom");
|
|
135
|
-
if (hasLangChainListener)
|
|
136
|
-
modes.push("events");
|
|
137
|
-
if (hasDebugListener)
|
|
138
|
-
modes.push("debug");
|
|
139
|
-
if (hasCheckpointListener)
|
|
140
|
-
modes.push("checkpoints");
|
|
141
|
-
if (hasTaskListener)
|
|
142
|
-
modes.push("tasks");
|
|
143
|
-
return modes;
|
|
144
|
-
}, [
|
|
145
|
-
hasUpdateListener,
|
|
146
|
-
hasCustomListener,
|
|
147
|
-
hasLangChainListener,
|
|
148
|
-
hasDebugListener,
|
|
149
|
-
hasCheckpointListener,
|
|
150
|
-
hasTaskListener,
|
|
151
|
-
]);
|
|
152
|
-
const clearCallbackRef = (0, react_1.useRef)(null);
|
|
153
|
-
clearCallbackRef.current = stream.clear;
|
|
154
|
-
const submittingRef = (0, react_1.useRef)(false);
|
|
155
|
-
submittingRef.current = stream.isLoading;
|
|
156
|
-
const onErrorRef = (0, react_1.useRef)(undefined);
|
|
157
|
-
onErrorRef.current = options.onError;
|
|
158
|
-
const historyLimit = typeof options.fetchStateHistory === "object" &&
|
|
159
|
-
options.fetchStateHistory != null
|
|
160
|
-
? options.fetchStateHistory.limit ?? false
|
|
161
|
-
: options.fetchStateHistory ?? false;
|
|
162
|
-
const history = useThreadHistory(threadId, client, historyLimit, clearCallbackRef, submittingRef, onErrorRef);
|
|
163
|
-
const getMessages = (value) => {
|
|
164
|
-
const messagesKey = options.messagesKey ?? "messages";
|
|
165
|
-
return Array.isArray(value[messagesKey]) ? value[messagesKey] : [];
|
|
166
|
-
};
|
|
167
|
-
const setMessages = (current, messages) => {
|
|
168
|
-
const messagesKey = options.messagesKey ?? "messages";
|
|
169
|
-
return { ...current, [messagesKey]: messages };
|
|
170
|
-
};
|
|
171
|
-
const [branch, setBranch] = (0, react_1.useState)("");
|
|
172
|
-
const branchContext = (0, branching_js_1.getBranchContext)(branch, history.data);
|
|
173
|
-
const historyValues = branchContext.threadHead?.values ??
|
|
174
|
-
options.initialValues ??
|
|
175
|
-
{};
|
|
176
|
-
const historyError = (() => {
|
|
177
|
-
const error = branchContext.threadHead?.tasks?.at(-1)?.error;
|
|
178
|
-
if (error == null)
|
|
179
|
-
return undefined;
|
|
180
|
-
try {
|
|
181
|
-
const parsed = JSON.parse(error);
|
|
182
|
-
if (errors_js_1.StreamError.isStructuredError(parsed))
|
|
183
|
-
return new errors_js_1.StreamError(parsed);
|
|
184
|
-
return parsed;
|
|
185
|
-
}
|
|
186
|
-
catch {
|
|
187
|
-
// do nothing
|
|
188
|
-
}
|
|
189
|
-
return error;
|
|
190
|
-
})();
|
|
191
|
-
const messageMetadata = (() => {
|
|
192
|
-
const alreadyShown = new Set();
|
|
193
|
-
return getMessages(historyValues).map((message, idx) => {
|
|
194
|
-
const messageId = message.id ?? idx;
|
|
195
|
-
// Find the first checkpoint where the message was seen
|
|
196
|
-
const firstSeenState = (0, utils_js_1.findLast)(history.data ?? [], (state) => getMessages(state.values)
|
|
197
|
-
.map((m, idx) => m.id ?? idx)
|
|
198
|
-
.includes(messageId));
|
|
199
|
-
const checkpointId = firstSeenState?.checkpoint?.checkpoint_id;
|
|
200
|
-
let branch = checkpointId != null
|
|
201
|
-
? branchContext.branchByCheckpoint[checkpointId]
|
|
202
|
-
: undefined;
|
|
203
|
-
if (!branch?.branch?.length)
|
|
204
|
-
branch = undefined;
|
|
205
|
-
// serialize branches
|
|
206
|
-
const optionsShown = branch?.branchOptions?.flat(2).join(",");
|
|
207
|
-
if (optionsShown) {
|
|
208
|
-
if (alreadyShown.has(optionsShown))
|
|
209
|
-
branch = undefined;
|
|
210
|
-
alreadyShown.add(optionsShown);
|
|
211
|
-
}
|
|
212
|
-
return {
|
|
213
|
-
messageId: messageId.toString(),
|
|
214
|
-
firstSeenState,
|
|
215
|
-
branch: branch?.branch,
|
|
216
|
-
branchOptions: branch?.branchOptions,
|
|
217
|
-
};
|
|
218
|
-
});
|
|
219
|
-
})();
|
|
220
|
-
const stop = () => stream.stop(historyValues, { onStop: options.onStop });
|
|
221
|
-
// --- TRANSPORT ---
|
|
222
|
-
const submit = async (values, submitOptions) => {
|
|
223
|
-
// Unbranch things
|
|
224
|
-
const checkpointId = submitOptions?.checkpoint?.checkpoint_id;
|
|
225
|
-
setBranch(checkpointId != null
|
|
226
|
-
? branchContext.branchByCheckpoint[checkpointId]?.branch ?? ""
|
|
227
|
-
: "");
|
|
228
|
-
stream.setStreamValues(() => {
|
|
229
|
-
if (submitOptions?.optimisticValues != null) {
|
|
230
|
-
return {
|
|
231
|
-
...historyValues,
|
|
232
|
-
...(typeof submitOptions.optimisticValues === "function"
|
|
233
|
-
? submitOptions.optimisticValues(historyValues)
|
|
234
|
-
: submitOptions.optimisticValues),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return { ...historyValues };
|
|
238
|
-
});
|
|
239
|
-
// When `fetchStateHistory` is requested, thus we assume that branching
|
|
240
|
-
// is enabled. We then need to include the implicit branch.
|
|
241
|
-
const includeImplicitBranch = historyLimit === true || typeof historyLimit === "number";
|
|
242
|
-
let callbackMeta;
|
|
243
|
-
let rejoinKey;
|
|
244
|
-
let usableThreadId = threadId;
|
|
245
|
-
await stream.start(async (signal) => {
|
|
246
|
-
if (!usableThreadId) {
|
|
247
|
-
const thread = await client.threads.create({
|
|
248
|
-
threadId: submitOptions?.threadId,
|
|
249
|
-
metadata: submitOptions?.metadata,
|
|
250
|
-
});
|
|
251
|
-
onThreadId(thread.thread_id);
|
|
252
|
-
usableThreadId = thread.thread_id;
|
|
253
|
-
}
|
|
254
|
-
if (!usableThreadId) {
|
|
255
|
-
throw new Error("Failed to obtain valid thread ID.");
|
|
256
|
-
}
|
|
257
|
-
const streamMode = (0, utils_js_1.unique)([
|
|
258
|
-
...(submitOptions?.streamMode ?? []),
|
|
259
|
-
...trackStreamModeRef.current,
|
|
260
|
-
...callbackStreamMode,
|
|
261
|
-
]);
|
|
262
|
-
let checkpoint = submitOptions?.checkpoint ??
|
|
263
|
-
(includeImplicitBranch
|
|
264
|
-
? branchContext.threadHead?.checkpoint
|
|
265
|
-
: undefined) ??
|
|
266
|
-
undefined;
|
|
267
|
-
// Avoid specifying a checkpoint if user explicitly set it to null
|
|
268
|
-
if (submitOptions?.checkpoint === null)
|
|
269
|
-
checkpoint = undefined;
|
|
270
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
271
|
-
// @ts-expect-error
|
|
272
|
-
if (checkpoint != null)
|
|
273
|
-
delete checkpoint.thread_id;
|
|
274
|
-
const streamResumable = submitOptions?.streamResumable ?? !!runMetadataStorage;
|
|
275
|
-
return client.runs.stream(usableThreadId, options.assistantId, {
|
|
276
|
-
input: values,
|
|
277
|
-
config: submitOptions?.config,
|
|
278
|
-
context: submitOptions?.context,
|
|
279
|
-
command: submitOptions?.command,
|
|
280
|
-
interruptBefore: submitOptions?.interruptBefore,
|
|
281
|
-
interruptAfter: submitOptions?.interruptAfter,
|
|
282
|
-
metadata: submitOptions?.metadata,
|
|
283
|
-
multitaskStrategy: submitOptions?.multitaskStrategy,
|
|
284
|
-
onCompletion: submitOptions?.onCompletion,
|
|
285
|
-
onDisconnect: submitOptions?.onDisconnect ??
|
|
286
|
-
(streamResumable ? "continue" : "cancel"),
|
|
287
|
-
signal,
|
|
288
|
-
checkpoint,
|
|
289
|
-
streamMode,
|
|
290
|
-
streamSubgraphs: submitOptions?.streamSubgraphs,
|
|
291
|
-
streamResumable,
|
|
292
|
-
durability: submitOptions?.durability,
|
|
293
|
-
onRunCreated(params) {
|
|
294
|
-
callbackMeta = {
|
|
295
|
-
run_id: params.run_id,
|
|
296
|
-
thread_id: params.thread_id ?? usableThreadId,
|
|
297
|
-
};
|
|
298
|
-
if (runMetadataStorage) {
|
|
299
|
-
rejoinKey = `lg:stream:${usableThreadId}`;
|
|
300
|
-
runMetadataStorage.setItem(rejoinKey, callbackMeta.run_id);
|
|
301
|
-
}
|
|
302
|
-
options.onCreated?.(callbackMeta);
|
|
303
|
-
},
|
|
304
|
-
});
|
|
305
|
-
}, {
|
|
306
|
-
getMessages,
|
|
307
|
-
setMessages,
|
|
308
|
-
initialValues: historyValues,
|
|
309
|
-
callbacks: options,
|
|
310
|
-
async onSuccess() {
|
|
311
|
-
if (rejoinKey)
|
|
312
|
-
runMetadataStorage?.removeItem(rejoinKey);
|
|
313
|
-
const shouldRefetch =
|
|
314
|
-
// We're expecting the whole thread state in onFinish
|
|
315
|
-
options.onFinish != null ||
|
|
316
|
-
// We're fetching history, thus we need the latest checkpoint
|
|
317
|
-
// to ensure we're not accidentally submitting to a wrong branch
|
|
318
|
-
includeImplicitBranch;
|
|
319
|
-
if (shouldRefetch) {
|
|
320
|
-
const newHistory = await history.mutate(usableThreadId);
|
|
321
|
-
const lastHead = newHistory.at(0);
|
|
322
|
-
if (lastHead) {
|
|
323
|
-
// We now have the latest update from /history
|
|
324
|
-
// Thus we can clear the local stream state
|
|
325
|
-
options.onFinish?.(lastHead, callbackMeta);
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
return undefined;
|
|
330
|
-
},
|
|
331
|
-
onError(error) {
|
|
332
|
-
options.onError?.(error, callbackMeta);
|
|
333
|
-
},
|
|
334
|
-
});
|
|
335
|
-
};
|
|
336
|
-
const joinStream = async (runId, lastEventId, joinOptions) => {
|
|
337
|
-
// eslint-disable-next-line no-param-reassign
|
|
338
|
-
lastEventId ??= "-1";
|
|
339
|
-
if (!threadId)
|
|
340
|
-
return;
|
|
341
|
-
const callbackMeta = {
|
|
342
|
-
thread_id: threadId,
|
|
343
|
-
run_id: runId,
|
|
344
|
-
};
|
|
345
|
-
await stream.start(async (signal) => {
|
|
346
|
-
return client.runs.joinStream(threadId, runId, {
|
|
347
|
-
signal,
|
|
348
|
-
lastEventId,
|
|
349
|
-
streamMode: joinOptions?.streamMode,
|
|
350
|
-
});
|
|
351
|
-
}, {
|
|
352
|
-
getMessages,
|
|
353
|
-
setMessages,
|
|
354
|
-
initialValues: historyValues,
|
|
355
|
-
callbacks: options,
|
|
356
|
-
async onSuccess() {
|
|
357
|
-
runMetadataStorage?.removeItem(`lg:stream:${threadId}`);
|
|
358
|
-
const newHistory = await history.mutate(threadId);
|
|
359
|
-
const lastHead = newHistory.at(0);
|
|
360
|
-
if (lastHead)
|
|
361
|
-
options.onFinish?.(lastHead, callbackMeta);
|
|
362
|
-
},
|
|
363
|
-
onError(error) {
|
|
364
|
-
options.onError?.(error, callbackMeta);
|
|
365
|
-
},
|
|
366
|
-
});
|
|
367
|
-
};
|
|
368
|
-
const reconnectKey = (0, react_1.useMemo)(() => {
|
|
369
|
-
if (!runMetadataStorage || stream.isLoading)
|
|
370
|
-
return undefined;
|
|
371
|
-
if (typeof window === "undefined")
|
|
372
|
-
return undefined;
|
|
373
|
-
const runId = runMetadataStorage?.getItem(`lg:stream:${threadId}`);
|
|
374
|
-
if (!runId)
|
|
375
|
-
return undefined;
|
|
376
|
-
return { runId, threadId };
|
|
377
|
-
}, [runMetadataStorage, stream.isLoading, threadId]);
|
|
378
|
-
const shouldReconnect = !!runMetadataStorage;
|
|
379
|
-
const reconnectRef = (0, react_1.useRef)({ threadId, shouldReconnect });
|
|
380
|
-
const joinStreamRef = (0, react_1.useRef)(joinStream);
|
|
381
|
-
joinStreamRef.current = joinStream;
|
|
382
|
-
(0, react_1.useEffect)(() => {
|
|
383
|
-
// reset shouldReconnect when switching threads
|
|
384
|
-
if (reconnectRef.current.threadId !== threadId) {
|
|
385
|
-
reconnectRef.current = { threadId, shouldReconnect };
|
|
386
|
-
}
|
|
387
|
-
}, [threadId, shouldReconnect]);
|
|
388
|
-
(0, react_1.useEffect)(() => {
|
|
389
|
-
if (reconnectKey && reconnectRef.current.shouldReconnect) {
|
|
390
|
-
reconnectRef.current.shouldReconnect = false;
|
|
391
|
-
void joinStreamRef.current?.(reconnectKey.runId);
|
|
392
|
-
}
|
|
393
|
-
}, [reconnectKey]);
|
|
394
|
-
// --- END TRANSPORT ---
|
|
395
|
-
const error = stream.error ?? historyError ?? history.error;
|
|
396
|
-
const values = stream.values ?? historyValues;
|
|
397
|
-
return {
|
|
398
|
-
get values() {
|
|
399
|
-
trackStreamMode("values");
|
|
400
|
-
return values;
|
|
401
|
-
},
|
|
402
|
-
client,
|
|
403
|
-
assistantId: options.assistantId,
|
|
404
|
-
error,
|
|
405
|
-
isLoading: stream.isLoading,
|
|
406
|
-
stop,
|
|
407
|
-
submit,
|
|
408
|
-
joinStream,
|
|
409
|
-
branch,
|
|
410
|
-
setBranch,
|
|
411
|
-
get history() {
|
|
412
|
-
if (historyLimit === false) {
|
|
413
|
-
throw new Error("`fetchStateHistory` must be set to `true` to use `history`");
|
|
414
|
-
}
|
|
415
|
-
return branchContext.flatHistory;
|
|
416
|
-
},
|
|
417
|
-
isThreadLoading: history.isLoading && history.data == null,
|
|
418
|
-
get experimental_branchTree() {
|
|
419
|
-
if (historyLimit === false) {
|
|
420
|
-
throw new Error("`fetchStateHistory` must be set to `true` to use `experimental_branchTree`");
|
|
421
|
-
}
|
|
422
|
-
return branchContext.branchTree;
|
|
423
|
-
},
|
|
424
|
-
get interrupt() {
|
|
425
|
-
if (values != null &&
|
|
426
|
-
"__interrupt__" in values &&
|
|
427
|
-
Array.isArray(values.__interrupt__)) {
|
|
428
|
-
const valueInterrupts = values.__interrupt__;
|
|
429
|
-
if (valueInterrupts.length === 0)
|
|
430
|
-
return { when: "breakpoint" };
|
|
431
|
-
if (valueInterrupts.length === 1)
|
|
432
|
-
return valueInterrupts[0];
|
|
433
|
-
// TODO: fix the typing of interrupts if multiple interrupts are returned
|
|
434
|
-
return valueInterrupts;
|
|
435
|
-
}
|
|
436
|
-
// If we're deferring to old interrupt detection logic, don't show the interrupt if the stream is loading
|
|
437
|
-
if (stream.isLoading)
|
|
438
|
-
return undefined;
|
|
439
|
-
const interrupts = branchContext.threadHead?.tasks?.at(-1)?.interrupts;
|
|
440
|
-
if (interrupts == null || interrupts.length === 0) {
|
|
441
|
-
// check if there's a next task present
|
|
442
|
-
const next = branchContext.threadHead?.next ?? [];
|
|
443
|
-
if (!next.length || error != null)
|
|
444
|
-
return undefined;
|
|
445
|
-
return { when: "breakpoint" };
|
|
446
|
-
}
|
|
447
|
-
// Return only the current interrupt
|
|
448
|
-
return interrupts.at(-1);
|
|
449
|
-
},
|
|
450
|
-
get messages() {
|
|
451
|
-
trackStreamMode("messages-tuple", "values");
|
|
452
|
-
return getMessages(values);
|
|
453
|
-
},
|
|
454
|
-
getMessagesMetadata(message, index) {
|
|
455
|
-
trackStreamMode("values");
|
|
456
|
-
const streamMetadata = messageManager.get(message.id)?.metadata;
|
|
457
|
-
const historyMetadata = messageMetadata?.find((m) => m.messageId === (message.id ?? index));
|
|
458
|
-
if (streamMetadata != null || historyMetadata != null) {
|
|
459
|
-
return {
|
|
460
|
-
...historyMetadata,
|
|
461
|
-
streamMetadata,
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
return undefined;
|
|
465
|
-
},
|
|
466
|
-
};
|
|
11
|
+
// Store this in useState to make sure we're not changing the implementation in re-renders
|
|
12
|
+
const [isCustom] = (0, react_1.useState)(isCustomOptions(options));
|
|
13
|
+
if (isCustom) {
|
|
14
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
15
|
+
return (0, stream_custom_js_1.useStreamCustom)(options);
|
|
16
|
+
}
|
|
17
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
18
|
+
return (0, stream_lgp_js_1.useStreamLGP)(options);
|
|
467
19
|
}
|