1. AG-UI verstehen: Der Standard für Agentic User Interfaces
  2. AG-UI in der Praxis: Das SDK für TypeScript
  3. AG-UI End-2-End: Server und Client verbinden
  4. Agentic UI mit Angular, CopilotKit und AG-UI umsetzen
  5. A2UI in Angular: Wie KI dynamische UIs zur Laufzeit erzeugt
  6. A2UI mit AG-UI und CopilotKit in Angular integrieren
  7. Custom Catalogs in A2UI: Eigene Komponenten für KI-generierte UIs
  8. A2UI mit DSL: Kontrollierbare Dashboards optimiert für Performance
  9. Agentic UI mit MCP Apps: Tool-Ergebnisse als interaktive Widgets
  10. MCP Apps in Angular mit CopilotKit: Rich Chat Interfaces Instead of Text Responses

Ein Agent, das AG-UI SDK und CopilotKit für Angular

Im vorherigen Beitrag haben wir AG-UI-Nachrichten noch manuell erzeugt, um das SDK besser zu verstehen. Im echten Einsatz stammen diese Nachrichten jedoch von einem tatsächlichen Agenten, der ein Sprachmodell steuert, Werkzeuge verwendet und den Verlauf der Konversation speichert. Dieses Kapitel füllt genau diese Lücke: Es demonstriert, wie ein mit Mastra gebauter Agent über AG-UI verfügbar gemacht wird und danach von zwei Clients genutzt wird – einem bewusst simplen Terminal-Client und einem ersten Angular-Client, der auf CopilotKit basiert.

In diesem Abschnitt der Serie wird beleuchtet, wie der Agent mit seinem Tool, dem Prompt und der Memory strukturiert ist, worin die AG-UI-Anbindung von Mastra besteht und weshalb der Client dank AG-UI keine Kenntnis über das genutzte Agent-Framework benötigt.

📂 Source Code (siehe Branch copilotkit)

Ein Agent mit Mastra

Die meisten Agent-Frameworks stellen ähnliche Konzepte bereit: einen Agenten, der ein Sprachmodell mit einem Prompt kombiniert, Tools für den Agenten sowie eine Memory, die sich den Dialog merkt. In diesem Beispiel kommt Mastra zum Einsatz, da es nativ für TypeScript ist und sich dadurch perfekt in die Frontend-Welt integriert. Mit LangGraph, Google ADK oder dem Microsoft Agent Framework sähe das Vorgehen strukturell kaum anders aus.

Mastra und serverseitige Agents stehen nicht im Mittelpunkt dieser Artikelreihe. Ein Blick auf die Serverseite ist dennoch hilfreich, um nachzuvollziehen, woher die AG-UI-Nachrichten stammen, die unser Client später erhält. Die folgenden Abschnitte beschreiben daher Schritt für Schritt die Komponenten unseres Beispiel-Agents: die Projektinitialisierung, den Agent selbst, seinen Prompt und das Wetter-Tool.

Ein neues Mastra-Projekt anlegen

Die Erstellung eines neuen Mastra-Projekts gelingt mit einem einzelnen Befehl:

npm create mastra@latest

Der interaktive Assistent hinterlässt ein sofort nutzbares Projekt mit einem Beispiel-Agenten. Zusätzlich bietet Mastra offizielle Agent Skills an: vorgefertigte Pakete mit Anweisungen und Dokumentation, die für Tools wie Claude Code gedacht sind. Liegen sie einmal im Projektverzeichnis unter .claude/skills, erhalten Codierungs-Assistenten Zugriff auf die neueste API – das ist nützlich, weil Mastra ständig Updates erfährt und das modellbasierte Wissen häufig nicht mehr aktuell ist.

Dank dieser Skills ließen wir in unserem Bereich flights42 ein bewusst reduziertes Mastra-Gerüst erzeugen. Das findet man unter ai-demo/server, wo nur eine kleine Anzahl von Dateien vorhanden ist.

Der Weather-Agent

Den Kern bildet der Agent, der Prompt, Modell, Werkzeuge und Gedächtnis kombiniert:

import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';

import { weatherTool } from './weather-tool.js';

export const weatherAgent = new Agent({
  id: 'weatherAgent',
  name: 'Weather Assistant',
  instructions: `[...]`,
  model: 'openai/gpt-5.6-luna',
  tools: { getWeather: weatherTool },
  memory: new Memory(),
});

