@assistant-ui/react-langchain 0.0.32 → 0.0.33
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/attachSubagentTranscripts.d.ts +13 -14
- package/dist/attachSubagentTranscripts.d.ts.map +1 -1
- package/dist/convertMessages.d.ts +6 -9
- package/dist/convertMessages.d.ts.map +1 -1
- package/dist/convertMessages.js +53 -15
- package/dist/convertMessages.js.map +1 -1
- package/dist/converter.d.ts +128 -128
- package/dist/converter.d.ts.map +1 -1
- package/dist/converter.js +2 -1
- package/dist/converter.js.map +1 -1
- package/dist/findForkCheckpointInHistory.d.ts +15 -16
- package/dist/findForkCheckpointInHistory.d.ts.map +1 -1
- package/dist/hooks.d.ts +5 -7
- package/dist/hooks.d.ts.map +1 -1
- package/dist/index.d.ts +7 -8
- package/dist/index.d.ts.map +1 -0
- package/dist/resolveForkCheckpoint.d.ts +4 -5
- package/dist/resolveForkCheckpoint.d.ts.map +1 -1
- package/dist/runtimeExtras.d.ts +1 -3
- package/dist/runtimeExtras.d.ts.map +1 -1
- package/dist/sdkIdentity.d.ts +1 -3
- package/dist/sdkIdentity.d.ts.map +1 -1
- package/dist/sdkIdentity.js +1 -1
- package/dist/streamingTiming.d.ts +2 -4
- package/dist/streamingTiming.d.ts.map +1 -1
- package/dist/subagentMessagesProjection.d.ts +17 -0
- package/dist/subagentMessagesProjection.d.ts.map +1 -0
- package/dist/subagentMessagesProjection.js +40 -0
- package/dist/subagentMessagesProjection.js.map +1 -0
- package/dist/types.d.ts +100 -103
- package/dist/types.d.ts.map +1 -1
- package/dist/uiMessages.d.ts +18 -6
- package/dist/uiMessages.d.ts.map +1 -1
- package/dist/uiMessages.js +33 -1
- package/dist/uiMessages.js.map +1 -1
- package/dist/useStreamRuntime.d.ts +7 -10
- package/dist/useStreamRuntime.d.ts.map +1 -1
- package/dist/useStreamRuntime.js +99 -25
- package/dist/useStreamRuntime.js.map +1 -1
- package/dist/useSubagentTranscripts.d.ts +3 -5
- package/dist/useSubagentTranscripts.d.ts.map +1 -1
- package/dist/useSubagentTranscripts.js +3 -2
- package/dist/useSubagentTranscripts.js.map +1 -1
- package/package.json +9 -5
- package/src/convertMessages.test.ts +69 -0
- package/src/convertMessages.ts +46 -8
- package/src/converter.ts +6 -0
- package/src/subagentMessagesProjection.test.ts +175 -0
- package/src/subagentMessagesProjection.ts +50 -0
- package/src/uiMessages.test.ts +106 -0
- package/src/uiMessages.ts +43 -0
- package/src/useStreamRuntime.test.tsx +100 -0
- package/src/useStreamRuntime.ts +193 -44
- package/src/useStreamRuntime.voice.test.tsx +712 -0
- package/src/useSubagentTranscripts.ts +3 -6
package/dist/uiMessages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uiMessages.js","names":[],"sources":["../src/uiMessages.ts"],"sourcesContent":["import type { Channel } from \"@langchain/react\";\nimport type { RemoveUIMessage, UIMessage } from \"./types\";\n\n/** Channels the generative-UI fold reads, at the root and per subagent. */\nexport const UI_CUSTOM_CHANNELS: readonly Channel[] = [\"custom\"];\n\nexport type UIUpdate = UIMessage | RemoveUIMessage;\n\nexport const isUIUpdate = (\n value: unknown,\n): value is UIUpdate | readonly UIUpdate[] => {\n if (Array.isArray(value)) return value.length > 0 && value.every(isUIUpdate);\n if (value == null || typeof value !== \"object\") return false;\n const v = value as {\n type?: unknown;\n id?: unknown;\n name?: unknown;\n props?: unknown;\n };\n if (typeof v.id !== \"string\") return false;\n if (v.type === \"remove-ui\") return true;\n return (\n v.type === \"ui\" &&\n typeof v.name === \"string\" &&\n typeof v.props === \"object\" &&\n v.props !== null\n );\n};\n\nexport const applyUIUpdate = (\n list: readonly UIMessage[],\n update: UIUpdate | readonly UIUpdate[],\n): UIMessage[] => {\n const events = Array.isArray(update) ? update : [update as UIUpdate];\n let next = list.slice();\n for (const event of events) {\n if (event.type === \"remove-ui\") {\n next = next.filter((ui) => ui.id !== event.id);\n continue;\n }\n const index = next.findIndex((ui) => ui.id === event.id);\n if (index === -1) {\n next.push(event);\n continue;\n }\n next[index] =\n event.metadata?.merge === true\n ? { ...event, props: { ...next[index]!.props, ...event.props } }\n : event;\n }\n return next;\n};\n\n/**\n * Pulls a UI update out of a raw `custom`-channel event. The graph writes the\n * `UIMessage` straight to the channel, so it lands at `params.data`; some\n * transports wrap it one level deeper at `params.data.payload`.\n */\nexport const extractUIUpdate = (\n event: unknown,\n): UIUpdate | readonly UIUpdate[] | undefined => {\n const data = (event as { params?: { data?: unknown } } | null)?.params?.data;\n if (isUIUpdate(data)) return data;\n const payload = (data as { payload?: unknown } | undefined)?.payload;\n if (isUIUpdate(payload)) return payload;\n return undefined;\n};\n\nexport type UIFoldMemo = {\n events: readonly unknown[];\n messages: UIMessage[];\n};\n\nexport const createUIFoldMemo = (): UIFoldMemo => ({\n events: [],\n messages: [],\n});\n\n/**\n * Folds `custom`-channel events into UI messages, continuing the fold held in\n * `memo`. The channel buffer holds each event object once, appends new events\n * and drops its oldest ones once full, so only events after the previously\n * folded last event are applied, and entries no later event touches keep\n * their identity. A buffer that no longer contains that event was replaced\n * and is folded from scratch.\n */\nexport const foldUIUpdates = (\n events: readonly unknown[],\n memo: UIFoldMemo = createUIFoldMemo(),\n): UIMessage[] => {\n const previous = memo.events;\n const resumeAt =\n previous.length === 0\n ? 0\n : events.lastIndexOf(previous.at(-1), previous.length - 1) + 1;\n let acc = previous.length > 0 && resumeAt === 0 ? [] : memo.messages;\n for (let i = resumeAt; i < events.length; i++) {\n const update = extractUIUpdate(events[i]);\n if (update) acc = applyUIUpdate(acc, update);\n }\n memo.events = events;\n memo.messages = acc;\n return acc;\n};\n\n/**\n * Merges live-streamed UI with the state snapshot. The snapshot is\n * authoritative by id: once a UI lands in graph state it supersedes its live\n * copy. A consequence is that a live `remove-ui` is overridden while the\n * snapshot still contains that id; the removal only takes visible effect once\n * the snapshot catches up.\n */\nexport const mergeUIMessages = (\n live: readonly UIMessage[],\n snapshot: unknown,\n): UIMessage[] => {\n const byId = new Map<string, UIMessage>();\n for (const ui of live) byId.set(ui.id, ui);\n if (Array.isArray(snapshot)) {\n for (const ui of snapshot as UIMessage[]) byId.set(ui.id, ui);\n }\n return [...byId.values()];\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"uiMessages.js","names":[],"sources":["../src/uiMessages.ts"],"sourcesContent":["import type { Channel } from \"@langchain/react\";\nimport { isJSONValueEqual } from \"@assistant-ui/core/internal\";\nimport type { RemoveUIMessage, UIMessage } from \"./types\";\n\n/** Channels the generative-UI fold reads, at the root and per subagent. */\nexport const UI_CUSTOM_CHANNELS: readonly Channel[] = [\"custom\"];\n\nexport type UIUpdate = UIMessage | RemoveUIMessage;\n\nexport const isUIUpdate = (\n value: unknown,\n): value is UIUpdate | readonly UIUpdate[] => {\n if (Array.isArray(value)) return value.length > 0 && value.every(isUIUpdate);\n if (value == null || typeof value !== \"object\") return false;\n const v = value as {\n type?: unknown;\n id?: unknown;\n name?: unknown;\n props?: unknown;\n };\n if (typeof v.id !== \"string\") return false;\n if (v.type === \"remove-ui\") return true;\n return (\n v.type === \"ui\" &&\n typeof v.name === \"string\" &&\n typeof v.props === \"object\" &&\n v.props !== null\n );\n};\n\nexport const applyUIUpdate = (\n list: readonly UIMessage[],\n update: UIUpdate | readonly UIUpdate[],\n): UIMessage[] => {\n const events = Array.isArray(update) ? update : [update as UIUpdate];\n let next = list.slice();\n for (const event of events) {\n if (event.type === \"remove-ui\") {\n next = next.filter((ui) => ui.id !== event.id);\n continue;\n }\n const index = next.findIndex((ui) => ui.id === event.id);\n if (index === -1) {\n next.push(event);\n continue;\n }\n next[index] =\n event.metadata?.merge === true\n ? { ...event, props: { ...next[index]!.props, ...event.props } }\n : event;\n }\n return next;\n};\n\n/**\n * Pulls a UI update out of a raw `custom`-channel event. The graph writes the\n * `UIMessage` straight to the channel, so it lands at `params.data`; some\n * transports wrap it one level deeper at `params.data.payload`.\n */\nexport const extractUIUpdate = (\n event: unknown,\n): UIUpdate | readonly UIUpdate[] | undefined => {\n const data = (event as { params?: { data?: unknown } } | null)?.params?.data;\n if (isUIUpdate(data)) return data;\n const payload = (data as { payload?: unknown } | undefined)?.payload;\n if (isUIUpdate(payload)) return payload;\n return undefined;\n};\n\nexport type UIFoldMemo = {\n events: readonly unknown[];\n messages: UIMessage[];\n};\n\nexport const createUIFoldMemo = (): UIFoldMemo => ({\n events: [],\n messages: [],\n});\n\n/**\n * Folds `custom`-channel events into UI messages, continuing the fold held in\n * `memo`. The channel buffer holds each event object once, appends new events\n * and drops its oldest ones once full, so only events after the previously\n * folded last event are applied, and entries no later event touches keep\n * their identity. A buffer that no longer contains that event was replaced\n * and is folded from scratch.\n */\nexport const foldUIUpdates = (\n events: readonly unknown[],\n memo: UIFoldMemo = createUIFoldMemo(),\n): UIMessage[] => {\n const previous = memo.events;\n const resumeAt =\n previous.length === 0\n ? 0\n : events.lastIndexOf(previous.at(-1), previous.length - 1) + 1;\n let acc = previous.length > 0 && resumeAt === 0 ? [] : memo.messages;\n for (let i = resumeAt; i < events.length; i++) {\n const update = extractUIUpdate(events[i]);\n if (update) acc = applyUIUpdate(acc, update);\n }\n memo.events = events;\n memo.messages = acc;\n return acc;\n};\n\nexport type UISnapshotMemo = {\n snapshot: unknown;\n entries: readonly UIMessage[];\n};\n\nexport const createUISnapshotMemo = (): UISnapshotMemo => ({\n snapshot: undefined,\n entries: [],\n});\n\n/**\n * Recovers entry identity across `values` events. The SDK rebuilds the\n * `values` object from every snapshot and reconciles only the messages slot by\n * id, so an unchanged UI list arrives as a new array of new objects on every\n * superstep. An entry structurally equal to the previous entry with its id is\n * replaced by that previous object, and a list whose entries all survive in\n * place is replaced by the previous list.\n */\nexport const reconcileUISnapshot = (\n snapshot: unknown,\n memo: UISnapshotMemo,\n): readonly UIMessage[] => {\n if (snapshot === memo.snapshot) return memo.entries;\n memo.snapshot = snapshot;\n if (!Array.isArray(snapshot)) {\n if (memo.entries.length > 0) memo.entries = [];\n return memo.entries;\n }\n const previous = memo.entries;\n const previousById = new Map(previous.map((ui) => [ui.id, ui]));\n let same = snapshot.length === previous.length;\n const entries = (snapshot as UIMessage[]).map((ui, index) => {\n const before = previousById.get(ui.id);\n const entry =\n before !== undefined && isJSONValueEqual(before, ui) ? before : ui;\n if (entry !== previous[index]) same = false;\n return entry;\n });\n if (!same) memo.entries = entries;\n return memo.entries;\n};\n\n/**\n * Merges live-streamed UI with the state snapshot. The snapshot is\n * authoritative by id: once a UI lands in graph state it supersedes its live\n * copy. A consequence is that a live `remove-ui` is overridden while the\n * snapshot still contains that id; the removal only takes visible effect once\n * the snapshot catches up.\n */\nexport const mergeUIMessages = (\n live: readonly UIMessage[],\n snapshot: unknown,\n): UIMessage[] => {\n const byId = new Map<string, UIMessage>();\n for (const ui of live) byId.set(ui.id, ui);\n if (Array.isArray(snapshot)) {\n for (const ui of snapshot as UIMessage[]) byId.set(ui.id, ui);\n }\n return [...byId.values()];\n};\n"],"mappings":"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"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
/// <reference types="@assistant-ui/core/store" />
|
|
2
|
-
import {
|
|
3
|
-
import { UseStreamRuntimeOptions } from "./types.js";
|
|
4
|
-
|
|
5
|
-
//#region src/useStreamRuntime.d.ts
|
|
1
|
+
/// <reference types="@assistant-ui/core/store" preserve="true" />
|
|
2
|
+
import type { AppendMessage } from "@assistant-ui/core";
|
|
3
|
+
import type { UseStreamRuntimeOptions } from "./types.js";
|
|
4
|
+
export { groupUIMessagesByParent } from "./converter.js";
|
|
6
5
|
export declare const runConfigToSubmitOptions: (runConfig: AppendMessage["runConfig"]) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
config: {
|
|
7
|
+
configurable: Record<string, unknown>;
|
|
8
|
+
};
|
|
10
9
|
} | undefined;
|
|
11
10
|
/**
|
|
12
11
|
* Creates an assistant-ui runtime backed by LangChain's `useStream` hook.
|
|
@@ -33,6 +32,4 @@ export declare const runConfigToSubmitOptions: (runConfig: AppendMessage["runCon
|
|
|
33
32
|
* ```
|
|
34
33
|
*/
|
|
35
34
|
export declare const useStreamRuntime: (rawOptions: UseStreamRuntimeOptions) => import("@assistant-ui/core").AssistantRuntime;
|
|
36
|
-
//#endregion
|
|
37
|
-
export { groupUIMessagesByParent };
|
|
38
35
|
//# sourceMappingURL=useStreamRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStreamRuntime.d.ts","
|
|
1
|
+
{"version":3,"file":"useStreamRuntime.d.ts","sourceRoot":"","sources":["../src/useStreamRuntime.ts"],"names":[],"mappings":";AAWA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,oBAAoB,CAAC;AAqB7E,OAAO,KAAK,EAIV,uBAAuB,EACxB,mBAAgB;AAEjB,OAAO,EAAE,uBAAuB,EAAE,uBAAoB;AAwBtD,eAAO,MAAM,wBAAwB,GACnC,WAAW,aAAa,CAAC,WAAW,CAAC;;;;aAIxB,CAAC;AA6rBhB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,gBAAgB,GAAI,YAAY,uBAAuB,kDA8BnE,CAAC"}
|
package/dist/useStreamRuntime.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { attachSubagentTranscripts, createAttachMemo } from "./attachSubagentTranscripts.js";
|
|
3
|
-
import { getMessageContent, groupUIMessagesByParent } from "./converter.js";
|
|
3
|
+
import { getMessageContent, getMessageModality, groupUIMessagesByParent } from "./converter.js";
|
|
4
4
|
import { convertLangChainBaseMessage, getMessageType } from "./convertMessages.js";
|
|
5
5
|
import { langChainExtras } from "./runtimeExtras.js";
|
|
6
6
|
import { useLangChainStreamingTiming } from "./streamingTiming.js";
|
|
7
|
-
import { UI_CUSTOM_CHANNELS, createUIFoldMemo, foldUIUpdates, mergeUIMessages } from "./uiMessages.js";
|
|
7
|
+
import { UI_CUSTOM_CHANNELS, createUIFoldMemo, createUISnapshotMemo, foldUIUpdates, mergeUIMessages, reconcileUISnapshot } from "./uiMessages.js";
|
|
8
8
|
import { useSubagentTranscripts } from "./useSubagentTranscripts.js";
|
|
9
9
|
import { resolveForkCheckpoint } from "./resolveForkCheckpoint.js";
|
|
10
10
|
import { LANGCHAIN_SDK } from "./sdkIdentity.js";
|
|
11
11
|
import { generateId, getExternalStoreMessages, pickExternalStoreSharedOptions } from "@assistant-ui/core";
|
|
12
|
-
import { createCloudThreadListAdapterCreateFallback, createToolCallCancellationStub, scanPendingToolCalls } from "@assistant-ui/core/internal";
|
|
12
|
+
import { createCloudThreadListAdapterCreateFallback, createToolCallCancellationStub, getThreadMessageText, scanPendingToolCalls } from "@assistant-ui/core/internal";
|
|
13
13
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
14
14
|
import { useCloudThreadListAdapter, useExternalMessageConverter, useExternalStoreRuntime, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
|
|
15
15
|
import { useCallback, useEffect, useInsertionEffect, useMemo, useRef, useState } from "react";
|
|
@@ -26,6 +26,12 @@ const toStagedHumanMessage = (msg, id = generateId()) => ({
|
|
|
26
26
|
_getType: () => "human",
|
|
27
27
|
content: getMessageContent(msg)
|
|
28
28
|
});
|
|
29
|
+
const toStagedMessageInput = (message) => ({
|
|
30
|
+
id: message.id,
|
|
31
|
+
type: getMessageType(message) === "ai" ? "ai" : "human",
|
|
32
|
+
content: message.content,
|
|
33
|
+
...message.additional_kwargs && { additional_kwargs: message.additional_kwargs }
|
|
34
|
+
});
|
|
29
35
|
const humanContentText = (content) => {
|
|
30
36
|
if (typeof content === "string") return content;
|
|
31
37
|
if (!Array.isArray(content)) return "";
|
|
@@ -51,7 +57,8 @@ const useStreamThreadRuntime = (options) => {
|
|
|
51
57
|
const [toolStatuses, setToolStatuses] = useState({});
|
|
52
58
|
const hasExecutingTools = Object.values(toolStatuses).some((s) => s?.type === "executing");
|
|
53
59
|
const effectiveIsRunning = stream.isLoading || hasExecutingTools;
|
|
54
|
-
const
|
|
60
|
+
const [uiSnapshotMemo] = useState(createUISnapshotMemo);
|
|
61
|
+
const uiStateValue = reconcileUISnapshot(stream.values[uiStateKey], uiSnapshotMemo);
|
|
55
62
|
const customEvents = useChannel(stream, UI_CUSTOM_CHANNELS);
|
|
56
63
|
const [uiFoldMemo] = useState(createUIFoldMemo);
|
|
57
64
|
const liveUiMessages = useMemo(() => foldUIUpdates(customEvents, uiFoldMemo), [customEvents, uiFoldMemo]);
|
|
@@ -156,15 +163,75 @@ const useStreamThreadRuntime = (options) => {
|
|
|
156
163
|
setStagedMessages(nextMessages);
|
|
157
164
|
}, [stream.messages]);
|
|
158
165
|
const getStagedRun = (parentId) => {
|
|
159
|
-
|
|
166
|
+
const parent = parentId ? stagedMessagesRef.current.get(parentId) : void 0;
|
|
167
|
+
if (!parent || parent.transcriptStatus === "sent") return null;
|
|
160
168
|
const staged = [];
|
|
161
169
|
for (const message of visibleMessagesRef.current) {
|
|
162
|
-
|
|
170
|
+
const entry = message.id ? stagedMessagesRef.current.get(message.id) : void 0;
|
|
171
|
+
if (entry && entry.transcriptStatus !== "sent") staged.push(entry.message);
|
|
163
172
|
if (message.id === parentId) break;
|
|
164
173
|
}
|
|
165
174
|
return {
|
|
166
175
|
messages: staged,
|
|
167
|
-
runConfig:
|
|
176
|
+
runConfig: parent.runConfig
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
const appendVoiceTranscript = (message) => {
|
|
180
|
+
const transcript = {
|
|
181
|
+
id: message.id,
|
|
182
|
+
_getType: () => message.role === "assistant" ? "ai" : "human",
|
|
183
|
+
content: getThreadMessageText(message),
|
|
184
|
+
...message.metadata.modality && { additional_kwargs: { modality: message.metadata.modality } }
|
|
185
|
+
};
|
|
186
|
+
stagedMessagesRef.current.set(transcript.id, {
|
|
187
|
+
message: transcript,
|
|
188
|
+
runConfig: void 0,
|
|
189
|
+
reconcileOnEcho: false,
|
|
190
|
+
baseMessageCount: streamRef.current.messages.length,
|
|
191
|
+
transcriptStatus: "unsent"
|
|
192
|
+
});
|
|
193
|
+
const nextMessages = [...visibleMessagesRef.current, transcript];
|
|
194
|
+
visibleMessagesRef.current = nextMessages;
|
|
195
|
+
setStagedMessages(nextMessages);
|
|
196
|
+
};
|
|
197
|
+
const getUnsentTranscripts = () => visibleMessagesRef.current.filter((message) => message.id !== void 0 && stagedMessagesRef.current.get(message.id)?.transcriptStatus === "unsent");
|
|
198
|
+
const setTranscriptStatus = (messages, status) => {
|
|
199
|
+
for (const message of messages) {
|
|
200
|
+
const staged = message.id ? stagedMessagesRef.current.get(message.id) : void 0;
|
|
201
|
+
if (staged?.transcriptStatus) staged.transcriptStatus = status;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
const submitCarryingTranscripts = async (transcripts, submit) => {
|
|
205
|
+
setTranscriptStatus(transcripts, "sent");
|
|
206
|
+
try {
|
|
207
|
+
await submit();
|
|
208
|
+
} catch (error) {
|
|
209
|
+
setTranscriptStatus(transcripts, "unsent");
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const dropTranscripts = (messages) => {
|
|
214
|
+
for (const message of messages) if (message.id && stagedMessagesRef.current.get(message.id)?.transcriptStatus) removeStagedMessage(message.id);
|
|
215
|
+
};
|
|
216
|
+
const isTranscriptMessage = (message) => {
|
|
217
|
+
if ((message.id ? stagedMessagesRef.current.get(message.id) : void 0)?.transcriptStatus === "unsent") return true;
|
|
218
|
+
const type = getMessageType(message);
|
|
219
|
+
return (type === "human" || type === "ai") && getMessageModality(message.additional_kwargs) !== void 0;
|
|
220
|
+
};
|
|
221
|
+
const planForkTranscripts = (parentId) => {
|
|
222
|
+
const visible = visibleMessagesRef.current;
|
|
223
|
+
const parentIndex = parentId == null ? -1 : visible.findIndex((m) => m.id === parentId);
|
|
224
|
+
if (parentId != null && parentIndex === -1) return {
|
|
225
|
+
forkParentId: parentId,
|
|
226
|
+
transcripts: [],
|
|
227
|
+
truncated: []
|
|
228
|
+
};
|
|
229
|
+
let start = parentIndex + 1;
|
|
230
|
+
while (start > 0 && isTranscriptMessage(visible[start - 1])) start--;
|
|
231
|
+
return {
|
|
232
|
+
forkParentId: start > 0 ? visible[start - 1].id ?? null : null,
|
|
233
|
+
transcripts: visible.slice(start, parentIndex + 1),
|
|
234
|
+
truncated: visible.slice(parentIndex + 1)
|
|
168
235
|
};
|
|
169
236
|
};
|
|
170
237
|
const stageUserMessage = (msg, reconcileOnEcho = false) => {
|
|
@@ -230,19 +297,25 @@ const useStreamThreadRuntime = (options) => {
|
|
|
230
297
|
const cancellations = autoCancelPendingToolCalls !== false ? getPendingToolCalls(streamRef.current.messages).map(createToolCallCancellationStub) : [];
|
|
231
298
|
try {
|
|
232
299
|
const { externalId } = await aui.threadListItem.initialize();
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
300
|
+
const transcripts = getUnsentTranscripts();
|
|
301
|
+
await submitCarryingTranscripts(transcripts, () => streamRef.current.submit({ [messagesKey]: [
|
|
302
|
+
...cancellations,
|
|
303
|
+
...transcripts.map(toStagedMessageInput),
|
|
304
|
+
{
|
|
305
|
+
id: stagedMessageId,
|
|
306
|
+
type: "human",
|
|
307
|
+
content
|
|
308
|
+
}
|
|
309
|
+
] }, {
|
|
238
310
|
...runConfigToSubmitOptions(msg.runConfig),
|
|
239
311
|
...externalId != null ? { threadId: externalId } : {}
|
|
240
|
-
});
|
|
312
|
+
}));
|
|
241
313
|
} catch (error) {
|
|
242
314
|
removeStagedMessage(stagedMessageId);
|
|
243
315
|
throw error;
|
|
244
316
|
}
|
|
245
317
|
},
|
|
318
|
+
onVoiceTranscript: appendVoiceTranscript,
|
|
246
319
|
onAddToolResult: async ({ messageId, toolCallId, toolName, result, isError, artifact }) => {
|
|
247
320
|
const runConfig = runConfigByMessageIdRef.current.has(messageId) ? runConfigByMessageIdRef.current.get(messageId) : activeRunConfigRef.current;
|
|
248
321
|
await stream.submit({ [messagesKey]: [{
|
|
@@ -257,9 +330,10 @@ const useStreamThreadRuntime = (options) => {
|
|
|
257
330
|
onReload: async (parentId, config) => {
|
|
258
331
|
const stagedRun = getStagedRun(parentId);
|
|
259
332
|
if (stagedRun) {
|
|
333
|
+
if (config.sourceId && stagedMessagesRef.current.get(config.sourceId)?.transcriptStatus) removeStagedMessage(config.sourceId);
|
|
260
334
|
const promotedIds = /* @__PURE__ */ new Set();
|
|
261
335
|
for (const message of stagedRun.messages) {
|
|
262
|
-
if (!message.id) continue;
|
|
336
|
+
if (!message.id || stagedMessagesRef.current.get(message.id)?.transcriptStatus) continue;
|
|
263
337
|
promotedIds.add(message.id);
|
|
264
338
|
stagedMessagesRef.current.delete(message.id);
|
|
265
339
|
}
|
|
@@ -271,23 +345,21 @@ const useStreamThreadRuntime = (options) => {
|
|
|
271
345
|
} else setStagedMessages(null);
|
|
272
346
|
const runConfig = config.runConfig ?? stagedRun.runConfig;
|
|
273
347
|
setActiveRunConfig(runConfig);
|
|
274
|
-
await stream.submit({ [messagesKey]: stagedRun.messages.map(
|
|
275
|
-
id: message.id,
|
|
276
|
-
type: "human",
|
|
277
|
-
content: message.content
|
|
278
|
-
})) }, runConfigToSubmitOptions(runConfig));
|
|
348
|
+
await submitCarryingTranscripts(stagedRun.messages, () => stream.submit({ [messagesKey]: stagedRun.messages.map(toStagedMessageInput) }, runConfigToSubmitOptions(runConfig)));
|
|
279
349
|
return;
|
|
280
350
|
}
|
|
281
351
|
const threadId = externalId;
|
|
282
352
|
if (!threadId || parentId == null) return;
|
|
283
353
|
const s = streamRef.current;
|
|
284
|
-
const
|
|
354
|
+
const fork = planForkTranscripts(parentId);
|
|
355
|
+
const checkpointId = await resolveForkCheckpoint(s.client, threadId, s.messages, fork.forkParentId, config.sourceId, s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(), messagesKey);
|
|
285
356
|
if (!checkpointId) return;
|
|
357
|
+
dropTranscripts(fork.truncated);
|
|
286
358
|
setActiveRunConfig(config.runConfig);
|
|
287
|
-
await s.submit(null, {
|
|
359
|
+
await submitCarryingTranscripts(fork.transcripts, () => s.submit(fork.transcripts.length > 0 ? { [messagesKey]: fork.transcripts.map(toStagedMessageInput) } : null, {
|
|
288
360
|
forkFrom: checkpointId,
|
|
289
361
|
...runConfigToSubmitOptions(config.runConfig)
|
|
290
|
-
});
|
|
362
|
+
}));
|
|
291
363
|
},
|
|
292
364
|
onEdit: async (message) => {
|
|
293
365
|
if (!(message.startRun ?? message.role === "user")) {
|
|
@@ -308,17 +380,19 @@ const useStreamThreadRuntime = (options) => {
|
|
|
308
380
|
const threadId = externalId;
|
|
309
381
|
if (!threadId) return;
|
|
310
382
|
const s = streamRef.current;
|
|
311
|
-
const
|
|
383
|
+
const fork = planForkTranscripts(message.parentId);
|
|
384
|
+
const checkpointId = await resolveForkCheckpoint(s.client, threadId, s.messages, fork.forkParentId, message.sourceId, s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(), messagesKey);
|
|
312
385
|
if (!checkpointId) return;
|
|
386
|
+
dropTranscripts(fork.truncated);
|
|
313
387
|
const content = getMessageContent(message);
|
|
314
388
|
setActiveRunConfig(message.runConfig);
|
|
315
|
-
await s.submit({ [messagesKey]: [{
|
|
389
|
+
await submitCarryingTranscripts(fork.transcripts, () => s.submit({ [messagesKey]: [...fork.transcripts.map(toStagedMessageInput), {
|
|
316
390
|
type: "human",
|
|
317
391
|
content
|
|
318
392
|
}] }, {
|
|
319
393
|
forkFrom: checkpointId,
|
|
320
394
|
...runConfigToSubmitOptions(message.runConfig)
|
|
321
|
-
});
|
|
395
|
+
}));
|
|
322
396
|
},
|
|
323
397
|
onCancel: unstable_allowCancellation !== false ? async () => {
|
|
324
398
|
activeRunConfigRef.current = void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStreamRuntime.js","names":[],"sources":["../src/useStreamRuntime.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/store\" />\n\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} 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 createCloudThreadListAdapterCreateFallback,\n createToolCallCancellationStub,\n scanPendingToolCalls,\n} from \"@assistant-ui/core/internal\";\nimport {\n useCloudThreadListAdapter,\n useExternalStoreRuntime,\n useExternalMessageConverter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { STREAM_CONTROLLER, useChannel, useStream } from \"@langchain/react\";\nimport type {\n LangChainBaseMessage,\n LangChainToolCall,\n UIMessage,\n UseStreamRuntimeOptions,\n} from \"./types\";\nimport { groupUIMessagesByParent } from \"./converter\";\nexport { groupUIMessagesByParent } from \"./converter\";\nimport {\n convertLangChainBaseMessage,\n getMessageContent,\n getMessageType,\n} from \"./convertMessages\";\nimport {\n attachSubagentTranscripts,\n createAttachMemo,\n} from \"./attachSubagentTranscripts\";\nimport { useSubagentTranscripts } from \"./useSubagentTranscripts\";\nimport {\n createUIFoldMemo,\n foldUIUpdates,\n mergeUIMessages,\n UI_CUSTOM_CHANNELS,\n} from \"./uiMessages\";\nimport { langChainExtras } from \"./runtimeExtras\";\nimport { resolveForkCheckpoint } from \"./resolveForkCheckpoint\";\nimport { useLangChainStreamingTiming } from \"./streamingTiming\";\nimport { LANGCHAIN_SDK } from \"./sdkIdentity\";\n\nexport const runConfigToSubmitOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n) =>\n runConfig?.custom\n ? { config: { configurable: runConfig.custom } }\n : undefined;\n\ntype NormalizedRunConfigOptions = NonNullable<\n ReturnType<typeof runConfigToSubmitOptions>\n>;\n\nconst getPendingToolCalls = (\n messages: readonly LangChainBaseMessage[],\n): LangChainToolCall[] =>\n scanPendingToolCalls(\n messages,\n (message) => {\n const type = getMessageType(message);\n if (type === \"ai\") return { toolCalls: message.tool_calls ?? [] };\n if (type === \"tool\" && message.tool_call_id) {\n return { toolCallId: message.tool_call_id };\n }\n return undefined;\n },\n (toolCall) => toolCall.id,\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 humanContentText = (content: LangChainBaseMessage[\"content\"]) => {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n typeof part === \"object\" &&\n part !== null &&\n part.type === \"text\" &&\n typeof part.text === \"string\",\n )\n .map((part) => part.text)\n .join(\"\");\n};\n\nconst hasSameMessageContent = (\n a: LangChainBaseMessage,\n b: LangChainBaseMessage,\n) => humanContentText(a.content) === humanContentText(b.content);\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 aui = useAui();\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 // Object.assign preserves the discriminated transport union; object spread\n // collapses its arms and no longer satisfies UseStreamOptions.\n const stream = useStream(\n Object.assign({}, options, { threadId: externalId }),\n );\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 [uiFoldMemo] = useState(createUIFoldMemo);\n const liveUiMessages = useMemo(\n () => foldUIUpdates(customEvents, uiFoldMemo),\n [customEvents, uiFoldMemo],\n );\n\n const mergedUiMessages = useMemo(\n () => mergeUIMessages(liveUiMessages, uiStateValue),\n [liveUiMessages, uiStateValue],\n );\n\n const uiMessagesByParent = useMemo(\n () => groupUIMessagesByParent<UIMessage>(mergedUiMessages),\n [mergedUiMessages],\n );\n\n const visibleMessages =\n stagedMessages ?? (stream.messages as LangChainBaseMessage[]);\n\n const messageTiming = useLangChainStreamingTiming(\n visibleMessages,\n effectiveIsRunning,\n );\n\n const subagentTranscripts = useSubagentTranscripts(\n stream,\n uiMessagesByParent,\n );\n\n const convertWithUI = useMemo<\n useExternalMessageConverter.Callback<LangChainBaseMessage>\n >(\n () => (message, metadata) =>\n convertLangChainBaseMessage(message, {\n ...metadata,\n uiMessagesByParent,\n messageTiming,\n }),\n [uiMessagesByParent, messageTiming],\n );\n\n const threadMessages = useExternalMessageConverter({\n callback: convertWithUI,\n messages: visibleMessages,\n isRunning: effectiveIsRunning,\n });\n const [memo] = useState(createAttachMemo);\n const messagesWithTranscripts = useMemo(\n () => attachSubagentTranscripts(threadMessages, subagentTranscripts, memo),\n [threadMessages, subagentTranscripts, memo],\n );\n\n const streamRef = useRef(stream);\n useInsertionEffect(() => {\n streamRef.current = stream;\n }, [stream]);\n\n const activeRunConfigRef = useRef<\n NormalizedRunConfigOptions[\"config\"] | undefined\n >(undefined);\n const runConfigByMessageIdRef = useRef(\n new Map<string, NormalizedRunConfigOptions[\"config\"] | undefined>(),\n );\n const activeThreadIdRef = useRef(externalId);\n const setActiveRunConfig = useCallback(\n (runConfig: AppendMessage[\"runConfig\"]) => {\n activeRunConfigRef.current = runConfigToSubmitOptions(runConfig)?.config;\n },\n [],\n );\n const withActiveRunConfig = useCallback(\n (submitOptions?: Record<string, unknown>) => {\n if (submitOptions && \"config\" in submitOptions) return submitOptions;\n if (activeRunConfigRef.current === undefined) return submitOptions;\n return { ...submitOptions, config: activeRunConfigRef.current };\n },\n [],\n );\n\n useEffect(() => {\n if (\n activeThreadIdRef.current !== null &&\n activeThreadIdRef.current !== externalId\n ) {\n activeRunConfigRef.current = undefined;\n runConfigByMessageIdRef.current.clear();\n }\n activeThreadIdRef.current = externalId;\n }, [externalId]);\n\n useEffect(() => {\n const messages = stream.messages as readonly LangChainBaseMessage[];\n const owned = runConfigByMessageIdRef.current;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages.at(i);\n if (\n !message?.id ||\n getMessageType(message) !== \"ai\" ||\n !message.tool_calls?.length\n ) {\n continue;\n }\n if (owned.has(message.id)) return;\n break;\n }\n for (const message of messages) {\n if (\n !message.id ||\n getMessageType(message) !== \"ai\" ||\n !message.tool_calls?.length ||\n owned.has(message.id)\n ) {\n continue;\n }\n owned.set(message.id, activeRunConfigRef.current);\n }\n }, [stream.messages]);\n\n const visibleMessagesRef = useRef(visibleMessages);\n useInsertionEffect(() => {\n visibleMessagesRef.current = visibleMessages;\n }, [visibleMessages]);\n\n const threadMessagesRef = useRef(messagesWithTranscripts);\n useInsertionEffect(() => {\n threadMessagesRef.current = messagesWithTranscripts;\n }, [messagesWithTranscripts]);\n\n const stagedMessagesRef = useRef(\n new Map<\n string,\n {\n message: LangChainBaseMessage & { id: string };\n runConfig: AppendMessage[\"runConfig\"];\n reconcileOnEcho: boolean;\n baseMessageCount: number;\n }\n >(),\n );\n const stagedBaseMessagesRef = useRef<LangChainBaseMessage[] | null>(null);\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 remainingStagedMessages: LangChainBaseMessage[] = [];\n const matchedBaseMessageIndexes = new Set<number>();\n const visibleStagedIds = new Set(\n visibleMessagesRef.current.flatMap((m) => (m.id ? [m.id] : [])),\n );\n for (const [id, staged] of stagedMessagesRef.current) {\n if (!visibleStagedIds.has(id)) continue;\n const echoed = baseMessages.some((message, index) => {\n if (matchedBaseMessageIndexes.has(index)) return false;\n if (message.id === id) {\n matchedBaseMessageIndexes.add(index);\n return true;\n }\n if (\n !staged.reconcileOnEcho ||\n index < staged.baseMessageCount ||\n getMessageType(message) !== \"human\" ||\n !hasSameMessageContent(message, staged.message)\n ) {\n return false;\n }\n matchedBaseMessageIndexes.add(index);\n return true;\n });\n if (echoed) stagedMessagesRef.current.delete(id);\n else remainingStagedMessages.push(staged.message);\n }\n\n if (remainingStagedMessages.length === 0) {\n stagedBaseMessagesRef.current = null;\n visibleMessagesRef.current = baseMessages;\n // Reconciling against the upstream stream mutates the staged refs above,\n // which cannot happen during render.\n // eslint-disable-next-line react-hooks/set-state-in-effect\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, reconcileOnEcho = false) => {\n const stagedMessage = toStagedHumanMessage(msg);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: msg.runConfig,\n reconcileOnEcho,\n baseMessageCount: streamRef.current.messages.length,\n });\n const nextMessages = [...visibleMessagesRef.current, stagedMessage];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n return stagedMessage;\n };\n\n const removeStagedMessage = (id: string) => {\n if (!stagedMessagesRef.current.delete(id)) return;\n const nextMessages = visibleMessagesRef.current.filter(\n (message) => message.id !== id,\n );\n visibleMessagesRef.current = nextMessages;\n if (stagedMessagesRef.current.size === 0) {\n stagedBaseMessagesRef.current = null;\n setStagedMessages(null);\n } else {\n setStagedMessages(nextMessages);\n }\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: (values, submitOptions) => {\n const isResume = values == null || submitOptions?.command != null;\n return stream.submit(\n values,\n isResume ? withActiveRunConfig(submitOptions) : submitOptions,\n );\n },\n respond: (response, respondOptions) =>\n stream.respond(response, withActiveRunConfig(respondOptions)),\n respondAll: (responsesById, respondOptions) =>\n stream.respondAll(responsesById, withActiveRunConfig(respondOptions)),\n values: stream.values,\n messagesKey,\n }),\n [stream, messagesKey, withActiveRunConfig],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: stream.isLoading,\n isLoading: stream.isThreadLoading,\n messages: messagesWithTranscripts,\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 stagedMessage = stageUserMessage(msg, true);\n const stagedMessageId = stagedMessage.id;\n setActiveRunConfig(msg.runConfig);\n const content = getMessageContent(msg);\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(\n streamRef.current.messages as readonly LangChainBaseMessage[],\n ).map(createToolCallCancellationStub)\n : [];\n // A null threadId is not a no-op for the SDK: it rebinds the controller\n // away from its self-created thread and forces a fresh one, so the\n // submit waits for initialization to produce an identity; core no\n // longer holds appends on that barrier.\n try {\n const { externalId } = await aui.threadListItem.initialize();\n await streamRef.current.submit(\n {\n [messagesKey]: [\n ...cancellations,\n {\n id: stagedMessageId,\n type: \"human\",\n content,\n },\n ],\n },\n {\n ...runConfigToSubmitOptions(msg.runConfig),\n ...(externalId != null ? { threadId: externalId } : {}),\n },\n );\n } catch (error) {\n removeStagedMessage(stagedMessageId);\n throw error;\n }\n },\n onAddToolResult: async ({\n messageId,\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n const runConfig = runConfigByMessageIdRef.current.has(messageId)\n ? runConfigByMessageIdRef.current.get(messageId)\n : activeRunConfigRef.current;\n await stream.submit(\n {\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 runConfig === undefined ? undefined : { config: runConfig },\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 const runConfig = config.runConfig ?? stagedRun.runConfig;\n setActiveRunConfig(runConfig);\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(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 setActiveRunConfig(config.runConfig);\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 reconcileOnEcho: false,\n baseMessageCount: 0,\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 setActiveRunConfig(message.runConfig);\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 activeRunConfigRef.current = undefined;\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 aui = useAui();\n const cloudAdapter = useCloudThreadListAdapter({\n sdk: LANGCHAIN_SDK,\n cloud,\n create: createCloudThreadListAdapterCreateFallback(\n create,\n aui.threadListItem,\n ),\n delete: deleteFn,\n });\n const adapter = unstable_threadListAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useStreamThreadRuntime(options);\n },\n adapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA4DA,MAAa,4BACX,cAEA,WAAW,SACP,EAAE,QAAQ,EAAE,cAAc,UAAU,OAAO,EAAE,IAC7C,KAAA;AAMN,MAAM,uBACJ,aAEA,qBACE,WACC,YAAY;CACX,MAAM,OAAO,eAAe,OAAO;CACnC,IAAI,SAAS,MAAM,OAAO,EAAE,WAAW,QAAQ,cAAc,CAAC,EAAE;CAChE,IAAI,SAAS,UAAU,QAAQ,cAC7B,OAAO,EAAE,YAAY,QAAQ,aAAa;AAG9C,IACC,aAAa,SAAS,EACzB;AAEF,MAAM,wBACJ,KACA,KAAK,WAAW,OAC2B;CAC3C;CACA,gBAAgB;CAChB,SAAS,kBAAkB,GAAG;AAChC;AAEA,MAAM,oBAAoB,YAA6C;CACrE,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,IAAI,CAAC,MAAM,QAAQ,OAAO,GAAG,OAAO;CACpC,OAAO,QACJ,QACE,SACC,OAAO,SAAS,YAChB,SAAS,QACT,KAAK,SAAS,UACd,OAAO,KAAK,SAAS,QACzB,CAAC,CACA,KAAK,SAAS,KAAK,IAAI,CAAC,CACxB,KAAK,EAAE;AACZ;AAEA,MAAM,yBACJ,GACA,MACG,iBAAiB,EAAE,OAAO,MAAM,iBAAiB,EAAE,OAAO;AAE/D,MAAM,iCACJ,gBACA,aAC2B;CAC3B,IAAI,aAAa,MAAM,OAAO,CAAC;CAC/B,MAAM,cAAc,eAAe,WAAW,MAAM,EAAE,OAAO,QAAQ;CACrE,IAAI,gBAAgB,IAAI,OAAO,CAAC;CAChC,MAAM,YAAoC,CAAC;CAC3C,KAAK,IAAI,IAAI,GAAG,KAAK,eAAe,IAAI,eAAe,QAAQ,KAC7D,UAAU,KACR,GAAG,yBAA+C,eAAe,EAAG,CACtE;CAEF,OAAO;AACT;AAMA,MAAM,0BACJ,YAIG;CACH,MAAM,EAAE,UAAU,4BAA4B,+BAC5C;CACF,MAAM,MAAM,OAAO;CACnB,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,aAAa,QAAQ,cAAc;CAEzC,MAAM,aAAa,aAAa,MAAM,EAAE,eAAe,UAAU;CAKjE,MAAM,SAAS,UACb,OAAO,OAAO,CAAC,GAAG,SAAS,EAAE,UAAU,WAAW,CAAC,CACrD;CACA,MAAM,CAAC,gBAAgB,qBAAqB,SAE1C,IAAI;CAEN,MAAM,CAAC,cAAc,mBAAmB,SAEtC,CAAC,CAAC;CACJ,MAAM,oBAAoB,OAAO,OAAO,YAAY,CAAC,CAAC,MACnD,MAAM,GAAG,SAAS,WACrB;CACA,MAAM,qBAAqB,OAAO,aAAa;CAE/C,MAAM,eAAe,OAAO,OAAO;CAEnC,MAAM,eAAe,WAAW,QAAQ,kBAAkB;CAC1D,MAAM,CAAC,cAAc,SAAS,gBAAgB;CAC9C,MAAM,iBAAiB,cACf,cAAc,cAAc,UAAU,GAC5C,CAAC,cAAc,UAAU,CAC3B;CAEA,MAAM,mBAAmB,cACjB,gBAAgB,gBAAgB,YAAY,GAClD,CAAC,gBAAgB,YAAY,CAC/B;CAEA,MAAM,qBAAqB,cACnB,wBAAmC,gBAAgB,GACzD,CAAC,gBAAgB,CACnB;CAEA,MAAM,kBACJ,kBAAmB,OAAO;CAE5B,MAAM,gBAAgB,4BACpB,iBACA,kBACF;CAEA,MAAM,sBAAsB,uBAC1B,QACA,kBACF;CAEA,MAAM,gBAAgB,eAGb,SAAS,aACd,4BAA4B,SAAS;EACnC,GAAG;EACH;EACA;CACF,CAAC,GACH,CAAC,oBAAoB,aAAa,CACpC;CAEA,MAAM,iBAAiB,4BAA4B;EACjD,UAAU;EACV,UAAU;EACV,WAAW;CACb,CAAC;CACD,MAAM,CAAC,QAAQ,SAAS,gBAAgB;CACxC,MAAM,0BAA0B,cACxB,0BAA0B,gBAAgB,qBAAqB,IAAI,GACzE;EAAC;EAAgB;EAAqB;CAAI,CAC5C;CAEA,MAAM,YAAY,OAAO,MAAM;CAC/B,yBAAyB;EACvB,UAAU,UAAU;CACtB,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,qBAAqB,OAEzB,KAAA,CAAS;CACX,MAAM,0BAA0B,uBAC9B,IAAI,IAA8D,CACpE;CACA,MAAM,oBAAoB,OAAO,UAAU;CAC3C,MAAM,qBAAqB,aACxB,cAA0C;EACzC,mBAAmB,UAAU,yBAAyB,SAAS,CAAC,EAAE;CACpE,GACA,CAAC,CACH;CACA,MAAM,sBAAsB,aACzB,kBAA4C;EAC3C,IAAI,iBAAiB,YAAY,eAAe,OAAO;EACvD,IAAI,mBAAmB,YAAY,KAAA,GAAW,OAAO;EACrD,OAAO;GAAE,GAAG;GAAe,QAAQ,mBAAmB;EAAQ;CAChE,GACA,CAAC,CACH;CAEA,gBAAgB;EACd,IACE,kBAAkB,YAAY,QAC9B,kBAAkB,YAAY,YAC9B;GACA,mBAAmB,UAAU,KAAA;GAC7B,wBAAwB,QAAQ,MAAM;EACxC;EACA,kBAAkB,UAAU;CAC9B,GAAG,CAAC,UAAU,CAAC;CAEf,gBAAgB;EACd,MAAM,WAAW,OAAO;EACxB,MAAM,QAAQ,wBAAwB;EACtC,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAC7C,MAAM,UAAU,SAAS,GAAG,CAAC;GAC7B,IACE,CAAC,SAAS,MACV,eAAe,OAAO,MAAM,QAC5B,CAAC,QAAQ,YAAY,QAErB;GAEF,IAAI,MAAM,IAAI,QAAQ,EAAE,GAAG;GAC3B;EACF;EACA,KAAK,MAAM,WAAW,UAAU;GAC9B,IACE,CAAC,QAAQ,MACT,eAAe,OAAO,MAAM,QAC5B,CAAC,QAAQ,YAAY,UACrB,MAAM,IAAI,QAAQ,EAAE,GAEpB;GAEF,MAAM,IAAI,QAAQ,IAAI,mBAAmB,OAAO;EAClD;CACF,GAAG,CAAC,OAAO,QAAQ,CAAC;CAEpB,MAAM,qBAAqB,OAAO,eAAe;CACjD,yBAAyB;EACvB,mBAAmB,UAAU;CAC/B,GAAG,CAAC,eAAe,CAAC;CAEpB,MAAM,oBAAoB,OAAO,uBAAuB;CACxD,yBAAyB;EACvB,kBAAkB,UAAU;CAC9B,GAAG,CAAC,uBAAuB,CAAC;CAE5B,MAAM,oBAAoB,uBACxB,IAAI,IAQF,CACJ;CACA,MAAM,wBAAwB,OAAsC,IAAI;CACxE,gBAAgB;EACd,IAAI,kBAAkB,QAAQ,SAAS,GAAG;EAG1C,MAAM,eACJ,sBAAsB,WACrB,OAAO;EACV,MAAM,0BAAkD,CAAC;EACzD,MAAM,4CAA4B,IAAI,IAAY;EAClD,MAAM,mBAAmB,IAAI,IAC3B,mBAAmB,QAAQ,SAAS,MAAO,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAE,CAChE;EACA,KAAK,MAAM,CAAC,IAAI,WAAW,kBAAkB,SAAS;GACpD,IAAI,CAAC,iBAAiB,IAAI,EAAE,GAAG;GAkB/B,IAjBe,aAAa,MAAM,SAAS,UAAU;IACnD,IAAI,0BAA0B,IAAI,KAAK,GAAG,OAAO;IACjD,IAAI,QAAQ,OAAO,IAAI;KACrB,0BAA0B,IAAI,KAAK;KACnC,OAAO;IACT;IACA,IACE,CAAC,OAAO,mBACR,QAAQ,OAAO,oBACf,eAAe,OAAO,MAAM,WAC5B,CAAC,sBAAsB,SAAS,OAAO,OAAO,GAE9C,OAAO;IAET,0BAA0B,IAAI,KAAK;IACnC,OAAO;GACT,CACS,GAAG,kBAAkB,QAAQ,OAAO,EAAE;QAC1C,wBAAwB,KAAK,OAAO,OAAO;EAClD;EAEA,IAAI,wBAAwB,WAAW,GAAG;GACxC,sBAAsB,UAAU;GAChC,mBAAmB,UAAU;GAI7B,kBAAkB,IAAI;GACtB;EACF;EAEA,MAAM,eAAe,CAAC,GAAG,cAAc,GAAG,uBAAuB;EACjE,mBAAmB,UAAU;EAC7B,kBAAkB,YAAY;CAChC,GAAG,CAAC,OAAO,QAAQ,CAAC;CAEpB,MAAM,gBAAgB,aAA4B;EAChD,IAAI,CAAC,YAAY,CAAC,kBAAkB,QAAQ,IAAI,QAAQ,GAAG,OAAO;EAElE,MAAM,SAAiC,CAAC;EACxC,KAAK,MAAM,WAAW,mBAAmB,SAAS;GAChD,IAAI,QAAQ,MAAM,kBAAkB,QAAQ,IAAI,QAAQ,EAAE,GACxD,OAAO,KAAK,kBAAkB,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAE,OAAO;GAEhE,IAAI,QAAQ,OAAO,UAAU;EAC/B;EAEA,OAAO;GACL,UAAU;GACV,WAAW,kBAAkB,QAAQ,IAAI,QAAQ,CAAC,CAAE;EACtD;CACF;CAEA,MAAM,oBAAoB,KAAoB,kBAAkB,UAAU;EACxE,MAAM,gBAAgB,qBAAqB,GAAG;EAC9C,kBAAkB,QAAQ,IAAI,cAAc,IAAI;GAC9C,SAAS;GACT,WAAW,IAAI;GACf;GACA,kBAAkB,UAAU,QAAQ,SAAS;EAC/C,CAAC;EACD,MAAM,eAAe,CAAC,GAAG,mBAAmB,SAAS,aAAa;EAClE,mBAAmB,UAAU;EAC7B,kBAAkB,YAAY;EAC9B,OAAO;CACT;CAEA,MAAM,uBAAuB,OAAe;EAC1C,IAAI,CAAC,kBAAkB,QAAQ,OAAO,EAAE,GAAG;EAC3C,MAAM,eAAe,mBAAmB,QAAQ,QAC7C,YAAY,QAAQ,OAAO,EAC9B;EACA,mBAAmB,UAAU;EAC7B,IAAI,kBAAkB,QAAQ,SAAS,GAAG;GACxC,sBAAsB,UAAU;GAChC,kBAAkB,IAAI;EACxB,OACE,kBAAkB,YAAY;CAElC;CAEA,MAAM,SAAS,cAEX,gBAAgB,QAAQ;EACtB,WAAW,OAAO;EAClB,YAAY,OAAO;EACnB,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB;EACA,OAAO,OAAO;EACd,SAAS,QAAQ,kBAAkB;GACjC,MAAM,WAAW,UAAU,QAAQ,eAAe,WAAW;GAC7D,OAAO,OAAO,OACZ,QACA,WAAW,oBAAoB,aAAa,IAAI,aAClD;EACF;EACA,UAAU,UAAU,mBAClB,OAAO,QAAQ,UAAU,oBAAoB,cAAc,CAAC;EAC9D,aAAa,eAAe,mBAC1B,OAAO,WAAW,eAAe,oBAAoB,cAAc,CAAC;EACtE,QAAQ,OAAO;EACf;CACF,CAAC,GACH;EAAC;EAAQ;EAAa;CAAmB,CAC3C;CA0LA,OAxLgB,wBAAwB;EACtC,GAAG,+BAA+B,OAAO;EACzC,WAAW,OAAO;EAClB,WAAW,OAAO;EAClB,UAAU;EACV;EACA;EACA,gCAAgC;EAChC;EACA,OAAO,OAAO,QAAQ;GACpB,IAAI,EAAE,IAAI,YAAY,IAAI,SAAS,SAAS;IAC1C,iBAAiB,GAAG;IACpB;GACF;GAGA,MAAM,kBADgB,iBAAiB,KAAK,IACR,CAAC,CAAC;GACtC,mBAAmB,IAAI,SAAS;GAChC,MAAM,UAAU,kBAAkB,GAAG;GACrC,MAAM,gBACJ,+BAA+B,QAC3B,oBACE,UAAU,QAAQ,QACpB,CAAC,CAAC,IAAI,8BAA8B,IACpC,CAAC;GAKP,IAAI;IACF,MAAM,EAAE,eAAe,MAAM,IAAI,eAAe,WAAW;IAC3D,MAAM,UAAU,QAAQ,OACtB,GACG,cAAc,CACb,GAAG,eACH;KACE,IAAI;KACJ,MAAM;KACN;IACF,CACF,EACF,GACA;KACE,GAAG,yBAAyB,IAAI,SAAS;KACzC,GAAI,cAAc,OAAO,EAAE,UAAU,WAAW,IAAI,CAAC;IACvD,CACF;GACF,SAAS,OAAO;IACd,oBAAoB,eAAe;IACnC,MAAM;GACR;EACF;EACA,iBAAiB,OAAO,EACtB,WACA,YACA,UACA,QACA,SACA,eACI;GACJ,MAAM,YAAY,wBAAwB,QAAQ,IAAI,SAAS,IAC3D,wBAAwB,QAAQ,IAAI,SAAS,IAC7C,mBAAmB;GACvB,MAAM,OAAO,OACX,GACG,cAAc,CACb;IACE,MAAM;IACN,MAAM;IACN,cAAc;IACd,SAAS,KAAK,UAAU,MAAM;IAC9B,GAAI,aAAa,KAAA,KAAa,EAAE,SAAS;IACzC,QAAQ,UAAU,UAAU;GAC9B,CACF,EACF,GACA,cAAc,KAAA,IAAY,KAAA,IAAY,EAAE,QAAQ,UAAU,CAC5D;EACF;EACA,UAAU,OAAO,UAAU,WAAW;GACpC,MAAM,YAAY,aAAa,QAAQ;GACvC,IAAI,WAAW;IACb,MAAM,8BAAc,IAAI,IAAY;IACpC,KAAK,MAAM,WAAW,UAAU,UAAU;KACxC,IAAI,CAAC,QAAQ,IAAI;KACjB,YAAY,IAAI,QAAQ,EAAE;KAC1B,kBAAkB,QAAQ,OAAO,QAAQ,EAAE;IAC7C;IACA,sBAAsB,UAAU;IAChC,IAAI,kBAAkB,QAAQ,OAAO,GAAG;KACtC,MAAM,eAAe,mBAAmB,QAAQ,QAC7C,YAAY,CAAC,QAAQ,MAAM,CAAC,YAAY,IAAI,QAAQ,EAAE,CACzD;KACA,mBAAmB,UAAU;KAC7B,kBAAkB,YAAY;IAChC,OACE,kBAAkB,IAAI;IAExB,MAAM,YAAY,OAAO,aAAa,UAAU;IAChD,mBAAmB,SAAS;IAC5B,MAAM,OAAO,OACX,GACG,cAAc,UAAU,SAAS,KAAK,aAAa;KAClD,IAAI,QAAQ;KACZ,MAAM;KACN,SAAS,QAAQ;IACnB,EAAE,EACJ,GACA,yBAAyB,SAAS,CACpC;IACA;GACF;GAEA,MAAM,WAAW;GACjB,IAAI,CAAC,YAAY,YAAY,MAAM;GACnC,MAAM,IAAI,UAAU;GACpB,MAAM,eAAe,MAAM,sBACzB,EAAE,QACF,UACA,EAAE,UACF,UACA,OAAO,UACP,EAAE,kBAAkB,EAAE,sBAAsB,cAAc,GAC1D,WACF;GACA,IAAI,CAAC,cAAc;GACnB,mBAAmB,OAAO,SAAS;GACnC,MAAM,EAAE,OAAO,MAAM;IACnB,UAAU;IACV,GAAG,yBAAyB,OAAO,SAAS;GAC9C,CAAC;EACH;EACA,QAAQ,OAAO,YAAY;GACzB,IAAI,EAAE,QAAQ,YAAY,QAAQ,SAAS,SAAS;IAClD,MAAM,YAAY,8BAChB,kBAAkB,SAClB,QAAQ,QACV;IACA,MAAM,gBAAgB,qBAAqB,OAAO;IAClD,kBAAkB,QAAQ,IAAI,cAAc,IAAI;KAC9C,SAAS;KACT,WAAW,QAAQ;KACnB,iBAAiB;KACjB,kBAAkB;IACpB,CAAC;IACD,sBAAsB,UAAU;IAChC,MAAM,eAAe,CAAC,GAAG,WAAW,aAAa;IACjD,mBAAmB,UAAU;IAC7B,kBAAkB,YAAY;IAC9B;GACF;GAEA,MAAM,WAAW;GACjB,IAAI,CAAC,UAAU;GACf,MAAM,IAAI,UAAU;GACpB,MAAM,eAAe,MAAM,sBACzB,EAAE,QACF,UACA,EAAE,UACF,QAAQ,UACR,QAAQ,UACR,EAAE,kBAAkB,EAAE,sBAAsB,cAAc,GAC1D,WACF;GACA,IAAI,CAAC,cAAc;GACnB,MAAM,UAAU,kBAAkB,OAAO;GACzC,mBAAmB,QAAQ,SAAS;GACpC,MAAM,EAAE,OACN,GAAG,cAAc,CAAC;IAAE,MAAM;IAAS;GAAQ,CAAC,EAAE,GAC9C;IACE,UAAU;IACV,GAAG,yBAAyB,QAAQ,SAAS;GAC/C,CACF;EACF;EACA,UACE,+BAA+B,QAC3B,YAAY;GACV,mBAAmB,UAAU,KAAA;GAC7B,MAAM,OAAO,KAAK;EACpB,IACA,KAAA;CACR,CAEa;AACf;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,oBAAoB,eAAwC;CACvE,MAAM,EACJ,OACA,4BACA,QACA,QAAQ,UACR,kBACA,GAAG,YACD;CAEJ,MAAM,MAAM,OAAO;CACnB,MAAM,eAAe,0BAA0B;EAC7C,KAAK;EACL;EACA,QAAQ,2CACN,QACA,IAAI,cACN;EACA,QAAQ;CACV,CAAC;CAGD,OAAO,2BAA2B;EAChC,aAAa,SAAS,cAAc;GAClC,OAAO,uBAAuB,OAAO;EACvC;EACA,SANc,8BAA8B;EAO5C,cAAc;EACd;CACF,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"useStreamRuntime.js","names":[],"sources":["../src/useStreamRuntime.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/store\" preserve=\"true\" />\n\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} 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 createCloudThreadListAdapterCreateFallback,\n createToolCallCancellationStub,\n getThreadMessageText,\n scanPendingToolCalls,\n} from \"@assistant-ui/core/internal\";\nimport {\n useCloudThreadListAdapter,\n useExternalStoreRuntime,\n useExternalMessageConverter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { STREAM_CONTROLLER, useChannel, useStream } from \"@langchain/react\";\nimport type {\n LangChainBaseMessage,\n LangChainToolCall,\n UIMessage,\n UseStreamRuntimeOptions,\n} from \"./types\";\nimport { getMessageModality, groupUIMessagesByParent } from \"./converter\";\nexport { groupUIMessagesByParent } from \"./converter\";\nimport {\n convertLangChainBaseMessage,\n getMessageContent,\n getMessageType,\n} from \"./convertMessages\";\nimport {\n attachSubagentTranscripts,\n createAttachMemo,\n} from \"./attachSubagentTranscripts\";\nimport { useSubagentTranscripts } from \"./useSubagentTranscripts\";\nimport {\n createUIFoldMemo,\n createUISnapshotMemo,\n foldUIUpdates,\n mergeUIMessages,\n reconcileUISnapshot,\n UI_CUSTOM_CHANNELS,\n} from \"./uiMessages\";\nimport { langChainExtras } from \"./runtimeExtras\";\nimport { resolveForkCheckpoint } from \"./resolveForkCheckpoint\";\nimport { useLangChainStreamingTiming } from \"./streamingTiming\";\nimport { LANGCHAIN_SDK } from \"./sdkIdentity\";\n\nexport const runConfigToSubmitOptions = (\n runConfig: AppendMessage[\"runConfig\"],\n) =>\n runConfig?.custom\n ? { config: { configurable: runConfig.custom } }\n : undefined;\n\ntype NormalizedRunConfigOptions = NonNullable<\n ReturnType<typeof runConfigToSubmitOptions>\n>;\n\nconst getPendingToolCalls = (\n messages: readonly LangChainBaseMessage[],\n): LangChainToolCall[] =>\n scanPendingToolCalls(\n messages,\n (message) => {\n const type = getMessageType(message);\n if (type === \"ai\") return { toolCalls: message.tool_calls ?? [] };\n if (type === \"tool\" && message.tool_call_id) {\n return { toolCallId: message.tool_call_id };\n }\n return undefined;\n },\n (toolCall) => toolCall.id,\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 toStagedMessageInput = (message: LangChainBaseMessage) => ({\n id: message.id,\n type: getMessageType(message) === \"ai\" ? (\"ai\" as const) : (\"human\" as const),\n content: message.content,\n ...(message.additional_kwargs && {\n additional_kwargs: message.additional_kwargs,\n }),\n});\n\nconst humanContentText = (content: LangChainBaseMessage[\"content\"]) => {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .filter(\n (part): part is { type: \"text\"; text: string } =>\n typeof part === \"object\" &&\n part !== null &&\n part.type === \"text\" &&\n typeof part.text === \"string\",\n )\n .map((part) => part.text)\n .join(\"\");\n};\n\nconst hasSameMessageContent = (\n a: LangChainBaseMessage,\n b: LangChainBaseMessage,\n) => humanContentText(a.content) === humanContentText(b.content);\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 aui = useAui();\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 // Object.assign preserves the discriminated transport union; object spread\n // collapses its arms and no longer satisfies UseStreamOptions.\n const stream = useStream(\n Object.assign({}, options, { threadId: externalId }),\n );\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 [uiSnapshotMemo] = useState(createUISnapshotMemo);\n const uiStateValue = reconcileUISnapshot(\n stream.values[uiStateKey],\n uiSnapshotMemo,\n );\n\n const customEvents = useChannel(stream, UI_CUSTOM_CHANNELS);\n const [uiFoldMemo] = useState(createUIFoldMemo);\n const liveUiMessages = useMemo(\n () => foldUIUpdates(customEvents, uiFoldMemo),\n [customEvents, uiFoldMemo],\n );\n\n const mergedUiMessages = useMemo(\n () => mergeUIMessages(liveUiMessages, uiStateValue),\n [liveUiMessages, uiStateValue],\n );\n\n const uiMessagesByParent = useMemo(\n () => groupUIMessagesByParent<UIMessage>(mergedUiMessages),\n [mergedUiMessages],\n );\n\n const visibleMessages =\n stagedMessages ?? (stream.messages as LangChainBaseMessage[]);\n\n const messageTiming = useLangChainStreamingTiming(\n visibleMessages,\n effectiveIsRunning,\n );\n\n const subagentTranscripts = useSubagentTranscripts(\n stream,\n uiMessagesByParent,\n );\n\n const convertWithUI = useMemo<\n useExternalMessageConverter.Callback<LangChainBaseMessage>\n >(\n () => (message, metadata) =>\n convertLangChainBaseMessage(message, {\n ...metadata,\n uiMessagesByParent,\n messageTiming,\n }),\n [uiMessagesByParent, messageTiming],\n );\n\n const threadMessages = useExternalMessageConverter({\n callback: convertWithUI,\n messages: visibleMessages,\n isRunning: effectiveIsRunning,\n });\n const [memo] = useState(createAttachMemo);\n const messagesWithTranscripts = useMemo(\n () => attachSubagentTranscripts(threadMessages, subagentTranscripts, memo),\n [threadMessages, subagentTranscripts, memo],\n );\n\n const streamRef = useRef(stream);\n useInsertionEffect(() => {\n streamRef.current = stream;\n }, [stream]);\n\n const activeRunConfigRef = useRef<\n NormalizedRunConfigOptions[\"config\"] | undefined\n >(undefined);\n const runConfigByMessageIdRef = useRef(\n new Map<string, NormalizedRunConfigOptions[\"config\"] | undefined>(),\n );\n const activeThreadIdRef = useRef(externalId);\n const setActiveRunConfig = useCallback(\n (runConfig: AppendMessage[\"runConfig\"]) => {\n activeRunConfigRef.current = runConfigToSubmitOptions(runConfig)?.config;\n },\n [],\n );\n const withActiveRunConfig = useCallback(\n (submitOptions?: Record<string, unknown>) => {\n if (submitOptions && \"config\" in submitOptions) return submitOptions;\n if (activeRunConfigRef.current === undefined) return submitOptions;\n return { ...submitOptions, config: activeRunConfigRef.current };\n },\n [],\n );\n\n useEffect(() => {\n if (\n activeThreadIdRef.current !== null &&\n activeThreadIdRef.current !== externalId\n ) {\n activeRunConfigRef.current = undefined;\n runConfigByMessageIdRef.current.clear();\n }\n activeThreadIdRef.current = externalId;\n }, [externalId]);\n\n useEffect(() => {\n const messages = stream.messages as readonly LangChainBaseMessage[];\n const owned = runConfigByMessageIdRef.current;\n for (let i = messages.length - 1; i >= 0; i--) {\n const message = messages.at(i);\n if (\n !message?.id ||\n getMessageType(message) !== \"ai\" ||\n !message.tool_calls?.length\n ) {\n continue;\n }\n if (owned.has(message.id)) return;\n break;\n }\n for (const message of messages) {\n if (\n !message.id ||\n getMessageType(message) !== \"ai\" ||\n !message.tool_calls?.length ||\n owned.has(message.id)\n ) {\n continue;\n }\n owned.set(message.id, activeRunConfigRef.current);\n }\n }, [stream.messages]);\n\n const visibleMessagesRef = useRef(visibleMessages);\n useInsertionEffect(() => {\n visibleMessagesRef.current = visibleMessages;\n }, [visibleMessages]);\n\n const threadMessagesRef = useRef(messagesWithTranscripts);\n useInsertionEffect(() => {\n threadMessagesRef.current = messagesWithTranscripts;\n }, [messagesWithTranscripts]);\n\n const stagedMessagesRef = useRef(\n new Map<\n string,\n {\n message: LangChainBaseMessage & { id: string };\n runConfig: AppendMessage[\"runConfig\"];\n reconcileOnEcho: boolean;\n baseMessageCount: number;\n transcriptStatus?: \"unsent\" | \"sent\";\n }\n >(),\n );\n const stagedBaseMessagesRef = useRef<LangChainBaseMessage[] | null>(null);\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 remainingStagedMessages: LangChainBaseMessage[] = [];\n const matchedBaseMessageIndexes = new Set<number>();\n const visibleStagedIds = new Set(\n visibleMessagesRef.current.flatMap((m) => (m.id ? [m.id] : [])),\n );\n for (const [id, staged] of stagedMessagesRef.current) {\n if (!visibleStagedIds.has(id)) continue;\n const echoed = baseMessages.some((message, index) => {\n if (matchedBaseMessageIndexes.has(index)) return false;\n if (message.id === id) {\n matchedBaseMessageIndexes.add(index);\n return true;\n }\n if (\n !staged.reconcileOnEcho ||\n index < staged.baseMessageCount ||\n getMessageType(message) !== \"human\" ||\n !hasSameMessageContent(message, staged.message)\n ) {\n return false;\n }\n matchedBaseMessageIndexes.add(index);\n return true;\n });\n if (echoed) stagedMessagesRef.current.delete(id);\n else remainingStagedMessages.push(staged.message);\n }\n\n if (remainingStagedMessages.length === 0) {\n stagedBaseMessagesRef.current = null;\n visibleMessagesRef.current = baseMessages;\n // Reconciling against the upstream stream mutates the staged refs above,\n // which cannot happen during render.\n // eslint-disable-next-line react-hooks/set-state-in-effect\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 const parent = parentId\n ? stagedMessagesRef.current.get(parentId)\n : undefined;\n if (!parent || parent.transcriptStatus === \"sent\") return null;\n\n const staged: LangChainBaseMessage[] = [];\n for (const message of visibleMessagesRef.current) {\n const entry = message.id\n ? stagedMessagesRef.current.get(message.id)\n : undefined;\n if (entry && entry.transcriptStatus !== \"sent\") {\n staged.push(entry.message);\n }\n if (message.id === parentId) break;\n }\n\n return {\n messages: staged,\n runConfig: parent.runConfig,\n };\n };\n\n const appendVoiceTranscript = (message: ThreadMessage) => {\n const transcript = {\n id: message.id,\n _getType: () => (message.role === \"assistant\" ? \"ai\" : \"human\"),\n content: getThreadMessageText(message),\n ...(message.metadata.modality && {\n additional_kwargs: { modality: message.metadata.modality },\n }),\n };\n stagedMessagesRef.current.set(transcript.id, {\n message: transcript,\n runConfig: undefined,\n reconcileOnEcho: false,\n baseMessageCount: streamRef.current.messages.length,\n transcriptStatus: \"unsent\",\n });\n const nextMessages = [...visibleMessagesRef.current, transcript];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n };\n\n const getUnsentTranscripts = () =>\n visibleMessagesRef.current.filter(\n (message) =>\n message.id !== undefined &&\n stagedMessagesRef.current.get(message.id)?.transcriptStatus ===\n \"unsent\",\n );\n\n const setTranscriptStatus = (\n messages: readonly LangChainBaseMessage[],\n status: \"unsent\" | \"sent\",\n ) => {\n for (const message of messages) {\n const staged = message.id\n ? stagedMessagesRef.current.get(message.id)\n : undefined;\n if (staged?.transcriptStatus) staged.transcriptStatus = status;\n }\n };\n\n // Reserving before the submit keeps an overlapping submit from carrying the\n // same transcript; a failed submit hands it back to the next run.\n const submitCarryingTranscripts = async (\n transcripts: readonly LangChainBaseMessage[],\n submit: () => Promise<void>,\n ) => {\n setTranscriptStatus(transcripts, \"sent\");\n try {\n await submit();\n } catch (error) {\n setTranscriptStatus(transcripts, \"unsent\");\n throw error;\n }\n };\n\n const dropTranscripts = (messages: readonly LangChainBaseMessage[]) => {\n for (const message of messages) {\n if (\n message.id &&\n stagedMessagesRef.current.get(message.id)?.transcriptStatus\n )\n removeStagedMessage(message.id);\n }\n };\n\n const isTranscriptMessage = (message: LangChainBaseMessage) => {\n const staged = message.id\n ? stagedMessagesRef.current.get(message.id)\n : undefined;\n if (staged?.transcriptStatus === \"unsent\") return true;\n const type = getMessageType(message);\n return (\n (type === \"human\" || type === \"ai\") &&\n getMessageModality(message.additional_kwargs) !== undefined\n );\n };\n\n // A transcript reaches the graph in the same input as the message after it, so\n // no checkpoint ends at one; a fork starts before the trailing transcripts.\n const planForkTranscripts = (parentId: string | null) => {\n const visible = visibleMessagesRef.current;\n const parentIndex =\n parentId == null ? -1 : visible.findIndex((m) => m.id === parentId);\n if (parentId != null && parentIndex === -1)\n return { forkParentId: parentId, transcripts: [], truncated: [] };\n\n let start = parentIndex + 1;\n while (start > 0 && isTranscriptMessage(visible[start - 1]!)) start--;\n return {\n forkParentId: start > 0 ? (visible[start - 1]!.id ?? null) : null,\n transcripts: visible.slice(start, parentIndex + 1),\n truncated: visible.slice(parentIndex + 1),\n };\n };\n\n const stageUserMessage = (msg: AppendMessage, reconcileOnEcho = false) => {\n const stagedMessage = toStagedHumanMessage(msg);\n stagedMessagesRef.current.set(stagedMessage.id, {\n message: stagedMessage,\n runConfig: msg.runConfig,\n reconcileOnEcho,\n baseMessageCount: streamRef.current.messages.length,\n });\n const nextMessages = [...visibleMessagesRef.current, stagedMessage];\n visibleMessagesRef.current = nextMessages;\n setStagedMessages(nextMessages);\n return stagedMessage;\n };\n\n const removeStagedMessage = (id: string) => {\n if (!stagedMessagesRef.current.delete(id)) return;\n const nextMessages = visibleMessagesRef.current.filter(\n (message) => message.id !== id,\n );\n visibleMessagesRef.current = nextMessages;\n if (stagedMessagesRef.current.size === 0) {\n stagedBaseMessagesRef.current = null;\n setStagedMessages(null);\n } else {\n setStagedMessages(nextMessages);\n }\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: (values, submitOptions) => {\n const isResume = values == null || submitOptions?.command != null;\n return stream.submit(\n values,\n isResume ? withActiveRunConfig(submitOptions) : submitOptions,\n );\n },\n respond: (response, respondOptions) =>\n stream.respond(response, withActiveRunConfig(respondOptions)),\n respondAll: (responsesById, respondOptions) =>\n stream.respondAll(responsesById, withActiveRunConfig(respondOptions)),\n values: stream.values,\n messagesKey,\n }),\n [stream, messagesKey, withActiveRunConfig],\n );\n\n const runtime = useExternalStoreRuntime({\n ...pickExternalStoreSharedOptions(options),\n isRunning: stream.isLoading,\n isLoading: stream.isThreadLoading,\n messages: messagesWithTranscripts,\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 stagedMessage = stageUserMessage(msg, true);\n const stagedMessageId = stagedMessage.id;\n setActiveRunConfig(msg.runConfig);\n const content = getMessageContent(msg);\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(\n streamRef.current.messages as readonly LangChainBaseMessage[],\n ).map(createToolCallCancellationStub)\n : [];\n // A null threadId is not a no-op for the SDK: it rebinds the controller\n // away from its self-created thread and forces a fresh one, so the\n // submit waits for initialization to produce an identity; core no\n // longer holds appends on that barrier.\n try {\n const { externalId } = await aui.threadListItem.initialize();\n const transcripts = getUnsentTranscripts();\n await submitCarryingTranscripts(transcripts, () =>\n streamRef.current.submit(\n {\n [messagesKey]: [\n ...cancellations,\n ...transcripts.map(toStagedMessageInput),\n {\n id: stagedMessageId,\n type: \"human\",\n content,\n },\n ],\n },\n {\n ...runConfigToSubmitOptions(msg.runConfig),\n ...(externalId != null ? { threadId: externalId } : {}),\n },\n ),\n );\n } catch (error) {\n removeStagedMessage(stagedMessageId);\n throw error;\n }\n },\n onVoiceTranscript: appendVoiceTranscript,\n onAddToolResult: async ({\n messageId,\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n const runConfig = runConfigByMessageIdRef.current.has(messageId)\n ? runConfigByMessageIdRef.current.get(messageId)\n : activeRunConfigRef.current;\n await stream.submit(\n {\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 runConfig === undefined ? undefined : { config: runConfig },\n );\n },\n onReload: async (parentId, config) => {\n const stagedRun = getStagedRun(parentId);\n if (stagedRun) {\n if (\n config.sourceId &&\n stagedMessagesRef.current.get(config.sourceId)?.transcriptStatus\n )\n removeStagedMessage(config.sourceId);\n const promotedIds = new Set<string>();\n for (const message of stagedRun.messages) {\n if (\n !message.id ||\n stagedMessagesRef.current.get(message.id)?.transcriptStatus\n )\n 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 const runConfig = config.runConfig ?? stagedRun.runConfig;\n setActiveRunConfig(runConfig);\n await submitCarryingTranscripts(stagedRun.messages, () =>\n stream.submit(\n {\n [messagesKey]: stagedRun.messages.map(toStagedMessageInput),\n },\n runConfigToSubmitOptions(runConfig),\n ),\n );\n return;\n }\n\n const threadId = externalId;\n if (!threadId || parentId == null) return;\n const s = streamRef.current;\n const fork = planForkTranscripts(parentId);\n const checkpointId = await resolveForkCheckpoint(\n s.client,\n threadId,\n s.messages as readonly LangChainBaseMessage[],\n fork.forkParentId,\n config.sourceId,\n s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(),\n messagesKey,\n );\n if (!checkpointId) return;\n dropTranscripts(fork.truncated);\n setActiveRunConfig(config.runConfig);\n await submitCarryingTranscripts(fork.transcripts, () =>\n s.submit(\n fork.transcripts.length > 0\n ? { [messagesKey]: fork.transcripts.map(toStagedMessageInput) }\n : null,\n {\n forkFrom: checkpointId,\n ...runConfigToSubmitOptions(config.runConfig),\n },\n ),\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 reconcileOnEcho: false,\n baseMessageCount: 0,\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 fork = planForkTranscripts(message.parentId);\n const checkpointId = await resolveForkCheckpoint(\n s.client,\n threadId,\n s.messages as readonly LangChainBaseMessage[],\n fork.forkParentId,\n message.sourceId,\n s[STREAM_CONTROLLER]?.messageMetadataStore?.getSnapshot?.(),\n messagesKey,\n );\n if (!checkpointId) return;\n dropTranscripts(fork.truncated);\n const content = getMessageContent(message);\n setActiveRunConfig(message.runConfig);\n await submitCarryingTranscripts(fork.transcripts, () =>\n s.submit(\n {\n [messagesKey]: [\n ...fork.transcripts.map(toStagedMessageInput),\n { type: \"human\", content },\n ],\n },\n {\n forkFrom: checkpointId,\n ...runConfigToSubmitOptions(message.runConfig),\n },\n ),\n );\n },\n onCancel:\n unstable_allowCancellation !== false\n ? async () => {\n activeRunConfigRef.current = undefined;\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 aui = useAui();\n const cloudAdapter = useCloudThreadListAdapter({\n sdk: LANGCHAIN_SDK,\n cloud,\n create: createCloudThreadListAdapterCreateFallback(\n create,\n aui.threadListItem,\n ),\n delete: deleteFn,\n });\n const adapter = unstable_threadListAdapter ?? cloudAdapter;\n\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useStreamThreadRuntime(options);\n },\n adapter,\n allowNesting: true,\n onThreadIdChange,\n });\n};\n"],"mappings":"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"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
//#region src/useSubagentTranscripts.d.ts
|
|
1
|
+
import { type AnyStream } from "@langchain/react";
|
|
2
|
+
import { type SubagentTranscript } from "./attachSubagentTranscripts.js";
|
|
3
|
+
import type { UIMessage } from "./types.js";
|
|
5
4
|
export declare const MAX_SUBAGENT_DEPTH = 16;
|
|
6
5
|
export declare const useSubagentTranscripts: (stream: AnyStream, uiMessagesByParent: Map<string, UIMessage[]>) => ReadonlyMap<string, SubagentTranscript>;
|
|
7
|
-
//#endregion
|
|
8
6
|
//# sourceMappingURL=useSubagentTranscripts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSubagentTranscripts.d.ts","
|
|
1
|
+
{"version":3,"file":"useSubagentTranscripts.d.ts","sourceRoot":"","sources":["../src/useSubagentTranscripts.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIrE,OAAO,EAIL,KAAK,kBAAkB,EACxB,uCAAoC;AAKrC,OAAO,KAAK,EAAwB,SAAS,EAAE,mBAAgB;AAS/D,eAAO,MAAM,kBAAkB,KAAK,CAAC;AA6crC,eAAO,MAAM,sBAAsB,GACjC,QAAQ,SAAS,EACjB,oBAAoB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,KAC3C,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAmBxC,CAAC"}
|
|
@@ -3,12 +3,13 @@ import { attachSubagentTranscripts, createAttachMemo } from "./attachSubagentTra
|
|
|
3
3
|
import { groupUIMessagesByParent } from "./converter.js";
|
|
4
4
|
import { convertLangChainBaseMessage } from "./convertMessages.js";
|
|
5
5
|
import { langChainStreamingTimingAccessors } from "./streamingTiming.js";
|
|
6
|
+
import { subagentMessagesProjection } from "./subagentMessagesProjection.js";
|
|
6
7
|
import { UI_CUSTOM_CHANNELS, createUIFoldMemo, foldUIUpdates, mergeUIMessages } from "./uiMessages.js";
|
|
7
8
|
import { stepStreamingTiming } from "@assistant-ui/core";
|
|
8
9
|
import { convertExternalMessages, createExternalMessageConversionCache } from "@assistant-ui/core/react";
|
|
9
10
|
import { useEffect, useRef, useSyncExternalStore } from "react";
|
|
10
11
|
import { STREAM_CONTROLLER } from "@langchain/react";
|
|
11
|
-
import { channelProjection
|
|
12
|
+
import { channelProjection } from "@langchain/langgraph-sdk/stream";
|
|
12
13
|
//#region src/useSubagentTranscripts.ts
|
|
13
14
|
const MAX_SUBAGENT_DEPTH = 16;
|
|
14
15
|
const ROOT_UI_CHANNEL_DEPTH = 1;
|
|
@@ -127,7 +128,7 @@ const createSubagentTranscriptSource = () => {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
if (source.resources.has(snapshot.id)) continue;
|
|
130
|
-
const acquired = controller.registry.acquire(
|
|
131
|
+
const acquired = controller.registry.acquire(subagentMessagesProjection(snapshot.namespace));
|
|
131
132
|
const acquiredUI = snapshot.namespace.length > ROOT_UI_CHANNEL_DEPTH ? controller.registry.acquire(channelProjection(UI_CUSTOM_CHANNELS, snapshot.namespace)) : void 0;
|
|
132
133
|
const resource = {
|
|
133
134
|
snapshot,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSubagentTranscripts.js","names":[],"sources":["../src/useSubagentTranscripts.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport {\n stepStreamingTiming,\n type MessageTiming,\n type StreamingTimingState,\n type ThreadMessage,\n type ToolCallTiming,\n} from \"@assistant-ui/core\";\nimport {\n convertExternalMessages,\n createExternalMessageConversionCache,\n type ExternalMessageConversionCache,\n type useExternalMessageConverter,\n} from \"@assistant-ui/core/react\";\nimport { STREAM_CONTROLLER, type AnyStream } from \"@langchain/react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport {\n channelProjection,\n messagesProjection,\n type Event,\n} from \"@langchain/langgraph-sdk/stream\";\nimport type { SubagentDiscoverySnapshot } from \"@langchain/react\";\nimport {\n attachSubagentTranscripts,\n type AttachMemo,\n createAttachMemo,\n type SubagentTranscript,\n} from \"./attachSubagentTranscripts\";\nimport { convertLangChainBaseMessage } from \"./convertMessages\";\nimport { groupUIMessagesByParent } from \"./converter\";\nimport { langChainStreamingTimingAccessors } from \"./streamingTiming\";\nimport type { LangChainBaseMessage, UIMessage } from \"./types\";\nimport {\n createUIFoldMemo,\n foldUIUpdates,\n mergeUIMessages,\n UI_CUSTOM_CHANNELS,\n type UIFoldMemo,\n} from \"./uiMessages\";\n\nexport const MAX_SUBAGENT_DEPTH = 16;\n\nconst ROOT_UI_CHANNEL_DEPTH = 1;\n\nconst TRANSCRIPT_METADATA = {};\n\nconst NO_UI_MESSAGES: readonly UIMessage[] = [];\n\nconst NO_MESSAGE_TIMING: Record<string, MessageTiming> = {};\n\ntype ProjectionStore<T> = {\n getSnapshot(): T;\n subscribe(listener: () => void): () => void;\n};\n\ntype ProjectionResource = {\n snapshot: SubagentDiscoverySnapshot;\n namespace: readonly string[];\n store: ProjectionStore<BaseMessage[]>;\n uiStore: ProjectionStore<readonly Event[]> | undefined;\n dispose: () => void;\n storeSnapshot: BaseMessage[] | undefined;\n status: SubagentDiscoverySnapshot[\"status\"] | undefined;\n uiFoldMemo: UIFoldMemo;\n localUiMessages: readonly UIMessage[];\n rootUiMessagesByParent: Map<string, UIMessage[]>;\n uiMessagesByParent: Map<string, UIMessage[]>;\n timingState: StreamingTimingState | null;\n messageTiming: Record<string, MessageTiming>;\n convertedMessageTiming: Record<string, MessageTiming> | undefined;\n convert: useExternalMessageConverter.Callback<LangChainBaseMessage>;\n uiMessages: readonly UIMessage[];\n converted: readonly ThreadMessage[] | undefined;\n childTranscripts: ReadonlyMap<string, SubagentTranscript> | undefined;\n transcript: readonly ThreadMessage[] | undefined;\n timing: ToolCallTiming | undefined;\n entry: SubagentTranscript | undefined;\n memo: AttachMemo;\n cache: ExternalMessageConversionCache;\n};\n\ntype MeasuredTiming = {\n timing: ToolCallTiming | undefined;\n timingState: StreamingTimingState | null;\n messageTiming: Record<string, MessageTiming>;\n};\n\ntype NamespaceRequest = {\n id: string;\n attempts: number;\n pending: boolean;\n retryQueued: boolean;\n status: SubagentDiscoverySnapshot[\"status\"];\n};\n\ntype SubagentTranscriptSource = {\n resources: Map<string, ProjectionResource>;\n namespaceRequests: Map<string, NamespaceRequest>;\n snapshot: ReadonlyMap<string, SubagentTranscript>;\n listeners: Set<() => void>;\n controller: AnyStream[typeof STREAM_CONTROLLER] | undefined;\n uiMessagesByParent: Map<string, UIMessage[]>;\n subscribe(listener: () => void): () => void;\n getSnapshot(): ReadonlyMap<string, SubagentTranscript>;\n reconcile(\n controller: AnyStream[typeof STREAM_CONTROLLER],\n subagents: AnyStream[\"subagents\"],\n uiMessagesByParent: Map<string, UIMessage[]>,\n ): void;\n dispose(): void;\n};\n\nconst sameNamespace = (a: readonly string[], b: readonly string[]) =>\n a.length === b.length && a.every((segment, index) => segment === b[index]);\n\nconst needsNamespaceResolution = (snapshot: SubagentDiscoverySnapshot) =>\n snapshot.namespace.length === 1 &&\n snapshot.namespace[0] === `tools:${snapshot.id}`;\n\nconst requestSubagentNamespace = (\n source: SubagentTranscriptSource,\n controller: AnyStream[typeof STREAM_CONTROLLER],\n request: NamespaceRequest,\n) => {\n request.attempts += 1;\n request.pending = true;\n request.retryQueued = false;\n void controller\n .resolveSubagentNamespace(request.id)\n .catch(() => {})\n .finally(() => {\n if (\n source.controller !== controller ||\n source.namespaceRequests.get(request.id) !== request\n )\n return;\n\n request.pending = false;\n if (\n !request.retryQueued &&\n request.attempts === 1 &&\n request.status !== \"running\"\n ) {\n request.retryQueued = true;\n }\n if (!request.retryQueued || request.attempts >= 2) {\n request.retryQueued = false;\n return;\n }\n requestSubagentNamespace(source, controller, request);\n });\n};\n\nconst sameTranscriptEntries = (\n a: ReadonlyMap<string, SubagentTranscript> | undefined,\n b: ReadonlyMap<string, SubagentTranscript>,\n) =>\n a?.size === b.size &&\n [...b].every(([id, transcript]) => a.get(id) === transcript);\n\nconst collectUIMessages = (\n messages: readonly BaseMessage[],\n uiMessagesByParent: Map<string, UIMessage[]>,\n) => {\n const collected: UIMessage[] = [];\n if (uiMessagesByParent.size === 0) return collected;\n for (const message of messages) {\n const uiMessages = message.id && uiMessagesByParent.get(message.id);\n if (uiMessages) collected.push(...uiMessages);\n }\n return collected;\n};\n\nconst sameUIMessages = (a: readonly UIMessage[], b: readonly UIMessage[]) =>\n a.length === b.length && a.every((ui, index) => ui === b[index]);\n\nconst foldLocalUIMessages = (resource: ProjectionResource) => {\n const events = resource.uiStore?.getSnapshot();\n if (events === undefined) return NO_UI_MESSAGES;\n return foldUIUpdates(events, resource.uiFoldMemo);\n};\n\nconst mergeLocalUIMessages = (\n uiMessagesByParent: Map<string, UIMessage[]>,\n localUiMessages: readonly UIMessage[],\n) => {\n const merged = new Map(uiMessagesByParent);\n for (const [parentId, messages] of groupUIMessagesByParent<UIMessage>(\n localUiMessages,\n )) {\n merged.set(parentId, mergeUIMessages(messages, merged.get(parentId)));\n }\n return merged;\n};\n\nconst createConverter =\n (\n uiMessagesByParent: Map<string, UIMessage[]>,\n messageTiming: Record<string, MessageTiming>,\n ): useExternalMessageConverter.Callback<LangChainBaseMessage> =>\n (message, metadata) =>\n convertLangChainBaseMessage(message, {\n ...metadata,\n uiMessagesByParent,\n messageTiming,\n });\n\nconst updateTiming = (resource: ProjectionResource) => {\n if (resource.timing === undefined) return;\n const startedAt = resource.snapshot.startedAt.getTime();\n const completedAt = resource.snapshot.completedAt?.getTime();\n if (\n resource.timing.startedAt === startedAt &&\n resource.timing.completedAt === completedAt\n )\n return;\n resource.timing = {\n startedAt,\n ...(completedAt !== undefined && { completedAt }),\n };\n};\n\nconst createSubagentTranscriptSource = (): SubagentTranscriptSource => {\n const uiMessagesByParent = new Map<string, UIMessage[]>();\n const source: SubagentTranscriptSource = {\n resources: new Map(),\n namespaceRequests: new Map(),\n snapshot: new Map(),\n listeners: new Set(),\n controller: undefined,\n uiMessagesByParent,\n subscribe(listener) {\n source.listeners.add(listener);\n return () => source.listeners.delete(listener);\n },\n getSnapshot() {\n return source.snapshot;\n },\n reconcile(controller, subagents, uiMessagesByParent) {\n source.uiMessagesByParent = uiMessagesByParent;\n // A resource is rebuilt from scratch when its namespace resolves, which\n // routinely happens after the subagent finished. Its timing was measured\n // while the client watched the task run and cannot be measured again.\n const rebound = new Map<string, MeasuredTiming>();\n\n if (source.controller !== controller) {\n source.dispose();\n source.controller = controller;\n }\n\n for (const id of source.namespaceRequests.keys()) {\n if (!subagents.has(id)) source.namespaceRequests.delete(id);\n }\n\n for (const [id, resource] of source.resources) {\n const snapshot = subagents.get(id);\n if (\n !snapshot ||\n snapshot.depth > MAX_SUBAGENT_DEPTH ||\n !sameNamespace(resource.namespace, snapshot.namespace)\n ) {\n if (snapshot && snapshot.depth <= MAX_SUBAGENT_DEPTH)\n rebound.set(id, {\n timing: resource.timing,\n timingState: resource.timingState,\n messageTiming: resource.messageTiming,\n });\n resource.dispose();\n source.resources.delete(id);\n continue;\n }\n resource.snapshot = snapshot;\n }\n\n for (const snapshot of subagents.values()) {\n if (snapshot.depth > MAX_SUBAGENT_DEPTH) continue;\n if (!needsNamespaceResolution(snapshot)) {\n source.namespaceRequests.delete(snapshot.id);\n } else {\n const request = source.namespaceRequests.get(snapshot.id);\n if (!request) {\n const nextRequest: NamespaceRequest = {\n id: snapshot.id,\n attempts: 0,\n pending: false,\n retryQueued: false,\n status: snapshot.status,\n };\n source.namespaceRequests.set(snapshot.id, nextRequest);\n requestSubagentNamespace(source, controller, nextRequest);\n } else if (request.status !== snapshot.status) {\n request.status = snapshot.status;\n if (request.pending) {\n request.retryQueued = request.attempts < 2;\n } else if (request.attempts < 2) {\n requestSubagentNamespace(source, controller, request);\n }\n }\n }\n if (source.resources.has(snapshot.id)) continue;\n const acquired = controller.registry.acquire(\n messagesProjection(snapshot.namespace),\n );\n const acquiredUI =\n snapshot.namespace.length > ROOT_UI_CHANNEL_DEPTH\n ? controller.registry.acquire(\n channelProjection(UI_CUSTOM_CHANNELS, snapshot.namespace),\n )\n : undefined;\n const resource: ProjectionResource = {\n snapshot,\n namespace: snapshot.namespace,\n store: acquired.store,\n uiStore: acquiredUI?.store,\n dispose: () => {},\n storeSnapshot: undefined,\n status: undefined,\n uiFoldMemo: createUIFoldMemo(),\n localUiMessages: NO_UI_MESSAGES,\n rootUiMessagesByParent: source.uiMessagesByParent,\n uiMessagesByParent: source.uiMessagesByParent,\n timingState: rebound.get(snapshot.id)?.timingState ?? null,\n messageTiming:\n rebound.get(snapshot.id)?.messageTiming ?? NO_MESSAGE_TIMING,\n convertedMessageTiming: undefined,\n convert: createConverter(\n source.uiMessagesByParent,\n NO_MESSAGE_TIMING,\n ),\n uiMessages: [],\n converted: undefined,\n childTranscripts: undefined,\n transcript: undefined,\n timing: rebound.has(snapshot.id)\n ? rebound.get(snapshot.id)!.timing\n : snapshot.status === \"running\"\n ? { startedAt: snapshot.startedAt.getTime() }\n : undefined,\n entry: undefined,\n memo: createAttachMemo(),\n cache: createExternalMessageConversionCache(),\n };\n const unsubscribe = resource.store.subscribe(() => rebuild());\n const unsubscribeUI = resource.uiStore?.subscribe(() => rebuild());\n resource.dispose = () => {\n unsubscribe();\n unsubscribeUI?.();\n acquired.release();\n acquiredUI?.release();\n };\n source.resources.set(snapshot.id, resource);\n }\n\n rebuild();\n },\n dispose() {\n for (const resource of source.resources.values()) resource.dispose();\n source.resources.clear();\n source.namespaceRequests.clear();\n source.snapshot = new Map();\n for (const listener of source.listeners) listener();\n },\n };\n\n const rebuild = () => {\n const { uiMessagesByParent } = source;\n const resources = [...source.resources.values()];\n const childrenByParent = new Map<string, ProjectionResource[]>();\n\n for (const resource of resources) {\n const parentId = resource.snapshot.parentId;\n if (parentId == null) continue;\n const children = childrenByParent.get(parentId);\n if (children) children.push(resource);\n else childrenByParent.set(parentId, [resource]);\n }\n\n const transcripts = new Map<string, SubagentTranscript>();\n let changed = source.snapshot.size !== resources.length;\n const built = new Set<string>();\n\n const build = (resource: ProjectionResource, depth: number) => {\n if (built.has(resource.snapshot.id)) return;\n built.add(resource.snapshot.id);\n const children =\n depth < MAX_SUBAGENT_DEPTH\n ? (childrenByParent.get(resource.snapshot.id) ?? [])\n : [];\n for (const child of children) build(child, depth + 1);\n const childTranscripts = new Map(\n children.flatMap((child) =>\n child.entry ? [[child.snapshot.id, child.entry] as const] : [],\n ),\n );\n const storeSnapshot = resource.store.getSnapshot();\n const status = resource.snapshot.status;\n const stepped = stepStreamingTiming(\n resource.timingState,\n storeSnapshot as LangChainBaseMessage[],\n status === \"running\",\n langChainStreamingTimingAccessors,\n undefined,\n );\n resource.timingState = stepped.state;\n if (Object.keys(stepped.timings).length > 0) {\n resource.messageTiming = {\n ...resource.messageTiming,\n ...stepped.timings,\n };\n }\n const localUiMessages = foldLocalUIMessages(resource);\n if (\n resource.localUiMessages !== localUiMessages ||\n resource.rootUiMessagesByParent !== uiMessagesByParent ||\n resource.convertedMessageTiming !== resource.messageTiming\n ) {\n resource.localUiMessages = localUiMessages;\n resource.rootUiMessagesByParent = uiMessagesByParent;\n resource.uiMessagesByParent =\n localUiMessages.length === 0\n ? uiMessagesByParent\n : mergeLocalUIMessages(uiMessagesByParent, localUiMessages);\n resource.convert = createConverter(\n resource.uiMessagesByParent,\n resource.messageTiming,\n );\n }\n const uiMessages = collectUIMessages(\n storeSnapshot,\n resource.uiMessagesByParent,\n );\n\n const conversionChanged =\n resource.converted === undefined ||\n resource.storeSnapshot !== storeSnapshot ||\n resource.status !== status ||\n resource.convertedMessageTiming !== resource.messageTiming ||\n !sameUIMessages(resource.uiMessages, uiMessages);\n if (conversionChanged) {\n resource.converted = convertExternalMessages(\n storeSnapshot as LangChainBaseMessage[],\n resource.convert,\n status === \"running\",\n TRANSCRIPT_METADATA,\n resource.cache,\n );\n resource.storeSnapshot = storeSnapshot;\n resource.status = status;\n resource.uiMessages = uiMessages;\n resource.convertedMessageTiming = resource.messageTiming;\n }\n\n if (\n resource.transcript === undefined ||\n conversionChanged ||\n !sameTranscriptEntries(resource.childTranscripts, childTranscripts)\n ) {\n const transcript = attachSubagentTranscripts(\n resource.converted!,\n childTranscripts,\n resource.memo,\n );\n changed ||= resource.transcript !== transcript;\n resource.transcript = transcript;\n resource.childTranscripts = childTranscripts;\n }\n\n updateTiming(resource);\n if (\n resource.entry === undefined ||\n resource.entry.messages !== resource.transcript ||\n resource.entry.timing !== resource.timing\n ) {\n resource.entry = {\n messages: resource.transcript!,\n ...(resource.timing && { timing: resource.timing }),\n };\n changed = true;\n }\n\n if (!source.snapshot.has(resource.snapshot.id)) changed = true;\n transcripts.set(resource.snapshot.id, resource.entry);\n };\n\n for (const resource of resources) {\n if (\n resource.snapshot.parentId == null ||\n !source.resources.has(resource.snapshot.parentId)\n )\n build(resource, 1);\n }\n for (const resource of resources) build(resource, MAX_SUBAGENT_DEPTH);\n\n if (!changed) return;\n source.snapshot = transcripts;\n for (const listener of source.listeners) listener();\n };\n\n return source;\n};\n\nexport const useSubagentTranscripts = (\n stream: AnyStream,\n uiMessagesByParent: Map<string, UIMessage[]>,\n): ReadonlyMap<string, SubagentTranscript> => {\n const sourceRef = useRef<SubagentTranscriptSource | undefined>(undefined);\n if (!sourceRef.current) {\n sourceRef.current = createSubagentTranscriptSource();\n }\n const source = sourceRef.current;\n const controller = stream[STREAM_CONTROLLER];\n\n useEffect(() => {\n source.reconcile(controller, stream.subagents, uiMessagesByParent);\n }, [controller, source, stream.subagents, uiMessagesByParent]);\n\n useEffect(() => () => source.dispose(), [source]);\n\n return useSyncExternalStore(\n source.subscribe,\n source.getSnapshot,\n source.getSnapshot,\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSubagentTranscripts.js","names":[],"sources":["../src/useSubagentTranscripts.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useSyncExternalStore } from \"react\";\nimport {\n stepStreamingTiming,\n type MessageTiming,\n type StreamingTimingState,\n type ThreadMessage,\n type ToolCallTiming,\n} from \"@assistant-ui/core\";\nimport {\n convertExternalMessages,\n createExternalMessageConversionCache,\n type ExternalMessageConversionCache,\n type useExternalMessageConverter,\n} from \"@assistant-ui/core/react\";\nimport { STREAM_CONTROLLER, type AnyStream } from \"@langchain/react\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport { channelProjection, type Event } from \"@langchain/langgraph-sdk/stream\";\nimport type { SubagentDiscoverySnapshot } from \"@langchain/react\";\nimport {\n attachSubagentTranscripts,\n type AttachMemo,\n createAttachMemo,\n type SubagentTranscript,\n} from \"./attachSubagentTranscripts\";\nimport { convertLangChainBaseMessage } from \"./convertMessages\";\nimport { groupUIMessagesByParent } from \"./converter\";\nimport { langChainStreamingTimingAccessors } from \"./streamingTiming\";\nimport { subagentMessagesProjection } from \"./subagentMessagesProjection\";\nimport type { LangChainBaseMessage, UIMessage } from \"./types\";\nimport {\n createUIFoldMemo,\n foldUIUpdates,\n mergeUIMessages,\n UI_CUSTOM_CHANNELS,\n type UIFoldMemo,\n} from \"./uiMessages\";\n\nexport const MAX_SUBAGENT_DEPTH = 16;\n\nconst ROOT_UI_CHANNEL_DEPTH = 1;\n\nconst TRANSCRIPT_METADATA = {};\n\nconst NO_UI_MESSAGES: readonly UIMessage[] = [];\n\nconst NO_MESSAGE_TIMING: Record<string, MessageTiming> = {};\n\ntype ProjectionStore<T> = {\n getSnapshot(): T;\n subscribe(listener: () => void): () => void;\n};\n\ntype ProjectionResource = {\n snapshot: SubagentDiscoverySnapshot;\n namespace: readonly string[];\n store: ProjectionStore<BaseMessage[]>;\n uiStore: ProjectionStore<readonly Event[]> | undefined;\n dispose: () => void;\n storeSnapshot: BaseMessage[] | undefined;\n status: SubagentDiscoverySnapshot[\"status\"] | undefined;\n uiFoldMemo: UIFoldMemo;\n localUiMessages: readonly UIMessage[];\n rootUiMessagesByParent: Map<string, UIMessage[]>;\n uiMessagesByParent: Map<string, UIMessage[]>;\n timingState: StreamingTimingState | null;\n messageTiming: Record<string, MessageTiming>;\n convertedMessageTiming: Record<string, MessageTiming> | undefined;\n convert: useExternalMessageConverter.Callback<LangChainBaseMessage>;\n uiMessages: readonly UIMessage[];\n converted: readonly ThreadMessage[] | undefined;\n childTranscripts: ReadonlyMap<string, SubagentTranscript> | undefined;\n transcript: readonly ThreadMessage[] | undefined;\n timing: ToolCallTiming | undefined;\n entry: SubagentTranscript | undefined;\n memo: AttachMemo;\n cache: ExternalMessageConversionCache;\n};\n\ntype MeasuredTiming = {\n timing: ToolCallTiming | undefined;\n timingState: StreamingTimingState | null;\n messageTiming: Record<string, MessageTiming>;\n};\n\ntype NamespaceRequest = {\n id: string;\n attempts: number;\n pending: boolean;\n retryQueued: boolean;\n status: SubagentDiscoverySnapshot[\"status\"];\n};\n\ntype SubagentTranscriptSource = {\n resources: Map<string, ProjectionResource>;\n namespaceRequests: Map<string, NamespaceRequest>;\n snapshot: ReadonlyMap<string, SubagentTranscript>;\n listeners: Set<() => void>;\n controller: AnyStream[typeof STREAM_CONTROLLER] | undefined;\n uiMessagesByParent: Map<string, UIMessage[]>;\n subscribe(listener: () => void): () => void;\n getSnapshot(): ReadonlyMap<string, SubagentTranscript>;\n reconcile(\n controller: AnyStream[typeof STREAM_CONTROLLER],\n subagents: AnyStream[\"subagents\"],\n uiMessagesByParent: Map<string, UIMessage[]>,\n ): void;\n dispose(): void;\n};\n\nconst sameNamespace = (a: readonly string[], b: readonly string[]) =>\n a.length === b.length && a.every((segment, index) => segment === b[index]);\n\nconst needsNamespaceResolution = (snapshot: SubagentDiscoverySnapshot) =>\n snapshot.namespace.length === 1 &&\n snapshot.namespace[0] === `tools:${snapshot.id}`;\n\nconst requestSubagentNamespace = (\n source: SubagentTranscriptSource,\n controller: AnyStream[typeof STREAM_CONTROLLER],\n request: NamespaceRequest,\n) => {\n request.attempts += 1;\n request.pending = true;\n request.retryQueued = false;\n void controller\n .resolveSubagentNamespace(request.id)\n .catch(() => {})\n .finally(() => {\n if (\n source.controller !== controller ||\n source.namespaceRequests.get(request.id) !== request\n )\n return;\n\n request.pending = false;\n if (\n !request.retryQueued &&\n request.attempts === 1 &&\n request.status !== \"running\"\n ) {\n request.retryQueued = true;\n }\n if (!request.retryQueued || request.attempts >= 2) {\n request.retryQueued = false;\n return;\n }\n requestSubagentNamespace(source, controller, request);\n });\n};\n\nconst sameTranscriptEntries = (\n a: ReadonlyMap<string, SubagentTranscript> | undefined,\n b: ReadonlyMap<string, SubagentTranscript>,\n) =>\n a?.size === b.size &&\n [...b].every(([id, transcript]) => a.get(id) === transcript);\n\nconst collectUIMessages = (\n messages: readonly BaseMessage[],\n uiMessagesByParent: Map<string, UIMessage[]>,\n) => {\n const collected: UIMessage[] = [];\n if (uiMessagesByParent.size === 0) return collected;\n for (const message of messages) {\n const uiMessages = message.id && uiMessagesByParent.get(message.id);\n if (uiMessages) collected.push(...uiMessages);\n }\n return collected;\n};\n\nconst sameUIMessages = (a: readonly UIMessage[], b: readonly UIMessage[]) =>\n a.length === b.length && a.every((ui, index) => ui === b[index]);\n\nconst foldLocalUIMessages = (resource: ProjectionResource) => {\n const events = resource.uiStore?.getSnapshot();\n if (events === undefined) return NO_UI_MESSAGES;\n return foldUIUpdates(events, resource.uiFoldMemo);\n};\n\nconst mergeLocalUIMessages = (\n uiMessagesByParent: Map<string, UIMessage[]>,\n localUiMessages: readonly UIMessage[],\n) => {\n const merged = new Map(uiMessagesByParent);\n for (const [parentId, messages] of groupUIMessagesByParent<UIMessage>(\n localUiMessages,\n )) {\n merged.set(parentId, mergeUIMessages(messages, merged.get(parentId)));\n }\n return merged;\n};\n\nconst createConverter =\n (\n uiMessagesByParent: Map<string, UIMessage[]>,\n messageTiming: Record<string, MessageTiming>,\n ): useExternalMessageConverter.Callback<LangChainBaseMessage> =>\n (message, metadata) =>\n convertLangChainBaseMessage(message, {\n ...metadata,\n uiMessagesByParent,\n messageTiming,\n });\n\nconst updateTiming = (resource: ProjectionResource) => {\n if (resource.timing === undefined) return;\n const startedAt = resource.snapshot.startedAt.getTime();\n const completedAt = resource.snapshot.completedAt?.getTime();\n if (\n resource.timing.startedAt === startedAt &&\n resource.timing.completedAt === completedAt\n )\n return;\n resource.timing = {\n startedAt,\n ...(completedAt !== undefined && { completedAt }),\n };\n};\n\nconst createSubagentTranscriptSource = (): SubagentTranscriptSource => {\n const uiMessagesByParent = new Map<string, UIMessage[]>();\n const source: SubagentTranscriptSource = {\n resources: new Map(),\n namespaceRequests: new Map(),\n snapshot: new Map(),\n listeners: new Set(),\n controller: undefined,\n uiMessagesByParent,\n subscribe(listener) {\n source.listeners.add(listener);\n return () => source.listeners.delete(listener);\n },\n getSnapshot() {\n return source.snapshot;\n },\n reconcile(controller, subagents, uiMessagesByParent) {\n source.uiMessagesByParent = uiMessagesByParent;\n // A resource is rebuilt from scratch when its namespace resolves, which\n // routinely happens after the subagent finished. Its timing was measured\n // while the client watched the task run and cannot be measured again.\n const rebound = new Map<string, MeasuredTiming>();\n\n if (source.controller !== controller) {\n source.dispose();\n source.controller = controller;\n }\n\n for (const id of source.namespaceRequests.keys()) {\n if (!subagents.has(id)) source.namespaceRequests.delete(id);\n }\n\n for (const [id, resource] of source.resources) {\n const snapshot = subagents.get(id);\n if (\n !snapshot ||\n snapshot.depth > MAX_SUBAGENT_DEPTH ||\n !sameNamespace(resource.namespace, snapshot.namespace)\n ) {\n if (snapshot && snapshot.depth <= MAX_SUBAGENT_DEPTH)\n rebound.set(id, {\n timing: resource.timing,\n timingState: resource.timingState,\n messageTiming: resource.messageTiming,\n });\n resource.dispose();\n source.resources.delete(id);\n continue;\n }\n resource.snapshot = snapshot;\n }\n\n for (const snapshot of subagents.values()) {\n if (snapshot.depth > MAX_SUBAGENT_DEPTH) continue;\n if (!needsNamespaceResolution(snapshot)) {\n source.namespaceRequests.delete(snapshot.id);\n } else {\n const request = source.namespaceRequests.get(snapshot.id);\n if (!request) {\n const nextRequest: NamespaceRequest = {\n id: snapshot.id,\n attempts: 0,\n pending: false,\n retryQueued: false,\n status: snapshot.status,\n };\n source.namespaceRequests.set(snapshot.id, nextRequest);\n requestSubagentNamespace(source, controller, nextRequest);\n } else if (request.status !== snapshot.status) {\n request.status = snapshot.status;\n if (request.pending) {\n request.retryQueued = request.attempts < 2;\n } else if (request.attempts < 2) {\n requestSubagentNamespace(source, controller, request);\n }\n }\n }\n if (source.resources.has(snapshot.id)) continue;\n const acquired = controller.registry.acquire(\n subagentMessagesProjection(snapshot.namespace),\n );\n const acquiredUI =\n snapshot.namespace.length > ROOT_UI_CHANNEL_DEPTH\n ? controller.registry.acquire(\n channelProjection(UI_CUSTOM_CHANNELS, snapshot.namespace),\n )\n : undefined;\n const resource: ProjectionResource = {\n snapshot,\n namespace: snapshot.namespace,\n store: acquired.store,\n uiStore: acquiredUI?.store,\n dispose: () => {},\n storeSnapshot: undefined,\n status: undefined,\n uiFoldMemo: createUIFoldMemo(),\n localUiMessages: NO_UI_MESSAGES,\n rootUiMessagesByParent: source.uiMessagesByParent,\n uiMessagesByParent: source.uiMessagesByParent,\n timingState: rebound.get(snapshot.id)?.timingState ?? null,\n messageTiming:\n rebound.get(snapshot.id)?.messageTiming ?? NO_MESSAGE_TIMING,\n convertedMessageTiming: undefined,\n convert: createConverter(\n source.uiMessagesByParent,\n NO_MESSAGE_TIMING,\n ),\n uiMessages: [],\n converted: undefined,\n childTranscripts: undefined,\n transcript: undefined,\n timing: rebound.has(snapshot.id)\n ? rebound.get(snapshot.id)!.timing\n : snapshot.status === \"running\"\n ? { startedAt: snapshot.startedAt.getTime() }\n : undefined,\n entry: undefined,\n memo: createAttachMemo(),\n cache: createExternalMessageConversionCache(),\n };\n const unsubscribe = resource.store.subscribe(() => rebuild());\n const unsubscribeUI = resource.uiStore?.subscribe(() => rebuild());\n resource.dispose = () => {\n unsubscribe();\n unsubscribeUI?.();\n acquired.release();\n acquiredUI?.release();\n };\n source.resources.set(snapshot.id, resource);\n }\n\n rebuild();\n },\n dispose() {\n for (const resource of source.resources.values()) resource.dispose();\n source.resources.clear();\n source.namespaceRequests.clear();\n source.snapshot = new Map();\n for (const listener of source.listeners) listener();\n },\n };\n\n const rebuild = () => {\n const { uiMessagesByParent } = source;\n const resources = [...source.resources.values()];\n const childrenByParent = new Map<string, ProjectionResource[]>();\n\n for (const resource of resources) {\n const parentId = resource.snapshot.parentId;\n if (parentId == null) continue;\n const children = childrenByParent.get(parentId);\n if (children) children.push(resource);\n else childrenByParent.set(parentId, [resource]);\n }\n\n const transcripts = new Map<string, SubagentTranscript>();\n let changed = source.snapshot.size !== resources.length;\n const built = new Set<string>();\n\n const build = (resource: ProjectionResource, depth: number) => {\n if (built.has(resource.snapshot.id)) return;\n built.add(resource.snapshot.id);\n const children =\n depth < MAX_SUBAGENT_DEPTH\n ? (childrenByParent.get(resource.snapshot.id) ?? [])\n : [];\n for (const child of children) build(child, depth + 1);\n const childTranscripts = new Map(\n children.flatMap((child) =>\n child.entry ? [[child.snapshot.id, child.entry] as const] : [],\n ),\n );\n const storeSnapshot = resource.store.getSnapshot();\n const status = resource.snapshot.status;\n const stepped = stepStreamingTiming(\n resource.timingState,\n storeSnapshot as LangChainBaseMessage[],\n status === \"running\",\n langChainStreamingTimingAccessors,\n undefined,\n );\n resource.timingState = stepped.state;\n if (Object.keys(stepped.timings).length > 0) {\n resource.messageTiming = {\n ...resource.messageTiming,\n ...stepped.timings,\n };\n }\n const localUiMessages = foldLocalUIMessages(resource);\n if (\n resource.localUiMessages !== localUiMessages ||\n resource.rootUiMessagesByParent !== uiMessagesByParent ||\n resource.convertedMessageTiming !== resource.messageTiming\n ) {\n resource.localUiMessages = localUiMessages;\n resource.rootUiMessagesByParent = uiMessagesByParent;\n resource.uiMessagesByParent =\n localUiMessages.length === 0\n ? uiMessagesByParent\n : mergeLocalUIMessages(uiMessagesByParent, localUiMessages);\n resource.convert = createConverter(\n resource.uiMessagesByParent,\n resource.messageTiming,\n );\n }\n const uiMessages = collectUIMessages(\n storeSnapshot,\n resource.uiMessagesByParent,\n );\n\n const conversionChanged =\n resource.converted === undefined ||\n resource.storeSnapshot !== storeSnapshot ||\n resource.status !== status ||\n resource.convertedMessageTiming !== resource.messageTiming ||\n !sameUIMessages(resource.uiMessages, uiMessages);\n if (conversionChanged) {\n resource.converted = convertExternalMessages(\n storeSnapshot as LangChainBaseMessage[],\n resource.convert,\n status === \"running\",\n TRANSCRIPT_METADATA,\n resource.cache,\n );\n resource.storeSnapshot = storeSnapshot;\n resource.status = status;\n resource.uiMessages = uiMessages;\n resource.convertedMessageTiming = resource.messageTiming;\n }\n\n if (\n resource.transcript === undefined ||\n conversionChanged ||\n !sameTranscriptEntries(resource.childTranscripts, childTranscripts)\n ) {\n const transcript = attachSubagentTranscripts(\n resource.converted!,\n childTranscripts,\n resource.memo,\n );\n changed ||= resource.transcript !== transcript;\n resource.transcript = transcript;\n resource.childTranscripts = childTranscripts;\n }\n\n updateTiming(resource);\n if (\n resource.entry === undefined ||\n resource.entry.messages !== resource.transcript ||\n resource.entry.timing !== resource.timing\n ) {\n resource.entry = {\n messages: resource.transcript!,\n ...(resource.timing && { timing: resource.timing }),\n };\n changed = true;\n }\n\n if (!source.snapshot.has(resource.snapshot.id)) changed = true;\n transcripts.set(resource.snapshot.id, resource.entry);\n };\n\n for (const resource of resources) {\n if (\n resource.snapshot.parentId == null ||\n !source.resources.has(resource.snapshot.parentId)\n )\n build(resource, 1);\n }\n for (const resource of resources) build(resource, MAX_SUBAGENT_DEPTH);\n\n if (!changed) return;\n source.snapshot = transcripts;\n for (const listener of source.listeners) listener();\n };\n\n return source;\n};\n\nexport const useSubagentTranscripts = (\n stream: AnyStream,\n uiMessagesByParent: Map<string, UIMessage[]>,\n): ReadonlyMap<string, SubagentTranscript> => {\n const sourceRef = useRef<SubagentTranscriptSource | undefined>(undefined);\n if (!sourceRef.current) {\n sourceRef.current = createSubagentTranscriptSource();\n }\n const source = sourceRef.current;\n const controller = stream[STREAM_CONTROLLER];\n\n useEffect(() => {\n source.reconcile(controller, stream.subagents, uiMessagesByParent);\n }, [controller, source, stream.subagents, uiMessagesByParent]);\n\n useEffect(() => () => source.dispose(), [source]);\n\n return useSyncExternalStore(\n source.subscribe,\n source.getSnapshot,\n source.getSnapshot,\n );\n};\n"],"mappings":"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"}
|