Introduction
@threadplane/ag-ui is protocol-first: it consumes the AG-UI event vocabulary rather than any one runtime's SDK. That makes "any AG-UI backend plugs in" a claim that can be tested instead of asserted.
This section documents what happened when it was tested. On 2026-08-31 the adapter was run against three runtimes that have nothing to do with LangGraph, in two languages, with no adapter changes for messages, tool calls, or state. Each runtime has a standalone Angular example, a real backend, and a committed transcript of its wire traffic.
These pages document runtimes as backends measured against the adapter. They are not a substitute for each vendor's own documentation, and Threadplane does not maintain any of the upstream AG-UI bridges described here.
The runtimes
Python. Messages, tool calls, and interrupts work. Shared state is snapshot-only and opt-in per tool.
Python. Messages, tool calls, state, and interrupts all work. Azure OpenAI by default.
TypeScript. Messages, tool calls, state, and interrupts all work, against a hand-written Node hosting service.
Measured support
| Runtime | Messages | Tool calls | State | Interrupts | Subagents |
|---|---|---|---|---|---|
| LangGraph (via the AG-UI bridge) | Yes | Yes | Yes | Yes | Yes |
| AWS Strands (Python) | Yes | Yes | Partial | Yes | No |
| Microsoft Agent Framework (Python) | Yes | Yes | Yes | Yes | No |
| Mastra (TypeScript) | Yes | Yes | Yes | Yes | No |
Every gap in that table is caused by an upstream integration, not by the AG-UI protocol and not by a defect in @threadplane/ag-ui. The full cause analysis, including the two adapter defects that were found and fixed, lives in Choosing an adapter.
What is the same everywhere
The Angular side does not change between these three runtimes. Each example uses the same provider call and the same component body:
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideAgent } from '@threadplane/ag-ui';
import { provideChat } from '@threadplane/chat';
export const appConfig: ApplicationConfig = {
providers: [
provideAgent({ url: '/agent' }),
provideChat({}),
],
};import { Component } from '@angular/core';
import { ChatComponent } from '@threadplane/chat';
import { injectAgent } from '@threadplane/ag-ui';
@Component({
selector: 'app-root',
imports: [ChatComponent],
template: `<chat [agent]="agent" />`,
})
export class App {
protected readonly agent = injectAgent();
}What changes is the backend, its hosting lane, and the wire conventions it happens to use. The How It Connects page for each runtime records those conventions as they were measured.
What is different everywhere
Three differences turned up repeatedly, and each runtime page returns to them.
Interrupts arrive by two different conventions. AWS Strands and Microsoft Agent Framework signal an interrupt only through the protocol-standard RUN_FINISHED outcome. The LangGraph bridge signals it only through a CUSTOM event named on_interrupt. Mastra emits both. The adapter accepts either, and within a single run the first signal wins.
Resume payloads are not portable. The adapter derives the wire shape from how the interrupt arrived, so application code passes one neutral submit({ resume }) regardless of runtime.
Subagents are unavailable on every third-party runtime. The three runtimes model delegation in three different ways, and none of them emits the dedicated SUBAGENT_* events that @ag-ui/core has carried since 0.0.59. Treat server-declared subagents as a capability of LangGraph and of backends you control.
Further reading
- Choosing an adapter — the full measured matrix, cause-by-cause.
- AG-UI adapter introduction — the adapter these runtimes bind through.
- What changes when the runtime changes — the argument for measuring portability.
- We measured the runtime swap — the results write-up.
libs/ag-ui/fixtures/runtime-transcripts/— the captured Server-Sent Events, verbatim from the wire.