{"id":34423,"date":"2026-04-20T14:55:32","date_gmt":"2026-04-20T12:55:32","guid":{"rendered":"https:\/\/www.angulararchitects.io\/?p=34423"},"modified":"2026-07-22T12:25:22","modified_gmt":"2026-07-22T10:25:22","slug":"ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client","status":"publish","type":"post","link":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/","title":{"rendered":"AG-UI End to End: Connecting Server and Client"},"content":{"rendered":"<div class=\"wp-post-series-box series-agentic-angular wp-post-series-box--expandable\">\n\t\t\t<input id=\"collapsible-series-agentic-angular6a679492d6a81\" class=\"wp-post-series-box__toggle_checkbox\" type=\"checkbox\">\n\t\n\t<label\n\t\tclass=\"wp-post-series-box__label\"\n\t\t\t\t\tfor=\"collapsible-series-agentic-angular6a679492d6a81\"\n\t\t\ttabindex=\"0\"\n\t\t\t\t>\n\t\t<p class=\"wp-post-series-box__name wp-post-series-name\">\n\t\t\tThis is post 3 of 9 in the series <em>&ldquo;Agentic Angular&rdquo;<\/em>\t\t<\/p>\n\t\t\t<\/label>\n\n\t\t\t<div class=\"wp-post-series-box__posts\">\n\t\t\t<ol>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/understanding-ag-ui-the-standard-for-agentic-user-interfaces\/\">Understanding AG-UI: The Standard for Agentic User Interfaces<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-the-sdk-for-typescript\/\">AG-UI in Practice: The SDK for TypeScript<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><span class=\"wp-post-series-box__current\">AG-UI End to End: Connecting Server and Client<\/span><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/implementing-ag-ui-with-angular\/\">Agentic UI with Angular, CopilotKit, and AG-UI<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/a2ui-how-ai-generates-dynamic-uis-at-runtime\/\">A2UI: How AI Generates Dynamic UIs at Runtime<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/integrating-a2ui-with-ag-ui-in-angular\/\">Integrating A2UI with AG-UI and CopilotKit in Angular<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/custom-catalogs-in-a2ui-your-own-components-for-ai-generated-uis\/\">Custom Catalogs in A2UI: Your Own Components for AI-Generated UIs<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/how-i-made-my-a2ui-dashboard-300-times-faster\/\">A2UI with a DSL: Controllable Dashboards Optimized for Performance<\/a><\/li>\n\t\t\t\t\t\t\t\t\t<li><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/architecture-as-a-guardrail-structurally-ruling-out-entire-classes-of-errors\/\">Architecture as a Guardrail: Structurally Ruling Out Entire Classes of Errors<\/a><\/li>\n\t\t\t\t\t\t\t<\/ol>\n\t\t<\/div>\n\t<\/div>\n<p><em>An Agent, the AG-UI SDK, and CopilotKit for Angular<\/em><\/p>\n<p>In the previous part, we still created the AG-UI messages by hand in order to get to know the SDK. In practice, however, these messages come from a real agent that orchestrates a language model, calls tools, and remembers the conversation. This article closes exactly that gap: it shows how an agent built with <a href=\"https:\/\/mastra.ai\/\">Mastra<\/a> is exposed via AG-UI and then consumed by two clients \u2014 a deliberately simple command-line client and a first Angular client based on CopilotKit.<\/p>\n<p>This part of the series explains how the agent is built with its tool, prompt, and memory, what Mastra's AG-UI integration does, and why, thanks to AG-UI, the client does not have to care about the chosen agent framework.<\/p>\n<p>\ud83d\udcc2 <a href=\"https:\/\/github.com\/angular-architects\/flights42\/tree\/copilotkit\">Source Code<\/a> (see branch <code>copilotkit<\/code>)<\/p>\n<h2>An Agent with Mastra<\/h2>\n<p>Most agent frameworks offer very similar abstractions: an agent that supplies a language model with a prompt, tools the agent can call, and a memory for the conversation. We use Mastra here because it was built for TypeScript from the ground up and therefore fits seamlessly into the world of frontend teams. With LangGraph, Google ADK, or the Microsoft Agent Framework, the result would look structurally very similar.<\/p>\n<p>Mastra and server-side agents are not the focus of this article series. A short look at the server side does help, however, to understand where the AG-UI messages our client later receives come from. The following sections therefore show the building blocks of our example agent step by step: the project setup, the agent itself, its prompt, and the weather tool.<\/p>\n<h3>Creating a New Mastra Project<\/h3>\n<p>A new Mastra project is created with a single command:<\/p>\n<pre><code class=\"language-bash\">npm create mastra@latest<\/code><\/pre>\n<p>The interactive wizard generates a runnable project including an example agent. In addition, Mastra also provides official <a href=\"https:\/\/github.com\/mastra-ai\/skills\">Agent Skills<\/a>: packaged instructions and documentation for coding assistants such as Claude Code. Once placed in the project folder under <code>.claude\/skills<\/code>, they provide the assistant with the current state of the API \u2014 helpful, since Mastra evolves quickly and the knowledge the models were trained on is often outdated.<\/p>\n<p>Using these skills, we had a deliberately simple Mastra setup generated in our <code>flights42<\/code> workspace. It can be found in the folder <code>ai-demo\/server<\/code> and consists of just a handful of files.<\/p>\n<h3>The Weather Agent<\/h3>\n<p>The centerpiece is the agent, which brings together prompt, model, tools, and memory:<\/p>\n<pre><code class=\"language-ts\">import { Agent } from &#039;@mastra\/core\/agent&#039;;\nimport { Memory } from &#039;@mastra\/memory&#039;;\n\nimport { weatherTool } from &#039;.\/weather-tool.js&#039;;\n\nexport const weatherAgent = new Agent({\n  id: &#039;weatherAgent&#039;,\n  name: &#039;Weather Assistant&#039;,\n  instructions: `[...]`,\n  model: &#039;openai\/gpt-5.6-luna&#039;,\n  tools: { getWeather: weatherTool },\n  memory: new Memory(),\n});<\/code><\/pre>\n<p>The <code>model<\/code> property uses Mastra's model router: the string names the provider and the model, and Mastra expects the corresponding API key as an environment variable \u2014 in the case of OpenAI, as <code>OPENAI_API_KEY<\/code>. Switching to a different model or a different provider is therefore reduced to changing this string.<\/p>\n<p>Under <code>tools<\/code>, the agent registers the <code>weatherTool<\/code> discussed below under the name <code>getWeather<\/code>. That is the name the language model sees and uses in tool calls. The <code>Memory<\/code> addresses a peculiarity of language models: LLMs are stateless and remember nothing between two calls. Anyone who wants to hold a conversation must therefore send along the previous conversation with every call. That is exactly the job of the <code>Memory<\/code> \u2014 it stores the history on the server and passes it to the model on every run, so the client only has to transmit the new question.<\/p>\n<h3>The Prompt<\/h3>\n<p>The <code>instructions<\/code> stored in the agent form the system prompt:<\/p>\n<pre><code>You are a friendly weather assistant.\n\nWhen the user asks about the weather in a city,\nlook it up. Then answer in one short, natural sentence that mentions the\ncondition and the temperature in degrees Celsius.<\/code><\/pre>\n<p>The prompt defines the agent's role, describes the task, and specifies the desired answer format. Language models assign considerably more weight to the system prompt than to ordinary user messages, because they have been specifically trained to give instructions from this role priority. The system prompt is therefore the right place for behavioral rules and guardrails \u2014 and it offers at least some protection against cleverly worded user input redefining the agent's behavior.<\/p>\n<p>What the prompt does not contain is also remarkable: the tool <code>getWeather<\/code> is not mentioned by name. The phrase <code>look it up<\/code> is enough, because the model selects the appropriate tool itself based on its description. What that description looks like is shown in the next section.<\/p>\n<h3>The Weather Tool<\/h3>\n<p>At its core, the tool consists of a name, a description, and schemas. This information gives the language model the basis for deciding when and how to call the tool:<\/p>\n<pre><code class=\"language-ts\">import { createTool } from &#039;@mastra\/core\/tools&#039;;\nimport { z } from &#039;zod&#039;;\n\nimport { getWeather } from &#039;.\/weather-api.js&#039;;\n\nexport const weatherTool = createTool({\n  id: &#039;getWeather&#039;,\n  description: &#039;Returns the current weather and temperature for a given city.&#039;,\n  inputSchema: z.object({\n    city: z.string().trim().min(1).describe(&#039;The name of the city.&#039;),\n  }),\n  outputSchema: z.object({\n    city: z.string(),\n    condition: z.enum([&#039;rainy&#039;, &#039;sunny&#039;, &#039;cloudy&#039;]),\n    temperature: z.number(),\n  }),\n  execute: async ({ city }) =&gt; {\n    return getWeather(city);\n  },\n});<\/code><\/pre>\n<p>The schemas defined with <a href=\"https:\/\/zod.dev\/\">zod<\/a> describe the expected parameters as well as the structure of the result and are internally passed on to the model as JSON Schema. The actual work is done by <code>execute<\/code>. The <code>getWeather<\/code> function called there merely simulates a weather service: it randomly determines the weather condition and temperature once per city and returns the same values for subsequent requests. This lets the demo run without access to an external weather API.<\/p>\n<h3>Providing an AG-UI Endpoint<\/h3>\n<p>The agent now runs on the server \u2014 but the question arises how the frontend should talk to it. Mastra does come with its own HTTP endpoints and its own client SDK \u2014 however, anyone programming against them couples their frontend to the chosen agent framework. A later switch, for example to LangGraph, would then ripple through to the client. That is exactly why we insert AG-UI as a slim, standardized waist in between: the client only knows the message types discussed in the first part and therefore remains independent of framework and model.<\/p>\n<p>The bridge between the two worlds is built by the package <code>@ag-ui\/mastra<\/code>. It contains the class <code>MastraAgent<\/code>, an implementation of the <code>AbstractAgent<\/code> known from the previous part. It takes a Mastra agent, calls it on every run, and translates its streaming events into AG-UI messages such as <code>TOOL_CALL_START<\/code> or <code>TEXT_MESSAGE_CONTENT<\/code>. The following route handler shows this adapter in action:<\/p>\n<pre><code class=\"language-ts\">import type { RunAgentInput } from &#039;@ag-ui\/core&#039;;\nimport { MastraAgent } from &#039;@ag-ui\/mastra&#039;;\nimport type { ContextWithMastra } from &#039;@mastra\/core\/server&#039;;\nimport { streamSSE } from &#039;hono\/streaming&#039;;\nimport { concatMap, lastValueFrom } from &#039;rxjs&#039;;\n\nexport async function chatRouteHandler(\n  c: ContextWithMastra,\n): Promise&lt;Response&gt; {\n  const input = (await c.req.json()) as RunAgentInput;\n\n  const agent = c.get(&#039;mastra&#039;).getAgent(&#039;weatherAgent&#039;);\n  const aguiAgent = new MastraAgent({ agent, resourceId: input.threadId });\n\n  return streamSSE(c, async (sse) =&gt; {\n    const send = (data: unknown): Promise&lt;void&gt; =&gt;\n      sse.writeSSE({ data: JSON.stringify(data) });\n\n    await lastValueFrom(aguiAgent.run(input).pipe(concatMap(send)), {\n      defaultValue: undefined,\n    });\n  });\n}<\/code><\/pre>\n<p>The handler first reads the <code>RunAgentInput<\/code> from the body of the HTTP request. This is exactly the payload the <code>HttpAgent<\/code> of the AG-UI SDK sends \u2014 including <code>threadId<\/code>, <code>runId<\/code>, and the new messages. The handler passes the <code>threadId<\/code> on to the <code>MastraAgent<\/code> as <code>resourceId<\/code>. Through it, Mastra's memory assigns the individual runs to the same conversation.<\/p>\n<p>The <code>run<\/code> method returns an observable with AG-UI messages. As mentioned in the previous part, the AG-UI SDK does not concern itself with the transport protocol. That job is taken over here by a bit of glue code that writes every message into the HTTP response stream as a server-sent event (SSE). Conveniently, Mastra's server is built on <a href=\"https:\/\/hono.dev\/\">Hono<\/a>, so its helper <code>streamSSE<\/code> can be used: it sets the necessary HTTP headers, keeps the connection open, and packs every message sent via <code>writeSSE<\/code> into an SSE frame.<\/p>\n<p>That leaves the bridge between observable and stream: <code>concatMap<\/code> sends the messages one after another via <code>send<\/code>, and <code>lastValueFrom<\/code> waits until the observable has completed \u2014 only then does the callback end and Hono closes the stream.<\/p>\n<p>For readability, the excerpt shown omits error handling; the full version in the repo sends a <code>RUN_ERROR<\/code> message in case of an error.<\/p>\n<h3>Registering the Route<\/h3>\n<p>Finally, the server still has to offer the route. To do so, the central <code>Mastra<\/code> instance registers the agent as well as the route handler:<\/p>\n<pre><code class=\"language-ts\">import { Mastra } from &#039;@mastra\/core\/mastra&#039;;\nimport { registerApiRoute } from &#039;@mastra\/core\/server&#039;;\nimport { InMemoryStore } from &#039;@mastra\/core\/storage&#039;;\n\nimport { weatherAgent } from &#039;.\/agent.js&#039;;\nimport { chatRouteHandler } from &#039;.\/chat-route.js&#039;;\n\nexport const mastra = new Mastra({\n  storage: new InMemoryStore(),\n  agents: { weatherAgent },\n  server: {\n    port: 4555,\n    cors: {\n      origin: &#039;*&#039;,\n    },\n    apiRoutes: [\n      registerApiRoute(&#039;\/chat&#039;, {\n        method: &#039;POST&#039;,\n        handler: chatRouteHandler,\n      }),\n    ],\n  },\n});<\/code><\/pre>\n<p>Mastra comes with its own HTTP server, to which custom endpoints can be added via <code>registerApiRoute<\/code>. Our route <code>POST \/chat<\/code> is thus the application's AG-UI endpoint. The <code>InMemoryStore<\/code> serves as storage for the memory; in a real-world application, a persistent store would be used here.<\/p>\n<p>The CORS configuration is intended for clients running in the browser: the Angular client presented below will access the endpoint from a different origin \u2014 the dev server on port <code>4300<\/code>. For the demo, the generous <code>origin: &#039;*&#039;<\/code> is fine; in a real-world application, you would restrict the allowed origins deliberately.<\/p>\n<p><div style=\"\nmargin: 8px 0;\npadding: 22px;\nborder: 1px solid #e5e7eb;\nborder-radius: 14px;\nbackground: #f8fafc;\n\">NOTE<\/p>\n<h3 style=\"margin-top:0\">Agentic UI with Angular<\/h3>\n<p>If you don\u2019t just want to integrate AG-UI but embed it into a scalable architecture:<br \/>\nIn my book Agentic UI with Angular, I cover the underlying patterns and trade-offs in depth.<\/p>\n<p><a href=\"https:\/\/agentic-angular.com\/\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/cover.png\" width=\"400\" alt=\"Cover of the eBook Agentic UI with Angular\" style=\"cursor:pointer !important\"><\/a><\/p>\n<p><a style=\"cursor:pointer !important\" href=\"https:\/\/agentic-angular.com\/\">Learn more about the eBook \u2192<\/a>\n<\/div>\n<\/p>\n<h2>The AG-UI Client<\/h2>\n<p>To keep things simple and to focus on the essentials, we start with a command-line application. It can be found in the folder <code>ai-demo\/client<\/code> and uses the same building blocks of the AG-UI SDK that will later be used in the browser as well. What is most remarkable is what the client does not contain: not a single line of Mastra-specific code. It only knows the URL of the endpoint and the AG-UI message types.<\/p>\n<pre><code class=\"language-ts\">import { type AgentSubscriber, HttpAgent, randomUUID } from &#039;@ag-ui\/client&#039;;\n\nconst threadId = randomUUID();\n\nconst agent = new HttpAgent({\n  url: &#039;http:\/\/localhost:4555\/chat&#039;,\n  threadId,\n});<\/code><\/pre>\n<p>The <code>HttpAgent<\/code> known from the previous part receives the URL of the endpoint as well as a <code>threadId<\/code> that the client generates once per session. The <code>ask<\/code> function passes a single question on to the agent:<\/p>\n<pre><code class=\"language-ts\">async function ask(prompt: string): Promise&lt;void&gt; {\n  agent.addMessage({\n    id: randomUUID(),\n    role: &#039;user&#039;,\n    content: prompt,\n  });\n\n  const subscriber: AgentSubscriber = {};\n\n  if (SHOW_DETAILS) {\n    subscriber.onEvent = ({ event }) =&gt; logEvent(event);\n  } else {\n    subscriber.onTextMessageContentEvent = ({ event }) =&gt; {\n      stdout.write(event.delta);\n    };\n  }\n\n  await agent.runAgent({ runId: randomUUID() }, subscriber);\n}<\/code><\/pre>\n<p>Since the agent remembers the history on the server, it is enough for <code>ask<\/code> to store only the new user message per question via <code>addMessage<\/code> and then start a new run with <code>runAgent<\/code>.<\/p>\n<p>The <code>AgentSubscriber<\/code> processes the incoming messages. Normally, a single handler is enough for that: <code>onTextMessageContentEvent<\/code> writes every received text fragment directly to the console, so the answer appears word by word \u2014 streaming in its simplest form. If, on the other hand, you start the client with the flag <code>--details<\/code>, the generic handler <code>onEvent<\/code> logs every single AG-UI message instead.<\/p>\n<p>What is still missing is the user input. A small helper function based on Node's <code>readline<\/code> API displays a prompt and returns the entered line:<\/p>\n<pre><code class=\"language-ts\">import { stdin, stdout } from &#039;node:process&#039;;\nimport { createInterface } from &#039;node:readline\/promises&#039;;\n\nconst rl = createInterface({ input: stdin, output: stdout, terminal: false });\n\nexport async function readLine(label: string): Promise&lt;string&gt; {\n  return (await rl.question(label)).trim();\n}<\/code><\/pre>\n<p>Finally, an endless loop wires both together: it reads line by line from the console and passes every input on to <code>ask<\/code>:<\/p>\n<pre><code class=\"language-ts\">async function main(): Promise&lt;void&gt; {\n  console.log(&#039;Ask about the weather in a city.&#039;);\n\n  for (;;) {\n    const prompt = await readLine(&#039;\\n&gt; &#039;);\n    if (!prompt) {\n      continue;\n    }\n    await ask(prompt);\n  }\n}\n\nmain();<\/code><\/pre>\n<p>The loop simply skips empty inputs. The excerpt shown deliberately omits a proper exit \u2014 <code>Ctrl+C<\/code> is entirely sufficient here. The version in the repo additionally supports the <code>exit<\/code> command.<\/p>\n<h2>Testing the Application<\/h2>\n<p>To try it out, you need two terminals in the root of the workspace as well as an API key in the environment variable <code>OPENAI_API_KEY<\/code>. The first terminal starts the Mastra server, which listens on port <code>4555<\/code>:<\/p>\n<pre><code class=\"language-bash\">npm run ai-demo-server<\/code><\/pre>\n<p>The second terminal starts the client:<\/p>\n<pre><code class=\"language-bash\">npm run ai-demo-client<\/code><\/pre>\n<p>Now you can, for example, ask about the weather in Vienna:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/console-chat-client.png\" alt=\"The command-line client answers questions about the weather in Vienna and Paris\" \/><\/p>\n<p>Thanks to the server-side memory, follow-up questions such as <code>Is it warmer than in Paris?<\/code> work as well \u2014 the agent correctly relates the question to Vienna, since both questions are assigned to the same conversation via the same <code>threadId<\/code>.<\/p>\n<p>A look behind the scenes is where it gets really interesting. If you start the client in detail mode and ask, for example, about the weather in Graz, it displays the individual AG-UI messages that the adapter generates from the work of the Mastra agent:<\/p>\n<pre><code class=\"language-bash\">npm run ai-demo-client -- --details<\/code><\/pre>\n<pre><code>[RUN_STARTED         ]\n[TOOL_CALL_START     ] getWeather\n[TOOL_CALL_ARGS      ] {&quot;city&quot;:&quot;Graz&quot;}\n[TOOL_CALL_END       ]\n[TOOL_CALL_RESULT    ] {&quot;city&quot;:&quot;Graz&quot;,&quot;condition&quot;:&quot;sunny&quot;,&quot;temperature&quot;:17}\n[TEXT_MESSAGE_START  ]\n[TEXT_MESSAGE_CONTENT] G\n[TEXT_MESSAGE_CONTENT] raz\n[TEXT_MESSAGE_CONTENT]  is\n[TEXT_MESSAGE_CONTENT]  sunny\n[...]\n[TEXT_MESSAGE_END    ]\n[RUN_FINISHED        ]<\/code><\/pre>\n<p>Here, the message types known from the first part show up in action: the run starts, the model requests a tool call for <code>getWeather<\/code>, the agent executes the tool on the server and logs the result. Then the answer arrives as a stream of individual text fragments before the run is completed. This time, however, the messages do not come from hardcoded examples but from a real agent with a language model.<\/p>\n<h2>An Angular Client with CopilotKit<\/h2>\n<p>After the command line, we take a first look at the actual target environment of this series: the browser. For this, the workspace contains a deliberately minimal Angular application under <code>projects\/simple-client<\/code> that talks to the same AG-UI endpoint as the command-line client.<\/p>\n<p>It uses <a href=\"https:\/\/www.copilotkit.ai\/\">CopilotKit<\/a> \u2014 the open-source frontend SDK for AI assistants and copilots whose makers are also behind AG-UI. CopilotKit comes with ready-made UI building blocks for chats and speaks AG-UI natively. The Angular support comes as a separate package via npm:<\/p>\n<pre><code class=\"language-bash\">npm i @copilotkit\/angular<\/code><\/pre>\n<p>The connection to our agent is established by <code>provideCopilotKit<\/code> in the <code>app.config.ts<\/code>:<\/p>\n<pre><code class=\"language-ts\">import { HttpAgent } from &#039;@ag-ui\/client&#039;;\nimport { provideCopilotKit } from &#039;@copilotkit\/angular&#039;;\n\nconst chatUrl = &#039;http:\/\/localhost:4555\/chat&#039;;\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideBrowserGlobalErrorListeners(),\n    provideCopilotKit({\n      agents: {\n        weatherAgent: new HttpAgent({ url: chatUrl }),\n      },\n    }),\n  ],\n};<\/code><\/pre>\n<p>Here the charm of AG-UI shows once more: CopilotKit simply expects an AG-UI agent. Therefore, the already familiar <code>HttpAgent<\/code> is used, pointing to our <code>\/chat<\/code> endpoint. The key <code>weatherAgent<\/code> assigns a client-side name through which components can refer to this agent.<\/p>\n<p>The actual user interface is provided by the chat control <code>CopilotChat<\/code>:<\/p>\n<pre><code class=\"language-ts\">import { CopilotChat } from &#039;@copilotkit\/angular&#039;;\n\n@Component({\n  selector: &#039;app-root&#039;,\n  imports: [CopilotChat],\n  templateUrl: &#039;.\/app.html&#039;,\n  styleUrl: &#039;.\/app.css&#039;,\n})\nexport class App {}<\/code><\/pre>\n<pre><code class=\"language-html\">&lt;main class=&quot;chat-container&quot;&gt;\n  &lt;copilot-chat agentId=&quot;weatherAgent&quot; \/&gt;\n&lt;\/main&gt;<\/code><\/pre>\n<p>That is all it takes: <code>copilot-chat<\/code> comes with a message list, an input field, and a streaming display, and handles the AG-UI communication in the background. The <code>agentId<\/code> attribute refers to the previously registered agent. The following command starts the application via the Angular dev server on <code>http:\/\/localhost:4300<\/code>:<\/p>\n<pre><code class=\"language-bash\">npm run simple-client<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/07\/copilotkit-chat-control.png\" alt=\"CopilotKit&#039;s chat control answers questions about the weather in Graz and London\" \/><\/p>\n<p>Follow-up questions such as <code>Is it warmer than in London?<\/code> work here too, because behind the chat sits the same agent with its server-side memory.<\/p>\n<p>The ready-made chat control is the fastest way to a runnable result and therefore ideal for getting up and running quickly. In the coming parts of this series, however, we will use CopilotKit's headless mode: it provides the state and behavior of the chat but leaves the presentation entirely to the application. That is always important when the chat should match your own design, when custom widgets should appear in the conversation, or when tool calls should interact with the application's stores, forms, and routing.<\/p>\n<h2>Summary<\/h2>\n<p>An agent framework such as Mastra reduces the server side to a few, easily readable building blocks: an agent with a prompt and memory, a tool with schemas, and a central configuration. The adapter from <code>@ag-ui\/mastra<\/code> translates the work of this agent into AG-UI messages, and a bit of glue code streams them to the client as server-sent events.<\/p>\n<p>The decisive point is the decoupling: the client knows neither Mastra nor the language model being used. It speaks AG-UI exclusively. This applies to the command line just as much as to the Angular client, which comes together in a few lines of code thanks to CopilotKit's chat control. This means the agent framework could be swapped out without touching a single line of client code \u2014 exactly the promise this series started with.<\/p>\n<h2>The Next Step<\/h2>\n<p>With CopilotKit's ready-made chat control, we quickly arrived at a runnable result. From the next part on, however, we switch to the flexible headless mode of CopilotKit mentioned above and show how agents can be integrated deeply and idiomatically into Angular applications with it \u2014 with a custom-rendered chat history, client-side tools, and custom widgets.<\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/en\/blog\/implementing-ag-ui-with-angular\/\" class=\"button\" style=\"text-decoration:none !important\"><strong>Next article \u2192<\/strong><\/a><\/p>\n<hr \/>\n<p><div style=\"\nmargin: 8px 0;\npadding: 22px;\nborder: 1px solid #e5e7eb;\nborder-radius: 14px;\nbackground: #f8fafc;\n\"><\/p>\n<h3 style=\"margin-top:0\">Interested in production-ready Agentic UI architectures?<\/h3>\n<p>In my workshop, we dig into AG-UI, A2UI, MCP Apps, HITL patterns, and modern Angular architectures for real-world agentic systems.<\/p>\n<p><a href=\"https:\/\/www.angulararchitects.io\/en\/training\/agentic-ai-with-angular-architecture-patterns\/\"><img decoding=\"async\" src=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/05\/sujet-workshop-en.png\" width=\"400\" alt=\"Workshop: Agentic AI with Angular \u2013 AG-UI, A2UI, MCP Apps & HITL patterns\" style=\"cursor:pointer !important\"><\/a><\/p>\n<p><a style=\"cursor:pointer !important\" href=\"https:\/\/www.angulararchitects.io\/en\/training\/agentic-ai-with-angular-architecture-patterns\/\">See all details \u2192<\/a>\n<\/div>\n<\/p>\n<h2>FAQ<\/h2>\n<h3>Why Does the Article Use Mastra?<\/h3>\n<p>Mastra was built for TypeScript from the ground up and therefore fits well into the toolbox of frontend teams. The concepts shown \u2014 agent, tools, memory, and prompt \u2014 can, however, also be found in a very similar form in other agent frameworks such as LangGraph, Google ADK, or the Microsoft Agent Framework.<\/p>\n<h3>What Does the Adapter from <code>@ag-ui\/mastra<\/code> Do?<\/h3>\n<p>The class <code>MastraAgent<\/code> implements the <code>AbstractAgent<\/code> of the AG-UI SDK. It calls the Mastra agent passed to it and translates its streaming events into AG-UI messages such as <code>TOOL_CALL_START<\/code> or <code>TEXT_MESSAGE_CONTENT<\/code>. This eliminates the need to create these messages manually.<\/p>\n<h3>Does the Client Have to Know That Mastra Is Involved?<\/h3>\n<p>No. The client only knows the URL of the AG-UI endpoint and the standardized message types. The agent framework, the language model, and the server-side tools can be swapped out without changing the client.<\/p>\n<h3>What Is CopilotKit?<\/h3>\n<p>CopilotKit is an open-source frontend SDK for AI assistants and agentic UIs, created by the same people behind AG-UI. It offers ready-made building blocks such as the chat control shown here as well as a headless mode for fully custom user interfaces, and it communicates with agents natively via AG-UI.<\/p>\n<h3>How Does the Agent Remember the Conversation?<\/h3>\n<p>The client generates a <code>threadId<\/code> per session, which the route handler passes on to Mastra's memory as <code>resourceId<\/code>. This way, the agent assigns all runs to the same conversation, and the client only has to transmit the new messages.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is post 3 of 9 in the series &ldquo;Agentic Angular&rdquo; Understanding AG-UI: The Standard for Agentic User Interfaces AG-UI in Practice: The SDK for TypeScript AG-UI End to End: Connecting Server and Client Agentic UI with Angular, CopilotKit, and AG-UI A2UI: How AI Generates Dynamic UIs at Runtime Integrating A2UI with AG-UI and CopilotKit [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":33193,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"_acf_changed":false,"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":""},"categories":[18],"tags":[],"class_list":["post-34423","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","post_series-agentic-angular"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>AG-UI End to End: Connecting Server and Client - ANGULARarchitects<\/title>\n<meta name=\"description\" content=\"Einen Agent via AG-UI anbinden&quot;description: &quot;Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"AG-UI End to End: Connecting Server and Client - ANGULARarchitects\" \/>\n<meta property=\"og:description\" content=\"Einen Agent via AG-UI anbinden&quot;description: &quot;Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\" \/>\n<meta property=\"og:site_name\" content=\"ANGULARarchitects\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-20T12:55:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-22T10:25:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/Kopie-von-Kopie-von-Kopie-von-Kopie-von-Kopie-von-Blue-White-and-Red-Modern-Digital-Marketing-Agency-Facebook-Ad-1200-x-628-px-1.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"628\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Manfred Steyer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/Kopie-von-Kopie-von-Kopie-von-Kopie-von-Kopie-von-Blue-White-and-Red-Modern-Digital-Marketing-Agency-Facebook-Ad-1200-x-628-px-1.png\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Manfred Steyer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\"},\"author\":{\"name\":\"Manfred Steyer\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a\"},\"headline\":\"AG-UI End to End: Connecting Server and Client\",\"datePublished\":\"2026-04-20T12:55:32+00:00\",\"dateModified\":\"2026-07-22T10:25:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\"},\"wordCount\":2496,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\",\"name\":\"AG-UI End to End: Connecting Server and Client - ANGULARarchitects\",\"isPartOf\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg\",\"datePublished\":\"2026-04-20T12:55:32+00:00\",\"dateModified\":\"2026-07-22T10:25:22+00:00\",\"description\":\"Einen Agent via AG-UI anbinden\\\"description: \\\"Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg\",\"width\":1000,\"height\":563},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.angulararchitects.io\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"AG-UI End to End: Connecting Server and Client\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#website\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"name\":\"ANGULARarchitects\",\"description\":\"AngularArchitects.io\",\"publisher\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#organization\",\"name\":\"ANGULARarchitects\",\"alternateName\":\"SOFTWAREarchitects\",\"url\":\"https:\/\/www.angulararchitects.io\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"contentUrl\":\"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg\",\"width\":644,\"height\":216,\"caption\":\"ANGULARarchitects\"},\"image\":{\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/github.com\/angular-architects\",\"https:\/\/www.linkedin.com\/company\/angular-architects\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a\",\"name\":\"Manfred Steyer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g\",\"caption\":\"Manfred Steyer\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"AG-UI End to End: Connecting Server and Client - ANGULARarchitects","description":"Einen Agent via AG-UI anbinden\"description: \"Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/","og_locale":"en_US","og_type":"article","og_title":"AG-UI End to End: Connecting Server and Client - ANGULARarchitects","og_description":"Einen Agent via AG-UI anbinden\"description: \"Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.","og_url":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/","og_site_name":"ANGULARarchitects","article_published_time":"2026-04-20T12:55:32+00:00","article_modified_time":"2026-07-22T10:25:22+00:00","og_image":[{"width":1200,"height":628,"url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/Kopie-von-Kopie-von-Kopie-von-Kopie-von-Kopie-von-Blue-White-and-Red-Modern-Digital-Marketing-Agency-Facebook-Ad-1200-x-628-px-1.png","type":"image\/png"}],"author":"Manfred Steyer","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/Kopie-von-Kopie-von-Kopie-von-Kopie-von-Kopie-von-Blue-White-and-Red-Modern-Digital-Marketing-Agency-Facebook-Ad-1200-x-628-px-1.png","twitter_misc":{"Written by":"Manfred Steyer","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#article","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/"},"author":{"name":"Manfred Steyer","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a"},"headline":"AG-UI End to End: Connecting Server and Client","datePublished":"2026-04-20T12:55:32+00:00","dateModified":"2026-07-22T10:25:22+00:00","mainEntityOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/"},"wordCount":2496,"commentCount":0,"publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/","url":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/","name":"AG-UI End to End: Connecting Server and Client - ANGULARarchitects","isPartOf":{"@id":"https:\/\/www.angulararchitects.io\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage"},"thumbnailUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg","datePublished":"2026-04-20T12:55:32+00:00","dateModified":"2026-07-22T10:25:22+00:00","description":"Einen Agent via AG-UI anbinden\"description: \"Wie verbindet man einen serverseitigen Agent mit AG-UI? Dieser Artikel zeigt einen mit Mastra umgesetzten Weather-Agent samt Tool, Prompt und Memory, die AG-UI-Integration \u00fcber den Mastra-Adapter, einen schlanken Kommandozeilen-Client und einen ersten Angular-Client mit CopilotKit.","breadcrumb":{"@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#primaryimage","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2026\/04\/shutterstock_2650298597.jpg","width":1000,"height":563},{"@type":"BreadcrumbList","@id":"https:\/\/www.angulararchitects.io\/en\/blog\/ag-ui-in-practice-ag-ui-end-to-end-connecting-server-and-client\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.angulararchitects.io\/en\/"},{"@type":"ListItem","position":2,"name":"AG-UI End to End: Connecting Server and Client"}]},{"@type":"WebSite","@id":"https:\/\/www.angulararchitects.io\/en\/#website","url":"https:\/\/www.angulararchitects.io\/en\/","name":"ANGULARarchitects","description":"AngularArchitects.io","publisher":{"@id":"https:\/\/www.angulararchitects.io\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.angulararchitects.io\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.angulararchitects.io\/en\/#organization","name":"ANGULARarchitects","alternateName":"SOFTWAREarchitects","url":"https:\/\/www.angulararchitects.io\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/","url":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","contentUrl":"https:\/\/www.angulararchitects.io\/wp-content\/uploads\/2023\/07\/AA-Logo-RGB-horizontal-inside-knowledge-black.svg","width":644,"height":216,"caption":"ANGULARarchitects"},"image":{"@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/github.com\/angular-architects","https:\/\/www.linkedin.com\/company\/angular-architects\/"]},{"@type":"Person","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/f3de69c1e2bdb5ba04d8d2f5f998b81a","name":"Manfred Steyer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.angulararchitects.io\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/8778dfb353992fa3a0d909beee085a088891e5bfce65cdb3631801da527cf11b?s=96&d=mm&r=g","caption":"Manfred Steyer"}}]}},"_links":{"self":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34423","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/comments?post=34423"}],"version-history":[{"count":3,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34423\/revisions"}],"predecessor-version":[{"id":34463,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/posts\/34423\/revisions\/34463"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media\/33193"}],"wp:attachment":[{"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/media?parent=34423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/categories?post=34423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.angulararchitects.io\/en\/wp-json\/wp\/v2\/tags?post=34423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}