Das model-Attribut greift auf Mastras Model-Router zurück: Der übergebene String definiert Provider und Modell, den passenden API-Key liest Mastra aus der Umgebungsvariable — bei OpenAI also aus OPENAI_API_KEY. Dadurch genügt eine Anpassung dieses Strings, um auf ein anderes Modell oder einen anderen Anbieter umzusteigen.

Über tools stellt der Agent das weiter unten beschriebene weatherTool unter der Bezeichnung getWeather bereit. Genau unter diesem Namen taucht das Tool für das Sprachmodell auf und wird in Tool Calls referenziert. Die Memory löst eine inhärente Einschränkung von LLMs: Diese sind zustandslos und behalten keine Informationen über vorherige Anfragen. Für eine Konversation muss daher jedes Mal der gesamte bisherige Verlauf mitgesendet werden. Hier greift die Memory ein — sie verwaltet den Verlauf serverseitig und fügt ihn bei jedem Run dem Modell hinzu, sodass der Client lediglich die aktuelle Anfrage übertragen muss.

Der Prompt

Die im Agent hinterlegten instructions dienen als System-Prompt:

You are a friendly weather assistant.

When the user asks about the weather in a city,
look it up. Then answer in one short, natural sentence that mentions the
condition and the temperature in degrees Celsius.

Der Prompt definiert den Handlungsrahmen des Agents, spezifiziert die Anforderungen und legt das vorgesehene Antwortformat fest. Sprachmodelle gewichten den System-Prompt deutlich stärker als reguläre Nutzeranfragen, da sie im Training darauf optimiert wurden, Instruktionen aus dieser Rolle priorisiert zu behandeln. Somit eignet sich der System-Prompt optimal für Verhaltensrichtlinien und Sicherheitsvorgaben – er bietet zumindest einen gewissen Rahmen, um manipulationsversuche durch ausgeklügelt formulierte Nutzereingaben zu begrenzen.

Auffallend ist zudem, was im Prompt fehlt: Den Namen des Werkzeugs getWeather sucht man hier vergebens. Die Anweisung look it up reicht bereits aus, da das Modell die passende Tool-Auswahl eigenständig anhand der jeweiligen Beschreibung trifft. Wie genau eine solche Beschreibung strukturiert ist, wird im folgenden Teil erläutert.

Das Wetter-Tool

Im Kern besteht dieses Werkzeug aus einem Namen, einer Charakterisierung und Schemata. Diese Daten liefern dem Sprachmodell die entscheidenden Hinweise darüber, unter welchen Bedingungen und auf welche Weise das Werkzeug zur Anwendung kommen soll:

import { createTool } from '@mastra/core/tools';
import { z } from 'zod';

import { getWeather } from './weather-api.js';

export const weatherTool = createTool({
  id: 'getWeather',
  description: 'Returns the current weather and temperature for a given city.',
  inputSchema: z.object({
    city: z.string().trim().min(1).describe('The name of the city.'),
  }),
  outputSchema: z.object({
    city: z.string(),
    condition: z.enum(['rainy', 'sunny', 'cloudy']),
    temperature: z.number(),
  }),
  execute: async ({ city }) => {
    return getWeather(city);
  },
});

Die mittels zod erstellten Schemata legen sowohl die erwarteten Parameter als auch die Form des Ergebnisses fest und werden intern als JSON Schema dem Modell übergeben. Die eigentliche Verarbeitung übernimmt execute. Die dort verwendete Funktion getWeather bildet lediglich einen Wetterdienst nach: Sie generiert für jede Stadt einmalig Wetterlage und Temperatur und bleibt bei nachfolgenden Aufrufen konstant. So funktioniert die Demonstration ohne Anbindung an eine echte Wetter-API.

AG-UI-Endpunkt bereitstellen

Der Agent läuft nun serverseitig – die Frage ist, wie das Frontend mit ihm kommuniziert. Mastra bietet zwar eigene HTTP-Endpunkte sowie ein zugehöriges Client-SDK an – wer das jedoch nutzt, bindet sein Frontend an das gewählte Agent-Framework. Ein späterer Umstieg, beispielsweise auf LangGraph, würde dann direkte Auswirkungen auf den Client haben. Deshalb schalten wir AG-UI als minimale, standardisierte Schnittstelle dazwischen: Der Client ist nur mit den im ersten Teil eingeführten Nachrichtentypen vertraut und bleibt dadurch unabhängig von Framework und Modell.

