diff options
| author | Adam Malczewski <[email protected]> | 2026-06-07 16:22:31 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-07 16:22:31 +0900 |
| commit | 17bc0a2cdaeefd4974f785c907d3515a38d45363 (patch) | |
| tree | 1834867d2f0ad5e82fbb985d7f602d8e1dffdb42 /src/features/chat/ui.test.ts | |
| parent | 635cb6de7342ac87b27243652b1ad3b3a133d6a4 (diff) | |
| download | dispatch-web-17bc0a2cdaeefd4974f785c907d3515a38d45363.tar.gz dispatch-web-17bc0a2cdaeefd4974f785c907d3515a38d45363.zip | |
feat(chat): group batched tool calls into one DaisyUI list
Consume the backend's new stepId grouping key (wire/transport-contract
0.1.0 -> 0.2.0). foldEvent copies event.stepId onto live tool chunks so
live and replay group identically. New pure selector groupRenderedChunks
(core/chunks) folds a step's 2+ tool calls into one tool-batch group,
pairing each call with its result by toolCallId; single/no-stepId calls
stay as cards. ChatView renders a batch as a DaisyUI list (list-row per
pair). Fixtures updated for the now-required event stepId.
Diffstat (limited to 'src/features/chat/ui.test.ts')
| -rw-r--r-- | src/features/chat/ui.test.ts | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/features/chat/ui.test.ts b/src/features/chat/ui.test.ts index 2099257..43822a7 100644 --- a/src/features/chat/ui.test.ts +++ b/src/features/chat/ui.test.ts @@ -1,3 +1,4 @@ +import type { StepId } from "@dispatch/wire"; import { render, screen } from "@testing-library/svelte"; import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi } from "vitest"; @@ -158,6 +159,61 @@ describe("ChatView", () => { expect(log.children).toHaveLength(0); }); + it("groups batched tool calls (shared stepId) into one DaisyUI list", () => { + const chunks: RenderedChunk[] = [ + { + seq: 1, + role: "assistant", + chunk: { + type: "tool-call", + toolCallId: "a", + toolName: "read_file", + input: { path: "/a" }, + stepId: "t1#0" as StepId, + }, + provisional: false, + }, + { + seq: 2, + role: "assistant", + chunk: { + type: "tool-call", + toolCallId: "b", + toolName: "list_dir", + input: { path: "/b" }, + stepId: "t1#0" as StepId, + }, + provisional: false, + }, + { + seq: 3, + role: "tool", + chunk: { + type: "tool-result", + toolCallId: "a", + toolName: "read_file", + content: "contents-of-a", + isError: false, + stepId: "t1#0" as StepId, + }, + provisional: false, + }, + ]; + + const { container } = render(ChatView, { props: { chunks } }); + + // One DaisyUI list with two rows (one per call), not separate cards. + const lists = container.querySelectorAll("ul.list"); + expect(lists).toHaveLength(1); + expect(container.querySelectorAll("ul.list > li.list-row")).toHaveLength(2); + + // Both call names + the available result are shown; the result is absorbed + // (no standalone tool-result card). + expect(screen.getByText("read_file")).toBeInTheDocument(); + expect(screen.getByText("list_dir")).toBeInTheDocument(); + expect(screen.getByText("contents-of-a")).toBeInTheDocument(); + }); + it("thinking <details> stays open across a streaming update", async () => { const initial: RenderedChunk[] = [ { |
