@assistant-ui/react-langgraph 0.6.11 → 0.7.1
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/useLangGraphMessages.d.ts +4 -0
- package/dist/useLangGraphMessages.d.ts.map +1 -1
- package/dist/useLangGraphMessages.js +6 -1
- package/dist/useLangGraphMessages.js.map +1 -1
- package/dist/useLangGraphRuntime.d.ts +15 -11
- package/dist/useLangGraphRuntime.d.ts.map +1 -1
- package/dist/useLangGraphRuntime.js +39 -19
- package/dist/useLangGraphRuntime.js.map +1 -1
- package/package.json +7 -7
- package/src/useLangGraphMessages.ts +12 -1
- package/src/useLangGraphRuntime.test.tsx +25 -10
- package/src/useLangGraphRuntime.ts +61 -41
|
@@ -12,6 +12,10 @@ export type LangGraphMessagesEvent<TMessage> = {
|
|
|
12
12
|
};
|
|
13
13
|
export type LangGraphStreamCallback<TMessage> = (messages: TMessage[], config: LangGraphSendMessageConfig & {
|
|
14
14
|
abortSignal: AbortSignal;
|
|
15
|
+
initialize: () => Promise<{
|
|
16
|
+
remoteId: string;
|
|
17
|
+
externalId: string | undefined;
|
|
18
|
+
}>;
|
|
15
19
|
}) => Promise<AsyncGenerator<LangGraphMessagesEvent<TMessage>>> | AsyncGenerator<LangGraphMessagesEvent<TMessage>>;
|
|
16
20
|
export type LangGraphInterruptState = {
|
|
17
21
|
value?: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLangGraphMessages.d.ts","sourceRoot":"","sources":["../src/useLangGraphMessages.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,SAAS,EAIT,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"useLangGraphMessages.d.ts","sourceRoot":"","sources":["../src/useLangGraphMessages.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,SAAS,EAIT,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAGjB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,QAAQ,IAAI;IAC7C,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,uBAAuB,CAAC,QAAQ,IAAI,CAC9C,QAAQ,EAAE,QAAQ,EAAE,EACpB,MAAM,EAAE,0BAA0B,GAAG;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,OAAO,CAAC;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;KAChC,CAAC,CAAC;CACJ,KAEC,OAAO,CAAC,cAAc,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,GACzD,cAAc,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAErD,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;CACf,CAAC;AAuBF,eAAO,MAAM,oBAAoB,GAAI,QAAQ,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,2CAIpE;IACD,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC;IACzE,aAAa,CAAC,EAAE;QACd,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAC/B,aAAa,CAAC,EAAE,qBAAqB,CAAC;KACvC,CAAC;CACH;;;+BAcuB,QAAQ,EAAE,UAAU,0BAA0B;;;;CAiHrE,CAAC"}
|
|
@@ -5,6 +5,7 @@ import { LangGraphMessageAccumulator } from "./LangGraphMessageAccumulator.js";
|
|
|
5
5
|
import {
|
|
6
6
|
LangGraphKnownEventTypes
|
|
7
7
|
} from "./types.js";
|
|
8
|
+
import { useAssistantApi } from "@assistant-ui/react";
|
|
8
9
|
var DEFAULT_APPEND_MESSAGE = (_, curr) => curr;
|
|
9
10
|
var isLangChainMessageChunk = (value) => {
|
|
10
11
|
if (!value || typeof value !== "object") return false;
|
|
@@ -23,6 +24,7 @@ var useLangGraphMessages = ({
|
|
|
23
24
|
() => eventHandlers ?? {},
|
|
24
25
|
[eventHandlers]
|
|
25
26
|
);
|
|
27
|
+
const api = useAssistantApi();
|
|
26
28
|
const sendMessage = useCallback(
|
|
27
29
|
async (newMessages, config) => {
|
|
28
30
|
const newMessagesWithId = newMessages.map(
|
|
@@ -37,7 +39,10 @@ var useLangGraphMessages = ({
|
|
|
37
39
|
abortControllerRef.current = abortController;
|
|
38
40
|
const response = await stream(newMessagesWithId, {
|
|
39
41
|
...config,
|
|
40
|
-
abortSignal: abortController.signal
|
|
42
|
+
abortSignal: abortController.signal,
|
|
43
|
+
initialize: async () => {
|
|
44
|
+
return await api.threadListItem().initialize();
|
|
45
|
+
}
|
|
41
46
|
});
|
|
42
47
|
for await (const chunk of response) {
|
|
43
48
|
switch (chunk.event) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useLangGraphMessages.ts"],"sourcesContent":["import { useState, useCallback, useRef, useMemo } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { LangGraphMessageAccumulator } from \"./LangGraphMessageAccumulator\";\nimport {\n EventType,\n LangChainMessageTupleEvent,\n LangGraphKnownEventTypes,\n LangChainMessageChunk,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\n\nexport type LangGraphCommand = {\n resume: string;\n};\n\nexport type LangGraphSendMessageConfig = {\n command?: LangGraphCommand;\n runConfig?: unknown;\n};\n\nexport type LangGraphMessagesEvent<TMessage> = {\n event: EventType;\n data: TMessage[] | any;\n};\n\nexport type LangGraphStreamCallback<TMessage> = (\n messages: TMessage[],\n config: LangGraphSendMessageConfig & {
|
|
1
|
+
{"version":3,"sources":["../src/useLangGraphMessages.ts"],"sourcesContent":["import { useState, useCallback, useRef, useMemo } from \"react\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { LangGraphMessageAccumulator } from \"./LangGraphMessageAccumulator\";\nimport {\n EventType,\n LangChainMessageTupleEvent,\n LangGraphKnownEventTypes,\n LangChainMessageChunk,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\nimport { useAssistantApi } from \"@assistant-ui/react\";\n\nexport type LangGraphCommand = {\n resume: string;\n};\n\nexport type LangGraphSendMessageConfig = {\n command?: LangGraphCommand;\n runConfig?: unknown;\n};\n\nexport type LangGraphMessagesEvent<TMessage> = {\n event: EventType;\n data: TMessage[] | any;\n};\n\nexport type LangGraphStreamCallback<TMessage> = (\n messages: TMessage[],\n config: LangGraphSendMessageConfig & {\n abortSignal: AbortSignal;\n initialize: () => Promise<{\n remoteId: string;\n externalId: string | undefined;\n }>;\n },\n) =>\n | Promise<AsyncGenerator<LangGraphMessagesEvent<TMessage>>>\n | AsyncGenerator<LangGraphMessagesEvent<TMessage>>;\n\nexport type LangGraphInterruptState = {\n value?: any;\n resumable?: boolean;\n when?: string;\n ns?: string[];\n};\n\nconst DEFAULT_APPEND_MESSAGE = <TMessage>(\n _: TMessage | undefined,\n curr: TMessage,\n) => curr;\n\nconst isLangChainMessageChunk = (\n value: unknown,\n): value is LangChainMessageChunk => {\n if (!value || typeof value !== \"object\") return false;\n const chunk = value as any;\n return (\n \"type\" in chunk &&\n chunk.type === \"AIMessageChunk\" &&\n (chunk.content === undefined ||\n typeof chunk.content === \"string\" ||\n Array.isArray(chunk.content)) &&\n (chunk.tool_call_chunks === undefined ||\n Array.isArray(chunk.tool_call_chunks))\n );\n};\n\nexport const useLangGraphMessages = <TMessage extends { id?: string }>({\n stream,\n appendMessage = DEFAULT_APPEND_MESSAGE,\n eventHandlers,\n}: {\n stream: LangGraphStreamCallback<TMessage>;\n appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;\n eventHandlers?: {\n onMetadata?: OnMetadataEventCallback;\n onInfo?: OnInfoEventCallback;\n onError?: OnErrorEventCallback;\n onCustomEvent?: OnCustomEventCallback;\n };\n}) => {\n const [interrupt, setInterrupt] = useState<\n LangGraphInterruptState | undefined\n >();\n const [messages, setMessages] = useState<TMessage[]>([]);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const { onMetadata, onInfo, onError, onCustomEvent } = useMemo(\n () => eventHandlers ?? {},\n [eventHandlers],\n );\n\n const api = useAssistantApi();\n const sendMessage = useCallback(\n async (newMessages: TMessage[], config: LangGraphSendMessageConfig) => {\n // ensure all messages have an ID\n const newMessagesWithId = newMessages.map((m) =>\n m.id ? m : { ...m, id: uuidv4() },\n );\n\n const accumulator = new LangGraphMessageAccumulator({\n initialMessages: messages,\n appendMessage,\n });\n setMessages(accumulator.addMessages(newMessagesWithId));\n\n const abortController = new AbortController();\n abortControllerRef.current = abortController;\n const response = await stream(newMessagesWithId, {\n ...config,\n abortSignal: abortController.signal,\n initialize: async () => {\n return await api.threadListItem().initialize();\n },\n });\n\n for await (const chunk of response) {\n switch (chunk.event) {\n case LangGraphKnownEventTypes.MessagesPartial:\n case LangGraphKnownEventTypes.MessagesComplete:\n setMessages(accumulator.addMessages(chunk.data));\n break;\n case LangGraphKnownEventTypes.Updates:\n setInterrupt(chunk.data.__interrupt__?.[0]);\n break;\n case LangGraphKnownEventTypes.Messages: {\n const [messageChunk] = (chunk as LangChainMessageTupleEvent).data;\n if (!isLangChainMessageChunk(messageChunk)) {\n console.warn(\n \"Received invalid message chunk format:\",\n messageChunk,\n );\n break;\n }\n const updatedMessages = accumulator.addMessages([\n messageChunk as unknown as TMessage,\n ]);\n setMessages(updatedMessages);\n break;\n }\n case LangGraphKnownEventTypes.Metadata:\n onMetadata?.(chunk.data);\n break;\n case LangGraphKnownEventTypes.Info:\n onInfo?.(chunk.data);\n break;\n case LangGraphKnownEventTypes.Error: {\n onError?.(chunk.data);\n // Update the last AI message with error status\n // Assumes last AI message is the one the error relates to\n const messages = accumulator.getMessages();\n const lastAiMessage = messages.findLast(\n (m): m is TMessage & { type: string; id: string } =>\n m != null && \"type\" in m && m.type === \"ai\" && m.id != null,\n );\n if (lastAiMessage) {\n const errorMessage = {\n ...lastAiMessage,\n status: {\n type: \"incomplete\" as const,\n reason: \"error\" as const,\n error: chunk.data,\n },\n };\n setMessages(accumulator.addMessages([errorMessage]));\n }\n break;\n }\n default:\n if (onCustomEvent) {\n onCustomEvent(chunk.event, chunk.data);\n } else {\n console.warn(\n \"Unhandled event received:\",\n chunk.event,\n chunk.data,\n );\n }\n break;\n }\n }\n },\n [\n messages,\n appendMessage,\n stream,\n onMetadata,\n onInfo,\n onError,\n onCustomEvent,\n ],\n );\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n }\n }, [abortControllerRef]);\n\n return {\n interrupt,\n messages,\n sendMessage,\n cancel,\n setInterrupt,\n setMessages,\n };\n};\n"],"mappings":"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","names":["messages"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LangChainMessage, OnCustomEventCallback, OnErrorEventCallback, OnInfoEventCallback, OnMetadataEventCallback } from "./types";
|
|
2
|
+
import { AssistantCloud } from "@assistant-ui/react";
|
|
2
3
|
import { LangGraphCommand, LangGraphInterruptState, LangGraphSendMessageConfig, LangGraphStreamCallback } from "./useLangGraphMessages";
|
|
3
4
|
import { AttachmentAdapter } from "@assistant-ui/react";
|
|
4
5
|
import { FeedbackAdapter } from "@assistant-ui/react";
|
|
@@ -6,30 +7,30 @@ import { SpeechSynthesisAdapter } from "@assistant-ui/react";
|
|
|
6
7
|
export declare const useLangGraphInterruptState: () => LangGraphInterruptState | undefined;
|
|
7
8
|
export declare const useLangGraphSend: () => (messages: LangChainMessage[], config: LangGraphSendMessageConfig) => Promise<void>;
|
|
8
9
|
export declare const useLangGraphSendCommand: () => (command: LangGraphCommand) => Promise<void>;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.
|
|
12
|
-
*/
|
|
13
|
-
threadId?: string | undefined;
|
|
10
|
+
type UseLangGraphRuntimeOptions = {
|
|
14
11
|
autoCancelPendingToolCalls?: boolean | undefined;
|
|
15
12
|
unstable_allowCancellation?: boolean | undefined;
|
|
16
13
|
stream: LangGraphStreamCallback<LangChainMessage>;
|
|
17
14
|
/**
|
|
18
|
-
* @deprecated
|
|
15
|
+
* @deprecated This method has been renamed to `load`. Use `load` instead.
|
|
19
16
|
*/
|
|
20
|
-
onSwitchToNewThread?: () => Promise<void> | void;
|
|
21
17
|
onSwitchToThread?: (threadId: string) => Promise<{
|
|
22
18
|
messages: LangChainMessage[];
|
|
23
19
|
interrupts?: LangGraphInterruptState[];
|
|
24
20
|
}>;
|
|
21
|
+
load?: (threadId: string) => Promise<{
|
|
22
|
+
messages: LangChainMessage[];
|
|
23
|
+
interrupts?: LangGraphInterruptState[];
|
|
24
|
+
}>;
|
|
25
|
+
create?: () => Promise<{
|
|
26
|
+
externalId: string;
|
|
27
|
+
}>;
|
|
28
|
+
delete?: (threadId: string) => Promise<void>;
|
|
25
29
|
adapters?: {
|
|
26
30
|
attachments?: AttachmentAdapter;
|
|
27
31
|
speech?: SpeechSynthesisAdapter;
|
|
28
32
|
feedback?: FeedbackAdapter;
|
|
29
33
|
} | undefined;
|
|
30
|
-
/**
|
|
31
|
-
* Event handlers for various LangGraph stream events
|
|
32
|
-
*/
|
|
33
34
|
eventHandlers?: {
|
|
34
35
|
/**
|
|
35
36
|
* Called when metadata is received from the LangGraph stream
|
|
@@ -48,5 +49,8 @@ export declare const useLangGraphRuntime: ({ autoCancelPendingToolCalls, adapter
|
|
|
48
49
|
*/
|
|
49
50
|
onCustomEvent?: OnCustomEventCallback;
|
|
50
51
|
} | undefined;
|
|
51
|
-
|
|
52
|
+
cloud?: AssistantCloud | undefined;
|
|
53
|
+
};
|
|
54
|
+
export declare const useLangGraphRuntime: ({ cloud, create, delete: deleteFn, ...options }: UseLangGraphRuntimeOptions) => import("@assistant-ui/react").AssistantRuntime;
|
|
55
|
+
export {};
|
|
52
56
|
//# sourceMappingURL=useLangGraphRuntime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLangGraphRuntime.d.ts","sourceRoot":"","sources":["../src/useLangGraphRuntime.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"useLangGraphRuntime.d.ts","sourceRoot":"","sources":["../src/useLangGraphRuntime.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,cAAc,EAOf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,0BAA0B,EAC1B,uBAAuB,EAExB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA0E7D,eAAO,MAAM,0BAA0B,2CAOtC,CAAC;AAEF,eAAO,MAAM,gBAAgB,SAGnB,UAAU,gBAAgB,EAAE,EAAE,QAAQ,0BAA0B,kBAKzE,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAE1B,SAAS,gBAAgB,kBAClC,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,0BAA0B,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjD,MAAM,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,CAAC;IAClD;;OAEG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QAC/C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;KACxC,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;QACnC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;KACxC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,EACL;QACE,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,MAAM,CAAC,EAAE,sBAAsB,CAAC;QAChC,QAAQ,CAAC,EAAE,eAAe,CAAC;KAC5B,GACD,SAAS,CAAC;IACd,aAAa,CAAC,EACV;QACE;;WAEG;QACH,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC;;WAEG;QACH,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B;;WAEG;QACH,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAC/B;;WAEG;QACH,aAAa,CAAC,EAAE,qBAAqB,CAAC;KACvC,GACD,SAAS,CAAC;IACd,KAAK,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;CACpC,CAAC;AA4IF,eAAO,MAAM,mBAAmB,GAAI,iDAKjC,0BAA0B,mDAyB5B,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/useLangGraphRuntime.ts
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
import {
|
|
4
|
+
unstable_useCloudThreadListAdapter,
|
|
5
|
+
unstable_useRemoteThreadListRuntime,
|
|
4
6
|
useAssistantApi,
|
|
5
7
|
useAssistantState,
|
|
6
8
|
useExternalMessageConverter,
|
|
@@ -79,14 +81,13 @@ var useLangGraphSendCommand = () => {
|
|
|
79
81
|
const send = useLangGraphSend();
|
|
80
82
|
return (command) => send([], { command });
|
|
81
83
|
};
|
|
82
|
-
var
|
|
84
|
+
var useLangGraphRuntimeImpl = ({
|
|
83
85
|
autoCancelPendingToolCalls,
|
|
84
86
|
adapters: { attachments, feedback, speech } = {},
|
|
85
87
|
unstable_allowCancellation,
|
|
86
88
|
stream,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
onSwitchToThread,
|
|
89
|
+
onSwitchToThread: _onSwitchToThread,
|
|
90
|
+
load = _onSwitchToThread,
|
|
90
91
|
eventHandlers
|
|
91
92
|
}) => {
|
|
92
93
|
const {
|
|
@@ -117,27 +118,18 @@ var useLangGraphRuntime = ({
|
|
|
117
118
|
messages,
|
|
118
119
|
isRunning
|
|
119
120
|
});
|
|
120
|
-
const
|
|
121
|
-
const { messages: messages2, interrupts } = await
|
|
121
|
+
const loadThread = !load ? void 0 : async (externalId) => {
|
|
122
|
+
const { messages: messages2, interrupts } = await load(externalId);
|
|
122
123
|
setMessages(messages2);
|
|
123
124
|
setInterrupt(interrupts?.[0]);
|
|
124
125
|
};
|
|
125
|
-
const threadList = {
|
|
126
|
-
threadId,
|
|
127
|
-
onSwitchToNewThread: !onSwitchToNewThread ? void 0 : async () => {
|
|
128
|
-
await onSwitchToNewThread();
|
|
129
|
-
setMessages([]);
|
|
130
|
-
setInterrupt(void 0);
|
|
131
|
-
},
|
|
132
|
-
onSwitchToThread: switchToThread
|
|
133
|
-
};
|
|
134
126
|
const loadingRef = useRef(false);
|
|
135
127
|
useEffect(() => {
|
|
136
|
-
if (!
|
|
128
|
+
if (!loadThread || loadingRef.current) return;
|
|
137
129
|
const externalId = runtime.threads.mainItem.getState().externalId;
|
|
138
130
|
if (externalId) {
|
|
139
131
|
loadingRef.current = true;
|
|
140
|
-
|
|
132
|
+
loadThread(externalId).finally(() => {
|
|
141
133
|
loadingRef.current = false;
|
|
142
134
|
});
|
|
143
135
|
}
|
|
@@ -148,8 +140,7 @@ var useLangGraphRuntime = ({
|
|
|
148
140
|
adapters: {
|
|
149
141
|
attachments,
|
|
150
142
|
feedback,
|
|
151
|
-
speech
|
|
152
|
-
threadList
|
|
143
|
+
speech
|
|
153
144
|
},
|
|
154
145
|
extras: {
|
|
155
146
|
[symbolLangGraphRuntimeExtras]: true,
|
|
@@ -207,6 +198,35 @@ var useLangGraphRuntime = ({
|
|
|
207
198
|
});
|
|
208
199
|
return runtime;
|
|
209
200
|
};
|
|
201
|
+
var useLangGraphRuntime = ({
|
|
202
|
+
cloud,
|
|
203
|
+
create,
|
|
204
|
+
delete: deleteFn,
|
|
205
|
+
...options
|
|
206
|
+
}) => {
|
|
207
|
+
const api = useAssistantApi();
|
|
208
|
+
const cloudAdapter = unstable_useCloudThreadListAdapter({
|
|
209
|
+
cloud,
|
|
210
|
+
create: async () => {
|
|
211
|
+
if (create) {
|
|
212
|
+
return create();
|
|
213
|
+
}
|
|
214
|
+
if (api.threadListItem.source) {
|
|
215
|
+
return api.threadListItem().initialize();
|
|
216
|
+
}
|
|
217
|
+
throw new Error(
|
|
218
|
+
"initialize function requires you to pass a create function to the useLangGraphRuntime hook"
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
delete: deleteFn
|
|
222
|
+
});
|
|
223
|
+
return unstable_useRemoteThreadListRuntime({
|
|
224
|
+
runtimeHook: function RuntimeHook() {
|
|
225
|
+
return useLangGraphRuntimeImpl(options);
|
|
226
|
+
},
|
|
227
|
+
adapter: cloudAdapter
|
|
228
|
+
});
|
|
229
|
+
};
|
|
210
230
|
export {
|
|
211
231
|
useLangGraphInterruptState,
|
|
212
232
|
useLangGraphRuntime,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useLangGraphRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n LangChainMessage,\n LangChainToolCall,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\nimport {\n useAssistantApi,\n useAssistantState,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangChainMessages } from \"./convertLangChainMessages\";\nimport {\n LangGraphCommand,\n LangGraphInterruptState,\n LangGraphSendMessageConfig,\n LangGraphStreamCallback,\n useLangGraphMessages,\n} from \"./useLangGraphMessages\";\nimport { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { AppendMessage } from \"@assistant-ui/react\";\nimport { ExternalStoreAdapter } from \"@assistant-ui/react\";\nimport { FeedbackAdapter } from \"@assistant-ui/react\";\nimport { SpeechSynthesisAdapter } from \"@assistant-ui/react\";\nimport { appendLangChainChunk } from \"./appendLangChainChunk\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nconst getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default:\n const _exhaustiveCheck: \"reasoning\" | \"source\" | \"file\" | \"audio\" =\n type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\nconst symbolLangGraphRuntimeExtras = Symbol(\"langgraph-runtime-extras\");\ntype LangGraphRuntimeExtras = {\n [symbolLangGraphRuntimeExtras]: true;\n send: (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => Promise<void>;\n interrupt: LangGraphInterruptState | undefined;\n};\n\nconst asLangGraphRuntimeExtras = (extras: unknown): LangGraphRuntimeExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolLangGraphRuntimeExtras in extras)\n )\n throw new Error(\n \"This method can only be called when you are using useLangGraphRuntime\",\n );\n\n return extras as LangGraphRuntimeExtras;\n};\n\nexport const useLangGraphInterruptState = () => {\n const interrupt = useAssistantState(({ thread }) => {\n const extras = thread.extras;\n if (!extras) return undefined;\n return asLangGraphRuntimeExtras(extras).interrupt;\n });\n return interrupt;\n};\n\nexport const useLangGraphSend = () => {\n const api = useAssistantApi();\n\n return (messages: LangChainMessage[], config: LangGraphSendMessageConfig) => {\n const extras = api.thread().getState().extras;\n const { send } = asLangGraphRuntimeExtras(extras);\n return send(messages, config);\n };\n};\n\nexport const useLangGraphSendCommand = () => {\n const send = useLangGraphSend();\n return (command: LangGraphCommand) => send([], { command });\n};\n\nexport const useLangGraphRuntime = ({\n autoCancelPendingToolCalls,\n adapters: { attachments, feedback, speech } = {},\n unstable_allowCancellation,\n stream,\n threadId,\n onSwitchToNewThread,\n onSwitchToThread,\n eventHandlers,\n}: {\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n threadId?: string | undefined;\n autoCancelPendingToolCalls?: boolean | undefined;\n unstable_allowCancellation?: boolean | undefined;\n stream: LangGraphStreamCallback<LangChainMessage>;\n /**\n * @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.\n */\n onSwitchToNewThread?: () => Promise<void> | void;\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: LangChainMessage[];\n interrupts?: LangGraphInterruptState[];\n }>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n /**\n * Event handlers for various LangGraph stream events\n */\n eventHandlers?:\n | {\n /**\n * Called when metadata is received from the LangGraph stream\n */\n onMetadata?: OnMetadataEventCallback;\n /**\n * Called when informational messages are received from the LangGraph stream\n */\n onInfo?: OnInfoEventCallback;\n /**\n * Called when errors occur during LangGraph stream processing\n */\n onError?: OnErrorEventCallback;\n /**\n * Called when custom events are received from the LangGraph stream\n */\n onCustomEvent?: OnCustomEventCallback;\n }\n | undefined;\n}) => {\n const {\n interrupt,\n setInterrupt,\n messages,\n sendMessage,\n cancel,\n setMessages,\n } = useLangGraphMessages({\n appendMessage: appendLangChainChunk,\n stream,\n ...(eventHandlers && { eventHandlers }),\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(messages, config);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangChainMessages,\n messages,\n isRunning,\n });\n\n const switchToThread = !onSwitchToThread\n ? undefined\n : async (externalId: string) => {\n const { messages, interrupts } = await onSwitchToThread(externalId);\n setMessages(messages);\n setInterrupt(interrupts?.[0]);\n };\n\n const threadList: NonNullable<\n ExternalStoreAdapter[\"adapters\"]\n >[\"threadList\"] = {\n threadId,\n onSwitchToNewThread: !onSwitchToNewThread\n ? undefined\n : async () => {\n await onSwitchToNewThread();\n setMessages([]);\n setInterrupt(undefined);\n },\n onSwitchToThread: switchToThread,\n };\n\n const loadingRef = useRef(false);\n useEffect(() => {\n if (!switchToThread || loadingRef.current) return;\n\n const externalId = runtime.threads.mainItem.getState().externalId;\n if (externalId) {\n loadingRef.current = true;\n switchToThread(externalId).finally(() => {\n loadingRef.current = false;\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const runtime = useExternalStoreRuntime({\n isRunning,\n messages: threadMessages,\n adapters: {\n attachments,\n feedback,\n speech,\n threadList,\n },\n extras: {\n [symbolLangGraphRuntimeExtras]: true,\n interrupt,\n send: handleSendMessage,\n } satisfies LangGraphRuntimeExtras,\n onNew: (msg) => {\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies LangChainMessage & { type: \"tool\" },\n )\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n {\n runConfig: msg.runConfig,\n },\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n // TODO parallel human in the loop calls\n await handleSendMessage(\n [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n // TODO reuse runconfig here!\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n\n return runtime;\n};\n"],"mappings":"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","names":["messages"]}
|
|
1
|
+
{"version":3,"sources":["../src/useLangGraphRuntime.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n LangChainMessage,\n LangChainToolCall,\n OnCustomEventCallback,\n OnErrorEventCallback,\n OnInfoEventCallback,\n OnMetadataEventCallback,\n} from \"./types\";\nimport {\n AssistantCloud,\n unstable_useCloudThreadListAdapter,\n unstable_useRemoteThreadListRuntime,\n useAssistantApi,\n useAssistantState,\n useExternalMessageConverter,\n useExternalStoreRuntime,\n} from \"@assistant-ui/react\";\nimport { convertLangChainMessages } from \"./convertLangChainMessages\";\nimport {\n LangGraphCommand,\n LangGraphInterruptState,\n LangGraphSendMessageConfig,\n LangGraphStreamCallback,\n useLangGraphMessages,\n} from \"./useLangGraphMessages\";\nimport { AttachmentAdapter } from \"@assistant-ui/react\";\nimport { AppendMessage } from \"@assistant-ui/react\";\nimport { FeedbackAdapter } from \"@assistant-ui/react\";\nimport { SpeechSynthesisAdapter } from \"@assistant-ui/react\";\nimport { appendLangChainChunk } from \"./appendLangChainChunk\";\n\nconst getPendingToolCalls = (messages: LangChainMessage[]) => {\n const pendingToolCalls = new Map<string, LangChainToolCall>();\n for (const message of messages) {\n if (message.type === \"ai\") {\n for (const toolCall of message.tool_calls ?? []) {\n pendingToolCalls.set(toolCall.id, toolCall);\n }\n }\n if (message.type === \"tool\") {\n pendingToolCalls.delete(message.tool_call_id);\n }\n }\n\n return [...pendingToolCalls.values()];\n};\n\nconst getMessageContent = (msg: AppendMessage) => {\n const allContent = [\n ...msg.content,\n ...(msg.attachments?.flatMap((a) => a.content) ?? []),\n ];\n const content = allContent.map((part) => {\n const type = part.type;\n switch (type) {\n case \"text\":\n return { type: \"text\" as const, text: part.text };\n case \"image\":\n return { type: \"image_url\" as const, image_url: { url: part.image } };\n\n case \"tool-call\":\n throw new Error(\"Tool call appends are not supported.\");\n\n default:\n const _exhaustiveCheck: \"reasoning\" | \"source\" | \"file\" | \"audio\" =\n type;\n throw new Error(\n `Unsupported append message part type: ${_exhaustiveCheck}`,\n );\n }\n });\n\n if (content.length === 1 && content[0]?.type === \"text\") {\n return content[0].text ?? \"\";\n }\n\n return content;\n};\n\nconst symbolLangGraphRuntimeExtras = Symbol(\"langgraph-runtime-extras\");\ntype LangGraphRuntimeExtras = {\n [symbolLangGraphRuntimeExtras]: true;\n send: (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => Promise<void>;\n interrupt: LangGraphInterruptState | undefined;\n};\n\nconst asLangGraphRuntimeExtras = (extras: unknown): LangGraphRuntimeExtras => {\n if (\n typeof extras !== \"object\" ||\n extras == null ||\n !(symbolLangGraphRuntimeExtras in extras)\n )\n throw new Error(\n \"This method can only be called when you are using useLangGraphRuntime\",\n );\n\n return extras as LangGraphRuntimeExtras;\n};\n\nexport const useLangGraphInterruptState = () => {\n const interrupt = useAssistantState(({ thread }) => {\n const extras = thread.extras;\n if (!extras) return undefined;\n return asLangGraphRuntimeExtras(extras).interrupt;\n });\n return interrupt;\n};\n\nexport const useLangGraphSend = () => {\n const api = useAssistantApi();\n\n return (messages: LangChainMessage[], config: LangGraphSendMessageConfig) => {\n const extras = api.thread().getState().extras;\n const { send } = asLangGraphRuntimeExtras(extras);\n return send(messages, config);\n };\n};\n\nexport const useLangGraphSendCommand = () => {\n const send = useLangGraphSend();\n return (command: LangGraphCommand) => send([], { command });\n};\n\ntype UseLangGraphRuntimeOptions = {\n autoCancelPendingToolCalls?: boolean | undefined;\n unstable_allowCancellation?: boolean | undefined;\n stream: LangGraphStreamCallback<LangChainMessage>;\n /**\n * @deprecated This method has been renamed to `load`. Use `load` instead.\n */\n onSwitchToThread?: (threadId: string) => Promise<{\n messages: LangChainMessage[];\n interrupts?: LangGraphInterruptState[];\n }>;\n load?: (threadId: string) => Promise<{\n messages: LangChainMessage[];\n interrupts?: LangGraphInterruptState[];\n }>;\n create?: () => Promise<{\n externalId: string;\n }>;\n delete?: (threadId: string) => Promise<void>;\n adapters?:\n | {\n attachments?: AttachmentAdapter;\n speech?: SpeechSynthesisAdapter;\n feedback?: FeedbackAdapter;\n }\n | undefined;\n eventHandlers?:\n | {\n /**\n * Called when metadata is received from the LangGraph stream\n */\n onMetadata?: OnMetadataEventCallback;\n /**\n * Called when informational messages are received from the LangGraph stream\n */\n onInfo?: OnInfoEventCallback;\n /**\n * Called when errors occur during LangGraph stream processing\n */\n onError?: OnErrorEventCallback;\n /**\n * Called when custom events are received from the LangGraph stream\n */\n onCustomEvent?: OnCustomEventCallback;\n }\n | undefined;\n cloud?: AssistantCloud | undefined;\n};\n\nconst useLangGraphRuntimeImpl = ({\n autoCancelPendingToolCalls,\n adapters: { attachments, feedback, speech } = {},\n unstable_allowCancellation,\n stream,\n onSwitchToThread: _onSwitchToThread,\n load = _onSwitchToThread,\n eventHandlers,\n}: UseLangGraphRuntimeOptions) => {\n const {\n interrupt,\n setInterrupt,\n messages,\n sendMessage,\n cancel,\n setMessages,\n } = useLangGraphMessages({\n appendMessage: appendLangChainChunk,\n stream,\n ...(eventHandlers && { eventHandlers }),\n });\n\n const [isRunning, setIsRunning] = useState(false);\n const handleSendMessage = async (\n messages: LangChainMessage[],\n config: LangGraphSendMessageConfig,\n ) => {\n try {\n setIsRunning(true);\n await sendMessage(messages, config);\n } catch (error) {\n console.error(\"Error streaming messages:\", error);\n } finally {\n setIsRunning(false);\n }\n };\n\n const threadMessages = useExternalMessageConverter({\n callback: convertLangChainMessages,\n messages,\n isRunning,\n });\n\n const loadThread = !load\n ? undefined\n : async (externalId: string) => {\n const { messages, interrupts } = await load(externalId);\n setMessages(messages);\n setInterrupt(interrupts?.[0]);\n };\n\n const loadingRef = useRef(false);\n useEffect(() => {\n if (!loadThread || loadingRef.current) return;\n\n const externalId = runtime.threads.mainItem.getState().externalId;\n if (externalId) {\n loadingRef.current = true;\n loadThread(externalId).finally(() => {\n loadingRef.current = false;\n });\n }\n }, []);\n\n const runtime = useExternalStoreRuntime({\n isRunning,\n messages: threadMessages,\n adapters: {\n attachments,\n feedback,\n speech,\n },\n extras: {\n [symbolLangGraphRuntimeExtras]: true,\n interrupt,\n send: handleSendMessage,\n } satisfies LangGraphRuntimeExtras,\n onNew: (msg) => {\n const cancellations =\n autoCancelPendingToolCalls !== false\n ? getPendingToolCalls(messages).map(\n (t) =>\n ({\n type: \"tool\",\n name: t.name,\n tool_call_id: t.id,\n content: JSON.stringify({ cancelled: true }),\n status: \"error\",\n }) satisfies LangChainMessage & { type: \"tool\" },\n )\n : [];\n\n return handleSendMessage(\n [\n ...cancellations,\n {\n type: \"human\",\n content: getMessageContent(msg),\n },\n ],\n {\n runConfig: msg.runConfig,\n },\n );\n },\n onAddToolResult: async ({\n toolCallId,\n toolName,\n result,\n isError,\n artifact,\n }) => {\n // TODO parallel human in the loop calls\n await handleSendMessage(\n [\n {\n type: \"tool\",\n name: toolName,\n tool_call_id: toolCallId,\n content: JSON.stringify(result),\n artifact,\n status: isError ? \"error\" : \"success\",\n },\n ],\n // TODO reuse runconfig here!\n {},\n );\n },\n onCancel: unstable_allowCancellation\n ? async () => {\n cancel();\n }\n : undefined,\n });\n\n return runtime;\n};\n\nexport const useLangGraphRuntime = ({\n cloud,\n create,\n delete: deleteFn,\n ...options\n}: UseLangGraphRuntimeOptions) => {\n const api = useAssistantApi();\n const cloudAdapter = unstable_useCloudThreadListAdapter({\n cloud,\n create: async () => {\n if (create) {\n return create();\n }\n\n if (api.threadListItem.source) {\n return api.threadListItem().initialize();\n }\n\n throw new Error(\n \"initialize function requires you to pass a create function to the useLangGraphRuntime hook\",\n );\n },\n delete: deleteFn,\n });\n return unstable_useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useLangGraphRuntimeImpl(options);\n },\n adapter: cloudAdapter,\n });\n};\n"],"mappings":"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","names":["messages"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-langgraph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
],
|
|
19
19
|
"sideEffects": false,
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"assistant-stream": "^0.2.
|
|
21
|
+
"assistant-stream": "^0.2.34",
|
|
22
22
|
"uuid": "^13.0.0",
|
|
23
23
|
"zod": "^4.1.11"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@assistant-ui/react": "^0.11.
|
|
26
|
+
"@assistant-ui/react": "^0.11.27",
|
|
27
27
|
"@types/react": "*",
|
|
28
28
|
"react": "^18 || ^19 || ^19.0.0-rc"
|
|
29
29
|
},
|
|
@@ -35,16 +35,16 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@testing-library/dom": "^10.4.1",
|
|
37
37
|
"@testing-library/react": "^16.3.0",
|
|
38
|
-
"@types/node": "^24.
|
|
39
|
-
"@types/react": "^19.
|
|
38
|
+
"@types/node": "^24.6.2",
|
|
39
|
+
"@types/react": "^19.2.0",
|
|
40
40
|
"@types/uuid": "^11.0.0",
|
|
41
41
|
"eslint": "^9",
|
|
42
42
|
"eslint-config-next": "15.5.4",
|
|
43
43
|
"jsdom": "^27.0.0",
|
|
44
|
-
"react": "19.
|
|
44
|
+
"react": "19.2.0",
|
|
45
45
|
"tsx": "^4.20.6",
|
|
46
46
|
"vitest": "^3.2.4",
|
|
47
|
-
"@assistant-ui/react": "0.11.
|
|
47
|
+
"@assistant-ui/react": "0.11.27",
|
|
48
48
|
"@assistant-ui/x-buildutils": "0.0.1"
|
|
49
49
|
},
|
|
50
50
|
"publishConfig": {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
OnInfoEventCallback,
|
|
12
12
|
OnMetadataEventCallback,
|
|
13
13
|
} from "./types";
|
|
14
|
+
import { useAssistantApi } from "@assistant-ui/react";
|
|
14
15
|
|
|
15
16
|
export type LangGraphCommand = {
|
|
16
17
|
resume: string;
|
|
@@ -28,7 +29,13 @@ export type LangGraphMessagesEvent<TMessage> = {
|
|
|
28
29
|
|
|
29
30
|
export type LangGraphStreamCallback<TMessage> = (
|
|
30
31
|
messages: TMessage[],
|
|
31
|
-
config: LangGraphSendMessageConfig & {
|
|
32
|
+
config: LangGraphSendMessageConfig & {
|
|
33
|
+
abortSignal: AbortSignal;
|
|
34
|
+
initialize: () => Promise<{
|
|
35
|
+
remoteId: string;
|
|
36
|
+
externalId: string | undefined;
|
|
37
|
+
}>;
|
|
38
|
+
},
|
|
32
39
|
) =>
|
|
33
40
|
| Promise<AsyncGenerator<LangGraphMessagesEvent<TMessage>>>
|
|
34
41
|
| AsyncGenerator<LangGraphMessagesEvent<TMessage>>;
|
|
@@ -86,6 +93,7 @@ export const useLangGraphMessages = <TMessage extends { id?: string }>({
|
|
|
86
93
|
[eventHandlers],
|
|
87
94
|
);
|
|
88
95
|
|
|
96
|
+
const api = useAssistantApi();
|
|
89
97
|
const sendMessage = useCallback(
|
|
90
98
|
async (newMessages: TMessage[], config: LangGraphSendMessageConfig) => {
|
|
91
99
|
// ensure all messages have an ID
|
|
@@ -104,6 +112,9 @@ export const useLangGraphMessages = <TMessage extends { id?: string }>({
|
|
|
104
112
|
const response = await stream(newMessagesWithId, {
|
|
105
113
|
...config,
|
|
106
114
|
abortSignal: abortController.signal,
|
|
115
|
+
initialize: async () => {
|
|
116
|
+
return await api.threadListItem().initialize();
|
|
117
|
+
},
|
|
107
118
|
});
|
|
108
119
|
|
|
109
120
|
for await (const chunk of response) {
|
|
@@ -73,6 +73,9 @@ describe("useLangGraphRuntime", () => {
|
|
|
73
73
|
wrapper,
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
// Wait a tick for the runtime to be fully mounted
|
|
77
|
+
await Promise.resolve();
|
|
78
|
+
|
|
76
79
|
act(() => {
|
|
77
80
|
sendResult.current(
|
|
78
81
|
[
|
|
@@ -109,16 +112,17 @@ describe("useLangGraphRuntime", () => {
|
|
|
109
112
|
{},
|
|
110
113
|
);
|
|
111
114
|
|
|
112
|
-
const wrapper = (
|
|
113
|
-
<AssistantRuntimeProvider runtime={runtimeResult.current}>
|
|
114
|
-
{children}
|
|
115
|
-
</AssistantRuntimeProvider>
|
|
116
|
-
);
|
|
115
|
+
const wrapper = wrapperFactory(runtimeResult.current);
|
|
117
116
|
|
|
118
117
|
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
119
118
|
wrapper,
|
|
120
119
|
});
|
|
121
120
|
|
|
121
|
+
// Wait a tick for the runtime to be fully mounted
|
|
122
|
+
await waitFor(() => {
|
|
123
|
+
expect(sendResult.current).toBeDefined();
|
|
124
|
+
});
|
|
125
|
+
|
|
122
126
|
act(() => {
|
|
123
127
|
sendResult.current(
|
|
124
128
|
[
|
|
@@ -155,16 +159,17 @@ describe("useLangGraphRuntime", () => {
|
|
|
155
159
|
{},
|
|
156
160
|
);
|
|
157
161
|
|
|
158
|
-
const wrapper = (
|
|
159
|
-
<AssistantRuntimeProvider runtime={runtimeResult.current}>
|
|
160
|
-
{children}
|
|
161
|
-
</AssistantRuntimeProvider>
|
|
162
|
-
);
|
|
162
|
+
const wrapper = wrapperFactory(runtimeResult.current);
|
|
163
163
|
|
|
164
164
|
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
165
165
|
wrapper,
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
// Wait a tick for the runtime to be fully mounted
|
|
169
|
+
await waitFor(() => {
|
|
170
|
+
expect(sendResult.current).toBeDefined();
|
|
171
|
+
});
|
|
172
|
+
|
|
168
173
|
act(() => {
|
|
169
174
|
sendResult.current(
|
|
170
175
|
[
|
|
@@ -207,6 +212,11 @@ describe("useLangGraphRuntime", () => {
|
|
|
207
212
|
wrapper,
|
|
208
213
|
});
|
|
209
214
|
|
|
215
|
+
// Wait a tick for the runtime to be fully mounted
|
|
216
|
+
await waitFor(() => {
|
|
217
|
+
expect(sendResult.current).toBeDefined();
|
|
218
|
+
});
|
|
219
|
+
|
|
210
220
|
act(() => {
|
|
211
221
|
sendResult.current(
|
|
212
222
|
[
|
|
@@ -255,6 +265,11 @@ describe("useLangGraphRuntime", () => {
|
|
|
255
265
|
wrapper,
|
|
256
266
|
});
|
|
257
267
|
|
|
268
|
+
// Wait a tick for the runtime to be fully mounted
|
|
269
|
+
await waitFor(() => {
|
|
270
|
+
expect(sendResult.current).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
258
273
|
act(() => {
|
|
259
274
|
sendResult.current(
|
|
260
275
|
[
|
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
OnMetadataEventCallback,
|
|
9
9
|
} from "./types";
|
|
10
10
|
import {
|
|
11
|
+
AssistantCloud,
|
|
12
|
+
unstable_useCloudThreadListAdapter,
|
|
13
|
+
unstable_useRemoteThreadListRuntime,
|
|
11
14
|
useAssistantApi,
|
|
12
15
|
useAssistantState,
|
|
13
16
|
useExternalMessageConverter,
|
|
@@ -23,7 +26,6 @@ import {
|
|
|
23
26
|
} from "./useLangGraphMessages";
|
|
24
27
|
import { AttachmentAdapter } from "@assistant-ui/react";
|
|
25
28
|
import { AppendMessage } from "@assistant-ui/react";
|
|
26
|
-
import { ExternalStoreAdapter } from "@assistant-ui/react";
|
|
27
29
|
import { FeedbackAdapter } from "@assistant-ui/react";
|
|
28
30
|
import { SpeechSynthesisAdapter } from "@assistant-ui/react";
|
|
29
31
|
import { appendLangChainChunk } from "./appendLangChainChunk";
|
|
@@ -123,31 +125,25 @@ export const useLangGraphSendCommand = () => {
|
|
|
123
125
|
return (command: LangGraphCommand) => send([], { command });
|
|
124
126
|
};
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
autoCancelPendingToolCalls,
|
|
128
|
-
adapters: { attachments, feedback, speech } = {},
|
|
129
|
-
unstable_allowCancellation,
|
|
130
|
-
stream,
|
|
131
|
-
threadId,
|
|
132
|
-
onSwitchToNewThread,
|
|
133
|
-
onSwitchToThread,
|
|
134
|
-
eventHandlers,
|
|
135
|
-
}: {
|
|
136
|
-
/**
|
|
137
|
-
* @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.
|
|
138
|
-
*/
|
|
139
|
-
threadId?: string | undefined;
|
|
128
|
+
type UseLangGraphRuntimeOptions = {
|
|
140
129
|
autoCancelPendingToolCalls?: boolean | undefined;
|
|
141
130
|
unstable_allowCancellation?: boolean | undefined;
|
|
142
131
|
stream: LangGraphStreamCallback<LangChainMessage>;
|
|
143
132
|
/**
|
|
144
|
-
* @deprecated
|
|
133
|
+
* @deprecated This method has been renamed to `load`. Use `load` instead.
|
|
145
134
|
*/
|
|
146
|
-
onSwitchToNewThread?: () => Promise<void> | void;
|
|
147
135
|
onSwitchToThread?: (threadId: string) => Promise<{
|
|
148
136
|
messages: LangChainMessage[];
|
|
149
137
|
interrupts?: LangGraphInterruptState[];
|
|
150
138
|
}>;
|
|
139
|
+
load?: (threadId: string) => Promise<{
|
|
140
|
+
messages: LangChainMessage[];
|
|
141
|
+
interrupts?: LangGraphInterruptState[];
|
|
142
|
+
}>;
|
|
143
|
+
create?: () => Promise<{
|
|
144
|
+
externalId: string;
|
|
145
|
+
}>;
|
|
146
|
+
delete?: (threadId: string) => Promise<void>;
|
|
151
147
|
adapters?:
|
|
152
148
|
| {
|
|
153
149
|
attachments?: AttachmentAdapter;
|
|
@@ -155,9 +151,6 @@ export const useLangGraphRuntime = ({
|
|
|
155
151
|
feedback?: FeedbackAdapter;
|
|
156
152
|
}
|
|
157
153
|
| undefined;
|
|
158
|
-
/**
|
|
159
|
-
* Event handlers for various LangGraph stream events
|
|
160
|
-
*/
|
|
161
154
|
eventHandlers?:
|
|
162
155
|
| {
|
|
163
156
|
/**
|
|
@@ -178,7 +171,18 @@ export const useLangGraphRuntime = ({
|
|
|
178
171
|
onCustomEvent?: OnCustomEventCallback;
|
|
179
172
|
}
|
|
180
173
|
| undefined;
|
|
181
|
-
|
|
174
|
+
cloud?: AssistantCloud | undefined;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const useLangGraphRuntimeImpl = ({
|
|
178
|
+
autoCancelPendingToolCalls,
|
|
179
|
+
adapters: { attachments, feedback, speech } = {},
|
|
180
|
+
unstable_allowCancellation,
|
|
181
|
+
stream,
|
|
182
|
+
onSwitchToThread: _onSwitchToThread,
|
|
183
|
+
load = _onSwitchToThread,
|
|
184
|
+
eventHandlers,
|
|
185
|
+
}: UseLangGraphRuntimeOptions) => {
|
|
182
186
|
const {
|
|
183
187
|
interrupt,
|
|
184
188
|
setInterrupt,
|
|
@@ -213,40 +217,25 @@ export const useLangGraphRuntime = ({
|
|
|
213
217
|
isRunning,
|
|
214
218
|
});
|
|
215
219
|
|
|
216
|
-
const
|
|
220
|
+
const loadThread = !load
|
|
217
221
|
? undefined
|
|
218
222
|
: async (externalId: string) => {
|
|
219
|
-
const { messages, interrupts } = await
|
|
223
|
+
const { messages, interrupts } = await load(externalId);
|
|
220
224
|
setMessages(messages);
|
|
221
225
|
setInterrupt(interrupts?.[0]);
|
|
222
226
|
};
|
|
223
227
|
|
|
224
|
-
const threadList: NonNullable<
|
|
225
|
-
ExternalStoreAdapter["adapters"]
|
|
226
|
-
>["threadList"] = {
|
|
227
|
-
threadId,
|
|
228
|
-
onSwitchToNewThread: !onSwitchToNewThread
|
|
229
|
-
? undefined
|
|
230
|
-
: async () => {
|
|
231
|
-
await onSwitchToNewThread();
|
|
232
|
-
setMessages([]);
|
|
233
|
-
setInterrupt(undefined);
|
|
234
|
-
},
|
|
235
|
-
onSwitchToThread: switchToThread,
|
|
236
|
-
};
|
|
237
|
-
|
|
238
228
|
const loadingRef = useRef(false);
|
|
239
229
|
useEffect(() => {
|
|
240
|
-
if (!
|
|
230
|
+
if (!loadThread || loadingRef.current) return;
|
|
241
231
|
|
|
242
232
|
const externalId = runtime.threads.mainItem.getState().externalId;
|
|
243
233
|
if (externalId) {
|
|
244
234
|
loadingRef.current = true;
|
|
245
|
-
|
|
235
|
+
loadThread(externalId).finally(() => {
|
|
246
236
|
loadingRef.current = false;
|
|
247
237
|
});
|
|
248
238
|
}
|
|
249
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
250
239
|
}, []);
|
|
251
240
|
|
|
252
241
|
const runtime = useExternalStoreRuntime({
|
|
@@ -256,7 +245,6 @@ export const useLangGraphRuntime = ({
|
|
|
256
245
|
attachments,
|
|
257
246
|
feedback,
|
|
258
247
|
speech,
|
|
259
|
-
threadList,
|
|
260
248
|
},
|
|
261
249
|
extras: {
|
|
262
250
|
[symbolLangGraphRuntimeExtras]: true,
|
|
@@ -323,3 +311,35 @@ export const useLangGraphRuntime = ({
|
|
|
323
311
|
|
|
324
312
|
return runtime;
|
|
325
313
|
};
|
|
314
|
+
|
|
315
|
+
export const useLangGraphRuntime = ({
|
|
316
|
+
cloud,
|
|
317
|
+
create,
|
|
318
|
+
delete: deleteFn,
|
|
319
|
+
...options
|
|
320
|
+
}: UseLangGraphRuntimeOptions) => {
|
|
321
|
+
const api = useAssistantApi();
|
|
322
|
+
const cloudAdapter = unstable_useCloudThreadListAdapter({
|
|
323
|
+
cloud,
|
|
324
|
+
create: async () => {
|
|
325
|
+
if (create) {
|
|
326
|
+
return create();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (api.threadListItem.source) {
|
|
330
|
+
return api.threadListItem().initialize();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
throw new Error(
|
|
334
|
+
"initialize function requires you to pass a create function to the useLangGraphRuntime hook",
|
|
335
|
+
);
|
|
336
|
+
},
|
|
337
|
+
delete: deleteFn,
|
|
338
|
+
});
|
|
339
|
+
return unstable_useRemoteThreadListRuntime({
|
|
340
|
+
runtimeHook: function RuntimeHook() {
|
|
341
|
+
return useLangGraphRuntimeImpl(options);
|
|
342
|
+
},
|
|
343
|
+
adapter: cloudAdapter,
|
|
344
|
+
});
|
|
345
|
+
};
|