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

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 (opens in a new tab) 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:
Die mittlere Spalte ist der Typ ToolCallStatus aus lib/ai-chat, den sich Tool Call Timeline und 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.
$ npx wingo-ui@latest add tool-call-timelineHinter jeder Zeile stehen einfache Daten:
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.
Der Adapter trennt das AI SDK sauber von der Komponente. Der strukturelle Typ ToolPart macht ihn unabhängig von deinen Tool-Definitionen:
Dann renderst du eine Timeline pro Assistant-Nachricht:
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 (opens in a new tab) 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 (opens in a new tab) 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:
Das Human-in-the-Loop-Rezept des AI SDK (opens in a new tab) 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 rendert das von selbst, wenn die NachrichttoolCallshat, undtoolCallPropsreichtonApproveund den Rest durch. - In einem Seitenpanel nimmst du
variant="timeline"mitsize="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 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.
$ npx wingo-ui@latest add agent-status-cardNimm 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 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 (opens in a new tab) willst. AI Elements von Vercel hat eine Komponente Tool (opens in a new tab), deren Header, Eingabe und Ausgabe direkt die Felder des Tool Parts aus dem SDK nehmen (state, input, output und errorText), und eine Komponente Confirmation (opens in a new tab), die approval und state eines Parts nimmt, alles auf Basis von shadcn/ui. Den Adapter von oben sparst du dir. Laut der Doku (opens in a new tab) 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.
Was probierst du als Nächstes?
Öffne die Doku zu 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. Wenn ein Coding-Agent deine Oberflächen baut, zeigt der Guide zum MCP-Server für Komponentenbibliotheken, wie er diese Props direkt lesen kann. Weitere Artikel wie diesen findest du unter UI mit KI-Agenten bauen.
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.
- KI-Agenten
- Tool Calls
- Human in the Loop
- React
- Barrierefreiheit


