mirror of
https://github.com/langchain-ai/langgraphjs.git
synced 2026-07-25 13:15:45 -04:00
feat(sdk): add isThreadLoading option to useStream, handle thread error fetching (#1466)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@langchain/langgraph-sdk": patch
|
||||
---
|
||||
|
||||
feat(sdk): add `isThreadLoading` option to `useStream`, handle thread error fetching
|
||||
@@ -351,9 +351,14 @@ function useThreadHistory<StateType extends Record<string, unknown>>(
|
||||
client: Client,
|
||||
limit: boolean | number,
|
||||
clearCallbackRef: RefObject<(() => void) | undefined>,
|
||||
submittingRef: RefObject<boolean>
|
||||
submittingRef: RefObject<boolean>,
|
||||
onErrorRef: RefObject<((error: unknown) => void) | undefined>
|
||||
) {
|
||||
const [history, setHistory] = useState<ThreadState<StateType>[]>([]);
|
||||
const [history, setHistory] = useState<ThreadState<StateType>[] | undefined>(
|
||||
undefined
|
||||
);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<unknown | undefined>(undefined);
|
||||
|
||||
const clientHash = getClientConfigHash(client);
|
||||
const clientRef = useRef(client);
|
||||
@@ -365,19 +370,35 @@ function useThreadHistory<StateType extends Record<string, unknown>>(
|
||||
): Promise<ThreadState<StateType>[]> => {
|
||||
if (threadId != null) {
|
||||
const client = clientRef.current;
|
||||
|
||||
setIsLoading(true);
|
||||
return fetchHistory<StateType>(client, threadId, {
|
||||
limit,
|
||||
}).then((history) => {
|
||||
setHistory(history);
|
||||
return history;
|
||||
});
|
||||
})
|
||||
.then(
|
||||
(history) => {
|
||||
setHistory(history);
|
||||
return history;
|
||||
},
|
||||
(error) => {
|
||||
setError(error);
|
||||
onErrorRef.current?.(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
)
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
setHistory([]);
|
||||
setHistory(undefined);
|
||||
setError(undefined);
|
||||
setIsLoading(false);
|
||||
|
||||
clearCallbackRef.current?.();
|
||||
return Promise.resolve([]);
|
||||
},
|
||||
[clearCallbackRef, limit]
|
||||
[clearCallbackRef, onErrorRef, limit]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -387,6 +408,8 @@ function useThreadHistory<StateType extends Record<string, unknown>>(
|
||||
|
||||
return {
|
||||
data: history,
|
||||
isLoading,
|
||||
error,
|
||||
mutate: (mutateId?: string) => fetcher(mutateId ?? threadId),
|
||||
};
|
||||
}
|
||||
@@ -642,6 +665,11 @@ export interface UseStream<
|
||||
*/
|
||||
isLoading: boolean;
|
||||
|
||||
/**
|
||||
* Whether the thread is currently being loaded.
|
||||
*/
|
||||
isThreadLoading: boolean;
|
||||
|
||||
/**
|
||||
* Stops the stream.
|
||||
*/
|
||||
@@ -936,6 +964,11 @@ export function useStream<
|
||||
messageManagerRef.current.clear();
|
||||
};
|
||||
|
||||
const onErrorRef = useRef<
|
||||
((error: unknown, run?: RunCallbackMeta) => void) | undefined
|
||||
>(undefined);
|
||||
onErrorRef.current = options.onError;
|
||||
|
||||
const historyLimit =
|
||||
typeof fetchStateHistory === "object" && fetchStateHistory != null
|
||||
? fetchStateHistory.limit ?? true
|
||||
@@ -946,7 +979,8 @@ export function useStream<
|
||||
client,
|
||||
historyLimit,
|
||||
clearCallbackRef,
|
||||
submittingRef
|
||||
submittingRef,
|
||||
onErrorRef
|
||||
);
|
||||
|
||||
const getMessages = useMemo(() => {
|
||||
@@ -956,7 +990,7 @@ export function useStream<
|
||||
: [];
|
||||
}, [messagesKey]);
|
||||
|
||||
const { rootSequence, paths } = getBranchSequence(history.data);
|
||||
const { rootSequence, paths } = getBranchSequence(history.data ?? []);
|
||||
const { history: flatHistory, branchByCheckpoint } = getBranchView(
|
||||
rootSequence,
|
||||
paths,
|
||||
@@ -967,7 +1001,7 @@ export function useStream<
|
||||
const historyValues =
|
||||
threadHead?.values ?? options.initialValues ?? ({} as StateType);
|
||||
|
||||
const historyError = (() => {
|
||||
const historyValueError = (() => {
|
||||
const error = threadHead?.tasks?.at(-1)?.error;
|
||||
if (error == null) return undefined;
|
||||
try {
|
||||
@@ -988,13 +1022,13 @@ export function useStream<
|
||||
return getMessages(historyValues).map(
|
||||
(message, idx): MessageMetadata<StateType> => {
|
||||
const messageId = message.id ?? idx;
|
||||
const firstSeenIdx = findLastIndex(history.data, (state) =>
|
||||
const firstSeenIdx = findLastIndex(history.data ?? [], (state) =>
|
||||
getMessages(state.values)
|
||||
.map((m, idx) => m.id ?? idx)
|
||||
.includes(messageId)
|
||||
);
|
||||
|
||||
const firstSeen = history.data[firstSeenIdx] as
|
||||
const firstSeen = history.data?.[firstSeenIdx] as
|
||||
| ThreadState<StateType>
|
||||
| undefined;
|
||||
|
||||
@@ -1300,7 +1334,7 @@ export function useStream<
|
||||
}
|
||||
}, [reconnectKey]);
|
||||
|
||||
const error = streamError ?? historyError;
|
||||
const error = streamError ?? historyValueError ?? history.error;
|
||||
const values = streamValues ?? historyValues;
|
||||
|
||||
return {
|
||||
@@ -1324,6 +1358,8 @@ export function useStream<
|
||||
setBranch,
|
||||
|
||||
history: flatHistory,
|
||||
isThreadLoading: history.isLoading && history.data == null,
|
||||
|
||||
get experimental_branchTree() {
|
||||
if (historyLimit === false) {
|
||||
throw new Error(
|
||||
|
||||
Reference in New Issue
Block a user