Repository navigation
Description
Summary
adk web renders A2UI v0.8 surfaces from <a2ui-json> blocks, but clicking an A2UI Button does nothing. No request is sent to the agent, nothing is logged, and the action is lost. Any A2UI surface with actions is effectively read-only in the dev UI.
Versions
- google-adk 2.13.0 (bundled dev UI,
main-KCUV4MHY.js) - Also present on adk-web
mainat dfac466 (@a2ui/angular^0.10.0) - macOS, Chromium-based browser
Reproduce
No model call or credentials are needed; a before_model_callback returns a fixed surface.
a2ui_click_repro/agent.py:
from google.adk.agents import Agent
from google.adk.models.llm_response import LlmResponse
from google.genai import types
SURFACE = """Click the button.
<a2ui-json>
[{"beginRendering": {"surfaceId": "s1", "root": "root"}},
{"surfaceUpdate": {"surfaceId": "s1", "components": [
{"id": "root", "component": {"Button": {"child": "label", "action": {"name": "clicked"}}}},
{"id": "label", "component": {"Text": {"text": {"literalString": "Click me"}}}}]}}]
</a2ui-json>"""
def reply(callback_context, llm_request):
return LlmResponse(content=types.Content(role="model", parts=[types.Part(text=SURFACE)]))
root_agent = Agent(name="a2ui_click_repro", model="gemini-2.5-flash", before_model_callback=reply)adk web .and open thea2ui_click_reproapp.- Send any message. The "Click me" button renders.
- Click it and watch the Network tab.
Expected: a new /run_sse request carrying the userAction ({"name": "clicked", "surfaceId": "s1", ...}), so the agent can handle the click.
Actual: no request. The only /run_sse is the one from step 2. No console error.
Cause
Button.sendAction() builds the userAction and calls MessageProcessor.dispatch(), which pushes {message, completion} onto eventsSubject and returns a promise that resolves when completion emits.
Nothing in adk-web subscribes to MessageProcessor.events. A2uiCanvasComponent (src/app/components/a2ui-canvas/a2ui-canvas.component.ts) only calls processMessages() and reads surfaces. The bundled 2.13 build has the same gap: the processor is referenced by the canvas, the surface, the renderer and the button base class, and none of them read events. So every action goes to a subject with no subscribers and its promise never settles.
Suggested fix
Subscribe once to MessageProcessor.events (in the chat component or the canvas) and turn each event into a user turn:
- send
JSON.stringify({userAction: event.message.userAction})(or a structured part) as a new message on the current session through the same path as the chat input, - then call
event.completion.next([])andcomplete()sodispatch()resolves.
A small note in the A2UI docs on how actions reach the agent in adk web would help too. #447 touches the same area from the A2A side.
Activity
huong8373tt-beep commentedon Oct 30, 2026
A focused fix is now available in PR #558: #558
It subscribes to the existing A2UI v0.8
MessageProcessor.eventsstream, routesuserActionthrough the current chat/run_ssepath, and completes dispatch after the user turn is accepted. The PR includes a regression test and the required disclosure.