# Tool Call UI für KI-Agenten: Schritte, Freigaben, Fehler

> So baust du eine Tool Call UI für KI-Agenten in React: Status für Warten, Laufen, Fehler und Freigabe, lesbare Ein- und Ausgaben, Anbindung ans AI SDK.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 16. Okt. 2026
- Kategorie: [UI mit KI-Agenten bauen](https://wingo-ui.com/de/blog/category/ai-agents)
- Lesezeit: 11 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/ai-agent-tool-call-ui
- Englische Fassung: https://wingo-ui.com/blog/ai-agent-tool-call-ui

## Kurz gesagt

Eine gute Tool Call UI für KI-Agenten zeigt jeden Aufruf als eine Zeile mit Status (in der Warteschlange, läuft, fertig, fehlgeschlagen, wartet auf Freigabe), einem verständlichen Titel, der ID des Tools, der Dauer und auf Wunsch der Ein- und Ausgabe als lesbares JSON. Fehlgeschlagene Aufrufe klappen von selbst auf und zeigen ihren Fehler, Aufrufe, die einen Menschen brauchen, zeigen Approve und Reject direkt neben genau den Argumenten, mit denen das Tool laufen wird, und Screenreader hören jede Statusänderung genau einmal. Bilde die Zustände deiner AI SDK Tool Parts auf diese Status ab, dann funktionieren dieselben Zeilen in einer Chat-Nachricht, einem Seitenpanel oder auf einer Agent-Seite.

Eine Tool Call UI für KI-Agenten hat genau eine Aufgabe: Wer davor sitzt, soll Schritt für Schritt sehen, was der Agent getan hat, und eingreifen können, wenn es darauf ankommt. Die meisten ersten Versionen scheitern an denselben Stellen. Ein laufender Aufruf rendert nichts, also sieht der Bildschirm untätig aus, während der Agent arbeitet. Ein fehlgeschlagener Aufruf verschwindet hinter einem nichtssagenden „Something went wrong“. Eine Freigabe fragt „E-Mail senden?“, ohne die Adresse zu zeigen, an die sie geht. Dieser Guide zeigt, welche Zustände eine Tool Call UI braucht, wie Ein- und Ausgaben lesbar werden, wie du Freigaben mit dem AI SDK verbindest und wohin die Zeilen gehören: in einen Chat, ein Seitenpanel oder auf eine Agent-Seite. Die Beispiele nutzen die Agent-Komponenten von Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral; Fakten von außen verlinken auf ihre Quellen.

## Welche Zustände braucht ein Tool Call bei KI-Agenten?

Sechs: in der Warteschlange, läuft, fertig, fehlgeschlagen, abgebrochen und wartet auf Freigabe. Jeder Zustand braucht eine eigene Darstellung, denn wer einen Lauf überfliegt, liest zuerst die Markierungen und erst dann den Text.

Wenn du das AI SDK nutzt, haben seine Tool Parts schon einen `state`. Die [Doku zur Tool-Nutzung im Chatbot](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-tool-usage) nennt `input-streaming`, `input-available`, `approval-requested`, `approval-responded`, `output-available`, `output-error` und `output-denied` (Stand Oktober 2026). So bildest du sie auf das ab, was eine Person sehen soll:

| Zustand im AI SDK | Status | Was die Zeile zeigt |
|---|---|---|
| `input-streaming` | `pending` | einen gestrichelten Ring, „Queued“ |
| `input-available` | `running` | einen Spinner, einen schimmernden Titel, eine mitlaufende Zeit |
| `approval-requested` | `awaiting-approval` | eine pulsierende Hand, „Needs approval“, Reject und Approve |
| `approval-responded` (freigegeben) | `running` | wieder den Spinner, während das Tool läuft |
| `output-available` | `complete` | einen Haken, der einmal aufploppt, die endgültige Zeit |
| `output-error` | `error` | ein Kreuz, die Zeile aufgeklappt mit ihrem Fehler, Retry, wenn du `onRetry` übergibst |
| `output-denied` | `canceled` | eine graue Markierung, „Canceled“ |

Die mittlere Spalte ist der Typ `ToolCallStatus` aus `lib/ai-chat`, den sich [Tool Call Timeline](https://wingo-ui.com/components/tool-call-timeline) und [Agent Status Card](https://wingo-ui.com/components/agent-status-card) teilen. Die Farben der Markierungen hängen nur vom Status ab, die Prop `tone` färbt also nur den Approve-Button und den Header. Läuft ist Info-Blau, fertig ist Grün, fehlgeschlagen ist Rot und wartend ist Amber.

Zwei Regeln sorgen dafür, dass diese Zustände in jeder Tool Call UI in React funktionieren. Zeig einen laufenden Aufruf, sobald seine Eingabe ankommt, damit echte Arbeit nie wie ein eingefrorener Bildschirm aussieht. Und lass fehlgeschlagene Aufrufe mit ihrem Fehler in der Liste, denn ein Fehler, der verschwindet, ist am schwersten zu debuggen.

## Wie werden Ein- und Ausgaben von Tools lesbar?

Stell einen verständlichen Titel nach vorn, halte die ID des Tools nur einen Tipp entfernt und zeig das JSON erst, wenn jemand danach fragt.

In der Demo unten liest sich jede Zeile der Timeline wie ein Satz: „Finding overdue invoices“, dann `search_invoices` in einem kleinen Mono-Chip, dann „0.8 s“. Klick oder tipp auf die Zeile (oder drück darauf Enter oder die Leertaste), und sie klappt auf: Du siehst die Eingabe, die das Modell geschickt hat, und die Ausgabe, die das Tool zurückgegeben hat, als JSON mit Syntax-Highlighting. Textergebnisse brechen um, statt als ein einziger langer String durchzulaufen. Jeder Block hat einen Kopier-Button, und ein Block, der höher als `codeMaxHeight` ist (standardmäßig 240px), scrollt in sich selbst. So schiebt eine Antwort mit 200 Zeilen den Rest des Laufs nicht aus dem Bild.

Wenn JSON die falsche Ansicht ist, tausch sie aus. `renderOutput` und `renderInput` bekommen den Aufruf und geben einen beliebigen React-Node zurück: Rechnungen als kleine Tabelle, einen E-Mail-Entwurf als Text, eine Karte. Gib `undefined` zurück, um das JSON zu behalten, und `null`, um den Abschnitt auszublenden.

> Live-Demo (Tool Call Timeline): Sieh zu, wie der Agent Rechnungen findet, Kontakte abruft und die E-Mail entwirft und dann bei Sending the email anhält. Klapp eine Zeile auf, um ihre Ein- und Ausgabe zu lesen, und drück dann Approve oder Reject. Probier sie unter [Tool Call Timeline](https://wingo-ui.com/components/tool-call-timeline) aus und installier sie mit `npx wingo-ui@latest add tool-call-timeline`.

Hinter jeder Zeile stehen einfache Daten:

```ts
import type { ToolCall } from "@/components/ui/tool-call-timeline";

export const search: ToolCall = {
  id: "call-search",
  name: "search_invoices",
  title: "Überfällige Rechnungen suchen",
  status: "complete",
  input: { status: "overdue", dueFrom: "2026-09-01", dueTo: "2026-09-24" },
  output: { total: 3, sum: 22775.95, currency: "USD" },
  durationMs: 820,
};
```

`startedAt` und `endedAt` funktionieren auch; `durationMs` hat Vorrang, wenn dein Server den Aufruf schon gemessen hat. `steps` enthält Unterschritte, die eingerückt unter ihrem übergeordneten Schritt erscheinen, und `logs` enthält einfache Logzeilen.

## Wie baust du eine Tool Call UI in React mit dem AI SDK?

Wandle die Tool Parts jeder Assistant-Nachricht in `ToolCall`-Objekte um, gib sie an die Timeline weiter und schick Freigaben mit `addToolApprovalResponse` zurück. Mehr als diesen Adapter braucht eine AI SDK Tool UI zusätzlich zur Komponente nicht.

```bash
npx wingo-ui@latest add tool-call-timeline
```

Der Adapter trennt das AI SDK sauber von der Komponente. Der strukturelle Typ `ToolPart` macht ihn unabhängig von deinen Tool-Definitionen:

```ts
// lib/agent-tool-calls.ts
import type { UIMessage } from "ai";
import type { ToolCall, ToolCallStatus } from "@/components/ui/tool-call-timeline";

type ToolPart = {
  type: string;
  toolCallId: string;
  toolName?: string;
  state: string;
  input?: unknown;
  output?: unknown;
  errorText?: string;
  approval?: { id: string; approved?: boolean; isAutomatic?: boolean };
};

const STATUS: Record<string, ToolCallStatus> = {
  "input-streaming": "pending",
  "input-available": "running",
  "approval-requested": "awaiting-approval",
  "approval-responded": "running",
  "output-available": "complete",
  "output-error": "error",
  "output-denied": "canceled",
};

// was die Leute lesen; die Tool-ID bleibt im Chip
const TITLES: Record<string, string> = {
  searchInvoices: "Überfällige Rechnungen suchen",
  sendEmail: "E-Mail senden",
};

function toolParts(message: UIMessage): ToolPart[] {
  return message.parts
    .filter((part) => part.type.startsWith("tool-") || part.type === "dynamic-tool")
    .map((part) => part as unknown as ToolPart);
}

export function toToolCalls(message: UIMessage): ToolCall[] {
  return toolParts(message).map((part) => {
    const name = part.type === "dynamic-tool" ? (part.toolName ?? "tool") : part.type.slice(5);
    const denied = part.state === "approval-responded" && part.approval?.approved === false;
    // eine serverseitige Regel hat entschieden: es gibt nichts zu klicken
    const automatic = part.state === "approval-requested" && part.approval?.isAutomatic === true;
    return {
      id: part.toolCallId,
      name,
      title: TITLES[name],
      status: denied ? "canceled" : automatic ? "running" : (STATUS[part.state] ?? "pending"),
      input: part.input,
      output: part.output,
      error: part.errorText,
    };
  });
}

export function approvalIdFor(message: UIMessage, callId: string): string | undefined {
  return toolParts(message).find((part) => part.toolCallId === callId)?.approval?.id;
}
```

Dann renderst du eine Timeline pro Assistant-Nachricht:

```tsx
// app/agent/agent-run.tsx
"use client";

import { useMemo } from "react";
import { useChat } from "@ai-sdk/react";
import { lastAssistantMessageIsCompleteWithApprovalResponses, type UIMessage } from "ai";
import { ToolCallTimeline, type ToolCall } from "@/components/ui/tool-call-timeline";
import { approvalIdFor, toToolCalls } from "@/lib/agent-tool-calls";

function RunSteps({
  message,
  respond,
}: {
  message: UIMessage;
  respond: (call: ToolCall, approved: boolean) => void;
}) {
  const calls = useMemo(() => toToolCalls(message), [message]);
  if (calls.length === 0) return null;
  return (
    <ToolCallTimeline
      variant="card"
      title="Inkasso-Agent"
      calls={calls}
      onApprove={(call) => respond(call, true)}
      onReject={(call) => respond(call, false)}
      locale="en-US"
    />
  );
}

export function AgentRun() {
  const { messages, addToolApprovalResponse } = useChat({
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithApprovalResponses,
  });

  return (
    <div className="flex flex-col gap-4">
      {messages
        .filter((message) => message.role === "assistant")
        .map((message) => (
          <RunSteps
            key={message.id}
            message={message}
            respond={(call, approved) => {
              const id = approvalIdFor(message, call.id);
              if (id) addToolApprovalResponse({ id, approved });
            }}
          />
        ))}
    </div>
  );
}
```

`useChat` liefert für die Nachricht, die gerade streamt, ein neues Objekt. `useMemo` baut also nur die Aufrufe dieser einen Nachricht neu auf, ältere Läufe behalten ihre. Dein Chat-Eingabefeld bleibt, wie es ist. Die Freigabe-Schranke ergänzt der Route Handler im nächsten Abschnitt.

Ein Stolperstein: Ein `approval-requested`-Part ist nicht immer eine Frage an einen Menschen. Wenn eine serverseitige Regel einen Aufruf selbst freigibt oder ablehnt, setzt das AI SDK `approval.isAutomatic` auf `true` und erwartet keine Antwort. Der Adapter zeigt solche Aufrufe als laufend, damit niemand Approve- und Reject-Buttons sieht, die nichts bewirken.

## Wie sollte eine Human-in-the-Loop-Freigabe funktionieren?

Halte vor dem Seiteneffekt an, zeig genau die Argumente, mit denen das Tool laufen wird, und mach die Entscheidung mit einem Tipp möglich. Eine Freigabe-UI für Human in the Loop, die die Eingabe versteckt, lässt Leute etwas freigeben, das sie nicht sehen können.

Auf dem Server gehört die Schranke an `streamText`. Laut der [Doku zur Tool-Nutzung im Chatbot](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot-tool-usage) setzt du ein Tool in der Option `toolApproval` auf `"user-approval"`; die ältere Tool-Eigenschaft `needsApproval` ist dort als veraltet markiert (Stand Oktober 2026). Die [Referenz zu streamText](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) erlaubt pro Tool auch eine Funktion, die die Eingabe bekommt, sodass nur riskante Aufrufe anhalten. Das Tool behält sein `execute`; das SDK wartet auf die Antwort, bevor es das Tool ausführt:

```ts
// lib/agent-tools.ts
import { tool } from "ai";
import { z } from "zod";
import { invoices } from "@/lib/invoices"; // deine Datenschicht
import { mailer } from "@/lib/mailer"; // dein Mail-Client

export const searchInvoices = tool({
  description: "Find invoices by status and due date",
  inputSchema: z.object({ status: z.enum(["open", "overdue", "paid"]), dueFrom: z.string(), dueTo: z.string() }),
  execute: async (input) => invoices.search(input),
});

export const sendEmail = tool({
  description: "Send a payment reminder to a client",
  inputSchema: z.object({ to: z.string().email(), subject: z.string() }),
  execute: async ({ to, subject }) => mailer.send({ to, subject }),
});
```

```ts
// app/api/chat/route.ts
import { convertToModelMessages, streamText, type UIMessage } from "ai";
import { model } from "@/lib/ai"; // das Modell deines Providers
import { searchInvoices, sendEmail } from "@/lib/agent-tools";

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model,
    system: "When a tool execution is not approved by the user, do not retry it.",
    messages: await convertToModelMessages(messages),
    tools: { searchInvoices, sendEmail },
    toolApproval: { sendEmail: "user-approval" },
  });

  return result.toUIMessageStreamResponse();
}
```

Das [Human-in-the-Loop-Rezept des AI SDK](https://ai-sdk.dev/cookbook/next/human-in-the-loop) setzt noch `needsApproval: true` direkt am Tool. Beide Wege erzeugen dieselben `approval-requested`-Parts, der Client-Code oben ändert sich also nicht, und laut der Referenz zu streamText hat `toolApproval` Vorrang, wenn beides gesetzt ist. Die Schlüssel der Tools werden zu Part-Typen (`tool-sendEmail`). Deshalb nutzt die `TITLES`-Map im Adapter dieselben camelCase-Namen.

Im Client zeigt ein Aufruf mit dem Status `awaiting-approval` Reject und Approve unter seinem Titel, und wer die Zeile aufklappt, sieht die Argumente direkt darüber. Sollen wartende Aufrufe von selbst aufklappen, steuerst du `expandedKeys` und ergänzt ihre IDs, sobald sie ankommen. Gibt `onApprove` ein Promise zurück, zeigt Approve einen Spinner und Reject bleibt deaktiviert, bis das Promise erledigt ist. Verschwinden die Buttons, springt der Fokus zurück auf die Zeile, damit niemand, der mit der Tastatur arbeitet, auf dem Body der Seite landet. Auf dem Smartphone sind die beiden Buttons 44px hoch und teilen sich die Breite der Zeile.

Ablehnen ist ein echtes Ergebnis. Zeig den Aufruf als `canceled` (der Adapter oben erkennt das an `approval.approved === false`). Lass die `system`-Zeile in der Route oben stehen: Das Rezept des AI SDK ergänzt diese Anweisung, damit das Modell einen abgelehnten Aufruf nicht wiederholt und der Person nicht zweimal dieselbe Frage stellt.

## Wohin gehören Tool Calls: in eine Chat-Nachricht, ein Panel oder eine Agent-Seite?

An alle drei Orte, jeweils mit einer anderen Variante.

- **In einer Chat-Nachricht** nimmst du `variant="inline"`: eine einzeilige Zusammenfassung wie „Used 4 tools, 2.8 s“, die aufklappt, solange ein Aufruf läuft oder auf Freigabe wartet, und 1,2 s nach dem Ende aller Aufrufe wieder zuklappt. Sie bleibt offen, wenn die Person sie selbst geöffnet hat oder der Fokus darin liegt. [Chat Message](https://wingo-ui.com/components/chat-message) rendert das von selbst, wenn die Nachricht `toolCalls` hat, und `toolCallProps` reicht `onApprove` und den Rest durch.
- **In einem Seitenpanel** nimmst du `variant="timeline"` mit `size="sm"`. Die Zeilen richten ihr Layout nach ihrer eigenen Breite, in einer schmalen Spalte rutscht die Tool-ID also unter den Titel.
- **Auf einer Agent-Seite** nimmst du `variant="card"`. Der Header zeigt den Zustand des Laufs in Worten, während des Laufs den Fortschritt („2 of 5 done“), die Gesamtzeit und einen Button, der alle Zeilen auf- oder zuklappt.

## Wie zeigst du den Gesamtstatus eines Agent-Laufs?

Setz eine Statuskarte über die Timeline mit den Agent-Schritten. Läuft ein Agent im Hintergrund, wollen die Leute wissen, ob er noch arbeitet, bevor sie überhaupt eine Zeile aufklappen.

[Agent Status Card](https://wingo-ui.com/components/agent-status-card) nimmt dasselbe `ToolCall[]` als `steps` und leitet daraus den Fortschritt („Step 3 of 5“), den aktuellen Schritt und die verstrichene Zeit ab. Es erscheinen nur die Bedienelemente, die gerade gebraucht werden: Pause und Stop, solange der Agent läuft, Approve und Reject in einer bernsteinfarbenen Box, solange er wartet, Retry in einer roten Box, wenn er fehlgeschlagen ist, und View result, wenn er fertig ist. Stop fragt vorher in einem Dialog nach, mounte deshalb einmal `AlertDialogProvider`.

```tsx
import { AlertDialogProvider } from "@/components/ui/alert-dialog";
import { AgentStatusCard, type ToolCall } from "@/components/ui/agent-status-card";

export function CollectionsAgent({ steps, onPause, onStop }: {
  steps: ToolCall[];
  onPause: () => Promise<void>;
  onStop: () => Promise<void>;
}) {
  return (
    <>
      <AlertDialogProvider />
      <AgentStatusCard
        name="Inkasso-Agent"
        task="Erinnerungen für die überfälligen Rechnungen aus dem September"
        status="running"
        steps={steps}
        startedAt={new Date(2026, 8, 24, 16, 38, 2)}
        logs={[]}
        onPause={onPause}
        onStop={onStop}
      />
    </>
  );
}
```

> Live-Demo (Agent Status Card): Der Lauf geht Schritt für Schritt weiter. Öffne Steps und Logs, drück Pause und probier dann Stop, um den Bestätigungsdialog zu sehen. Probier sie unter [Agent Status Card](https://wingo-ui.com/components/agent-status-card) aus und installier sie mit `npx wingo-ui@latest add agent-status-card`.

Nimm `variant="compact"` für ein Raster aus mehreren Agenten und `variant="row"` für eine 64px hohe Listenzeile mit Fortschrittsring. Unter 400px rutscht der Orb über den Text, und die Buttons teilen sich die Breite.

## Wie passen Reasoning und Tool Calls zusammen?

Reasoning kommt vor dem ersten Aufruf und zwischen den Aufrufen, und es sollte sich genauso zusammenklappen. [Reasoning Indicator](https://wingo-ui.com/components/reasoning-indicator) zeigt ein schimmerndes Label und einen Live-Timer, solange das Modell nachdenkt, und danach „Thought for 12 s“, das sich per Tipp aufklappen lässt. Die Prop `label` ersetzt den Text während einer Phase, zum Beispiel durch „Searching the web“, damit sich ein Denkschritt und ein Tool-Schritt gleich lesen. Chat Message stapelt die Reasoning-Zeile über der Tool-Zusammenfassung und setzt die Antwort unter beide.

## Was macht eine Tool Call UI auf dem Smartphone barrierefrei?

Sie braucht drei Dinge: eine Ansage pro Statusänderung, Touch-Ziele mit 44px und lange Inhalte, die in ihrem eigenen Block scrollen.

- **Einmal pro Änderung ansagen.** Die Liste ist keine Live-Region; ein Screenreader, der jede mitlaufende Dauer vorliest, ist unbrauchbar. Eine separate Live-Region (polite) sagt einmal „Sending the email: Needs approval“, wenn sich der Status ändert.
- **Den Status in Worten nennen.** Fehlgeschlagene und wartende Aufrufe nennen ihren Status neben dem Titel. Die übrigen tragen ihn in der Markierung und in einem Wort, das nur Screenreader vorlesen.
- **Touch-Ziele.** Auf Touchscreens wachsen die Zeilen auf 44px, und kleine Zeilen behalten ihr Aussehen, bekommen aber eine Trefferfläche von 44px.
- **Scrollen bleibt in der Zeile.** Code-Blöcke scrollen seitlich in sich selbst, eine lange URL in einer JSON-Ausgabe macht die Seite bei 360px also nie breiter. Agent-Logs sind auf 40 % der Bildschirmhöhe begrenzt.
- **Reduzierte Bewegung.** Spring-Animationen werden zu kurzen Überblendungen, Schimmer und Puls stoppen.

## Wann ist AI Elements die bessere Wahl?

AI Elements ist die bessere Wahl, wenn deine App schon auf dem AI SDK läuft und du kostenlose Komponenten unter der [Apache-2.0-Lizenz](https://github.com/vercel/ai-elements/blob/main/LICENSE) willst. AI Elements von Vercel hat eine Komponente [Tool](https://elements.ai-sdk.dev/components/tool), deren Header, Eingabe und Ausgabe direkt die Felder des Tool Parts aus dem SDK nehmen (`state`, `input`, `output` und `errorText`), und eine Komponente [Confirmation](https://elements.ai-sdk.dev/components/confirmation), die `approval` und `state` eines Parts nimmt, alles auf Basis von shadcn/ui. Den Adapter von oben sparst du dir. Laut der [Doku](https://elements.ai-sdk.dev/docs) zieht das Projekt außerdem zu shadcn/ui um, und die aktuelle Website wird Ende November 2026 eingestellt. Neue Projekte sollten es also von dort installieren (geprüft am 16. Oktober 2026). Die Timeline von Wingo UI passt, wenn du die Zeitachse, Dauern, Unterschritte, Retry, die Karte für den ganzen Lauf und die Smartphone-Layouts fertig eingebaut haben willst, oder wenn dein Agent das AI SDK gar nicht nutzt, denn `ToolCall` besteht nur aus einfachen Daten. Für den Chat drumherum lies unseren Guide zur [React AI Chat UI](https://wingo-ui.com/de/blog/react-ai-chat-ui).

## Was probierst du als Nächstes?

Öffne die Doku zu [Tool Call Timeline](https://wingo-ui.com/components/tool-call-timeline), wechsle im Playground zwischen den Varianten timeline, card und inline und installier die Komponente dann mit `npx wingo-ui@latest add tool-call-timeline`. Sie und die beiden anderen Komponenten aus diesem Guide gehören zu [Wingo UI Pro](https://wingo-ui.com/de/pricing). Wenn ein Coding-Agent deine Oberflächen baut, zeigt der [Guide zum MCP-Server für Komponentenbibliotheken](https://wingo-ui.com/de/blog/component-library-mcp-guide), wie er diese Props direkt lesen kann. Weitere Artikel wie diesen findest du unter [UI mit KI-Agenten bauen](https://wingo-ui.com/de/blog/category/ai-agents).

## Komponenten in diesem Artikel

- [Tool Call Timeline](https://wingo-ui.com/components/tool-call-timeline) (Pro): A React tool call timeline for AI agents: each step with its status, time, input and output, plus approval and retry when a call needs them. Installation: `npx wingo-ui@latest add tool-call-timeline`
- [Agent Status Card](https://wingo-ui.com/components/agent-status-card) (Pro): A React AI agent status card: orb, name, status, current step, progress, elapsed time, steps, logs and the controls that matter right now. Installation: `npx wingo-ui@latest add agent-status-card`
- [Reasoning Indicator](https://wingo-ui.com/components/reasoning-indicator) (Pro): A React reasoning indicator for AI chat: a shimmering live timer while the model thinks, then a quiet "Thought for 12 s" row to expand. Installation: `npx wingo-ui@latest add reasoning-indicator`

## Häufige Fragen

### Welche Zustände braucht eine Tool Call UI?

Für echte Agenten reichen sechs: in der Warteschlange, läuft, fertig, fehlgeschlagen, abgebrochen und wartet auf Freigabe. Die Zustände der Tool Parts im AI SDK (input-streaming, input-available, approval-requested, approval-responded, output-available, output-error, output-denied) lassen sich eins zu eins oder zwei zu eins darauf abbilden.

### Wie baue ich in ein AI SDK Tool eine Human-in-the-Loop-Freigabe ein?

Setz das Tool in der Option toolApproval von streamText auf 'user-approval' (die ältere Tool-Eigenschaft needsApproval ist in der Doku des AI SDK Stand Oktober 2026 als veraltet markiert). Zeig im Client Approve und Reject, wenn der Tool Part im Zustand approval-requested ist, und ruf addToolApprovalResponse mit der Freigabe-ID und approved true oder false auf. Gib lastAssistantMessageIsCompleteWithApprovalResponses als sendAutomaticallyWhen mit, damit der Chat weiterläuft, sobald jede Freigabe beantwortet ist.

### Sollen die Details eines Tool Calls standardmäßig offen oder zugeklappt sein?

Zugeklappt bei erfolgreichen Aufrufen, offen bei fehlgeschlagenen. Bei einem erfolgreichen Aufruf lesen die Leute Titel und Dauer; bei einem fehlgeschlagenen brauchen sie sofort den Fehler, die Eingabe und die Logs.

### Wie zeige ich Tool Calls in einer Chat-Nachricht?

Mit einer einzeiligen Zusammenfassung wie „Used 4 tools, 2.8 s“, die aufklappt, solange ein Aufruf läuft oder auf Freigabe wartet, und nach dem Lauf wieder zuklappt. Chat Message von Wingo UI macht das von selbst, wenn du der Nachricht toolCalls mitgibst.

### Sind die Agent-Komponenten von Wingo UI kostenlos?

Nein. Tool Call Timeline, Agent Status Card und Reasoning Indicator gehören zu Wingo UI Pro. Kostenlose Komponenten, auf denen sie aufbauen, etwa Button, Badge, Code Block und Progress, installierst du ohne bezahlten Plan.

---

Quelle: https://wingo-ui.com/de/blog/ai-agent-tool-call-ui