Diese Verbindung wird durch das Paket @ag-ui/mastra hergestellt. Es enthält die Klasse MastraAgent, eine Umsetzung des bereits besprochenen AbstractAgent. Der Adapter übernimmt einen Mastra-Agent, führt ihn bei jedem Run aus und wandelt dessen Streaming-Ereignisse in AG-UI-Nachrichten wie TOOL_CALL_START oder TEXT_MESSAGE_CONTENT. Der folgende Route-Handler zeigt genau diese Verwendung des Adapters:

import type { RunAgentInput } from '@ag-ui/core';
import { MastraAgent } from '@ag-ui/mastra';
import type { ContextWithMastra } from '@mastra/core/server';
import { streamSSE } from 'hono/streaming';
import { concatMap, lastValueFrom } from 'rxjs';

export async function chatRouteHandler(
  c: ContextWithMastra,
): Promise<Response> {
  const input = (await c.req.json()) as RunAgentInput;

  const agent = c.get('mastra').getAgent('weatherAgent');
  const aguiAgent = new MastraAgent({ agent, resourceId: input.threadId });

  return streamSSE(c, async (sse) => {
    const send = (data: unknown): Promise<void> =>
      sse.writeSSE({ data: JSON.stringify(data) });

    await lastValueFrom(aguiAgent.run(input).pipe(concatMap(send)), {
      defaultValue: undefined,
    });
  });
}

Der Handler entnimmt dem HTTP-Request-Body den RunAgentInput. Dieser ist exakt die von HttpAgent des AG-UI SDK gesendete Payload, mitsamt threadId, runId und den neuen Nachrichten. Die threadId wird vom Handler als resourceId an den MastraAgent übergeben. Dank dieser Zuordnung kann Mastras Memory die einzelnen Runs demselben Gesprächsverlauf zuordnen.

Die Ausführung der Methode run erzeugt ein Observable, das AG-UI-Nachrichten liefert. Wie im vorigen Abschnitt dargelegt, ist das AG-UI SDK für das Transportprotokoll nicht zuständig. Diese Funktion übernimmt hier etwas Gluencode, indem er jede Nachricht als Server-sent Event (SSE) in den HTTP-Response-Stream schreibt. Da Mastras Server auf Hono basiert, lässt sich dessen Helfer streamSSE bequem einsetzen: Dieser setzt die erforderlichen HTTP-Header, hält die Verbindung offen und formatiert jede via writeSSE übermittelte Nachricht als SSE-Frame.

Die Verbindung zwischen Observable und Stream stellt sich wie folgt dar: Über concatMap werden die Nachrichten sequenziell mittels send versendet, und lastValueFrom wartet auf den Abschluss des Observables – erst dann endet der Callback und Hono beendet den Stream.

Im Interesse der Übersichtlichkeit verzichtet der dargestellte Codeabschnitt auf die Fehlerbehandlung; die komplette Variante im Repository übermittelt bei einem Fehler eine RUN_ERROR-Nachricht.

Die Route anmelden

Schließlich muss die Route vom Server bereitgestellt werden. Hierfür verzeichnet die zentrale Mastra-Instanz den Agent sowie den Route-Handler:

import { Mastra } from '@mastra/core/mastra';
import { registerApiRoute } from '@mastra/core/server';
import { InMemoryStore } from '@mastra/core/storage';

import { weatherAgent } from './agent.js';
import { chatRouteHandler } from './chat-route.js';

export const mastra = new Mastra({
  storage: new InMemoryStore(),
  agents: { weatherAgent },
  server: {
    port: 4555,
    cors: {
      origin: '*',
    },
    apiRoutes: [
      registerApiRoute('/chat', {
        method: 'POST',
        handler: chatRouteHandler,
      }),
    ],
  },
});

Der mitgelieferte HTTP-Server von Mastra lässt sich über registerApiRoute um eigene Routen erweitern. Unsere definierte Route POST /chat fungiert damit als AG-UI-Schnittstelle der Applikation. Die Memory wird im InMemoryStore gehalten; eine produktive Anwendung würde hier einen dauerhaften Speicher verwenden.

