@assistant-ui/react-google-adk 0.0.18 → 0.0.20
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/AdkClient.js +15 -2
- package/dist/AdkClient.js.map +1 -1
- package/dist/adkExtras.d.ts +1 -1
- package/dist/adkExtras.d.ts.map +1 -1
- package/dist/adkExtras.js +1 -1
- package/dist/adkExtras.js.map +1 -1
- package/dist/convertAdkMessages.d.ts.map +1 -1
- package/dist/convertAdkMessages.js +19 -9
- package/dist/convertAdkMessages.js.map +1 -1
- package/dist/useAdkMessages.js +1 -1
- package/dist/useAdkMessages.js.map +1 -1
- package/dist/useAdkRuntime.d.ts.map +1 -1
- package/dist/useAdkRuntime.js +16 -6
- package/dist/useAdkRuntime.js.map +1 -1
- package/package.json +5 -5
- package/src/AdkClient.test.ts +55 -22
- package/src/AdkClient.ts +16 -2
- package/src/AdkEventAccumulator.test.ts +0 -36
- package/src/AdkSessionAdapter.test.ts +1 -11
- package/src/adkExtras.ts +1 -1
- package/src/convertAdkMessages.test.ts +79 -0
- package/src/convertAdkMessages.ts +23 -4
- package/src/useAdkMessages.ts +1 -1
- package/src/useAdkRuntime.test.ts +61 -0
- package/src/useAdkRuntime.ts +17 -11
- package/src/server/createAdkApiRoute.test.ts +0 -370
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
|
|
3
|
-
// ── Module mocks ──
|
|
4
|
-
|
|
5
|
-
vi.mock("./parseAdkRequest", () => ({
|
|
6
|
-
parseAdkRequest: vi.fn(),
|
|
7
|
-
toAdkContent: vi.fn(),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
vi.mock("./adkEventStream", () => ({
|
|
11
|
-
adkEventStream: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
import { createAdkApiRoute } from "./createAdkApiRoute";
|
|
15
|
-
import { parseAdkRequest, toAdkContent } from "./parseAdkRequest";
|
|
16
|
-
import { adkEventStream } from "./adkEventStream";
|
|
17
|
-
|
|
18
|
-
const mockParseAdkRequest = vi.mocked(parseAdkRequest);
|
|
19
|
-
const mockToAdkContent = vi.mocked(toAdkContent);
|
|
20
|
-
const mockAdkEventStream = vi.mocked(adkEventStream);
|
|
21
|
-
|
|
22
|
-
const makeRequest = (body: unknown = { message: "Hello" }) =>
|
|
23
|
-
new Request("http://localhost/api/adk", {
|
|
24
|
-
method: "POST",
|
|
25
|
-
headers: { "Content-Type": "application/json" },
|
|
26
|
-
body: JSON.stringify(body),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const makeRunner = () => ({
|
|
30
|
-
runAsync: vi.fn().mockReturnValue(
|
|
31
|
-
(async function* () {
|
|
32
|
-
yield { id: "e1" };
|
|
33
|
-
})(),
|
|
34
|
-
),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
beforeEach(() => {
|
|
38
|
-
vi.clearAllMocks();
|
|
39
|
-
mockParseAdkRequest.mockResolvedValue({
|
|
40
|
-
type: "message",
|
|
41
|
-
text: "Hello",
|
|
42
|
-
config: {},
|
|
43
|
-
});
|
|
44
|
-
mockToAdkContent.mockReturnValue({
|
|
45
|
-
role: "user",
|
|
46
|
-
parts: [{ text: "Hello" }],
|
|
47
|
-
});
|
|
48
|
-
mockAdkEventStream.mockReturnValue(new Response("stream", { status: 200 }));
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ── Basic flow ──
|
|
52
|
-
|
|
53
|
-
describe("createAdkApiRoute - basic flow", () => {
|
|
54
|
-
it("calls parseAdkRequest with the request", async () => {
|
|
55
|
-
const runner = makeRunner();
|
|
56
|
-
const handler = createAdkApiRoute({
|
|
57
|
-
runner,
|
|
58
|
-
userId: "user-1",
|
|
59
|
-
sessionId: "session-1",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const req = makeRequest();
|
|
63
|
-
await handler(req);
|
|
64
|
-
|
|
65
|
-
expect(mockParseAdkRequest).toHaveBeenCalledOnce();
|
|
66
|
-
expect(mockParseAdkRequest).toHaveBeenCalledWith(req);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("calls toAdkContent with the parsed request", async () => {
|
|
70
|
-
const parsed = { type: "message" as const, text: "Hi", config: {} };
|
|
71
|
-
mockParseAdkRequest.mockResolvedValue(parsed);
|
|
72
|
-
|
|
73
|
-
const runner = makeRunner();
|
|
74
|
-
const handler = createAdkApiRoute({
|
|
75
|
-
runner,
|
|
76
|
-
userId: "user-1",
|
|
77
|
-
sessionId: "session-1",
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
await handler(makeRequest());
|
|
81
|
-
|
|
82
|
-
expect(mockToAdkContent).toHaveBeenCalledOnce();
|
|
83
|
-
expect(mockToAdkContent).toHaveBeenCalledWith(parsed);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("calls runner.runAsync with the correct arguments", async () => {
|
|
87
|
-
const newMessage = { role: "user", parts: [{ text: "Hi" }] };
|
|
88
|
-
mockToAdkContent.mockReturnValue(newMessage);
|
|
89
|
-
|
|
90
|
-
const runner = makeRunner();
|
|
91
|
-
const handler = createAdkApiRoute({
|
|
92
|
-
runner,
|
|
93
|
-
userId: "user-1",
|
|
94
|
-
sessionId: "session-1",
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
await handler(makeRequest());
|
|
98
|
-
|
|
99
|
-
expect(runner.runAsync).toHaveBeenCalledOnce();
|
|
100
|
-
expect(runner.runAsync).toHaveBeenCalledWith({
|
|
101
|
-
userId: "user-1",
|
|
102
|
-
sessionId: "session-1",
|
|
103
|
-
newMessage,
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("passes runner.runAsync result to adkEventStream and returns its response", async () => {
|
|
108
|
-
const runner = makeRunner();
|
|
109
|
-
const expectedResponse = new Response("ok", { status: 200 });
|
|
110
|
-
mockAdkEventStream.mockReturnValue(expectedResponse);
|
|
111
|
-
|
|
112
|
-
const handler = createAdkApiRoute({
|
|
113
|
-
runner,
|
|
114
|
-
userId: "user-1",
|
|
115
|
-
sessionId: "session-1",
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const result = await handler(makeRequest());
|
|
119
|
-
|
|
120
|
-
expect(mockAdkEventStream).toHaveBeenCalledOnce();
|
|
121
|
-
expect(result).toBe(expectedResponse);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// ── userId and sessionId as functions ──
|
|
126
|
-
|
|
127
|
-
describe("createAdkApiRoute - dynamic userId/sessionId", () => {
|
|
128
|
-
it("resolves userId from a function", async () => {
|
|
129
|
-
const runner = makeRunner();
|
|
130
|
-
const handler = createAdkApiRoute({
|
|
131
|
-
runner,
|
|
132
|
-
userId: (req) => new URL(req.url).searchParams.get("user") ?? "default",
|
|
133
|
-
sessionId: "session-1",
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const req = new Request("http://localhost/api/adk?user=alice", {
|
|
137
|
-
method: "POST",
|
|
138
|
-
headers: { "Content-Type": "application/json" },
|
|
139
|
-
body: JSON.stringify({ message: "Hi" }),
|
|
140
|
-
});
|
|
141
|
-
await handler(req);
|
|
142
|
-
|
|
143
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
144
|
-
expect.objectContaining({ userId: "alice" }),
|
|
145
|
-
);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("resolves sessionId from a function", async () => {
|
|
149
|
-
const runner = makeRunner();
|
|
150
|
-
const handler = createAdkApiRoute({
|
|
151
|
-
runner,
|
|
152
|
-
userId: "user-1",
|
|
153
|
-
sessionId: (req) =>
|
|
154
|
-
new URL(req.url).searchParams.get("session") ?? "default",
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const req = new Request("http://localhost/api/adk?session=s42", {
|
|
158
|
-
method: "POST",
|
|
159
|
-
headers: { "Content-Type": "application/json" },
|
|
160
|
-
body: JSON.stringify({ message: "Hi" }),
|
|
161
|
-
});
|
|
162
|
-
await handler(req);
|
|
163
|
-
|
|
164
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
165
|
-
expect.objectContaining({ sessionId: "s42" }),
|
|
166
|
-
);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it("resolves async userId function", async () => {
|
|
170
|
-
const runner = makeRunner();
|
|
171
|
-
const handler = createAdkApiRoute({
|
|
172
|
-
runner,
|
|
173
|
-
userId: async () => "async-user",
|
|
174
|
-
sessionId: "session-1",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
await handler(makeRequest());
|
|
178
|
-
|
|
179
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
180
|
-
expect.objectContaining({ userId: "async-user" }),
|
|
181
|
-
);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("resolves async sessionId function", async () => {
|
|
185
|
-
const runner = makeRunner();
|
|
186
|
-
const handler = createAdkApiRoute({
|
|
187
|
-
runner,
|
|
188
|
-
userId: "user-1",
|
|
189
|
-
sessionId: async () => "async-session",
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
await handler(makeRequest());
|
|
193
|
-
|
|
194
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
195
|
-
expect.objectContaining({ sessionId: "async-session" }),
|
|
196
|
-
);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// ── stateDelta passthrough ──
|
|
201
|
-
|
|
202
|
-
describe("createAdkApiRoute - stateDelta", () => {
|
|
203
|
-
it("passes stateDelta to runner.runAsync when present", async () => {
|
|
204
|
-
mockParseAdkRequest.mockResolvedValue({
|
|
205
|
-
type: "message",
|
|
206
|
-
text: "Hello",
|
|
207
|
-
config: {},
|
|
208
|
-
stateDelta: { count: 1 },
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
const runner = makeRunner();
|
|
212
|
-
const handler = createAdkApiRoute({
|
|
213
|
-
runner,
|
|
214
|
-
userId: "user-1",
|
|
215
|
-
sessionId: "session-1",
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
await handler(makeRequest());
|
|
219
|
-
|
|
220
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
221
|
-
expect.objectContaining({ stateDelta: { count: 1 } }),
|
|
222
|
-
);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it("does not include stateDelta when it is null/undefined", async () => {
|
|
226
|
-
mockParseAdkRequest.mockResolvedValue({
|
|
227
|
-
type: "message",
|
|
228
|
-
text: "Hello",
|
|
229
|
-
config: {},
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
const runner = makeRunner();
|
|
233
|
-
const handler = createAdkApiRoute({
|
|
234
|
-
runner,
|
|
235
|
-
userId: "user-1",
|
|
236
|
-
sessionId: "session-1",
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
await handler(makeRequest());
|
|
240
|
-
|
|
241
|
-
const callArgs = runner.runAsync.mock.calls[0]![0];
|
|
242
|
-
expect(callArgs).not.toHaveProperty("stateDelta");
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// ── runConfig passthrough ──
|
|
247
|
-
|
|
248
|
-
describe("createAdkApiRoute - runConfig", () => {
|
|
249
|
-
it("passes runConfig to runner.runAsync when present", async () => {
|
|
250
|
-
mockParseAdkRequest.mockResolvedValue({
|
|
251
|
-
type: "message",
|
|
252
|
-
text: "Hello",
|
|
253
|
-
config: { runConfig: { temperature: 0.5 } },
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
const runner = makeRunner();
|
|
257
|
-
const handler = createAdkApiRoute({
|
|
258
|
-
runner,
|
|
259
|
-
userId: "user-1",
|
|
260
|
-
sessionId: "session-1",
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
await handler(makeRequest());
|
|
264
|
-
|
|
265
|
-
expect(runner.runAsync).toHaveBeenCalledWith(
|
|
266
|
-
expect.objectContaining({ runConfig: { temperature: 0.5 } }),
|
|
267
|
-
);
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it("does not include runConfig when it is null/undefined", async () => {
|
|
271
|
-
mockParseAdkRequest.mockResolvedValue({
|
|
272
|
-
type: "message",
|
|
273
|
-
text: "Hello",
|
|
274
|
-
config: {},
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
const runner = makeRunner();
|
|
278
|
-
const handler = createAdkApiRoute({
|
|
279
|
-
runner,
|
|
280
|
-
userId: "user-1",
|
|
281
|
-
sessionId: "session-1",
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
await handler(makeRequest());
|
|
285
|
-
|
|
286
|
-
const callArgs = runner.runAsync.mock.calls[0]![0];
|
|
287
|
-
expect(callArgs).not.toHaveProperty("runConfig");
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// ── onError passthrough ──
|
|
292
|
-
|
|
293
|
-
describe("createAdkApiRoute - onError", () => {
|
|
294
|
-
it("passes onError to adkEventStream", async () => {
|
|
295
|
-
const onError = vi.fn();
|
|
296
|
-
const runner = makeRunner();
|
|
297
|
-
const handler = createAdkApiRoute({
|
|
298
|
-
runner,
|
|
299
|
-
userId: "user-1",
|
|
300
|
-
sessionId: "session-1",
|
|
301
|
-
onError,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
await handler(makeRequest());
|
|
305
|
-
|
|
306
|
-
expect(mockAdkEventStream).toHaveBeenCalledWith(expect.anything(), {
|
|
307
|
-
onError,
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
it("does not pass onError when not provided", async () => {
|
|
312
|
-
const runner = makeRunner();
|
|
313
|
-
const handler = createAdkApiRoute({
|
|
314
|
-
runner,
|
|
315
|
-
userId: "user-1",
|
|
316
|
-
sessionId: "session-1",
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
await handler(makeRequest());
|
|
320
|
-
|
|
321
|
-
expect(mockAdkEventStream).toHaveBeenCalledWith(
|
|
322
|
-
expect.anything(),
|
|
323
|
-
undefined,
|
|
324
|
-
);
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
// ── tool-result flow ──
|
|
329
|
-
|
|
330
|
-
describe("createAdkApiRoute - tool-result flow", () => {
|
|
331
|
-
it("handles tool-result requests", async () => {
|
|
332
|
-
const toolParsed = {
|
|
333
|
-
type: "tool-result" as const,
|
|
334
|
-
toolCallId: "tc-1",
|
|
335
|
-
toolName: "search",
|
|
336
|
-
result: { found: true },
|
|
337
|
-
isError: false,
|
|
338
|
-
config: {},
|
|
339
|
-
};
|
|
340
|
-
mockParseAdkRequest.mockResolvedValue(toolParsed);
|
|
341
|
-
mockToAdkContent.mockReturnValue({
|
|
342
|
-
role: "user",
|
|
343
|
-
parts: [
|
|
344
|
-
{
|
|
345
|
-
functionResponse: {
|
|
346
|
-
name: "search",
|
|
347
|
-
id: "tc-1",
|
|
348
|
-
response: { found: true },
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
const runner = makeRunner();
|
|
355
|
-
const handler = createAdkApiRoute({
|
|
356
|
-
runner,
|
|
357
|
-
userId: "user-1",
|
|
358
|
-
sessionId: "session-1",
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
await handler(makeRequest());
|
|
362
|
-
|
|
363
|
-
expect(mockToAdkContent).toHaveBeenCalledWith(toolParsed);
|
|
364
|
-
expect(runner.runAsync).toHaveBeenCalledOnce();
|
|
365
|
-
const callArgs = runner.runAsync.mock.calls[0]![0];
|
|
366
|
-
expect(callArgs.newMessage.parts[0]).toMatchObject({
|
|
367
|
-
functionResponse: { name: "search", id: "tc-1" },
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
});
|