feat(composer): A2UI Dojo — interactive JSONL playback and streaming viewer#857
feat(composer): A2UI Dojo — interactive JSONL playback and streaming viewer#857zeroasterisk wants to merge 33 commits intogoogle:mainfrom
Conversation
…be component - New guide: design-system-integration.md — step-by-step for adding A2UI to an existing Material Angular application - Rewritten guide: custom-components.md — complete walkthrough for YouTube, Maps, and Charts custom components (replaces TODO skeleton) - New sample component: YouTube embed for rizzcharts catalog - Updated rizzcharts catalog.ts to include YouTube component - Friction log documenting 8 friction points (P2/P3) encountered during development, with recommendations - Added Design System Integration to mkdocs nav
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
- Remove friction log file (content already in issue google#825) - YouTube component: add video ID regex validation (security) - custom-components.md: rename to 'Custom Component Catalogs', reorder examples (media first), clarify basic catalog is optional, remove redundant heading, fix Maps input.required consistency, add encodeURIComponent to docs example - design-system-integration.md: rewrite to focus on wrapping Material components as A2UI components (not using DEFAULT_CATALOG), show custom catalog without basic components, add mixed catalog example - s/standard/basic/ throughout
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request introduces the A2UI Dojo, a playback tool for agent scenarios, along with new documentation and sample scripts. The changes are a great addition, providing valuable tooling for development and testing.
My review focuses on improving the portability of the new sample scripts by removing hardcoded paths, and enhancing the robustness and maintainability of the new Dojo UI component in React. Specifically, I've pointed out a bug with React keys and suggested improvements to TypeScript type safety. I've also provided feedback on the code examples in the new documentation to prevent potential bugs for developers following the guide.
| messages.append(p.root.data) | ||
|
|
||
| if messages: | ||
| out_path = "/home/node/.openclaw/projects/A2UI/tools/composer/src/data/dojo/contact-lookup.json" |
There was a problem hiding this comment.
The output path is hardcoded to an absolute path, which makes the script non-portable for other developers. It's better to construct a path relative to the script's location.
You can achieve this using pathlib. You'll need to add from pathlib import Path at the top of the file. Also, consider ensuring the directory exists before writing, for example with out_path.parent.mkdir(parents=True, exist_ok=True) before the with open(...) block.
| out_path = "/home/node/.openclaw/projects/A2UI/tools/composer/src/data/dojo/contact-lookup.json" | |
| out_path = Path(__file__).resolve().parents[4] / "tools/composer/src/data/dojo/contact-lookup.json" |
| messages.append(p.root.data) | ||
|
|
||
| if messages: | ||
| out_path = "/home/node/.openclaw/projects/A2UI/tools/composer/src/data/dojo/restaurant-finder.json" |
There was a problem hiding this comment.
The output path is hardcoded to an absolute path, which makes the script non-portable. It's better to construct a path relative to the script's location.
You can achieve this using pathlib. You'll need to add from pathlib import Path at the top of the file. Also, consider ensuring the directory exists before writing, for example with out_path.parent.mkdir(parents=True, exist_ok=True) before the with open(...) block.
| out_path = "/home/node/.openclaw/projects/A2UI/tools/composer/src/data/dojo/restaurant-finder.json" | |
| out_path = Path(__file__).resolve().parents[4] / "tools/composer/src/data/dojo/restaurant-finder.json" |
tools/composer/src/app/dojo/page.tsx
Outdated
| <div className="flex flex-col gap-2"> | ||
| {(scenarios[selectedScenario] as any).map((msg: any, index: number) => ( | ||
| <div | ||
| key={msg.id} |
There was a problem hiding this comment.
The key prop is set to msg.id, but the message objects in your scenario data don't have a top-level id property. This will cause React to issue a warning about missing or duplicate keys and can lead to unpredictable rendering behavior. Since this is a static list, using the index as a key is acceptable here.
| key={msg.id} | |
| key={index} |
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| source ~/.openclaw/credentials/secrets.sh | |||
| @@ -0,0 +1,4 @@ | |||
| #!/bin/bash | |||
| source ~/.openclaw/credentials/secrets.sh | |||
There was a problem hiding this comment.
tools/composer/src/app/dojo/page.tsx
Outdated
| seek, | ||
| setSpeed | ||
| } = useJsonlPlayer({ | ||
| messages: (scenarios[selectedScenario] as any) || [], |
There was a problem hiding this comment.
…or A2UI Dojo - Redesigned Top Command Center with glassmorphic header and functional timeline scrubber. - Replaced native scenario select with Shadcn DropdownMenu. - Polished Data Stream view with active state highlighting, glow effects, and auto-scrolling. - Replaced native checkboxes with custom Tailwind styled toggles in Config view. - Added dynamic grid layout for the Renderers Panel with sophisticated styling per surface (React Web, Discord dark mode replica, Lit Components). - Applied custom slim scrollbars throughout for a premium feel.
…r Vercel over Cloudflare Pages
… sync sample data
… update transcoder
- Replace invented v0.9 scenarios with real v0.8 samples from samples/agent/adk/ - Add restaurant-booking, restaurant-list, restaurant-grid, restaurant-confirmation - Add contact-card, contact-list, org-chart, floor-plan scenarios - Update index.ts to surface real scenarios as defaults - Default scenario is now restaurant-booking (verified rendering) - Fix transcoder.ts: pass v0.8 messages through unchanged - Fix useA2UISurface.ts: only process v0.8 format components (id + component) - Fix dataModelUpdate: parse ValueMap format correctly - Restaurant booking now renders: column, text, image, textfield, datetime, button - Locally verified with headless Chromium: all A2UI CSS classes present - Build passes (bun run build)
- Switch import to @copilotkit/a2ui-renderer (npm-published) - Remove file:../../renderers/react dep that breaks Vercel builds - @copilotkit/a2ui-renderer uses @a2ui/lit under the hood (npm transitive dep)
- Remove Discord mock pane and multi-renderer grid - Show single A2UI renderer (full width, centered) - Add human-readable step summaries to JSONL pane (e.g. 'Update 9 components: Column, Text, Image, TextField...') - Raw JSON collapsed by default behind 'Raw JSON ▸' toggle - Steps are clickable to seek directly - Wider left pane (35%) for better readability - Remove unused renderer toggle state
- Remove northstar-tour, flight-status, weather-widget (v0.9 format) - Remove kitchen-sink, component-gallery-stream (not real scenarios) - Keep only verified v0.8 scenarios from samples/agent/adk/ - 12 working scenarios remain in dropdown
…nt doesn't clip The browser-chrome container had h-full which constrained it to viewport height and overflow-hidden clipped any content below. This caused the DateTimeInput and fields below it to be cut off in restaurant-booking with no way to scroll. Fix: remove h-full from the frame so it grows with content, and drop flex-1 + overflow-auto from the content area since the outer pane wrapper already handles scrolling via overflow-y-auto. Fixes google#243
…nfirmation scenario The Card component referenced 'confirmation-column' as its child, but that component was never defined in the surfaceUpdate. This caused the model processor to return null for the unresolved child, making isResolvedCard() fail validation with 'Invalid data; expected Card'. Fix: add the confirmation-column Column component with an explicit children list wiring up all the confirmation content components.
On small screens (< sm breakpoint), the traffic light dots in the mock browser chrome header are hidden to reduce visual clutter. Uses Tailwind's hidden sm:flex responsive pattern. Task google#237
The route was incorrectly set to 'force-static' which caused Next.js to fail with a 500 error on every page load since the CopilotRuntime / InMemoryAgentRunner cannot be statically exported. Change to 'force-dynamic' so the route is properly handled server-side.
- URL state: scenario, step, renderer synced to query params (e.g. /dojo?scenario=contact-card&step=2&renderer=React) - Config panel: renderer dropdown + scenario dropdown (synced with header) - Sidebar nav: added 'Dojo' link with Play icon - Curated to 5 quality scenarios (removed broken/redundant ones) - Removed contact-lookup (crashes on step 4 — missing component refs)
…ario Major architecture change: - NEW useStreamingPlayer hook: explodes messages into individual JSONL lines that stream progressively (line-by-line) instead of whole-message chunks - Scrubber now has fine-grained control over 60+ stream positions per scenario - Three left pane tabs: (a) Events — lifecycle summaries (surface created, components registered, data bound) (b) Data — raw streaming lines appearing chunk by chunk with ↓/↑ badges (c) Config — scenario, renderer, transport dropdowns - Removed scenario dropdown from header (lives only in Config tab) - Streaming cursor animation shows which message is mid-delivery - Click any event/line to seek to that position - Server/client sections grouped with direction badges - Compact header with streaming status indicator
Each JSONL chunk is one complete JSON object on one line — that's how real SSE/JSONL works. Not individual formatted lines within a message. - Data tab now shows raw wire format (compact JSON, one chunk per card) - Shows byte size per chunk and total bytes received - Scrubber steps through 3 chunks for restaurant-booking (not 60+ fake lines) - Streaming cursor shows 'Waiting for next chunk...' between deliveries - Header shows total bytes received during playback
Adds 3 new chunks to the restaurant-booking scenario: - Chunk 4 (↑ CLIENT): User submits booking form with party size, date, dietary requirements via clientEvent/userAction - Chunk 5 (↓ SERVER): Agent responds with confirmation surface update (checkmark, title, details, summary, Done button) - Chunk 6 (↓ SERVER): Data model update with confirmation details Full bidirectional flow: server renders form → user fills and submits → server confirms with new surface state. Demonstrates the complete A2UI interaction lifecycle in 6 JSONL chunks.
A2UI Dojo
A new
/dojoroute in the Composer that acts as a VCR for A2UI protocol traces. Load a scenario, press play, and watch JSONL chunks stream in one-by-one while the renderer updates in real-time.Features
?scenario=restaurant-booking&step=4links directly to any statesamples/agent/adk/(real v0.8 wire format)Files Changed
src/app/dojo/page.tsxsrc/components/dojo/useStreamingPlayer.tssrc/components/dojo/useA2UISurface.tssrc/components/layout/sidebar-nav.tsxsrc/data/dojo/index.tssrc/data/dojo/restaurant-booking.jsonLive Demo
👉 https://composer-ten.vercel.app/dojo