Die CORS-Einstellungen richten sich an Browser-basierte Clients: Der Angular-Client, der später vorgestellt wird, greift von einem anderen Origin – dem Dev-Server unter Port 4300 – auf den Endpunkt zu. Für dieses Demonstrationsszenario ist die offene Einstellung origin: '*' akzeptabel; eine reale Anwendung sollte die zulässigen Origins explizit festlegen.

NOTE

Agentic UI with Angular

Wenn du AG-UI nicht nur integrieren, sondern sauber in größere Architekturen einbetten willst:
In meinem Buch Agentic UI mit Angular gehe ich genau auf diese Patterns und Trade-offs im Detail ein.

Cover des eBooks Agentic UI with Angular

Mehr zum eBook →

Der AG-UI-Client

Um die Dinge schlank zu halten und den Fokus auf das Kernthema zu richten, beginnt unsere Reise mit einem Terminal-Programm. Dieses liegt unter ai-demo/client und greift auf exakt jene AG-UI-SDK-Komponenten zurück, die später auch im Web-Umfeld zum Zug kommen. Besonders auffällig ist, was hier fehlt: Nicht eine Zeile Mastra-Code ist im Spiel. Der Client kennt ausschließlich die Endpunkt-URL und die AG-UI-Message-Strukturen.

import { type AgentSubscriber, HttpAgent, randomUUID } from '@ag-ui/client';

const threadId = randomUUID();

const agent = new HttpAgent({
  url: 'http://localhost:4555/chat',
  threadId,
});

The HttpAgent, introduced in the previous section, takes the endpoint URL and a threadId, which the client generates once per session. The ask method forwards a single query to the agent:

async function ask(prompt: string): Promise<void> {
  agent.addMessage({
    id: randomUUID(),
    role: 'user',
    content: prompt,
  });

  const subscriber: AgentSubscriber = {};

  if (SHOW_DETAILS) {
    subscriber.onEvent = ({ event }) => logEvent(event);
  } else {
    subscriber.onTextMessageContentEvent = ({ event }) => {
      stdout.write(event.delta);
    };
  }

  await agent.runAgent({ runId: randomUUID() }, subscriber);
}

Weil der Agent den bisherigen Gesprächsverlauf serverseitig speichert, muss ask je Anfrage lediglich die aktuelle Nutzereingabe über addMessage ablegen und danach einen frischen Durchlauf mit runAgent anstoßen.

Für die eingehenden Nachrichten ist der AgentSubscriber zuständig. Üblicherweise genügt ein einzelner Handler: onTextMessageContentEvent gibt jedes ankommende Textfragment unmittelbar auf der Konsole aus, wodurch die Antwort nach und nach erscheint – Streaming in der schlichtesten Ausführung. Wird der Client allerdings mit der Option --details gestartet, loggt der allgemeine Handler onEvent sämtliche AG-UI-Nachrichten im Einzelnen.

Was noch aussteht, ist die Eingabe durch den Benutzer. Eine kompakte Hilfsfunktion, die auf der readline-API von Node basiert, stellt eine Eingabeaufforderung dar und liefert die getippte Zeile zurück:

import { stdin, stdout } from 'node:process';
import { createInterface } from 'node:readline/promises';

const rl = createInterface({ input: stdin, output: stdout, terminal: false });

export async function readLine(label: string): Promise<string> {
  return (await rl.question(label)).trim();
}

Am Ende verbindet eine Endlosschleife die beiden Seiten: Sie liest die Konsole Zeile für Zeile aus und übergibt jede Eingabe an ask:

async function main(): Promise<void> {
  console.log('Ask about the weather in a city.');

  for (;;) {
    const prompt = await readLine('\n> ');
    if (!prompt) {
      continue;
    }
    await ask(prompt);
  }
}

main();

Die Schleife überspringt leere Eingaben schlichtweg. Der Codeauszug verzichtet bewusst auf eine saubere Beendigung – Ctrl+C reicht hier vollkommen aus. Die Version im Repository unterstützt zusätzlich den Befehl exit.

Die Anwendung testen

Für den Test benötigt man zwei Terminals im Root des Workspace sowie einen API-Key als Umgebungsvariable OPENAI_API_KEY. Im ersten Terminal startet man den Mastra-Server, welcher auf Port 4555 hört:

npm run ai-demo-server

Das zweite Terminal startet den Client:

npm run ai-demo-client

So kann man sich beispielsweise nun nach dem Wetter in Wien erkundigen:

Der Kommandozeilen-Client beantwortet Fragen zum Wetter in Wien und Paris

