@assistant-ui/react-langchain 0.0.15 → 0.0.17
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/convertMessages.d.ts +37 -3
- package/dist/convertMessages.d.ts.map +1 -1
- package/dist/convertMessages.js +57 -11
- package/dist/convertMessages.js.map +1 -1
- package/dist/findForkCheckpointInHistory.d.ts +26 -0
- package/dist/findForkCheckpointInHistory.d.ts.map +1 -0
- package/dist/findForkCheckpointInHistory.js +34 -0
- package/dist/findForkCheckpointInHistory.js.map +1 -0
- package/dist/hooks.d.ts +88 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +99 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -2
- package/dist/resolveForkCheckpoint.d.ts +17 -0
- package/dist/resolveForkCheckpoint.d.ts.map +1 -0
- package/dist/resolveForkCheckpoint.js +26 -0
- package/dist/resolveForkCheckpoint.js.map +1 -0
- package/dist/runtimeExtras.d.ts +7 -0
- package/dist/runtimeExtras.d.ts.map +1 -0
- package/dist/runtimeExtras.js +7 -0
- package/dist/runtimeExtras.js.map +1 -0
- package/dist/streamingTiming.d.ts +16 -0
- package/dist/streamingTiming.d.ts.map +1 -0
- package/dist/streamingTiming.js +53 -0
- package/dist/streamingTiming.js.map +1 -0
- package/dist/types.d.ts +105 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/uiMessages.d.ts +24 -0
- package/dist/uiMessages.d.ts.map +1 -0
- package/dist/uiMessages.js +68 -0
- package/dist/uiMessages.js.map +1 -0
- package/dist/useStreamRuntime.d.ts +10 -85
- package/dist/useStreamRuntime.d.ts.map +1 -1
- package/dist/useStreamRuntime.js +186 -135
- package/dist/useStreamRuntime.js.map +1 -1
- package/package.json +9 -9
- package/src/__tests__/langChainTestUtils.ts +3 -3
- package/src/convertMessages.test.ts +160 -3
- package/src/convertMessages.ts +104 -11
- package/src/findForkCheckpointInHistory.test.ts +263 -0
- package/src/findForkCheckpointInHistory.ts +68 -0
- package/src/groupUIMessagesByParent.test.ts +61 -0
- package/src/hooks.ts +156 -0
- package/src/index.ts +18 -3
- package/src/resolveForkCheckpoint.test.ts +202 -0
- package/src/resolveForkCheckpoint.ts +49 -0
- package/src/runtimeExtras.ts +5 -0
- package/src/streamingTiming.test.ts +118 -0
- package/src/streamingTiming.ts +85 -0
- package/src/types.ts +140 -3
- package/src/uiMessages.test.ts +190 -0
- package/src/uiMessages.ts +91 -0
- package/src/useLangChainError.test.tsx +1 -1
- package/src/useLangChainInterrupts.test.tsx +48 -0
- package/src/useLangChainRespond.test.tsx +49 -0
- package/src/useLangChainRespondAll.test.tsx +52 -0
- package/src/useLangChainState.test.tsx +1 -1
- package/src/useLangChainStream.test.tsx +42 -0
- package/src/useLangChainSubagents.test.tsx +48 -0
- package/src/useLangChainSubgraphs.test.tsx +48 -0
- package/src/useLangChainToolCalls.test.tsx +1 -1
- package/src/useStreamRuntime.test.tsx +232 -0
- package/src/useStreamRuntime.ts +301 -268
package/dist/useStreamRuntime.js
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { convertLangChainBaseMessage, getMessageType } from "./convertMessages.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { convertLangChainBaseMessage, getMessageContent, getMessageType } from "./convertMessages.js";
|
|
3
|
+
import { langChainExtras } from "./runtimeExtras.js";
|
|
4
|
+
import { foldUIUpdates, mergeUIMessages } from "./uiMessages.js";
|
|
5
|
+
import { resolveForkCheckpoint } from "./resolveForkCheckpoint.js";
|
|
6
|
+
import { useLangChainStreamingTiming } from "./streamingTiming.js";
|
|
7
|
+
import { useAuiState } from "@assistant-ui/store";
|
|
8
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
+
import { generateId, getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
5
10
|
import { useCloudThreadListAdapter, useExternalMessageConverter, useExternalStoreRuntime, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
|
|
6
|
-
import {
|
|
7
|
-
import { useStream } from "@langchain/react";
|
|
11
|
+
import { STREAM_CONTROLLER, useChannel, useStream } from "@langchain/react";
|
|
8
12
|
//#region src/useStreamRuntime.ts
|
|
9
|
-
const
|
|
10
|
-
const EMPTY_TOOL_CALLS = [];
|
|
11
|
-
const asLangChainRuntimeExtras = (extras) => {
|
|
12
|
-
if (typeof extras !== "object" || extras == null || !(symbolLangChainRuntimeExtras in extras)) throw new Error("This method can only be called when you are using useStreamRuntime");
|
|
13
|
-
return extras;
|
|
14
|
-
};
|
|
13
|
+
const UI_CUSTOM_CHANNELS = ["custom"];
|
|
15
14
|
const runConfigToSubmitOptions = (runConfig) => runConfig?.custom ? { config: { configurable: runConfig.custom } } : void 0;
|
|
15
|
+
/**
|
|
16
|
+
* Group the graph's accumulated `UIMessage`s by the assistant message they
|
|
17
|
+
* belong to. Non-array state and entries without a parent link are dropped.
|
|
18
|
+
* The parent id comes from `metadata.message_id` (Python SDK) or
|
|
19
|
+
* `metadata.id` (JS SDK).
|
|
20
|
+
*/
|
|
21
|
+
const groupUIMessagesByParent = (value) => {
|
|
22
|
+
const map = /* @__PURE__ */ new Map();
|
|
23
|
+
if (!Array.isArray(value)) return map;
|
|
24
|
+
for (const ui of value) {
|
|
25
|
+
const parentId = ui.metadata?.message_id ?? ui.metadata?.id;
|
|
26
|
+
if (!parentId) continue;
|
|
27
|
+
const existing = map.get(parentId);
|
|
28
|
+
if (existing) existing.push(ui);
|
|
29
|
+
else map.set(parentId, [ui]);
|
|
30
|
+
}
|
|
31
|
+
return map;
|
|
32
|
+
};
|
|
16
33
|
const getPendingToolCalls = (messages) => {
|
|
17
34
|
const pending = /* @__PURE__ */ new Map();
|
|
18
35
|
for (const m of messages) {
|
|
@@ -22,72 +39,116 @@ const getPendingToolCalls = (messages) => {
|
|
|
22
39
|
}
|
|
23
40
|
return [...pending.values()];
|
|
24
41
|
};
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
type: "text",
|
|
38
|
-
text: part.text
|
|
39
|
-
};
|
|
40
|
-
case "image": return {
|
|
41
|
-
type: "image_url",
|
|
42
|
-
image_url: { url: part.image }
|
|
43
|
-
};
|
|
44
|
-
case "file": return {
|
|
45
|
-
type: "file",
|
|
46
|
-
data: part.data,
|
|
47
|
-
mime_type: part.mimeType,
|
|
48
|
-
metadata: { filename: part.filename ?? "file" },
|
|
49
|
-
source_type: "base64"
|
|
50
|
-
};
|
|
51
|
-
case "tool-call": throw new Error("Tool call appends are not supported.");
|
|
52
|
-
default: throw new Error(`Unsupported append message part type: ${type}`);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
if (content.length === 1 && content[0]?.type === "text") return content[0].text ?? "";
|
|
56
|
-
return content;
|
|
42
|
+
const toStagedHumanMessage = (msg, id = generateId()) => ({
|
|
43
|
+
id,
|
|
44
|
+
_getType: () => "human",
|
|
45
|
+
content: getMessageContent(msg)
|
|
46
|
+
});
|
|
47
|
+
const truncateLangChainBaseMessages = (threadMessages, parentId) => {
|
|
48
|
+
if (parentId === null) return [];
|
|
49
|
+
const parentIndex = threadMessages.findIndex((m) => m.id === parentId);
|
|
50
|
+
if (parentIndex === -1) return [];
|
|
51
|
+
const truncated = [];
|
|
52
|
+
for (let i = 0; i <= parentIndex && i < threadMessages.length; i++) truncated.push(...getExternalStoreMessages(threadMessages[i]));
|
|
53
|
+
return truncated;
|
|
57
54
|
};
|
|
58
55
|
const useStreamThreadRuntime = (options) => {
|
|
59
56
|
const { adapters, autoCancelPendingToolCalls, unstable_allowCancellation } = options;
|
|
60
57
|
const messagesKey = options.messagesKey ?? "messages";
|
|
61
|
-
|
|
58
|
+
const uiStateKey = options.uiStateKey ?? "ui";
|
|
59
|
+
const externalId = useAuiState((s) => s.threadListItem.externalId);
|
|
60
|
+
options.threadId = externalId;
|
|
62
61
|
const stream = useStream(options);
|
|
62
|
+
const [stagedMessages, setStagedMessages] = useState(null);
|
|
63
63
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
64
64
|
const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
|
|
65
65
|
const effectiveIsRunning = stream.isLoading || hasExecutingTools;
|
|
66
|
+
const uiStateValue = stream.values[uiStateKey];
|
|
67
|
+
const customEvents = useChannel(stream, UI_CUSTOM_CHANNELS);
|
|
68
|
+
const liveUiMessages = useMemo(() => foldUIUpdates(customEvents), [customEvents]);
|
|
69
|
+
const mergedUiMessages = useMemo(() => mergeUIMessages(liveUiMessages, uiStateValue), [liveUiMessages, uiStateValue]);
|
|
70
|
+
const visibleMessages = stagedMessages ?? stream.messages;
|
|
71
|
+
const messageTiming = useLangChainStreamingTiming(visibleMessages, effectiveIsRunning);
|
|
66
72
|
const threadMessages = useExternalMessageConverter({
|
|
67
|
-
callback:
|
|
68
|
-
|
|
73
|
+
callback: useMemo(() => {
|
|
74
|
+
const uiMessagesByParent = groupUIMessagesByParent(mergedUiMessages);
|
|
75
|
+
return (message, metadata) => convertLangChainBaseMessage(message, {
|
|
76
|
+
...metadata,
|
|
77
|
+
uiMessagesByParent,
|
|
78
|
+
messageTiming
|
|
79
|
+
});
|
|
80
|
+
}, [mergedUiMessages, messageTiming]),
|
|
81
|
+
messages: visibleMessages,
|
|
69
82
|
isRunning: effectiveIsRunning
|
|
70
83
|
});
|
|
71
84
|
const streamRef = useRef(stream);
|
|
72
85
|
streamRef.current = stream;
|
|
73
|
-
const
|
|
74
|
-
|
|
86
|
+
const visibleMessagesRef = useRef(visibleMessages);
|
|
87
|
+
visibleMessagesRef.current = visibleMessages;
|
|
88
|
+
const threadMessagesRef = useRef(threadMessages);
|
|
89
|
+
threadMessagesRef.current = threadMessages;
|
|
90
|
+
const stagedMessagesRef = useRef(/* @__PURE__ */ new Map());
|
|
91
|
+
const stagedBaseMessagesRef = useRef(null);
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (stagedMessagesRef.current.size === 0) return;
|
|
94
|
+
const baseMessages = stagedBaseMessagesRef.current ?? stream.messages;
|
|
95
|
+
const baseMessageIds = new Set(baseMessages.flatMap((message) => message.id ? [message.id] : []));
|
|
96
|
+
const remainingStagedMessages = [];
|
|
97
|
+
const seenStagedIds = /* @__PURE__ */ new Set();
|
|
98
|
+
for (const message of visibleMessagesRef.current) {
|
|
99
|
+
if (!message.id || seenStagedIds.has(message.id)) continue;
|
|
100
|
+
if (baseMessageIds.has(message.id)) continue;
|
|
101
|
+
const staged = stagedMessagesRef.current.get(message.id);
|
|
102
|
+
if (!staged) continue;
|
|
103
|
+
remainingStagedMessages.push(staged.message);
|
|
104
|
+
seenStagedIds.add(message.id);
|
|
105
|
+
}
|
|
106
|
+
if (remainingStagedMessages.length === 0) {
|
|
107
|
+
stagedBaseMessagesRef.current = null;
|
|
108
|
+
visibleMessagesRef.current = baseMessages;
|
|
109
|
+
setStagedMessages(null);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const nextMessages = [...baseMessages, ...remainingStagedMessages];
|
|
113
|
+
visibleMessagesRef.current = nextMessages;
|
|
114
|
+
setStagedMessages(nextMessages);
|
|
115
|
+
}, [stream.messages]);
|
|
116
|
+
const getStagedRun = (parentId) => {
|
|
117
|
+
if (!parentId || !stagedMessagesRef.current.has(parentId)) return null;
|
|
118
|
+
const staged = [];
|
|
119
|
+
for (const message of visibleMessagesRef.current) {
|
|
120
|
+
if (message.id && stagedMessagesRef.current.has(message.id)) staged.push(stagedMessagesRef.current.get(message.id).message);
|
|
121
|
+
if (message.id === parentId) break;
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
messages: staged,
|
|
125
|
+
runConfig: stagedMessagesRef.current.get(parentId).runConfig
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
const stageUserMessage = (msg) => {
|
|
129
|
+
const stagedMessage = toStagedHumanMessage(msg);
|
|
130
|
+
stagedMessagesRef.current.set(stagedMessage.id, {
|
|
131
|
+
message: stagedMessage,
|
|
132
|
+
runConfig: msg.runConfig
|
|
133
|
+
});
|
|
134
|
+
const nextMessages = [...visibleMessagesRef.current, stagedMessage];
|
|
135
|
+
visibleMessagesRef.current = nextMessages;
|
|
136
|
+
setStagedMessages(nextMessages);
|
|
137
|
+
};
|
|
138
|
+
const extras = useMemo(() => langChainExtras.provide({
|
|
75
139
|
interrupt: stream.interrupt,
|
|
76
140
|
interrupts: stream.interrupts,
|
|
77
141
|
toolCalls: stream.toolCalls,
|
|
142
|
+
subagents: stream.subagents,
|
|
143
|
+
subgraphs: stream.subgraphs,
|
|
144
|
+
stream,
|
|
78
145
|
error: stream.error,
|
|
79
146
|
submit: stream.submit,
|
|
147
|
+
respond: stream.respond,
|
|
148
|
+
respondAll: stream.respondAll,
|
|
80
149
|
values: stream.values,
|
|
81
150
|
messagesKey
|
|
82
|
-
}), [
|
|
83
|
-
stream.interrupt,
|
|
84
|
-
stream.interrupts,
|
|
85
|
-
stream.toolCalls,
|
|
86
|
-
stream.error,
|
|
87
|
-
stream.submit,
|
|
88
|
-
stream.values,
|
|
89
|
-
messagesKey
|
|
90
|
-
]);
|
|
151
|
+
}), [stream, messagesKey]);
|
|
91
152
|
return useExternalStoreRuntime({
|
|
92
153
|
...pickExternalStoreSharedOptions(options),
|
|
93
154
|
isRunning: effectiveIsRunning,
|
|
@@ -98,6 +159,10 @@ const useStreamThreadRuntime = (options) => {
|
|
|
98
159
|
unstable_enableToolInvocations: true,
|
|
99
160
|
setToolStatuses,
|
|
100
161
|
onNew: async (msg) => {
|
|
162
|
+
if (!(msg.startRun ?? msg.role === "user")) {
|
|
163
|
+
stageUserMessage(msg);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
101
166
|
const content = getMessageContent(msg);
|
|
102
167
|
const cancellations = autoCancelPendingToolCalls !== false ? getPendingToolCalls(streamRef.current.messages).map((t) => ({
|
|
103
168
|
type: "tool",
|
|
@@ -121,6 +186,66 @@ const useStreamThreadRuntime = (options) => {
|
|
|
121
186
|
status: isError ? "error" : "success"
|
|
122
187
|
}] });
|
|
123
188
|
},
|
|
189
|
+
onReload: async (parentId, config) => {
|
|
190
|
+
const stagedRun = getStagedRun(parentId);
|
|
191
|
+
if (stagedRun) {
|
|
192
|
+
const promotedIds = /* @__PURE__ */ new Set();
|
|
193
|
+
for (const message of stagedRun.messages) {
|
|
194
|
+
if (!message.id) continue;
|
|
195
|
+
promotedIds.add(message.id);
|
|
196
|
+
stagedMessagesRef.current.delete(message.id);
|
|
197
|
+
}
|
|
198
|
+
stagedBaseMessagesRef.current = null;
|
|
199
|
+
if (stagedMessagesRef.current.size > 0) {
|
|
200
|
+
const nextMessages = visibleMessagesRef.current.filter((message) => !message.id || !promotedIds.has(message.id));
|
|
201
|
+
visibleMessagesRef.current = nextMessages;
|
|
202
|
+
setStagedMessages(nextMessages);
|
|
203
|
+
} else setStagedMessages(null);
|
|
204
|
+
await stream.submit({ [messagesKey]: stagedRun.messages.map((message) => ({
|
|
205
|
+
id: message.id,
|
|
206
|
+
type: "human",
|
|
207
|
+
content: message.content
|
|
208
|
+
})) }, runConfigToSubmitOptions(config.runConfig ?? stagedRun.runConfig));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const threadId = externalId;
|
|
212
|
+
if (!threadId || parentId == null) return;
|
|
213
|
+
const s = streamRef.current;
|
|
214
|
+
const checkpointId = await resolveForkCheckpoint(s.client, threadId, s.messages, parentId, config.sourceId, s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(), messagesKey);
|
|
215
|
+
if (!checkpointId) return;
|
|
216
|
+
await s.submit(null, {
|
|
217
|
+
forkFrom: checkpointId,
|
|
218
|
+
...runConfigToSubmitOptions(config.runConfig)
|
|
219
|
+
});
|
|
220
|
+
},
|
|
221
|
+
onEdit: async (message) => {
|
|
222
|
+
if (!(message.startRun ?? message.role === "user")) {
|
|
223
|
+
const truncated = truncateLangChainBaseMessages(threadMessagesRef.current, message.parentId);
|
|
224
|
+
const stagedMessage = toStagedHumanMessage(message);
|
|
225
|
+
stagedMessagesRef.current.set(stagedMessage.id, {
|
|
226
|
+
message: stagedMessage,
|
|
227
|
+
runConfig: message.runConfig
|
|
228
|
+
});
|
|
229
|
+
stagedBaseMessagesRef.current = truncated;
|
|
230
|
+
const nextMessages = [...truncated, stagedMessage];
|
|
231
|
+
visibleMessagesRef.current = nextMessages;
|
|
232
|
+
setStagedMessages(nextMessages);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const threadId = externalId;
|
|
236
|
+
if (!threadId) return;
|
|
237
|
+
const s = streamRef.current;
|
|
238
|
+
const checkpointId = await resolveForkCheckpoint(s.client, threadId, s.messages, message.parentId, message.sourceId, s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(), messagesKey);
|
|
239
|
+
if (!checkpointId) return;
|
|
240
|
+
const content = getMessageContent(message);
|
|
241
|
+
await s.submit({ [messagesKey]: [{
|
|
242
|
+
type: "human",
|
|
243
|
+
content
|
|
244
|
+
}] }, {
|
|
245
|
+
forkFrom: checkpointId,
|
|
246
|
+
...runConfigToSubmitOptions(message.runConfig)
|
|
247
|
+
});
|
|
248
|
+
},
|
|
124
249
|
onCancel: unstable_allowCancellation !== false ? async () => {
|
|
125
250
|
await stream.stop();
|
|
126
251
|
} : void 0
|
|
@@ -151,7 +276,7 @@ const useStreamThreadRuntime = (options) => {
|
|
|
151
276
|
* ```
|
|
152
277
|
*/
|
|
153
278
|
const useStreamRuntime = (rawOptions) => {
|
|
154
|
-
const { cloud, unstable_threadListAdapter, create, delete: deleteFn, ...options } = rawOptions;
|
|
279
|
+
const { cloud, unstable_threadListAdapter, create, delete: deleteFn, onThreadIdChange, ...options } = rawOptions;
|
|
155
280
|
const optionsRef = useRef(options);
|
|
156
281
|
optionsRef.current = options;
|
|
157
282
|
const cloudAdapter = useCloudThreadListAdapter({
|
|
@@ -164,85 +289,11 @@ const useStreamRuntime = (rawOptions) => {
|
|
|
164
289
|
return useStreamThreadRuntime(optionsRef.current);
|
|
165
290
|
},
|
|
166
291
|
adapter: unstable_threadListAdapter ?? cloudAdapter,
|
|
167
|
-
allowNesting: true
|
|
168
|
-
|
|
169
|
-
};
|
|
170
|
-
/**
|
|
171
|
-
* Read the current LangGraph interrupt state from the runtime extras.
|
|
172
|
-
*/
|
|
173
|
-
const useLangChainInterruptState = () => {
|
|
174
|
-
return useAuiState((s) => {
|
|
175
|
-
const extras = s.thread.extras;
|
|
176
|
-
if (!extras) return void 0;
|
|
177
|
-
return asLangChainRuntimeExtras(extras).interrupt;
|
|
178
|
-
});
|
|
179
|
-
};
|
|
180
|
-
/** Read the last run/hydration error from the runtime extras. */
|
|
181
|
-
const useLangChainError = () => {
|
|
182
|
-
return useAuiState((s) => {
|
|
183
|
-
const extras = s.thread.extras;
|
|
184
|
-
if (!extras) return void 0;
|
|
185
|
-
return asLangChainRuntimeExtras(extras).error;
|
|
186
|
-
});
|
|
187
|
-
};
|
|
188
|
-
/**
|
|
189
|
-
* Read the root tool calls assembled by `useStream` from the `tools`
|
|
190
|
-
* channel. Defaults to an empty array, so consumers can `.map` without
|
|
191
|
-
* a guard. Useful for rendering pending/streamed tool calls and
|
|
192
|
-
* approval UIs.
|
|
193
|
-
*/
|
|
194
|
-
const useLangChainToolCalls = () => {
|
|
195
|
-
return useAuiState((s) => {
|
|
196
|
-
const extras = s.thread.extras;
|
|
197
|
-
if (!extras) return EMPTY_TOOL_CALLS;
|
|
198
|
-
return asLangChainRuntimeExtras(extras).toolCalls ?? EMPTY_TOOL_CALLS;
|
|
292
|
+
allowNesting: true,
|
|
293
|
+
onThreadIdChange
|
|
199
294
|
});
|
|
200
295
|
};
|
|
201
|
-
/**
|
|
202
|
-
* Returns a function to submit raw state updates to the LangGraph agent,
|
|
203
|
-
* bypassing the normal message flow. Useful for sending interrupt resume
|
|
204
|
-
* commands.
|
|
205
|
-
*/
|
|
206
|
-
const useLangChainSubmit = () => {
|
|
207
|
-
const aui = useAui();
|
|
208
|
-
return (values, options) => {
|
|
209
|
-
const extras = aui.thread().getState().extras;
|
|
210
|
-
const { submit } = asLangChainRuntimeExtras(extras);
|
|
211
|
-
return submit(values, options);
|
|
212
|
-
};
|
|
213
|
-
};
|
|
214
|
-
/**
|
|
215
|
-
* Submit a list of LangChain-shaped messages on the current thread.
|
|
216
|
-
* Parity helper for migrating from `useLangGraphSend`. Routes to
|
|
217
|
-
* `useStream().submit({ [messagesKey]: messages }, options)`.
|
|
218
|
-
*/
|
|
219
|
-
const useLangChainSend = () => {
|
|
220
|
-
const aui = useAui();
|
|
221
|
-
return (messages, options) => {
|
|
222
|
-
const { submit, messagesKey } = asLangChainRuntimeExtras(aui.thread().getState().extras);
|
|
223
|
-
return submit({ [messagesKey]: messages }, options);
|
|
224
|
-
};
|
|
225
|
-
};
|
|
226
|
-
/**
|
|
227
|
-
* Submit a `useStream` command (e.g. interrupt resume). Parity helper
|
|
228
|
-
* for migrating from `useLangGraphSendCommand`. Note that v1's command
|
|
229
|
-
* shape (`{ resume?, goto?, update? }`) differs from the legacy
|
|
230
|
-
* `{ resume: string }` form — to carry a payload, use the input or
|
|
231
|
-
* `stream.respond` instead.
|
|
232
|
-
*/
|
|
233
|
-
const useLangChainSendCommand = () => {
|
|
234
|
-
const submit = useLangChainSubmit();
|
|
235
|
-
return (command) => submit(null, { command });
|
|
236
|
-
};
|
|
237
|
-
function useLangChainState(key, defaultValue) {
|
|
238
|
-
return useAuiState((s) => {
|
|
239
|
-
const extras = s.thread.extras;
|
|
240
|
-
if (!extras) return defaultValue;
|
|
241
|
-
const value = asLangChainRuntimeExtras(extras).values[key];
|
|
242
|
-
return value !== void 0 ? value : defaultValue;
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
296
|
//#endregion
|
|
246
|
-
export {
|
|
297
|
+
export { groupUIMessagesByParent, runConfigToSubmitOptions, useStreamRuntime };
|
|
247
298
|
|
|
248
299
|
//# sourceMappingURL=useStreamRuntime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStreamRuntime.js","names":["_exhaustiveCheck"],"sources":["../src/useStreamRuntime.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/store\" />\n\"use client\";\n\nimport { useMemo, useRef, useState } from \"react\";\nimport type {\n AppendMessage,\n AttachmentAdapter,\n DictationAdapter,\n ExternalStoreSharedOptions,\n FeedbackAdapter,\n RealtimeVoiceAdapter,\n RemoteThreadListAdapter,\n SpeechSynthesisAdapter,\n ToolExecutionStatus,\n} from \"@assistant-ui/core\";\nimport { pickExternalStoreSharedOptions } from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useExternalStoreRuntime,\n useExternalMessageConverter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n useStream,\n type UseStreamOptions,\n type AssembledToolCall,\n} from \"@langchain/react\";\nimport type { LangChainBaseMessage, LangChainToolCall } from \"./types\";\nimport { convertLangChainBaseMessage, getMessageType } from \"./convertMessages\";\n\nconst symbolLangChainRuntimeExtras = Symbol(\"langchain-runtime-extras\");\n\nconst EMPTY_TOOL_CALLS: readonly AssembledToolCall[] = [];\n\ntype LangChainRuntimeExtras = {\n [symbolLangChainRuntimeExtras]: true;\n interrupt: { value?: unknown } | undefined;\n interrupts: readonly { value?: unknown }[];\n toolCalls: readonly AssembledToolCall[];\n error: unknown;\n submit: (\n values: Record<string, unknown> | null | undefined,\n options?: Record<string, unknown>,\n ) => Promise<void>;\n values: Record<string, unknown>;\n messagesKey: string;\n};\n\nconst asLangChainRuntimeExtras = (extras: unknown): LangChainRuntimeExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolLangChainRuntimeExtras in extras)\n )\n throw new Error(\n \"This method can only be called when you are using useStreamRuntime\",\n );\n return extras as LangChainRuntimeExtras;\n};\n\ntype LangChainRuntimeExtraOptions = ExternalStoreSharedOptions & {\n cloud?: AssistantCloud | undefined;\n adapters?:\n | {\n attachments?: AttachmentAdapter | undefined;\n speech?: SpeechSynthesisAdapter | undefined;\n dictation?: DictationAdapter | undefined;\n voice?: RealtimeVoiceAdapter | undefined;\n feedback?: FeedbackAdapter | undefined;\n }\n | undefined;\n /**\n * When the user sends a new message while previous tool calls are\n * still pending, automatically submit `tool` messages that cancel\n * them so the agent's tool-call accounting stays consistent.\n * Defaults to `true`.\n */\n autoCancelPendingToolCalls?: boolean | undefined;\n /**\n * Routes the Cancel button's click to `useStream().stop()`. On by\n * default. Pass `false` to disable the Cancel button.\n */\n unstable_allowCancellation?: boolean | undefined;\n /**\n * Custom `RemoteThreadListAdapter`. When provided, replaces the\n * cloud-backed thread list adapter.\n */\n unstable_threadListAdapter?: RemoteThreadListAdapter | undefined;\n /** Custom thread-creation hook, forwarded to the cloud adapter. */\n create?: (() => Promise<{ externalId: string | undefined }>) | undefined;\n /** Custom thread-deletion hook, forwarded to the cloud adapter. */\n delete?: ((threadId: string) => Promise<void>) | undefined;\n};\n\nexport const runConfigToSubmitOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n) =>\n runConfig?.custom\n ? { config: { configurable: runConfig.custom } }\n : undefined;\n\nconst getPendingToolCalls = (\n messages: readonly LangChainBaseMessage[],\n): LangChainToolCall[] => {\n const pending = new Map<string, LangChainToolCall>();\n for (const m of messages) {\n const type = getMessageType(m);\n if (type === \"ai\") {\n for (const tc of m.tool_calls ?? []) pending.set(tc.id, tc);\n } else if (type === \"tool\" && m.tool_call_id) {\n pending.delete(m.tool_call_id);\n }\n }\n return [...pending.values()];\n};\n\n// Distribute the intersection through the union arms of `UseStreamOptions`\n// (`AgentServerOptions | CustomAdapterOptions`). Writing `UseStreamOptions & X`\n// directly collapses arm tracking, so `Omit<…, \"cloud\">` and the like would\n// produce a flattened structural type that no longer matches either arm.\nexport type UseStreamRuntimeOptions = UseStreamOptions extends infer O\n ? O extends UseStreamOptions\n ? O & LangChainRuntimeExtraOptions\n : never\n : never;\n\nconst getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n\n const hasNonText = allContent.some(\n (part) => part.type === \"file\" || part.type === \"image\",\n );\n const hasText = allContent.some((part) => part.type === \"text\");\n if (hasNonText && !hasText) {\n allContent.unshift({ type: \"text\", text: \" \" });\n }\n\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n case \"file\":\n return {\n type: \"file\" as const,\n data: part.data,\n mime_type: part.mimeType,\n metadata: { filename: part.filename ?? \"file\" },\n source_type: \"base64\" as const,\n };\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n default: {\n const _exhaustiveCheck:\n | \"reasoning\"\n | \"source\"\n | \"audio\"\n | \"data\"\n | \"generative-ui\" = type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n return content;\n};\n\ntype DistributiveOmit<T, K extends keyof any> = T extends unknown\n ? Omit<T, K>\n : never;\n\nconst useStreamThreadRuntime = (\n options: DistributiveOmit<\n UseStreamRuntimeOptions,\n \"cloud\" | \"unstable_threadListAdapter\" | \"create\" | \"delete\"\n >,\n) => {\n const { adapters, autoCancelPendingToolCalls, unstable_allowCancellation } =\n options;\n const messagesKey = options.messagesKey ?? \"messages\";\n\n const externalId = useAuiState((s) => s.threadListItem.externalId) as\n | string\n | null;\n // Mutate in place rather than `{ ...options, threadId }`: spreading\n // `UseStreamOptions` (a discriminated union on `transport`) into an object\n // literal merges both arms' transport types, breaking arm assignment.\n options.threadId = externalId;\n\n const stream = useStream(options);\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const effectiveIsRunning = stream.isLoading || hasExecutingTools;\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangChainBaseMessage,\n messages: stream.messages as LangChainBaseMessage[],\n isRunning: effectiveIsRunning,\n });\n\n const streamRef = useRef(stream);\n streamRef.current = stream;\n\n const extras = useMemo(\n (): LangChainRuntimeExtras => ({\n [symbolLangChainRuntimeExtras]: true,\n interrupt: stream.interrupt,\n interrupts: stream.interrupts,\n toolCalls: stream.toolCalls,\n error: stream.error,\n submit: stream.submit,\n values: stream.values,\n messagesKey,\n }),\n [\n stream.interrupt,\n stream.interrupts,\n stream.toolCalls,\n stream.error,\n stream.submit,\n stream.values,\n messagesKey,\n ],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: effectiveIsRunning,\n isLoading: stream.isThreadLoading,\n messages: threadMessages,\n adapters,\n extras,\n unstable_enableToolInvocations: true,\n setToolStatuses,\n onNew: async (msg) => {\n const content = getMessageContent(msg);\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(\n streamRef.current.messages as readonly LangChainBaseMessage[],\n ).map((t) => ({\n type: \"tool\" as const,\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\" as const,\n }))\n : [];\n await stream.submit(\n { [messagesKey]: [...cancellations, { type: \"human\", content }] },\n runConfigToSubmitOptions(msg.runConfig),\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n await stream.submit({\n [messagesKey]: [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n ...(artifact !== undefined && { artifact }),\n status: isError ? \"error\" : \"success\",\n },\n ],\n });\n },\n onCancel:\n unstable_allowCancellation !== false\n ? async () => {\n await stream.stop();\n }\n : undefined,\n });\n\n return runtime;\n};\n\n/**\n * Creates an assistant-ui runtime backed by LangChain's `useStream` hook.\n * Accepts the same options as `useStream` from `@langchain/react`, plus\n * `cloud` and `adapters`.\n *\n * @example\n * ```tsx\n * import { useStreamRuntime } from \"@assistant-ui/react-langchain\";\n * import { AssistantRuntimeProvider, Thread } from \"@assistant-ui/react\";\n *\n * function App() {\n * const runtime = useStreamRuntime({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n *\n * return (\n * <AssistantRuntimeProvider runtime={runtime}>\n * <Thread />\n * </AssistantRuntimeProvider>\n * );\n * }\n * ```\n */\nexport const useStreamRuntime = (rawOptions: UseStreamRuntimeOptions) => {\n const {\n cloud,\n unstable_threadListAdapter,\n create,\n delete: deleteFn,\n ...options\n } = rawOptions;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const cloudAdapter = useCloudThreadListAdapter({\n cloud,\n create,\n delete: deleteFn,\n });\n const adapter = unstable_threadListAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useStreamThreadRuntime(optionsRef.current);\n },\n adapter,\n allowNesting: true,\n });\n};\n\n/**\n * Read the current LangGraph interrupt state from the runtime extras.\n */\nexport const useLangChainInterruptState = () => {\n return useAuiState((s) => {\n const extras = s.thread.extras;\n if (!extras) return undefined;\n return asLangChainRuntimeExtras(extras).interrupt;\n });\n};\n\n/** Read the last run/hydration error from the runtime extras. */\nexport const useLangChainError = () => {\n return useAuiState((s) => {\n const extras = s.thread.extras;\n if (!extras) return undefined;\n return asLangChainRuntimeExtras(extras).error;\n });\n};\n\n/**\n * Read the root tool calls assembled by `useStream` from the `tools`\n * channel. Defaults to an empty array, so consumers can `.map` without\n * a guard. Useful for rendering pending/streamed tool calls and\n * approval UIs.\n */\nexport const useLangChainToolCalls = () => {\n return useAuiState((s) => {\n const extras = s.thread.extras;\n if (!extras) return EMPTY_TOOL_CALLS;\n return asLangChainRuntimeExtras(extras).toolCalls ?? EMPTY_TOOL_CALLS;\n });\n};\n\n/**\n * Returns a function to submit raw state updates to the LangGraph agent,\n * bypassing the normal message flow. Useful for sending interrupt resume\n * commands.\n */\nexport const useLangChainSubmit = () => {\n const aui = useAui();\n return (\n values: Record<string, unknown> | null | undefined,\n options?: Record<string, unknown>,\n ) => {\n const extras = aui.thread().getState().extras;\n const { submit } = asLangChainRuntimeExtras(extras);\n return submit(values, options);\n };\n};\n\n/**\n * Submit a list of LangChain-shaped messages on the current thread.\n * Parity helper for migrating from `useLangGraphSend`. Routes to\n * `useStream().submit({ [messagesKey]: messages }, options)`.\n */\nexport const useLangChainSend = () => {\n const aui = useAui();\n return (\n messages: readonly LangChainBaseMessage[],\n options?: Record<string, unknown>,\n ) => {\n const { submit, messagesKey } = asLangChainRuntimeExtras(\n aui.thread().getState().extras,\n );\n return submit({ [messagesKey]: messages }, options);\n };\n};\n\n/**\n * Submit a `useStream` command (e.g. interrupt resume). Parity helper\n * for migrating from `useLangGraphSendCommand`. Note that v1's command\n * shape (`{ resume?, goto?, update? }`) differs from the legacy\n * `{ resume: string }` form — to carry a payload, use the input or\n * `stream.respond` instead.\n */\nexport const useLangChainSendCommand = () => {\n const submit = useLangChainSubmit();\n return (command: Record<string, unknown>) => submit(null, { command });\n};\n\n/**\n * Read a custom LangGraph state key from the current thread. Mirrors\n * `useStream().values[key]` from `@langchain/react` and updates when the\n * stream emits new state.\n *\n * @example\n * ```tsx\n * const todos = useLangChainState<Todo[]>(\"todos\");\n * const files = useLangChainState<Record<string, string>>(\"files\", {});\n * ```\n */\nexport function useLangChainState<T>(key: string): T | undefined;\nexport function useLangChainState<T>(key: string, defaultValue: T): T;\nexport function useLangChainState<T>(\n key: string,\n defaultValue?: T,\n): T | undefined {\n return useAuiState((s) => {\n const extras = s.thread.extras;\n if (!extras) return defaultValue;\n const value = asLangChainRuntimeExtras(extras).values[key] as T | undefined;\n return value !== undefined ? value : defaultValue;\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useStreamRuntime.js","names":[],"sources":["../src/useStreamRuntime.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/store\" />\n\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { AppendMessage, ToolExecutionStatus } from \"@assistant-ui/core\";\nimport {\n generateId,\n getExternalStoreMessages,\n pickExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport type { ThreadMessage } from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useExternalStoreRuntime,\n useExternalMessageConverter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { STREAM_CONTROLLER, useChannel, useStream } from \"@langchain/react\";\nimport type { Channel } from \"@langchain/react\";\nimport type {\n LangChainBaseMessage,\n LangChainToolCall,\n UIMessage,\n UseStreamRuntimeOptions,\n} from \"./types\";\nimport {\n convertLangChainBaseMessage,\n getMessageContent,\n getMessageType,\n} from \"./convertMessages\";\nimport { foldUIUpdates, mergeUIMessages } from \"./uiMessages\";\nimport { langChainExtras } from \"./runtimeExtras\";\nimport { resolveForkCheckpoint } from \"./resolveForkCheckpoint\";\nimport { useLangChainStreamingTiming } from \"./streamingTiming\";\n\nconst UI_CUSTOM_CHANNELS: readonly Channel[] = [\"custom\"];\n\nexport const runConfigToSubmitOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n) =>\n runConfig?.custom\n ? { config: { configurable: runConfig.custom } }\n : undefined;\n\n/**\n * Group the graph's accumulated `UIMessage`s by the assistant message they\n * belong to. Non-array state and entries without a parent link are dropped.\n * The parent id comes from `metadata.message_id` (Python SDK) or\n * `metadata.id` (JS SDK).\n */\nexport const groupUIMessagesByParent = (\n value: unknown,\n): Map<string, UIMessage[]> => {\n const map = new Map<string, UIMessage[]>();\n if (!Array.isArray(value)) return map;\n for (const ui of value as UIMessage[]) {\n const parentId = ui.metadata?.message_id ?? ui.metadata?.id;\n if (!parentId) continue;\n const existing = map.get(parentId);\n if (existing) {\n existing.push(ui);\n } else {\n map.set(parentId, [ui]);\n }\n }\n return map;\n};\n\nconst getPendingToolCalls = (\n messages: readonly LangChainBaseMessage[],\n): LangChainToolCall[] => {\n const pending = new Map<string, LangChainToolCall>();\n for (const m of messages) {\n const type = getMessageType(m);\n if (type === \"ai\") {\n for (const tc of m.tool_calls ?? []) pending.set(tc.id, tc);\n } else if (type === \"tool\" && m.tool_call_id) {\n pending.delete(m.tool_call_id);\n }\n }\n return [...pending.values()];\n};\n\nconst toStagedHumanMessage = (\n msg: AppendMessage,\n id = generateId(),\n): LangChainBaseMessage & { id: string } => ({\n id,\n _getType: () => \"human\",\n content: getMessageContent(msg),\n});\n\nconst truncateLangChainBaseMessages = (\n threadMessages: readonly ThreadMessage[],\n parentId: string | null,\n): LangChainBaseMessage[] => {\n if (parentId === null) return [];\n const parentIndex = threadMessages.findIndex((m) => m.id === parentId);\n if (parentIndex === -1) return [];\n const truncated: LangChainBaseMessage[] = [];\n for (let i = 0; i <= parentIndex && i < threadMessages.length; i++) {\n truncated.push(\n ...getExternalStoreMessages<LangChainBaseMessage>(threadMessages[i]!),\n );\n }\n return truncated;\n};\n\ntype DistributiveOmit<T, K extends keyof any> = T extends unknown\n ? Omit<T, K>\n : never;\n\nconst useStreamThreadRuntime = (\n options: DistributiveOmit<\n UseStreamRuntimeOptions,\n \"cloud\" | \"unstable_threadListAdapter\" | \"create\" | \"delete\"\n >,\n) => {\n const { adapters, autoCancelPendingToolCalls, unstable_allowCancellation } =\n options;\n const messagesKey = options.messagesKey ?? \"messages\";\n const uiStateKey = options.uiStateKey ?? \"ui\";\n\n const externalId = useAuiState((s) => s.threadListItem.externalId) as\n | string\n | null;\n // Mutate in place rather than `{ ...options, threadId }`: spreading\n // `UseStreamOptions` (a discriminated union on `transport`) into an object\n // literal merges both arms' transport types, breaking arm assignment.\n options.threadId = externalId;\n\n const stream = useStream(options);\n const [stagedMessages, setStagedMessages] = useState<\n LangChainBaseMessage[] | null\n >(null);\n\n const [toolStatuses, setToolStatuses] = useState<\n Record<string, ToolExecutionStatus>\n >({});\n const hasExecutingTools = Object.values(toolStatuses).some(\n (s) => s?.type === \"executing\",\n );\n const effectiveIsRunning = stream.isLoading || hasExecutingTools;\n\n const uiStateValue = stream.values[uiStateKey];\n\n const customEvents = useChannel(stream, UI_CUSTOM_CHANNELS);\n const liveUiMessages = useMemo(\n () => foldUIUpdates(customEvents),\n [customEvents],\n );\n\n const mergedUiMessages = useMemo(\n () => mergeUIMessages(liveUiMessages, uiStateValue),\n [liveUiMessages, uiStateValue],\n );\n\n const visibleMessages =\n stagedMessages ?? (stream.messages as LangChainBaseMessage[]);\n\n const messageTiming = useLangChainStreamingTiming(\n visibleMessages,\n effectiveIsRunning,\n );\n\n const convertWithUI = useMemo<\n useExternalMessageConverter.Callback<LangChainBaseMessage>\n >(() => {\n const uiMessagesByParent = groupUIMessagesByParent(mergedUiMessages);\n return (message, metadata) =>\n convertLangChainBaseMessage(message, {\n ...metadata,\n uiMessagesByParent,\n messageTiming,\n });\n }, [mergedUiMessages, messageTiming]);\n\n const threadMessages = useExternalMessageConverter({\n callback: convertWithUI,\n messages: visibleMessages,\n isRunning: effectiveIsRunning,\n });\n\n const streamRef = useRef(stream);\n streamRef.current = stream;\n\n const visibleMessagesRef = useRef(visibleMessages);\n visibleMessagesRef.current = visibleMessages;\n\n const threadMessagesRef = useRef(threadMessages);\n threadMessagesRef.current = threadMessages;\n\n const stagedMessagesRef = useRef(\n new Map<\n string,\n {\n message: LangChainBaseMessage & { id: string };\n runConfig: AppendMessage[\"runConfig\"];\n }\n >(),\n );\n const stagedBaseMessagesRef = useRef<LangChainBaseMessage[] | null>(null);\n\n useEffect(() => {\n if (stagedMessagesRef.current.size === 0) return;\n\n // Staged edits must keep their truncated base while stream updates arrive before promotion.\n const baseMessages =\n stagedBaseMessagesRef.current ??\n (stream.messages as LangChainBaseMessage[]);\n const baseMessageIds = new Set(\n baseMessages.flatMap((message) => (message.id ? [message.id] : [])),\n );\n const remainingStagedMessages: LangChainBaseMessage[] = [];\n const seenStagedIds = new Set<string>();\n for (const message of visibleMessagesRef.current) {\n if (!message.id || seenStagedIds.has(message.id)) continue;\n if (baseMessageIds.has(message.id)) continue;\n const staged = stagedMessagesRef.current.get(message.id);\n if (!staged) continue;\n remainingStagedMessages.push(staged.message);\n seenStagedIds.add(message.id);\n }\n\n if (remainingStagedMessages.length === 0) {\n stagedBaseMessagesRef.current = null;\n visibleMessagesRef.current = baseMessages;\n setStagedMessages(null);\n return;\n }\n\n const nextMessages = [...baseMessages, ...remainingStagedMessages];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n }, [stream.messages]);\n\n const getStagedRun = (parentId: string | null) => {\n if (!parentId || !stagedMessagesRef.current.has(parentId)) return null;\n\n const staged: LangChainBaseMessage[] = [];\n for (const message of visibleMessagesRef.current) {\n if (message.id && stagedMessagesRef.current.has(message.id)) {\n staged.push(stagedMessagesRef.current.get(message.id)!.message);\n }\n if (message.id === parentId) break;\n }\n\n return {\n messages: staged,\n runConfig: stagedMessagesRef.current.get(parentId)!.runConfig,\n };\n };\n\n const stageUserMessage = (msg: AppendMessage) => {\n const stagedMessage = toStagedHumanMessage(msg);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: msg.runConfig,\n });\n const nextMessages = [...visibleMessagesRef.current, stagedMessage];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n };\n\n const extras = useMemo(\n () =>\n langChainExtras.provide({\n interrupt: stream.interrupt,\n interrupts: stream.interrupts,\n toolCalls: stream.toolCalls,\n subagents: stream.subagents,\n subgraphs: stream.subgraphs,\n stream,\n error: stream.error,\n submit: stream.submit,\n respond: stream.respond,\n respondAll: stream.respondAll,\n values: stream.values,\n messagesKey,\n }),\n [stream, messagesKey],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: effectiveIsRunning,\n isLoading: stream.isThreadLoading,\n messages: threadMessages,\n adapters,\n extras,\n unstable_enableToolInvocations: true,\n setToolStatuses,\n onNew: async (msg) => {\n if (!(msg.startRun ?? msg.role === \"user\")) {\n stageUserMessage(msg);\n return;\n }\n\n const content = getMessageContent(msg);\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(\n streamRef.current.messages as readonly LangChainBaseMessage[],\n ).map((t) => ({\n type: \"tool\" as const,\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\" as const,\n }))\n : [];\n await stream.submit(\n { [messagesKey]: [...cancellations, { type: \"human\", content }] },\n runConfigToSubmitOptions(msg.runConfig),\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n await stream.submit({\n [messagesKey]: [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n ...(artifact !== undefined && { artifact }),\n status: isError ? \"error\" : \"success\",\n },\n ],\n });\n },\n onReload: async (parentId, config) => {\n const stagedRun = getStagedRun(parentId);\n if (stagedRun) {\n const promotedIds = new Set<string>();\n for (const message of stagedRun.messages) {\n if (!message.id) continue;\n promotedIds.add(message.id);\n stagedMessagesRef.current.delete(message.id);\n }\n stagedBaseMessagesRef.current = null;\n if (stagedMessagesRef.current.size > 0) {\n const nextMessages = visibleMessagesRef.current.filter(\n (message) => !message.id || !promotedIds.has(message.id),\n );\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n } else {\n setStagedMessages(null);\n }\n await stream.submit(\n {\n [messagesKey]: stagedRun.messages.map((message) => ({\n id: message.id,\n type: \"human\",\n content: message.content,\n })),\n },\n runConfigToSubmitOptions(config.runConfig ?? stagedRun.runConfig),\n );\n return;\n }\n\n const threadId = externalId;\n if (!threadId || parentId == null) return;\n const s = streamRef.current;\n const checkpointId = await resolveForkCheckpoint(\n s.client,\n threadId,\n s.messages as readonly LangChainBaseMessage[],\n parentId,\n config.sourceId,\n s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(),\n messagesKey,\n );\n if (!checkpointId) return;\n await s.submit(null, {\n forkFrom: checkpointId,\n ...runConfigToSubmitOptions(config.runConfig),\n });\n },\n onEdit: async (message) => {\n if (!(message.startRun ?? message.role === \"user\")) {\n const truncated = truncateLangChainBaseMessages(\n threadMessagesRef.current,\n message.parentId,\n );\n const stagedMessage = toStagedHumanMessage(message);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: message.runConfig,\n });\n stagedBaseMessagesRef.current = truncated;\n const nextMessages = [...truncated, stagedMessage];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n return;\n }\n\n const threadId = externalId;\n if (!threadId) return;\n const s = streamRef.current;\n const checkpointId = await resolveForkCheckpoint(\n s.client,\n threadId,\n s.messages as readonly LangChainBaseMessage[],\n message.parentId,\n message.sourceId,\n s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(),\n messagesKey,\n );\n if (!checkpointId) return;\n const content = getMessageContent(message);\n await s.submit(\n { [messagesKey]: [{ type: \"human\", content }] },\n {\n forkFrom: checkpointId,\n ...runConfigToSubmitOptions(message.runConfig),\n },\n );\n },\n onCancel:\n unstable_allowCancellation !== false\n ? async () => {\n await stream.stop();\n }\n : undefined,\n });\n\n return runtime;\n};\n\n/**\n * Creates an assistant-ui runtime backed by LangChain's `useStream` hook.\n * Accepts the same options as `useStream` from `@langchain/react`, plus\n * `cloud` and `adapters`.\n *\n * @example\n * ```tsx\n * import { useStreamRuntime } from \"@assistant-ui/react-langchain\";\n * import { AssistantRuntimeProvider, Thread } from \"@assistant-ui/react\";\n *\n * function App() {\n * const runtime = useStreamRuntime({\n * assistantId: \"agent\",\n * apiUrl: \"http://localhost:2024\",\n * });\n *\n * return (\n * <AssistantRuntimeProvider runtime={runtime}>\n * <Thread />\n * </AssistantRuntimeProvider>\n * );\n * }\n * ```\n */\nexport const useStreamRuntime = (rawOptions: UseStreamRuntimeOptions) => {\n const {\n cloud,\n unstable_threadListAdapter,\n create,\n delete: deleteFn,\n onThreadIdChange,\n ...options\n } = rawOptions;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const cloudAdapter = useCloudThreadListAdapter({\n cloud,\n create,\n delete: deleteFn,\n });\n const adapter = unstable_threadListAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useStreamThreadRuntime(optionsRef.current);\n },\n adapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-langchain",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "LangChain useStream adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"langchain",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@assistant-ui/core": "^0.2.
|
|
33
|
-
"@assistant-ui/store": "^0.2.
|
|
32
|
+
"@assistant-ui/core": "^0.2.19",
|
|
33
|
+
"@assistant-ui/store": "^0.2.19",
|
|
34
34
|
"assistant-cloud": "*",
|
|
35
|
-
"assistant-stream": "^0.3.
|
|
35
|
+
"assistant-stream": "^0.3.24"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@langchain/react": "^1.0.2",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@langchain/core": "^1.
|
|
49
|
-
"@langchain/langgraph-sdk": "^1.9.
|
|
50
|
-
"@langchain/react": "^1.0.
|
|
48
|
+
"@langchain/core": "^1.2.0",
|
|
49
|
+
"@langchain/langgraph-sdk": "^1.9.23",
|
|
50
|
+
"@langchain/react": "^1.0.24",
|
|
51
51
|
"@testing-library/react": "^16.3.2",
|
|
52
52
|
"@types/react": "^19.2.17",
|
|
53
53
|
"jsdom": "^29.1.1",
|
|
54
54
|
"react": "^19.2.7",
|
|
55
|
-
"vitest": "^4.1.
|
|
56
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
55
|
+
"vitest": "^4.1.9",
|
|
56
|
+
"@assistant-ui/x-buildutils": "0.0.16"
|
|
57
57
|
},
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public",
|
|
@@ -2,14 +2,14 @@ import type { Mock } from "vitest";
|
|
|
2
2
|
|
|
3
3
|
export type Selector = (state: unknown) => unknown;
|
|
4
4
|
|
|
5
|
-
// The
|
|
5
|
+
// The createRuntimeExtras brand symbol is module-private. To stand in for
|
|
6
6
|
// runtime-produced extras, wrap a plain object in a Proxy whose `has` trap
|
|
7
|
-
// claims any symbol described "
|
|
7
|
+
// claims any symbol described "useStreamRuntime extras" is present.
|
|
8
8
|
export const makeExtras = (extras: Record<string, unknown>) =>
|
|
9
9
|
new Proxy(extras, {
|
|
10
10
|
has: (target, key) =>
|
|
11
11
|
(typeof key === "symbol" &&
|
|
12
|
-
key.description === "
|
|
12
|
+
key.description === "useStreamRuntime extras") ||
|
|
13
13
|
Reflect.has(target, key),
|
|
14
14
|
});
|
|
15
15
|
|