Add AI Elements-inspired chat primitives

This commit is contained in:
Matthias
2026-06-16 10:42:19 +02:00
parent 76b73ddb76
commit 28d0f4f852
5 changed files with 367 additions and 58 deletions

View File

@@ -0,0 +1,113 @@
import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, test } from "vitest";
import {
AgentConversation,
AgentMessage,
AgentPromptInput,
type AgentChatMessage,
} from "./AgentChat";
import { getToolTraceSummary } from "./agentChatModel";
const assistantMessage: AgentChatMessage = {
id: "assistant-1",
role: "assistant",
content: "Deine groesste Ausgabe war Miete.",
toolTrace: [
{
name: "summarize_transactions",
inputSummary: "Mai 2026",
resultSummary: "12 Umsaetze zusammengefasst",
},
{
name: "list_transactions",
inputSummary: "Miete",
resultSummary: "1 Treffer",
},
],
};
describe("AgentChat phase 1 components", () => {
test("summarizes tool traces for compact agent transparency", () => {
expect(getToolTraceSummary(undefined)).toBe("Keine Werkzeuge");
expect(getToolTraceSummary([])).toBe("Keine Werkzeuge");
expect(getToolTraceSummary(assistantMessage.toolTrace)).toBe("2 Werkzeuge verwendet");
});
test("renders conversation messages with assistant tool trace details", () => {
const markup = renderToStaticMarkup(
<AgentConversation
messages={[
{ id: "user-1", role: "user", content: "Was war teuer?" },
assistantMessage,
]}
/>,
);
expect(markup).toContain("Was war teuer?");
expect(markup).toContain("Deine groesste Ausgabe war Miete.");
expect(markup).toContain("2 Werkzeuge verwendet");
expect(markup).toContain("summarize_transactions");
expect(markup).toContain("12 Umsaetze zusammengefasst");
});
test("renders the prompt input with ready and busy states", () => {
const readyMarkup = renderToStaticMarkup(
<AgentPromptInput
value="Bitte analysieren"
disabled={false}
isSubmitting={false}
placeholder="Welche Auswertung soll ich machen?"
onChange={() => undefined}
onSubmit={() => undefined}
/>,
);
const busyMarkup = renderToStaticMarkup(
<AgentPromptInput
value="Bitte analysieren"
disabled
isSubmitting
placeholder="Chat wird vorbereitet..."
onChange={() => undefined}
onSubmit={() => undefined}
/>,
);
expect(readyMarkup).toContain("Welche Auswertung soll ich machen?");
expect(readyMarkup).toContain("Senden");
expect(busyMarkup).toContain("Antwort laeuft");
expect(busyMarkup).toContain("disabled");
});
test("disables prompt submit for whitespace-only input", () => {
const markup = renderToStaticMarkup(
<AgentPromptInput
value=" "
disabled={false}
isSubmitting={false}
placeholder="Welche Auswertung soll ich machen?"
onChange={() => undefined}
onSubmit={() => undefined}
/>,
);
expect(markup).toContain("disabled");
});
test("renders a thinking indicator while the agent is submitting", () => {
const markup = renderToStaticMarkup(
<AgentConversation messages={[assistantMessage]} isSubmitting />,
);
expect(markup).toContain("Denk mit der KI nach...");
});
test("renders a single message without a tool section when no trace exists", () => {
const markup = renderToStaticMarkup(
<AgentMessage message={{ id: "assistant-empty", role: "assistant", content: "Hallo" }} />,
);
expect(markup).toContain("Assistant");
expect(markup).toContain("Hallo");
expect(markup).not.toContain("Werkzeuge verwendet");
});
});