Distinguish AG-UI events from A2UI interface content
How to study this lesson
Read one section, trace the worked example, and try the knowledge check. Bookmark saves a shortcut; notes appear in My notebook. Mark lesson complete is your own assessment and does not mark its lab passed.
By the end, you can
- Map frontend/backend interaction to event categories.
- Explain how A2UI and AG-UI can complement one another.
- Design stream framing and lifecycle handling without invented guarantees.
Two protocols answer different questions
AG-UI defines an event-based connection between agent backends and user-facing applications. Its concerns include run lifecycle, streamed text, tool activity, and shared state. A2UI describes declarative interface content that a renderer can build from an approved catalog. The names are similar, but choosing a button and describing a run's progress are different layers of a system. AG-UI's own overview explicitly distinguishes these roles and describes them as complementary. [AG-UI overview](https://docs.ag-ui.com/introduction).
A dashboard can use AG-UI to show that a research run started, stream a status message, and deliver state changes. Within that interaction, A2UI content can describe a task-specific comparison panel. Neither protocol automatically supplies the application's database, access policy, or business logic. Draw these responsibilities separately when designing the integration so a renderer update is not accidentally treated as an authorized backend command.
Lifecycle and content need stable identities
AG-UI documents lifecycle events, text message events, tool call events, and state management events. Run identifiers and message identifiers let the frontend associate pieces with the right activity. Current lifecycle documentation also distinguishes interrupted outcomes where supported; a finished run event should not blindly be interpreted as every business task being complete. Pin the SDK and schema, because draft and evolving event features may not be supported uniformly. [AG-UI event documentation](https://docs.ag-ui.com/concepts/events).
In your local application model, use a reducer that accepts a well-defined sequence and updates UI state. For text, start a message, append content to that message, and mark it complete. If content arrives for an unknown message, decide whether to reject, buffer briefly, or resynchronize under the protocol adapter. Appending everything into one global string loses identity as soon as multiple messages or concurrent activities share the stream.
Framing is not the same as JSON generation
Streaming network bytes can split a JSON object between chunks or combine several objects in one chunk. The transport adapter must identify complete messages before schema validation and dispatch. A JSON Lines transport uses delimiters, while Server-Sent Events and WebSocket frames have their own framing rules. Do not assume one network read equals one application event, and do not parse a partial model token stream as a complete UI command.
Consider the bytes for a text update arriving in three fragments. The first fragment can contain a complete-looking label but no closing object. Rendering it prematurely might create an invalid component or expose a partial action identifier. Buffer to the defined message boundary, enforce size limits, parse, validate, and only then apply the event. Streaming improves responsiveness when incremental units are meaningful; it does not justify skipping the validation boundary.
Compose through an explicit adapter
To combine A2UI with AG-UI, use a documented compatible integration or define an application adapter that carries the chosen A2UI payloads through an appropriate event or content channel. Record the content version separately from the interaction-protocol version. Do not invent one shared version number or assume that an A2A extension payload can be copied unchanged into an AG-UI event. Each boundary has its own schema and lifecycle.
The host first interprets the interaction event, then routes UI content to the validated renderer. A user action travels back through the frontend/backend connection to an authenticated handler, which validates its business meaning and may produce new events and UI content. The two protocols can cooperate without collapsing their responsibilities. The code below models lifecycle and text reduction only, with deliberately local event names; it is not a conforming AG-UI transport or an A2UI payload example.
Design interruption and failure displays honestly
A network disconnect, a backend error, a user-requested interruption, and a completed run are different states. Show enough information for the user to understand whether work continues, needs input, or has failed. Keep the last valid UI available when a new malformed event arrives, and offer recovery through a fresh snapshot or a supported resume operation. Avoid leaving a permanent loading spinner merely because the connection ended without the event your reducer expected.
Test event traces with interleaved messages, duplicate frames, invalid order, unknown event types, and a reconnect. For each case, define whether the adapter rejects, deduplicates, or asks for authoritative state. An event protocol does not automatically provide durable replay or exactly-once application effects. Your application needs explicit event identity and recovery rules wherever those guarantees matter. That distinction keeps interface responsiveness from being mistaken for workflow correctness.
Work through the code
This teaching simulation uses local event names and a simplified success-only trace to demonstrate message identity and incremental reduction. It is not an AG-UI schema validator and does not cover the protocol interrupt lifecycle. A real adapter must use pinned official event types.
events = [
{'kind': 'run_start', 'run': 'r1'},
{'kind': 'text_start', 'message': 'm1'},
{'kind': 'text_delta', 'message': 'm1', 'text': 'Two '},
{'kind': 'text_delta', 'message': 'm1', 'text': 'checks passed.'},
{'kind': 'text_end', 'message': 'm1'},
{'kind': 'run_end', 'outcome': 'success'},
]
state = {'run': None, 'messages': {}, 'outcome': None}
for event in events:
kind = event['kind']
if kind == 'run_start':
state['run'] = event['run']
elif kind == 'text_start':
state['messages'][event['message']] = {'text': '', 'done': False}
elif kind == 'text_delta':
state['messages'][event['message']]['text'] += event['text']
elif kind == 'text_end':
state['messages'][event['message']]['done'] = True
elif kind == 'run_end':
state['outcome'] = event['outcome']
print(state['messages']['m1']['text'])
print('message complete:', state['messages']['m1']['done'])
print('run outcome:', state['outcome'])
Two checks passed. message complete: True run outcome: success
Run Python snippets locally with the prerequisites named above. The module coding lab runs directly in your browser.
Pause and reason
Your team says A2UI replaces AG-UI because both stream JSON. Explain the missing distinction with a concrete workflow.
Check your understanding
A network read contains half of a JSON event. What should the transport adapter do?
Your notes
Explain the mechanism in your own words. Add a failure you want to test.