Die serverseitige Memory erlaubt auch Folgefragen wie Is it warmer than in Paris? – der Agent ordnet sie korrekt Wien zu, weil beide Anfragen über die gleiche threadId demselben Gesprächsverlauf zugehören.

Besonders aufschlussreich ist der Blick ins Innere. Wenn man den Client mit dem Detail-Modus startet und etwa nach dem Wetter in Graz fragt, listet er sämtliche AG-UI-Nachrichten auf, die der Adapter aus der Mastra-Agentenarbeit generiert:

npm run ai-demo-client -- --details
[RUN_STARTED         ]
[TOOL_CALL_START     ] getWeather
[TOOL_CALL_ARGS      ] {"city":"Graz"}
[TOOL_CALL_END       ]
[TOOL_CALL_RESULT    ] {"city":"Graz","condition":"sunny","temperature":17}
[TEXT_MESSAGE_START  ]
[TEXT_MESSAGE_CONTENT] G
[TEXT_MESSAGE_CONTENT] raz
[TEXT_MESSAGE_CONTENT]  is
[TEXT_MESSAGE_CONTENT]  sunny
[...]
[TEXT_MESSAGE_END    ]
[RUN_FINISHED        ]

Die Nachrichtentypen aus dem ersten Teil treten hier sichtbar in Erscheinung: Der Run wird gestartet, das Modell fordert für getWeather einen Tool Call an, der Agent führt serverseitig das Tool aus und hält das Ergebnis fest. Anschließend erreicht die Antwort als Strom einzelner Textfragmente den Client, ehe der Run endet. In diesem Fall stammen die Nachrichten jedoch nicht aus fest verdrahteten Beispielen, sondern aus einem realen Agenten, der mit einem Sprachmodell arbeitet.

Ein Angular-Client auf Basis von CopilotKit

Nach der Arbeit in der Kommandozeile widmen wir uns nun kurz dem eigentlichen Zielumfeld dieser Artikelreihe, dem Browser. Dafür enthält der Workspace im Verzeichnis projects/simple-client eine bewusst schlank gehaltene Angular-App, die denselben AG-UI-Endpunkt nutzt wie der Befehlszeilen-Client.

Verwendet wird hierfür CopilotKit – das Open-Source-Frontend-SDK für KI-Assistenten und Copiloten, dessen Entwickler ebenfalls für AG-UI verantwortlich zeichnen. CopilotKit liefert vorgefertigte UI-Komponenten für Chats und kommuniziert nativ über AG-UI. Die Angular-Integration ist als separates npm-Paket verfügbar:

npm i @copilotkit/angular

provideCopilotKit in der app.config.ts etabliert die Verbindung zu unserem Agent.

import { HttpAgent } from '@ag-ui/client';
import { provideCopilotKit } from '@copilotkit/angular';

const chatUrl = 'http://localhost:4555/chat';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideCopilotKit({
      agents: {
        weatherAgent: new HttpAgent({ url: chatUrl }),
      },
    }),
  ],
};

An dieser Stelle zeigt sich der Vorteil von AG-UI erneut: CopilotKit benötigt lediglich einen AG-UI-Agent. Deshalb wird der vertraute HttpAgent verwendet, der auf unseren /chat-Endpunkt ausgerichtet ist. Mit dem Schlüssel weatherAgent wird ein clientseitiger Name festgelegt, der Komponenten als Referenz auf diesen Agent dient.

Das UI wird vom Chat-Control CopilotChat bereitgestellt:

import { CopilotChat } from '@copilotkit/angular';

@Component({
  selector: 'app-root',
  imports: [CopilotChat],
  templateUrl: './app.html',
  styleUrl: './app.css',
})
export class App {}
<main class="chat-container">
  <copilot-chat agentId="weatherAgent" />
</main>

That is all it takes: copilot-chat already includes the message list, input field, and streaming indicator, and handles the AG-UI communication behind the scenes. The agentId attribute points to the previously registered agent. The following command launches the app via the Angular dev server on http://localhost:4300:

npm run simple-client

Das Chat-Control von CopilotKit beantwortet Fragen zum Wetter in Graz und London

Auch hier greifen Rückfragen wie Is it warmer than in London?, weil der Chat auf demselben Agent und dessen serverseitigem Memory basiert.

