@assistant-ui/react-google-adk 0.0.35 → 0.0.36
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/README.md +12 -2
- package/dist/AdkClient.d.ts +4 -0
- package/dist/AdkClient.d.ts.map +1 -1
- package/dist/AdkClient.js +12 -7
- package/dist/AdkClient.js.map +1 -1
- package/dist/AdkSessionAdapter.d.ts.map +1 -1
- package/dist/AdkSessionAdapter.js +7 -7
- package/dist/AdkSessionAdapter.js.map +1 -1
- package/dist/AdkThreadController.d.ts +15 -0
- package/dist/AdkThreadController.d.ts.map +1 -0
- package/dist/AdkThreadController.js +35 -0
- package/dist/AdkThreadController.js.map +1 -0
- package/dist/adkThreadState.d.ts +54 -0
- package/dist/adkThreadState.d.ts.map +1 -0
- package/dist/adkThreadState.js +93 -0
- package/dist/adkThreadState.js.map +1 -0
- package/dist/convertToAdkMessages.js +1 -1
- package/dist/convertToAdkMessages.js.map +1 -1
- package/dist/sdkIdentity.js +1 -1
- package/dist/server/createAdkApiRoute.d.ts +37 -6
- package/dist/server/createAdkApiRoute.d.ts.map +1 -1
- package/dist/server/createAdkApiRoute.js +55 -5
- package/dist/server/createAdkApiRoute.js.map +1 -1
- package/dist/server/parseAdkRequest.d.ts +4 -1
- package/dist/server/parseAdkRequest.d.ts.map +1 -1
- package/dist/server/parseAdkRequest.js +5 -1
- package/dist/server/parseAdkRequest.js.map +1 -1
- package/dist/useAdkMessages.d.ts +9 -7
- package/dist/useAdkMessages.d.ts.map +1 -1
- package/dist/useAdkMessages.js +55 -77
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts +7 -1
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +134 -56
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +5 -5
- package/src/AdkClient.test.ts +78 -2
- package/src/AdkClient.ts +24 -6
- package/src/AdkSessionAdapter.ts +1 -1
- package/src/AdkThreadController.test.ts +90 -0
- package/src/AdkThreadController.ts +45 -0
- package/src/adkThreadState.test.ts +207 -0
- package/src/adkThreadState.ts +124 -0
- package/src/convertToAdkMessages.test.ts +19 -0
- package/src/convertToAdkMessages.ts +1 -1
- package/src/hooks.test.tsx +1 -0
- package/src/server/createAdkApiRoute.controls.test.ts +66 -0
- package/src/server/createAdkApiRoute.test.ts +282 -0
- package/src/server/createAdkApiRoute.ts +119 -11
- package/src/server/parseAdkRequest.test.ts +11 -3
- package/src/server/parseAdkRequest.ts +7 -1
- package/src/useAdkMessages.test.ts +1 -0
- package/src/useAdkMessages.ts +61 -96
- package/src/useAdkRuntime.cancellation.test.tsx +4 -3
- package/src/useAdkRuntime.cloud-options.test.tsx +59 -0
- package/src/useAdkRuntime.refetch.test.tsx +548 -4
- package/src/useAdkRuntime.replacement.test.tsx +718 -1
- package/src/useAdkRuntime.ts +169 -73
- package/src/useAdkRuntimeApproval.test.tsx +87 -1
- package/dist/raceWithAbortSignal.d.ts +0 -2
- package/dist/raceWithAbortSignal.d.ts.map +0 -1
- package/dist/raceWithAbortSignal.js +0 -45
- package/dist/raceWithAbortSignal.js.map +0 -1
- package/src/raceWithAbortSignal.test.ts +0 -73
- package/src/raceWithAbortSignal.ts +0 -48
package/src/useAdkMessages.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { isRecord } from "@assistant-ui/core/internal";
|
|
|
2
2
|
import {
|
|
3
3
|
useState,
|
|
4
4
|
useCallback,
|
|
5
|
-
useInsertionEffect,
|
|
6
5
|
useRef,
|
|
7
6
|
useMemo,
|
|
7
|
+
useSyncExternalStore,
|
|
8
8
|
} from "react";
|
|
9
9
|
import { generateId } from "@assistant-ui/core";
|
|
10
10
|
import { useReplaySafeEffect } from "@assistant-ui/store/internal";
|
|
@@ -15,16 +15,14 @@ import {
|
|
|
15
15
|
openAbortableIterable,
|
|
16
16
|
} from "@assistant-ui/core/internal";
|
|
17
17
|
import { AdkEventAccumulator } from "./AdkEventAccumulator";
|
|
18
|
+
import { AdkThreadController } from "./AdkThreadController";
|
|
18
19
|
import { contentToParts } from "./contentToParts";
|
|
19
20
|
import { toAdkFunctionResponse } from "./toAdkFunctionResponse";
|
|
20
21
|
import type {
|
|
21
22
|
AdkEvent,
|
|
22
23
|
AdkMessage,
|
|
23
|
-
AdkMessageMetadata,
|
|
24
24
|
AdkSendMessageConfig,
|
|
25
25
|
AdkStreamCallback,
|
|
26
|
-
AdkToolConfirmation,
|
|
27
|
-
AdkAuthRequest,
|
|
28
26
|
AdkThreadSnapshot,
|
|
29
27
|
OnAdkErrorCallback,
|
|
30
28
|
OnAdkCustomEventCallback,
|
|
@@ -59,49 +57,29 @@ const useAdkMessagesInternal = ({
|
|
|
59
57
|
eventHandlers,
|
|
60
58
|
onMessages,
|
|
61
59
|
}: UseAdkMessagesInternalOptions) => {
|
|
62
|
-
const [
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
const [controller] = useState(() => new AdkThreadController());
|
|
61
|
+
const {
|
|
62
|
+
messages,
|
|
63
|
+
stateDelta,
|
|
64
|
+
agentInfo,
|
|
65
|
+
longRunningToolIds,
|
|
66
|
+
artifactDelta,
|
|
67
|
+
toolConfirmations,
|
|
68
|
+
authRequests,
|
|
69
|
+
escalated,
|
|
70
|
+
messageMetadata,
|
|
71
|
+
} = useSyncExternalStore(
|
|
72
|
+
controller.subscribe,
|
|
73
|
+
controller.getState,
|
|
74
|
+
controller.getState,
|
|
71
75
|
);
|
|
72
|
-
const [toolConfirmations, setToolConfirmations] = useState<
|
|
73
|
-
AdkToolConfirmation[]
|
|
74
|
-
>([]);
|
|
75
|
-
const [authRequests, setAuthRequests] = useState<AdkAuthRequest[]>([]);
|
|
76
|
-
const [escalated, setEscalated] = useState(false);
|
|
77
|
-
const [messageMetadata, setMessageMetadata] = useState<
|
|
78
|
-
Map<string, AdkMessageMetadata>
|
|
79
|
-
>(new Map());
|
|
80
|
-
// setMessagesImmediate and setLongRunningToolIds are the only writers of their state and publish these refs with it, so neither ref trails a commit.
|
|
81
|
-
const messagesRef = useRef(messages);
|
|
82
|
-
const longRunningToolIdsRef = useRef(longRunningToolIds);
|
|
83
|
-
const stateDeltaRef = useRef(stateDelta);
|
|
84
|
-
useInsertionEffect(() => {
|
|
85
|
-
stateDeltaRef.current = stateDelta;
|
|
86
|
-
}, [stateDelta]);
|
|
87
|
-
const artifactDeltaRef = useRef(artifactDelta);
|
|
88
|
-
useInsertionEffect(() => {
|
|
89
|
-
artifactDeltaRef.current = artifactDelta;
|
|
90
|
-
}, [artifactDelta]);
|
|
91
|
-
const messageMetadataRef = useRef(messageMetadata);
|
|
92
|
-
useInsertionEffect(() => {
|
|
93
|
-
messageMetadataRef.current = messageMetadata;
|
|
94
|
-
}, [messageMetadata]);
|
|
95
|
-
|
|
96
|
-
const setMessagesImmediate = useCallback((msgs: AdkMessage[]) => {
|
|
97
|
-
messagesRef.current = msgs;
|
|
98
|
-
_setMessages(msgs);
|
|
99
|
-
}, []);
|
|
100
|
-
const setLongRunningToolIds = useCallback((ids: string[]) => {
|
|
101
|
-
longRunningToolIdsRef.current = ids;
|
|
102
|
-
_setLongRunningToolIds(ids);
|
|
103
|
-
}, []);
|
|
104
76
|
|
|
77
|
+
const setMessagesImmediate = useCallback(
|
|
78
|
+
(msgs: AdkMessage[]) => {
|
|
79
|
+
controller.dispatch({ type: "messages.set", messages: msgs });
|
|
80
|
+
},
|
|
81
|
+
[controller],
|
|
82
|
+
);
|
|
105
83
|
/**
|
|
106
84
|
* Swap the thread over to a loaded snapshot in one commit. Unlike
|
|
107
85
|
* {@link replaceMessages} this never passes through a cleared state, so a
|
|
@@ -110,17 +88,9 @@ const useAdkMessagesInternal = ({
|
|
|
110
88
|
*/
|
|
111
89
|
const applySnapshot = useCallback(
|
|
112
90
|
(snapshot: AdkThreadSnapshot) => {
|
|
113
|
-
|
|
114
|
-
setLongRunningToolIds(snapshot.longRunningToolIds ?? []);
|
|
115
|
-
setToolConfirmations(snapshot.toolConfirmations ?? []);
|
|
116
|
-
setAuthRequests(snapshot.authRequests ?? []);
|
|
117
|
-
setEscalated(snapshot.escalated ?? false);
|
|
118
|
-
setMessageMetadata(snapshot.messageMetadata ?? new Map());
|
|
119
|
-
setStateDelta(snapshot.stateDelta ?? {});
|
|
120
|
-
setArtifactDelta(snapshot.artifactDelta ?? {});
|
|
121
|
-
setAgentInfo(snapshot.agentInfo ?? {});
|
|
91
|
+
controller.dispatch({ type: "snapshot.applied", snapshot });
|
|
122
92
|
},
|
|
123
|
-
[
|
|
93
|
+
[controller],
|
|
124
94
|
);
|
|
125
95
|
|
|
126
96
|
// Replace the message list AND reset derived per-turn HITL state.
|
|
@@ -129,14 +99,9 @@ const useAdkMessagesInternal = ({
|
|
|
129
99
|
// into the next turn.
|
|
130
100
|
const replaceMessages = useCallback(
|
|
131
101
|
(msgs: AdkMessage[]) => {
|
|
132
|
-
|
|
133
|
-
setLongRunningToolIds([]);
|
|
134
|
-
setToolConfirmations([]);
|
|
135
|
-
setAuthRequests([]);
|
|
136
|
-
setEscalated(false);
|
|
137
|
-
setMessageMetadata(new Map());
|
|
102
|
+
controller.dispatch({ type: "messages.replaced", messages: msgs });
|
|
138
103
|
},
|
|
139
|
-
[
|
|
104
|
+
[controller],
|
|
140
105
|
);
|
|
141
106
|
|
|
142
107
|
const abortControllerRef = useRef<AbortController | null>(null);
|
|
@@ -164,9 +129,10 @@ const useAdkMessagesInternal = ({
|
|
|
164
129
|
m.type === "tool" ? [m.tool_call_id] : [],
|
|
165
130
|
),
|
|
166
131
|
);
|
|
132
|
+
const currentState = controller.getState();
|
|
167
133
|
const accumulator = new AdkEventAccumulator(
|
|
168
|
-
|
|
169
|
-
|
|
134
|
+
currentState.messages.filter((m) => !resentIds.has(m.id)),
|
|
135
|
+
currentState.longRunningToolIds.filter(
|
|
170
136
|
(id) => !answeredToolCallIds.has(id),
|
|
171
137
|
),
|
|
172
138
|
);
|
|
@@ -176,10 +142,13 @@ const useAdkMessagesInternal = ({
|
|
|
176
142
|
const initialMessages = accumulator.getMessages();
|
|
177
143
|
const initialMessageIds = new Set(initialMessages.map((m) => m.id));
|
|
178
144
|
const initialLongRunningToolIds = accumulator.getLongRunningToolIds();
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
145
|
+
controller.dispatch({
|
|
146
|
+
type: "run.started",
|
|
147
|
+
messages: initialMessages,
|
|
148
|
+
longRunningToolIds: initialLongRunningToolIds,
|
|
149
|
+
toolConfirmations: accumulator.getToolConfirmations(),
|
|
150
|
+
authRequests: accumulator.getAuthRequests(),
|
|
151
|
+
});
|
|
183
152
|
let lastTransferToAgent: string | undefined;
|
|
184
153
|
|
|
185
154
|
// Google ADK replaces active runs, while React LangGraph queues sends.
|
|
@@ -222,28 +191,20 @@ const useAdkMessagesInternal = ({
|
|
|
222
191
|
if (affectedMessages.length > 0) {
|
|
223
192
|
onMessages?.(affectedMessages, config.runConfig);
|
|
224
193
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
194
|
+
controller.dispatch({
|
|
195
|
+
type: "event.published",
|
|
196
|
+
state: {
|
|
197
|
+
messages: updatedMessages,
|
|
198
|
+
stateDelta: accumulator.getStateDelta(),
|
|
199
|
+
agentInfo: accumulator.getAgentInfo(),
|
|
200
|
+
longRunningToolIds: accumulator.getLongRunningToolIds(),
|
|
201
|
+
artifactDelta: accumulator.getArtifactDelta(),
|
|
202
|
+
toolConfirmations: accumulator.getToolConfirmations(),
|
|
203
|
+
authRequests: accumulator.getAuthRequests(),
|
|
204
|
+
escalated: accumulator.isEscalated(),
|
|
205
|
+
messageMetadata: accumulator.getMessageMetadata(),
|
|
206
|
+
},
|
|
235
207
|
});
|
|
236
|
-
setToolConfirmations(accumulator.getToolConfirmations());
|
|
237
|
-
setAuthRequests(accumulator.getAuthRequests());
|
|
238
|
-
setEscalated(accumulator.isEscalated());
|
|
239
|
-
{
|
|
240
|
-
const newMeta = accumulator.getMessageMetadata();
|
|
241
|
-
if (newMeta.size > 0) {
|
|
242
|
-
setMessageMetadata(
|
|
243
|
-
new Map([...messageMetadataRef.current, ...newMeta]),
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
208
|
|
|
248
209
|
const transfer = accumulator.getLastTransferToAgent();
|
|
249
210
|
if (transfer && transfer !== lastTransferToAgent) {
|
|
@@ -286,12 +247,13 @@ const useAdkMessagesInternal = ({
|
|
|
286
247
|
} finally {
|
|
287
248
|
if (abortControllerRef.current === abortController) {
|
|
288
249
|
if (abortController.signal.aborted) {
|
|
289
|
-
|
|
290
|
-
|
|
250
|
+
controller.dispatch({
|
|
251
|
+
type: "longRunningToolIds.set",
|
|
252
|
+
ids: accumulator
|
|
291
253
|
.getLongRunningToolIds()
|
|
292
254
|
.filter((id) => initialLongRunningToolIds.includes(id)),
|
|
293
|
-
);
|
|
294
|
-
const updatedMessages =
|
|
255
|
+
});
|
|
256
|
+
const updatedMessages = controller.getState().messages;
|
|
295
257
|
const lastAssistantMessage = updatedMessages.findLast(
|
|
296
258
|
(m) => m.type === "ai",
|
|
297
259
|
);
|
|
@@ -318,8 +280,8 @@ const useAdkMessagesInternal = ({
|
|
|
318
280
|
},
|
|
319
281
|
[
|
|
320
282
|
aui,
|
|
283
|
+
controller,
|
|
321
284
|
setMessagesImmediate,
|
|
322
|
-
setLongRunningToolIds,
|
|
323
285
|
stream,
|
|
324
286
|
onError,
|
|
325
287
|
onCustomEvent,
|
|
@@ -337,6 +299,7 @@ const useAdkMessagesInternal = ({
|
|
|
337
299
|
useReplaySafeEffect(() => cancel, []);
|
|
338
300
|
|
|
339
301
|
return {
|
|
302
|
+
controller,
|
|
340
303
|
messages,
|
|
341
304
|
stateDelta,
|
|
342
305
|
agentInfo,
|
|
@@ -357,11 +320,13 @@ const useAdkMessagesInternal = ({
|
|
|
357
320
|
export const useAdkMessages = ({
|
|
358
321
|
stream,
|
|
359
322
|
eventHandlers,
|
|
360
|
-
}: UseAdkMessagesOptions) =>
|
|
361
|
-
useAdkMessagesInternal({
|
|
323
|
+
}: UseAdkMessagesOptions) => {
|
|
324
|
+
const { controller: _controller, ...result } = useAdkMessagesInternal({
|
|
362
325
|
stream,
|
|
363
326
|
...(eventHandlers !== undefined && { eventHandlers }),
|
|
364
327
|
});
|
|
328
|
+
return result;
|
|
329
|
+
};
|
|
365
330
|
|
|
366
331
|
export { useAdkMessagesInternal };
|
|
367
332
|
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
import { useAdkRuntime } from "./useAdkRuntime";
|
|
12
12
|
import { useAdkLongRunningToolIds, useAdkSend } from "./hooks";
|
|
13
13
|
import { AdkEventAccumulator } from "./AdkEventAccumulator";
|
|
14
|
+
import { settleOutsideAct } from "./tests/settleOutsideAct";
|
|
14
15
|
import type { AdkEvent, AdkStreamCallback, AdkThreadSnapshot } from "./types";
|
|
15
16
|
|
|
16
17
|
const makeThreadListAdapter = (): RemoteThreadListAdapter => ({
|
|
@@ -85,9 +86,9 @@ const renderAdkRuntime = async (
|
|
|
85
86
|
render(<Inner />);
|
|
86
87
|
});
|
|
87
88
|
await waitFor(() => expect(capture.runtime).not.toBeNull());
|
|
88
|
-
await
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
await settleOutsideAct(() =>
|
|
90
|
+
capture.runtime!.threads.switchToThread("adk-1"),
|
|
91
|
+
);
|
|
91
92
|
|
|
92
93
|
return capture;
|
|
93
94
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { renderHook } from "@testing-library/react";
|
|
4
|
+
import { describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type { AssistantCloud } from "assistant-cloud";
|
|
6
|
+
import type { AssistantRuntime } from "@assistant-ui/core";
|
|
7
|
+
|
|
8
|
+
const mocks = vi.hoisted(() => ({
|
|
9
|
+
cloudAdapter: {},
|
|
10
|
+
runtime: {},
|
|
11
|
+
useCloudThreadListAdapter: vi.fn(() => ({})),
|
|
12
|
+
useRemoteThreadListRuntime: vi.fn(() => ({})),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock("@assistant-ui/core/react", async (importOriginal) => ({
|
|
16
|
+
...(await importOriginal<typeof import("@assistant-ui/core/react")>()),
|
|
17
|
+
useCloudThreadListAdapter: mocks.useCloudThreadListAdapter,
|
|
18
|
+
useRemoteThreadListRuntime: mocks.useRemoteThreadListRuntime,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock("@assistant-ui/store", async (importOriginal) => ({
|
|
22
|
+
...(await importOriginal<typeof import("@assistant-ui/store")>()),
|
|
23
|
+
useAui: () => ({
|
|
24
|
+
threadListItem: {
|
|
25
|
+
source: null,
|
|
26
|
+
getState: () => ({ externalId: undefined }),
|
|
27
|
+
initialize: vi.fn(),
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
import { ADK_SDK } from "./sdkIdentity";
|
|
33
|
+
import { useAdkRuntime } from "./useAdkRuntime";
|
|
34
|
+
|
|
35
|
+
describe("useAdkRuntime Cloud options", () => {
|
|
36
|
+
it("forwards the Cloud scope to the thread-list adapter", () => {
|
|
37
|
+
const cloud = {} as AssistantCloud;
|
|
38
|
+
mocks.useCloudThreadListAdapter.mockReturnValue(mocks.cloudAdapter);
|
|
39
|
+
mocks.useRemoteThreadListRuntime.mockReturnValue(
|
|
40
|
+
mocks.runtime as AssistantRuntime,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
renderHook(() =>
|
|
44
|
+
useAdkRuntime({
|
|
45
|
+
stream: vi.fn(),
|
|
46
|
+
cloud,
|
|
47
|
+
scopeId: "workspace-1",
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
expect(mocks.useCloudThreadListAdapter).toHaveBeenCalledWith(
|
|
52
|
+
expect.objectContaining({
|
|
53
|
+
cloud,
|
|
54
|
+
scopeId: "workspace-1",
|
|
55
|
+
sdk: ADK_SDK,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
});
|