@assistant-ui/react-google-adk 0.0.17 → 0.0.19

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.
@@ -34,6 +34,17 @@ const sseBody = (text: string): ReadableStream<Uint8Array> => {
34
34
  });
35
35
  };
36
36
 
37
+ const sseResponse = (
38
+ body: BodyInit | null,
39
+ contentType: string | null = "text/event-stream",
40
+ ): Response =>
41
+ new Response(body, {
42
+ status: 200,
43
+ ...(contentType === null
44
+ ? {}
45
+ : { headers: { "Content-Type": contentType } }),
46
+ });
47
+
37
48
  const nextWithTimeout = async <T>(
38
49
  promise: Promise<IteratorResult<T>>,
39
50
  ): Promise<IteratorResult<T> | "timeout"> => {
@@ -57,7 +68,7 @@ beforeEach(() => {
57
68
 
58
69
  describe("createAdkStream - proxy mode", () => {
59
70
  it("POSTs to the api URL directly", async () => {
60
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
71
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
61
72
 
62
73
  const stream = createAdkStream({ api: "/api/adk" });
63
74
  const messages: AdkMessage[] = [
@@ -78,7 +89,7 @@ describe("createAdkStream - proxy mode", () => {
78
89
  });
79
90
 
80
91
  it("sends runConfig and checkpointId in proxy body", async () => {
81
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
92
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
82
93
 
83
94
  const stream = createAdkStream({ api: "/api/adk" });
84
95
  const gen = await stream(
@@ -95,7 +106,7 @@ describe("createAdkStream - proxy mode", () => {
95
106
  });
96
107
 
97
108
  it("sends a tool-result body when message type is tool", async () => {
98
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
109
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
99
110
 
100
111
  const stream = createAdkStream({ api: "/api/adk" });
101
112
  const messages: AdkMessage[] = [
@@ -122,7 +133,7 @@ describe("createAdkStream - proxy mode", () => {
122
133
  });
123
134
 
124
135
  it("sends parts when message has multimodal content", async () => {
125
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
136
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
126
137
 
127
138
  const stream = createAdkStream({ api: "/api/adk" });
128
139
  const messages: AdkMessage[] = [
@@ -149,7 +160,7 @@ describe("createAdkStream - proxy mode", () => {
149
160
  });
150
161
 
151
162
  it("sends file parts as inlineData in proxy mode", async () => {
152
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
163
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
153
164
 
154
165
  const stream = createAdkStream({ api: "/api/adk" });
155
166
  const messages: AdkMessage[] = [
@@ -180,7 +191,7 @@ describe("createAdkStream - proxy mode", () => {
180
191
  });
181
192
 
182
193
  it("sends parts array when multiple messages are provided", async () => {
183
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
194
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
184
195
 
185
196
  const stream = createAdkStream({ api: "/api/adk" });
186
197
  const messages: AdkMessage[] = [
@@ -205,7 +216,7 @@ describe("createAdkStream - proxy mode", () => {
205
216
  });
206
217
 
207
218
  it("marks isError=true when tool status is error", async () => {
208
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
219
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
209
220
 
210
221
  const stream = createAdkStream({ api: "/api/adk" });
211
222
  const messages: AdkMessage[] = [
@@ -231,8 +242,35 @@ describe("createAdkStream - proxy mode", () => {
231
242
  // ── Direct mode ──
232
243
 
233
244
  describe("createAdkStream - direct mode", () => {
245
+ it("rejects direct mode with an empty appName", () => {
246
+ expect(() =>
247
+ createAdkStream({
248
+ api: "http://localhost:8000",
249
+ appName: "",
250
+ userId: "user-1",
251
+ }),
252
+ ).toThrow('createAdkStream direct mode requires a non-empty "appName".');
253
+ expect(mockFetch).not.toHaveBeenCalled();
254
+ });
255
+
256
+ it.each([
257
+ ["missing", undefined],
258
+ ["empty", ""],
259
+ ])("rejects direct mode with a %s userId", (_label, userId) => {
260
+ expect(() =>
261
+ createAdkStream({
262
+ api: "http://localhost:8000",
263
+ appName: "my-app",
264
+ userId,
265
+ }),
266
+ ).toThrow(
267
+ 'createAdkStream direct mode requires "userId" when "appName" is provided.',
268
+ );
269
+ expect(mockFetch).not.toHaveBeenCalled();
270
+ });
271
+
234
272
  it("POSTs to /run_sse with ADK-native body", async () => {
235
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
273
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
236
274
 
237
275
  const stream = createAdkStream({
238
276
  api: "http://localhost:8000",
@@ -264,9 +302,7 @@ describe("createAdkStream - direct mode", () => {
264
302
  it.each(["http://localhost:8000/", "http://localhost:8000//"])(
265
303
  "normalizes trailing slashes in the api URL: %s",
266
304
  async (api) => {
267
- mockFetch.mockResolvedValueOnce(
268
- new Response(sseBody(""), { status: 200 }),
269
- );
305
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
270
306
 
271
307
  const stream = createAdkStream({
272
308
  api,
@@ -289,7 +325,7 @@ describe("createAdkStream - direct mode", () => {
289
325
  const initialize = vi
290
326
  .fn()
291
327
  .mockResolvedValue({ remoteId: "r1", externalId: "s-42" });
292
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
328
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
293
329
 
294
330
  const stream = createAdkStream({
295
331
  api: "http://localhost:8000",
@@ -310,7 +346,7 @@ describe("createAdkStream - direct mode", () => {
310
346
  });
311
347
 
312
348
  it("converts tool messages to functionResponse parts", async () => {
313
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
349
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
314
350
 
315
351
  const stream = createAdkStream({
316
352
  api: "http://localhost:8000",
@@ -342,7 +378,7 @@ describe("createAdkStream - direct mode", () => {
342
378
  });
343
379
 
344
380
  it("falls back to raw string when tool content is not valid JSON", async () => {
345
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
381
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
346
382
 
347
383
  const stream = createAdkStream({
348
384
  api: "http://localhost:8000",
@@ -368,7 +404,7 @@ describe("createAdkStream - direct mode", () => {
368
404
  });
369
405
 
370
406
  it("sends empty text part when no messages provided", async () => {
371
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
407
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
372
408
 
373
409
  const stream = createAdkStream({
374
410
  api: "http://localhost:8000",
@@ -394,9 +430,7 @@ describe("createAdkStream - SSE parsing", () => {
394
430
  { id: "e2", content: { parts: [{ text: "world" }] } },
395
431
  ];
396
432
  const text = events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("");
397
- mockFetch.mockResolvedValueOnce(
398
- new Response(sseBody(text), { status: 200 }),
399
- );
433
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(text)));
400
434
 
401
435
  const stream = createAdkStream({ api: "/api/adk" });
402
436
  const gen = await stream(
@@ -413,11 +447,29 @@ describe("createAdkStream - SSE parsing", () => {
413
447
  expect(collected[1]!.id).toBe("e2");
414
448
  });
415
449
 
416
- it("skips :ok SSE comments", async () => {
417
- const text = `:ok\n\ndata: ${JSON.stringify({ id: "e1" })}\n\n`;
450
+ it("accepts parameterized event-stream content types", async () => {
451
+ const event: AdkEvent = { id: "e1" };
418
452
  mockFetch.mockResolvedValueOnce(
419
- new Response(sseBody(text), { status: 200 }),
453
+ sseResponse(
454
+ sseBody(`data: ${JSON.stringify(event)}\n\n`),
455
+ "Text/Event-Stream; charset=utf-8",
456
+ ),
457
+ );
458
+
459
+ const stream = createAdkStream({ api: "/api/adk" });
460
+ const gen = await stream(
461
+ [{ id: "m1", type: "human", content: "Hi" }],
462
+ makeConfig(),
420
463
  );
464
+ const collected: AdkEvent[] = [];
465
+ for await (const value of gen) collected.push(value);
466
+
467
+ expect(collected).toEqual([event]);
468
+ });
469
+
470
+ it("skips :ok SSE comments", async () => {
471
+ const text = `:ok\n\ndata: ${JSON.stringify({ id: "e1" })}\n\n`;
472
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(text)));
421
473
 
422
474
  const stream = createAdkStream({ api: "/api/adk" });
423
475
  const gen = await stream(
@@ -435,9 +487,7 @@ describe("createAdkStream - SSE parsing", () => {
435
487
 
436
488
  it("parses data fields without a space after the colon", async () => {
437
489
  const text = `data:${JSON.stringify({ id: "e1" })}\n\n`;
438
- mockFetch.mockResolvedValueOnce(
439
- new Response(sseBody(text), { status: 200 }),
440
- );
490
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(text)));
441
491
 
442
492
  const stream = createAdkStream({ api: "/api/adk" });
443
493
  const gen = await stream(
@@ -456,9 +506,7 @@ describe("createAdkStream - SSE parsing", () => {
456
506
  it("parses CR-delimited SSE events", async () => {
457
507
  const events: AdkEvent[] = [{ id: "e1" }, { id: "e2" }];
458
508
  const text = events.map((e) => `data: ${JSON.stringify(e)}\r\r`).join("");
459
- mockFetch.mockResolvedValueOnce(
460
- new Response(sseBody(text), { status: 200 }),
461
- );
509
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(text)));
462
510
 
463
511
  const stream = createAdkStream({ api: "/api/adk" });
464
512
  const gen = await stream(
@@ -483,7 +531,7 @@ describe("createAdkStream - SSE parsing", () => {
483
531
  controller = nextController;
484
532
  },
485
533
  });
486
- mockFetch.mockResolvedValueOnce(new Response(body, { status: 200 }));
534
+ mockFetch.mockResolvedValueOnce(sseResponse(body));
487
535
 
488
536
  const stream = createAdkStream({ api: "/api/adk" });
489
537
  const gen = await stream(
@@ -520,7 +568,7 @@ describe("createAdkStream - SSE parsing", () => {
520
568
  controller.close();
521
569
  },
522
570
  });
523
- mockFetch.mockResolvedValueOnce(new Response(body, { status: 200 }));
571
+ mockFetch.mockResolvedValueOnce(sseResponse(body));
524
572
 
525
573
  const stream = createAdkStream({ api: "/api/adk" });
526
574
  const gen = await stream(
@@ -547,7 +595,7 @@ describe("createAdkStream - SSE parsing", () => {
547
595
  controller.close();
548
596
  },
549
597
  });
550
- mockFetch.mockResolvedValueOnce(new Response(body, { status: 200 }));
598
+ mockFetch.mockResolvedValueOnce(sseResponse(body));
551
599
 
552
600
  const stream = createAdkStream({ api: "/api/adk" });
553
601
  const gen = await stream(
@@ -567,9 +615,7 @@ describe("createAdkStream - SSE parsing", () => {
567
615
  // No trailing \n\n
568
616
  const event = { id: "e1" };
569
617
  const text = `data: ${JSON.stringify(event)}\n`;
570
- mockFetch.mockResolvedValueOnce(
571
- new Response(sseBody(text), { status: 200 }),
572
- );
618
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(text)));
573
619
 
574
620
  const stream = createAdkStream({ api: "/api/adk" });
575
621
  const gen = await stream(
@@ -605,13 +651,57 @@ describe("createAdkStream - error handling", () => {
605
651
  }
606
652
  }).rejects.toThrow("ADK request failed: 404 Not Found");
607
653
  });
654
+
655
+ it("rejects successful HTML responses and cancels their body", async () => {
656
+ const cancelBody = vi.fn();
657
+ const body = new ReadableStream<Uint8Array>({
658
+ start(controller) {
659
+ controller.enqueue(new TextEncoder().encode("<html>Sign in</html>"));
660
+ },
661
+ cancel: cancelBody,
662
+ });
663
+ mockFetch.mockResolvedValueOnce(
664
+ sseResponse(body, "text/html; charset=utf-8"),
665
+ );
666
+
667
+ const stream = createAdkStream({ api: "/api/adk" });
668
+ await expect(async () => {
669
+ const gen = await stream(
670
+ [{ id: "m1", type: "human", content: "Hi" }],
671
+ makeConfig(),
672
+ );
673
+ for await (const _ of gen) {
674
+ /* noop */
675
+ }
676
+ }).rejects.toThrow(
677
+ 'Expected ADK stream response Content-Type "text/event-stream", received "text/html; charset=utf-8"',
678
+ );
679
+ expect(cancelBody).toHaveBeenCalledOnce();
680
+ });
681
+
682
+ it("rejects successful responses without a content type", async () => {
683
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody(""), null));
684
+
685
+ const stream = createAdkStream({ api: "/api/adk" });
686
+ await expect(async () => {
687
+ const gen = await stream(
688
+ [{ id: "m1", type: "human", content: "Hi" }],
689
+ makeConfig(),
690
+ );
691
+ for await (const _ of gen) {
692
+ /* noop */
693
+ }
694
+ }).rejects.toThrow(
695
+ 'Expected ADK stream response Content-Type "text/event-stream", received no Content-Type header',
696
+ );
697
+ });
608
698
  });
609
699
 
610
700
  // ── Headers ──
611
701
 
612
702
  describe("createAdkStream - headers", () => {
613
703
  it("sends static headers", async () => {
614
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
704
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
615
705
 
616
706
  const stream = createAdkStream({
617
707
  api: "/api/adk",
@@ -633,30 +723,8 @@ describe("createAdkStream - headers", () => {
633
723
  expect(headers["Content-Type"]).toBe("application/json");
634
724
  });
635
725
 
636
- it("resolves dynamic headers from a function", async () => {
637
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
638
-
639
- const stream = createAdkStream({
640
- api: "/api/adk",
641
- headers: () => ({ "X-Custom": "dynamic" }),
642
- });
643
- const gen = await stream(
644
- [{ id: "m1", type: "human", content: "Hi" }],
645
- makeConfig(),
646
- );
647
- for await (const _ of gen) {
648
- /* noop */
649
- }
650
-
651
- const headers = mockFetch.mock.calls[0]![1]?.headers as Record<
652
- string,
653
- string
654
- >;
655
- expect(headers["X-Custom"]).toBe("dynamic");
656
- });
657
-
658
726
  it("resolves async dynamic headers", async () => {
659
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
727
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
660
728
 
661
729
  const stream = createAdkStream({
662
730
  api: "/api/adk",
@@ -678,7 +746,7 @@ describe("createAdkStream - headers", () => {
678
746
  });
679
747
 
680
748
  it("sends no extra headers when headers option is undefined", async () => {
681
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
749
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
682
750
 
683
751
  const stream = createAdkStream({ api: "/api/adk" });
684
752
  const gen = await stream(
@@ -701,7 +769,7 @@ describe("createAdkStream - headers", () => {
701
769
 
702
770
  describe("createAdkStream - AbortSignal", () => {
703
771
  it("forwards the AbortSignal to fetch", async () => {
704
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
772
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
705
773
 
706
774
  const controller = new AbortController();
707
775
  const stream = createAdkStream({ api: "/api/adk" });
@@ -721,7 +789,7 @@ describe("createAdkStream - AbortSignal", () => {
721
789
 
722
790
  describe("createAdkStream - content conversion", () => {
723
791
  it("converts reasoning content parts to thought parts in direct mode", async () => {
724
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
792
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
725
793
 
726
794
  const stream = createAdkStream({
727
795
  api: "http://localhost:8000",
@@ -748,7 +816,7 @@ describe("createAdkStream - content conversion", () => {
748
816
  });
749
817
 
750
818
  it("converts image_url content parts to fileData in direct mode", async () => {
751
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
819
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
752
820
 
753
821
  const stream = createAdkStream({
754
822
  api: "http://localhost:8000",
@@ -774,7 +842,7 @@ describe("createAdkStream - content conversion", () => {
774
842
  });
775
843
 
776
844
  it("converts file content parts to inlineData in direct mode", async () => {
777
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
845
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
778
846
 
779
847
  const stream = createAdkStream({
780
848
  api: "http://localhost:8000",
@@ -807,7 +875,7 @@ describe("createAdkStream - content conversion", () => {
807
875
  });
808
876
 
809
877
  it("converts file_url content parts to fileData with mimeType in direct mode", async () => {
810
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
878
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
811
879
 
812
880
  const stream = createAdkStream({
813
881
  api: "http://localhost:8000",
@@ -842,7 +910,7 @@ describe("createAdkStream - content conversion", () => {
842
910
  });
843
911
 
844
912
  it("converts code content parts to executableCode", async () => {
845
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
913
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
846
914
 
847
915
  const stream = createAdkStream({
848
916
  api: "http://localhost:8000",
@@ -868,7 +936,7 @@ describe("createAdkStream - content conversion", () => {
868
936
  });
869
937
 
870
938
  it("converts code_result content parts to codeExecutionResult", async () => {
871
- mockFetch.mockResolvedValueOnce(new Response(sseBody(""), { status: 200 }));
939
+ mockFetch.mockResolvedValueOnce(sseResponse(sseBody("")));
872
940
 
873
941
  const stream = createAdkStream({
874
942
  api: "http://localhost:8000",
package/src/AdkClient.ts CHANGED
@@ -60,7 +60,18 @@ export type CreateAdkStreamOptions = {
60
60
  export function createAdkStream(
61
61
  options: CreateAdkStreamOptions,
62
62
  ): AdkStreamCallback {
63
+ if (options.appName === "") {
64
+ throw new Error(
65
+ 'createAdkStream direct mode requires a non-empty "appName".',
66
+ );
67
+ }
68
+
63
69
  const isDirect = options.appName != null;
70
+ if (isDirect && (options.userId == null || options.userId === "")) {
71
+ throw new Error(
72
+ 'createAdkStream direct mode requires "userId" when "appName" is provided.',
73
+ );
74
+ }
64
75
 
65
76
  return async function* (messages, config) {
66
77
  const headers = await resolveHeaders(options.headers);
@@ -99,12 +110,27 @@ export function createAdkStream(
99
110
  );
100
111
  }
101
112
 
113
+ validateEventStreamContentType(response);
102
114
  yield* parseSSEResponse(response);
103
115
  };
104
116
  }
105
117
 
106
118
  // ── Internal helpers ──
107
119
 
120
+ function validateEventStreamContentType(response: Response): void {
121
+ const contentType = response.headers.get("Content-Type");
122
+ const mediaType = contentType?.split(";", 1)[0]?.trim().toLowerCase();
123
+ if (mediaType !== "text/event-stream") {
124
+ const received = contentType
125
+ ? `"${contentType}"`
126
+ : "no Content-Type header";
127
+ void response.body?.cancel().catch(() => undefined);
128
+ throw new Error(
129
+ `Expected ADK stream response Content-Type "text/event-stream", received ${received}`,
130
+ );
131
+ }
132
+ }
133
+
108
134
  async function resolveHeaders(
109
135
  headers:
110
136
  | Record<string, string>
@@ -452,13 +452,6 @@ describe("AdkEventAccumulator - HITL requires-action", () => {
452
452
  expect(aiMsg.status).toBeUndefined();
453
453
  });
454
454
 
455
- it("matches tool call id to the longRunningToolIds entry", () => {
456
- const acc = new AdkEventAccumulator();
457
- const msgs = acc.processEvent(makeHitlEvent("tc-1"));
458
- const aiMsg = msgs[0] as AdkMessage & { type: "ai" };
459
- expect(aiMsg.tool_calls![0]!.id).toBe("tc-1");
460
- });
461
-
462
455
  it("stays pending across a subsequent bookkeeping event", () => {
463
456
  const acc = new AdkEventAccumulator();
464
457
  acc.processEvent(makeHitlEvent("tc-1", { author: "WorkflowA" }));
@@ -480,35 +473,6 @@ describe("AdkEventAccumulator - HITL requires-action", () => {
480
473
  expect(aiMsg!.status).toBeUndefined();
481
474
  });
482
475
 
483
- it("assigns manual complete status on non-HITL final event", () => {
484
- const acc = new AdkEventAccumulator();
485
- const msgs = acc.processEvent(
486
- makeEvent({
487
- author: "agent",
488
- content: { role: "model", parts: [{ text: "Done." }] },
489
- }),
490
- );
491
-
492
- expect(msgs[0]).toMatchObject({
493
- status: { type: "complete", reason: "stop" },
494
- });
495
- });
496
-
497
- it("assigns manual complete status on skipSummarization final event", () => {
498
- const acc = new AdkEventAccumulator();
499
- const msgs = acc.processEvent(
500
- makeEvent({
501
- author: "agent",
502
- actions: { skipSummarization: true },
503
- content: { role: "model", parts: [{ text: "skipped" }] },
504
- }),
505
- );
506
-
507
- expect(msgs[0]).toMatchObject({
508
- status: { type: "complete", reason: "stop" },
509
- });
510
- });
511
-
512
476
  it("prioritizes skipSummarization over longRunningToolIds", () => {
513
477
  const acc = new AdkEventAccumulator();
514
478
  const msgs = acc.processEvent(