Das vorgefertigte Chat-Control stellt den schnellsten Weg zu einem lauffähigen Ergebnis dar und eignet sich deshalb perfekt für den schnellen Einstieg. In den weiteren Folgen dieser Serie verwenden wir jedoch den Headless-Mode von CopilotKit: Er liefert den Zustand und die Logik des Chats, überlässt aber die komplette Gestaltung der Anwendung. Das wird relevant, wenn der Chat sich dem eigenen Design anpassen, eigene Widgets im Verlauf auftauchen oder Tool Calls mit Stores, Formularen und dem Routing der App interagieren müssen.

Zusammenfassung

Ein Agent-Framework wie Mastra macht die Serverseite kompakt und überschaubar: ein Agent mit Prompt und Memory, ein Tool mit Schemata sowie eine zentrale Konfiguration. Der Adapter aus @ag-ui/mastra überträgt die Ergebnisse dieses Agents in AG-UI-Nachrichten, und ein wenig Gluecode sendet sie als Server-sent Events an den Client.

Das zentrale Element ist die Entkopplung: Der Client hat keinerlei Wissen über Mastra oder das eingesetzte Sprachmodell. Er kommuniziert ausschließlich über AG-UI. Das gilt gleichermaßen für die Kommandozeile und den Angular-Client, der durch das Chat-Control von CopilotKit mit minimalem Aufwand entsteht. Auf diese Weise ließe sich das Agent-Framework austauschen, ohne auch nur eine Zeile am Client zu ändern – genau jenes Versprechen, das zu Beginn dieser Serie gegeben wurde.

Der nächste Schritt

Mit dem vorgefertigten Chat-Control von CopilotKit sind wir zügig zu einem lauffähigen Ergebnis gelangt. Ab der nächsten Folge nutzen wir dagegen den bereits angesprochenen flexiblen Headless-Mode von CopilotKit und veranschaulichen, wie sich Agents damit idiomatisch und tief in Angular-Anwendungen einbinden lassen – mit eigener Darstellung des Chatverlaufs, clientseitigen Tools und individuellen Widgets.

Nächster Artikel →


Interesse an produktionsreifen Agentic-UI-Architekturen?

In meinem Workshop beschäftigen wir uns mit AG-UI, A2UI, MCP Apps, HITL-Patterns und modernen Angular-Architekturen für reale agentische Systeme.

Workshop: Agentic AI mit Angular – AG-UI, A2UI, MCP Apps & HITL-Patterns

Alle Details →

FAQ

Warum fällt die Wahl im Artikel auf Mastra?

Mastra ist von Anfang an auf TypeScript ausgelegt und passt daher gut zum Arsenal von Frontend-Entwicklern. Die vorgestellten Bausteine wie Agent, Werkzeuge, Speicher und Prompts existieren in ähnlicher Form aber auch in anderen Agent-Frameworks, etwa LangGraph, Google ADK oder dem Microsoft Agent Framework.

Welche Aufgabe übernimmt der Adapter aus @ag-ui/mastra?

Die MastraAgent-Klasse setzt das AbstractAgent-Interface des AG-UI SDK um, ruft den bereitgestellten Mastra-Agenten auf und wandelt dessen gestreamte Events in AG-UI-Nachrichten wie TOOL_CALL_START oder TEXT_MESSAGE_CONTENT um. Das manuelle Erzeugen dieser Nachrichten entfällt damit.

Muss der Client wissen, dass dahinter Mastra steckt?

Überhaupt nicht. Für den Client zählen allein die URL des AG-UI-Endpunkts und die standardisierten Nachrichtentypen. Ob das Agent-Framework, das Sprachmodell oder die serverseitigen Tools ausgetauscht werden – der Client bleibt unverändert.

Worum handelt es sich bei CopilotKit?

CopilotKit ist ein quelloffenes Frontend-SDK für KI-Assistenten und agentische Oberflächen, entwickelt vom gleichen Team wie AG-UI. Es liefert vorgefertigte Komponenten, etwa das gezeigte Chat-Control, aber auch einen Headless-Modus für komplett eigene Interfaces, und spricht nativ AG-UI mit den Agenten.

Wie behält der Agent den Verlauf im Blick?

Für jede Sitzung erzeugt der Client eine threadId, die der Route-Handler als resourceId an den Speicher von Mastra übergibt. Dadurch ordnet der Agent sämtliche Runs demselben Verlauf zu und der Client schickt nur noch jeweils die neuen Nachrichten.