feat(a2ui,chat): honor beginRendering.styles per A2UI v1 spec (Pass 2a)#233
Merged
Conversation
The canonical A2UI v1 wire format defines exactly two theming knobs on
beginRendering.styles: `font` (primary font family) and `primaryColor`
(hex `#RRGGBB`). The lib's type system already declared the field but
no consumer read it — agents could emit `styles: { primaryColor:
"#FF0000" }` and the renderer silently dropped it.
Three coordinated changes for v1 spec compliance:
1. **`libs/a2ui` types** — `A2uiSurface` gains an optional `styles?:
{ font?, primaryColor? }` field mirroring the wire shape, used as
the renderer's single source of truth for v1-spec-defined theming
on a given surface.
2. **`libs/chat` surface-store** — beginRendering's `styles` are
captured onto the new `A2uiSurface.styles` field at commit time.
Re-renders preserve existing styles when the new beginRendering
omits them (matches the agent's likely "change the data, keep the
look" intent).
3. **`<a2ui-surface>` host** — applies `surface.styles.primaryColor`
as `--a2ui-primary` and `surface.styles.font` as `font-family` via
host bindings. `null` when unset so consumer-set `:root` defaults
are not overridden. Catalog components already consume
`var(--a2ui-primary)` for accents (buttons, sliders, focus, etc.);
font cascades naturally.
This is the spec-compliance half of the theming track (Pass 2a). The
internal token system that powers the rest of the catalog's visual
quality (spacing scale, typography scale, shape radius, focus ring,
motion, elevation) remains the renderer's private vocabulary —
explicitly NOT communicated through the wire format. That richer
token surface is Pass 2b.
Three new unit tests cover: capture from beginRendering, omission when
unset, and preservation across re-renders.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes a v1-spec compliance gap: the canonical A2UI v1 wire format defines exactly two theming knobs on `beginRendering.styles` — `font` (primary font family) and `primaryColor` (hex `#RRGGBB`). The type system declared the field but no consumer read it — agents could emit `styles: { primaryColor: "#FF0000" }` and the renderer silently dropped it.
This PR is Pass 2a of the A2UI theming track: ship spec compliance first, then layer on the richer internal token system (Pass 2b) that's the renderer's private vocabulary.
Changes
Why split from Pass 2b
The richer token surface (spacing/typography/shape/focus/motion/elevation/derived-colors) is the renderer's private vocabulary — explicitly NOT communicated through the wire format. The agent shouldn't know about it. Pass 2a is small, high-value (closes the spec gap), and unblocks live testing of agent-driven theming. Pass 2b refactors the catalog to consume an expanded internal token set; Pass 3 ships preset CSS files (Material flavor) consumers `@import`.
Test plan
Pending live verification
🤖 Generated with Claude Code