@assistant-ui/react-langgraph 0.5.5 → 0.5.7
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/LangGraphMessageAccumulator.d.ts +0 -4
- package/dist/LangGraphMessageAccumulator.d.ts.map +1 -1
- package/dist/LangGraphMessageAccumulator.js.map +1 -1
- package/dist/appendLangChainChunk.d.ts.map +1 -1
- package/dist/appendLangChainChunk.js +23 -10
- package/dist/appendLangChainChunk.js.map +1 -1
- package/dist/convertLangChainMessages.d.ts.map +1 -1
- package/dist/convertLangChainMessages.js +4 -0
- package/dist/convertLangChainMessages.js.map +1 -1
- package/dist/testUtils.d.ts +4 -0
- package/dist/testUtils.d.ts.map +1 -0
- package/dist/testUtils.js +10 -0
- package/dist/testUtils.js.map +1 -0
- package/dist/types.d.ts +29 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -1
- package/dist/useLangGraphMessages.d.ts +9 -2
- package/dist/useLangGraphMessages.d.ts.map +1 -1
- package/dist/useLangGraphMessages.js +72 -10
- package/dist/useLangGraphMessages.js.map +1 -1
- package/dist/useLangGraphRuntime.d.ts +23 -2
- package/dist/useLangGraphRuntime.d.ts.map +1 -1
- package/dist/useLangGraphRuntime.js +4 -2
- package/dist/useLangGraphRuntime.js.map +1 -1
- package/package.json +14 -8
- package/src/LangGraphMessageAccumulator.ts +0 -11
- package/src/appendLangChainChunk.ts +31 -11
- package/src/convertLangChainMessages.ts +4 -0
- package/src/testUtils.ts +11 -0
- package/src/types.ts +42 -8
- package/src/useLangGraphMessages.test.ts +611 -0
- package/src/useLangGraphMessages.ts +98 -19
- package/src/useLangGraphRuntime.test.tsx +276 -0
- package/src/useLangGraphRuntime.ts +33 -1
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from "react";
|
|
1
|
+
import { useState, useCallback, useRef, useMemo } from "react";
|
|
2
2
|
import { v4 as uuidv4 } from "uuid";
|
|
3
3
|
import { LangGraphMessageAccumulator } from "./LangGraphMessageAccumulator";
|
|
4
|
+
import {
|
|
5
|
+
EventType,
|
|
6
|
+
LangChainMessageTupleEvent,
|
|
7
|
+
LangGraphKnownEventTypes,
|
|
8
|
+
LangChainMessageChunk,
|
|
9
|
+
OnCustomEventCallback,
|
|
10
|
+
OnErrorEventCallback,
|
|
11
|
+
OnInfoEventCallback,
|
|
12
|
+
OnMetadataEventCallback,
|
|
13
|
+
} from "./types";
|
|
4
14
|
|
|
5
15
|
export type LangGraphCommand = {
|
|
6
16
|
resume: string;
|
|
@@ -12,15 +22,10 @@ export type LangGraphSendMessageConfig = {
|
|
|
12
22
|
};
|
|
13
23
|
|
|
14
24
|
export type LangGraphMessagesEvent<TMessage> = {
|
|
15
|
-
event:
|
|
16
|
-
| "messages"
|
|
17
|
-
| "messages/partial"
|
|
18
|
-
| "messages/complete"
|
|
19
|
-
| "metadata"
|
|
20
|
-
| "updates"
|
|
21
|
-
| string;
|
|
25
|
+
event: EventType;
|
|
22
26
|
data: TMessage[] | any;
|
|
23
27
|
};
|
|
28
|
+
|
|
24
29
|
export type LangGraphStreamCallback<TMessage> = (
|
|
25
30
|
messages: TMessage[],
|
|
26
31
|
config: LangGraphSendMessageConfig & { abortSignal: AbortSignal },
|
|
@@ -40,12 +45,35 @@ const DEFAULT_APPEND_MESSAGE = <TMessage>(
|
|
|
40
45
|
curr: TMessage,
|
|
41
46
|
) => curr;
|
|
42
47
|
|
|
48
|
+
const isLangChainMessageChunk = (
|
|
49
|
+
value: unknown,
|
|
50
|
+
): value is LangChainMessageChunk => {
|
|
51
|
+
if (!value || typeof value !== "object") return false;
|
|
52
|
+
const chunk = value as any;
|
|
53
|
+
return (
|
|
54
|
+
"type" in chunk &&
|
|
55
|
+
chunk.type === "AIMessageChunk" &&
|
|
56
|
+
(chunk.content === undefined ||
|
|
57
|
+
typeof chunk.content === "string" ||
|
|
58
|
+
Array.isArray(chunk.content)) &&
|
|
59
|
+
(chunk.tool_call_chunks === undefined ||
|
|
60
|
+
Array.isArray(chunk.tool_call_chunks))
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
43
64
|
export const useLangGraphMessages = <TMessage extends { id?: string }>({
|
|
44
65
|
stream,
|
|
45
66
|
appendMessage = DEFAULT_APPEND_MESSAGE,
|
|
67
|
+
eventHandlers,
|
|
46
68
|
}: {
|
|
47
69
|
stream: LangGraphStreamCallback<TMessage>;
|
|
48
70
|
appendMessage?: (prev: TMessage | undefined, curr: TMessage) => TMessage;
|
|
71
|
+
eventHandlers?: {
|
|
72
|
+
onMetadata?: OnMetadataEventCallback;
|
|
73
|
+
onInfo?: OnInfoEventCallback;
|
|
74
|
+
onError?: OnErrorEventCallback;
|
|
75
|
+
onCustomEvent?: OnCustomEventCallback;
|
|
76
|
+
};
|
|
49
77
|
}) => {
|
|
50
78
|
const [interrupt, setInterrupt] = useState<
|
|
51
79
|
LangGraphInterruptState | undefined
|
|
@@ -53,36 +81,87 @@ export const useLangGraphMessages = <TMessage extends { id?: string }>({
|
|
|
53
81
|
const [messages, setMessages] = useState<TMessage[]>([]);
|
|
54
82
|
const abortControllerRef = useRef<AbortController | null>(null);
|
|
55
83
|
|
|
84
|
+
const { onMetadata, onInfo, onError, onCustomEvent } = useMemo(
|
|
85
|
+
() => eventHandlers ?? {},
|
|
86
|
+
[eventHandlers],
|
|
87
|
+
);
|
|
88
|
+
|
|
56
89
|
const sendMessage = useCallback(
|
|
57
90
|
async (newMessages: TMessage[], config: LangGraphSendMessageConfig) => {
|
|
58
91
|
// ensure all messages have an ID
|
|
59
|
-
|
|
92
|
+
const newMessagesWithId = newMessages.map((m) =>
|
|
93
|
+
m.id ? m : { ...m, id: uuidv4() },
|
|
94
|
+
);
|
|
60
95
|
|
|
61
96
|
const accumulator = new LangGraphMessageAccumulator({
|
|
62
97
|
initialMessages: messages,
|
|
63
98
|
appendMessage,
|
|
64
99
|
});
|
|
65
|
-
setMessages(accumulator.addMessages(
|
|
100
|
+
setMessages(accumulator.addMessages(newMessagesWithId));
|
|
66
101
|
|
|
67
102
|
const abortController = new AbortController();
|
|
68
103
|
abortControllerRef.current = abortController;
|
|
69
|
-
const response = await stream(
|
|
104
|
+
const response = await stream(newMessagesWithId, {
|
|
70
105
|
...config,
|
|
71
106
|
abortSignal: abortController.signal,
|
|
72
107
|
});
|
|
73
108
|
|
|
74
109
|
for await (const chunk of response) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
110
|
+
switch (chunk.event) {
|
|
111
|
+
case LangGraphKnownEventTypes.MessagesPartial:
|
|
112
|
+
case LangGraphKnownEventTypes.MessagesComplete:
|
|
113
|
+
setMessages(accumulator.addMessages(chunk.data));
|
|
114
|
+
break;
|
|
115
|
+
case LangGraphKnownEventTypes.Updates:
|
|
116
|
+
setInterrupt(chunk.data.__interrupt__?.[0]);
|
|
117
|
+
break;
|
|
118
|
+
case LangGraphKnownEventTypes.Messages: {
|
|
119
|
+
const [messageChunk] = (chunk as LangChainMessageTupleEvent).data;
|
|
120
|
+
if (!isLangChainMessageChunk(messageChunk)) {
|
|
121
|
+
console.warn(
|
|
122
|
+
"Received invalid message chunk format:",
|
|
123
|
+
messageChunk,
|
|
124
|
+
);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
const updatedMessages = accumulator.addMessages([
|
|
128
|
+
messageChunk as unknown as TMessage,
|
|
129
|
+
]);
|
|
130
|
+
setMessages(updatedMessages);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case LangGraphKnownEventTypes.Metadata:
|
|
134
|
+
onMetadata?.(chunk.data);
|
|
135
|
+
break;
|
|
136
|
+
case LangGraphKnownEventTypes.Info:
|
|
137
|
+
onInfo?.(chunk.data);
|
|
138
|
+
break;
|
|
139
|
+
case LangGraphKnownEventTypes.Error:
|
|
140
|
+
onError?.(chunk.data);
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
if (onCustomEvent) {
|
|
144
|
+
onCustomEvent(chunk.event, chunk.data);
|
|
145
|
+
} else {
|
|
146
|
+
console.warn(
|
|
147
|
+
"Unhandled event received:",
|
|
148
|
+
chunk.event,
|
|
149
|
+
chunk.data,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
82
153
|
}
|
|
83
154
|
}
|
|
84
155
|
},
|
|
85
|
-
[
|
|
156
|
+
[
|
|
157
|
+
messages,
|
|
158
|
+
appendMessage,
|
|
159
|
+
stream,
|
|
160
|
+
onMetadata,
|
|
161
|
+
onInfo,
|
|
162
|
+
onError,
|
|
163
|
+
onCustomEvent,
|
|
164
|
+
],
|
|
86
165
|
);
|
|
87
166
|
|
|
88
167
|
const cancel = useCallback(() => {
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { act, renderHook, waitFor } from "@testing-library/react";
|
|
3
|
+
import {
|
|
4
|
+
AssistantRuntime,
|
|
5
|
+
AssistantRuntimeProvider,
|
|
6
|
+
} from "@assistant-ui/react";
|
|
7
|
+
import { useLangGraphRuntime, useLangGraphSend } from "./useLangGraphRuntime";
|
|
8
|
+
import { mockStreamCallbackFactory } from "./testUtils";
|
|
9
|
+
import React, { ReactNode } from "react";
|
|
10
|
+
|
|
11
|
+
const metadataEvent = {
|
|
12
|
+
event: "metadata",
|
|
13
|
+
data: {
|
|
14
|
+
thread_id: "123",
|
|
15
|
+
run_attempt: 1,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const infoEvent = {
|
|
20
|
+
event: "info",
|
|
21
|
+
data: {
|
|
22
|
+
message: "Processing request",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const errorEvent = {
|
|
27
|
+
event: "error",
|
|
28
|
+
data: {
|
|
29
|
+
message: "Something went wrong",
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const customEvent = {
|
|
34
|
+
event: "custom",
|
|
35
|
+
data: {
|
|
36
|
+
type: "test",
|
|
37
|
+
value: "custom data",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe("useLangGraphRuntime", () => {
|
|
42
|
+
const wrapperFactory =
|
|
43
|
+
(runtime: AssistantRuntime) =>
|
|
44
|
+
// eslint-disable-next-line react/display-name
|
|
45
|
+
({ children }: { children: ReactNode }) => (
|
|
46
|
+
<AssistantRuntimeProvider runtime={runtime}>
|
|
47
|
+
{children}
|
|
48
|
+
</AssistantRuntimeProvider>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
it("should handle metadata events", async () => {
|
|
52
|
+
const onMetadata = vi.fn();
|
|
53
|
+
|
|
54
|
+
const streamMock = vi
|
|
55
|
+
.fn()
|
|
56
|
+
.mockImplementation(() => mockStreamCallbackFactory([metadataEvent])());
|
|
57
|
+
|
|
58
|
+
const { result: runtimeResult } = renderHook(
|
|
59
|
+
() =>
|
|
60
|
+
useLangGraphRuntime({
|
|
61
|
+
stream: streamMock,
|
|
62
|
+
eventHandlers: {
|
|
63
|
+
onMetadata,
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
{},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const wrapper = wrapperFactory(runtimeResult.current);
|
|
70
|
+
|
|
71
|
+
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
72
|
+
wrapper,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
act(() => {
|
|
76
|
+
sendResult.current(
|
|
77
|
+
[
|
|
78
|
+
{
|
|
79
|
+
type: "human",
|
|
80
|
+
content: "Hello, world!",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
{},
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await waitFor(() => {
|
|
88
|
+
expect(streamMock).toHaveBeenCalled();
|
|
89
|
+
expect(onMetadata).toHaveBeenCalledWith(metadataEvent.data);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should handle info events", async () => {
|
|
94
|
+
const onInfo = vi.fn();
|
|
95
|
+
|
|
96
|
+
const streamMock = vi
|
|
97
|
+
.fn()
|
|
98
|
+
.mockImplementation(() => mockStreamCallbackFactory([infoEvent])());
|
|
99
|
+
|
|
100
|
+
const { result: runtimeResult } = renderHook(
|
|
101
|
+
() =>
|
|
102
|
+
useLangGraphRuntime({
|
|
103
|
+
stream: streamMock,
|
|
104
|
+
eventHandlers: {
|
|
105
|
+
onInfo,
|
|
106
|
+
},
|
|
107
|
+
}),
|
|
108
|
+
{},
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
112
|
+
<AssistantRuntimeProvider runtime={runtimeResult.current}>
|
|
113
|
+
{children}
|
|
114
|
+
</AssistantRuntimeProvider>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
118
|
+
wrapper,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
act(() => {
|
|
122
|
+
sendResult.current(
|
|
123
|
+
[
|
|
124
|
+
{
|
|
125
|
+
type: "human",
|
|
126
|
+
content: "Hello, world!",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
{},
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await waitFor(() => {
|
|
134
|
+
expect(streamMock).toHaveBeenCalled();
|
|
135
|
+
expect(onInfo).toHaveBeenCalledWith(infoEvent.data);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should handle error events", async () => {
|
|
140
|
+
const onError = vi.fn();
|
|
141
|
+
|
|
142
|
+
const streamMock = vi
|
|
143
|
+
.fn()
|
|
144
|
+
.mockImplementation(() => mockStreamCallbackFactory([errorEvent])());
|
|
145
|
+
|
|
146
|
+
const { result: runtimeResult } = renderHook(
|
|
147
|
+
() =>
|
|
148
|
+
useLangGraphRuntime({
|
|
149
|
+
stream: streamMock,
|
|
150
|
+
eventHandlers: {
|
|
151
|
+
onError,
|
|
152
|
+
},
|
|
153
|
+
}),
|
|
154
|
+
{},
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
158
|
+
<AssistantRuntimeProvider runtime={runtimeResult.current}>
|
|
159
|
+
{children}
|
|
160
|
+
</AssistantRuntimeProvider>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
164
|
+
wrapper,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
act(() => {
|
|
168
|
+
sendResult.current(
|
|
169
|
+
[
|
|
170
|
+
{
|
|
171
|
+
type: "human",
|
|
172
|
+
content: "Hello, world!",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
{},
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
await waitFor(() => {
|
|
180
|
+
expect(streamMock).toHaveBeenCalled();
|
|
181
|
+
expect(onError).toHaveBeenCalledWith(errorEvent.data);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should handle custom events", async () => {
|
|
186
|
+
const onCustomEvent = vi.fn();
|
|
187
|
+
|
|
188
|
+
const streamMock = vi
|
|
189
|
+
.fn()
|
|
190
|
+
.mockImplementation(() => mockStreamCallbackFactory([customEvent])());
|
|
191
|
+
|
|
192
|
+
const { result: runtimeResult } = renderHook(
|
|
193
|
+
() =>
|
|
194
|
+
useLangGraphRuntime({
|
|
195
|
+
stream: streamMock,
|
|
196
|
+
eventHandlers: {
|
|
197
|
+
onCustomEvent,
|
|
198
|
+
},
|
|
199
|
+
}),
|
|
200
|
+
{},
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const wrapper = wrapperFactory(runtimeResult.current);
|
|
204
|
+
|
|
205
|
+
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
206
|
+
wrapper,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
act(() => {
|
|
210
|
+
sendResult.current(
|
|
211
|
+
[
|
|
212
|
+
{
|
|
213
|
+
type: "human",
|
|
214
|
+
content: "Hello, world!",
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
{},
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await waitFor(() => {
|
|
222
|
+
expect(streamMock).toHaveBeenCalled();
|
|
223
|
+
expect(onCustomEvent).toHaveBeenCalledWith(
|
|
224
|
+
customEvent.event,
|
|
225
|
+
customEvent.data,
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should work without any provided callbacks", async () => {
|
|
231
|
+
const streamMock = vi
|
|
232
|
+
.fn()
|
|
233
|
+
.mockImplementation(() =>
|
|
234
|
+
mockStreamCallbackFactory([
|
|
235
|
+
metadataEvent,
|
|
236
|
+
infoEvent,
|
|
237
|
+
errorEvent,
|
|
238
|
+
customEvent,
|
|
239
|
+
])(),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const { result: runtimeResult } = renderHook(
|
|
243
|
+
() =>
|
|
244
|
+
useLangGraphRuntime({
|
|
245
|
+
stream: streamMock,
|
|
246
|
+
eventHandlers: {},
|
|
247
|
+
}),
|
|
248
|
+
{},
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const wrapper = wrapperFactory(runtimeResult.current);
|
|
252
|
+
|
|
253
|
+
const { result: sendResult } = renderHook(() => useLangGraphSend(), {
|
|
254
|
+
wrapper,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
act(() => {
|
|
258
|
+
sendResult.current(
|
|
259
|
+
[
|
|
260
|
+
{
|
|
261
|
+
type: "human",
|
|
262
|
+
content: "Hello, world!",
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
{},
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
await waitFor(() => {
|
|
270
|
+
expect(streamMock).toHaveBeenCalled();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Should not throw any errors even when events are processed without handlers
|
|
274
|
+
expect(runtimeResult.current).toBeDefined();
|
|
275
|
+
});
|
|
276
|
+
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
LangChainMessage,
|
|
4
|
+
LangChainToolCall,
|
|
5
|
+
OnCustomEventCallback,
|
|
6
|
+
OnErrorEventCallback,
|
|
7
|
+
OnInfoEventCallback,
|
|
8
|
+
OnMetadataEventCallback,
|
|
9
|
+
} from "./types";
|
|
3
10
|
import {
|
|
4
11
|
useExternalMessageConverter,
|
|
5
12
|
useExternalStoreRuntime,
|
|
@@ -115,6 +122,7 @@ export const useLangGraphRuntime = ({
|
|
|
115
122
|
threadId,
|
|
116
123
|
onSwitchToNewThread,
|
|
117
124
|
onSwitchToThread,
|
|
125
|
+
eventHandlers,
|
|
118
126
|
}: {
|
|
119
127
|
/**
|
|
120
128
|
* @deprecated For thread management use `useCloudThreadListRuntime` instead. This option will be removed in a future version.
|
|
@@ -138,6 +146,29 @@ export const useLangGraphRuntime = ({
|
|
|
138
146
|
feedback?: FeedbackAdapter;
|
|
139
147
|
}
|
|
140
148
|
| undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Event handlers for various LangGraph stream events
|
|
151
|
+
*/
|
|
152
|
+
eventHandlers?:
|
|
153
|
+
| {
|
|
154
|
+
/**
|
|
155
|
+
* Called when metadata is received from the LangGraph stream
|
|
156
|
+
*/
|
|
157
|
+
onMetadata?: OnMetadataEventCallback;
|
|
158
|
+
/**
|
|
159
|
+
* Called when informational messages are received from the LangGraph stream
|
|
160
|
+
*/
|
|
161
|
+
onInfo?: OnInfoEventCallback;
|
|
162
|
+
/**
|
|
163
|
+
* Called when errors occur during LangGraph stream processing
|
|
164
|
+
*/
|
|
165
|
+
onError?: OnErrorEventCallback;
|
|
166
|
+
/**
|
|
167
|
+
* Called when custom events are received from the LangGraph stream
|
|
168
|
+
*/
|
|
169
|
+
onCustomEvent?: OnCustomEventCallback;
|
|
170
|
+
}
|
|
171
|
+
| undefined;
|
|
141
172
|
}) => {
|
|
142
173
|
const {
|
|
143
174
|
interrupt,
|
|
@@ -149,6 +180,7 @@ export const useLangGraphRuntime = ({
|
|
|
149
180
|
} = useLangGraphMessages({
|
|
150
181
|
appendMessage: appendLangChainChunk,
|
|
151
182
|
stream,
|
|
183
|
+
...(eventHandlers && { eventHandlers }),
|
|
152
184
|
});
|
|
153
185
|
|
|
154
186
|
const [isRunning, setIsRunning] = useState(false);
|