feat(spec): add core A2UI templates specification, version 0.1 schema, and examples - #2380
feat(spec): add core A2UI templates specification, version 0.1 schema, and examples#2380jacobsimionato wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the A2UI Templates Specification, including a comprehensive markdown specification, a JSON schema for template definitions, and multiple YAML examples demonstrating template usage. The review feedback highlights several critical issues: the JSON schema needs to enforce that either template or item is provided in LoopDefinition, and it lacks a mechanism to declare required parameters. Additionally, there are duplicate templateId registrations across example files, type mismatches in section_card.yaml and two_column_layout.yaml, and the term normalized_type in the ID synthesis specification requires explicit definition in the README.
ecc0b9d to
636f817
Compare
|
Thank you for the detailed feedback! All comments have been addressed in the latest commit:
|
636f817 to
9393bf7
Compare
There was a problem hiding this comment.
Would it make sense for this to be a YAML schema instead of a JSON schema?
I mean, given that the format is in YAML, that makes sense to me.
I'm not sure it actually matters much, and I think the end result is the same, so maybe it makes sense to keep all the schema in one form. It was just a thought.
There was a problem hiding this comment.
I read that people normally use JSON schema to represent schemas for YAML files, so I just stuck with that. I don't feel strongly though - we can change this at any time.
From search:
"The most widely used method to validate YAML files (such as GitHub Actions, Kubernetes manifests, or custom configs) is to write a standard JSON Schema but format it as a YAML file"
| The template engine operates entirely server-side within the A2UI Agent SDK: | ||
|
|
||
| ``` | ||
| +-------------------------------------------------------------------------------+ |
There was a problem hiding this comment.
This could easily be a Mermaid diagram and be a lot nicer.
There was a problem hiding this comment.
Updated the execution pipeline ASCII box diagram to a clean Mermaid flowchart diagram!
| @@ -0,0 +1,582 @@ | |||
| # A2UI Templates Specification | |||
There was a problem hiding this comment.
Nit: Should it maybe be "A2UI Template Specification" (singular)?
There was a problem hiding this comment.
Updated the title to singular: # A2UI Template Specification.
|
|
||
| ## Abstract | ||
|
|
||
| This document defines the authoritative specification for the **A2UI Templates System**. |
There was a problem hiding this comment.
Is it a System or a Specification?
There was a problem hiding this comment.
Clarified phrasing to: "This document defines the authoritative specification for A2UI Templates."
|
|
||
| This document defines the authoritative specification for the **A2UI Templates System**. | ||
|
|
||
| Templates provide a declarative, human-readable mechanism for authoring reusable UI subtrees in nested YAML or via native programmatic render functions. At generation time, an agent or Large Language Model (LLM) outputs compact, high-level template invocations (such as `UserProfile("u1", "Alice")` or `PayrollSummary("Eng", true)`). The backend SDK expands these invocations into standard, flat A2UI Basic Catalog components in a single synchronous pass before emitting standard A2UI protocol messages (`updateComponents`) to the client. |
There was a problem hiding this comment.
The examples are all "programmatic render functions", so maybe we don't need the "nested YAML" case in the first sentence? Besides, seems weird to next YAML inside of A2UI (or maybe that's not what that means)?
There was a problem hiding this comment.
I'm actually a little confused about this reading the doc: it seems like the "nested YAML" part is the template definitions, while the "programmatic render functions" is the instantiations. This description makes it sound like they are interchangable.
There was a problem hiding this comment.
Re whether we need YAML at all, I think the main use case is to provide a smooth workflow from composer app to code, which people seem to like. E.g. you get the composer to create some YAML, then any SDK can use it. If we only allow the programmatic option, then the composer needs to output code, which is more of a pain, and ideally it should also be able to import code (to preview / modify existing layouts) which is probably too painful for us to pursue.
Let's discuss whether YAML is worthwhile tomorrow. I think @yjbanov maybe agrees with you that we should focus on programmatic.
Re nesting YAML inside A2UI. We're not doing that - the template process parses the YAML and then outputs pure JSON. The reason to use nested YAML here is because it's a better authoring experience for humans. Most of the time people author A2UI content and have a bad time, they should actually be authoring templates. Now we are designing templates, let's make it a human-friendly format (whether data or programmatic API).
|
|
||
| ## 2. Template Taxonomy | ||
|
|
||
| A2UI defines three template modalities: |
There was a problem hiding this comment.
Modalities feels like the wrong word. To me that implies doing the same thing in different ways. This seems like they are three different parts that serve different purposes.
There was a problem hiding this comment.
Changed "modalities" to "authoring styles" (Static YAML Templates, Dynamic Data-Binding Templates, and Dynamic Programmatic Render Functions).
| 3. The synthetic catalog is passed to `PromptGenerator` (Express, Elemental, Atom, Direct JSON), which automatically writes the syntax rules and documentation into the system prompt. | ||
|
|
||
| ### Surface Isolation Boundary | ||
| ``` |
There was a problem hiding this comment.
This could be a Mermaid diagram too.
There was a problem hiding this comment.
Replaced the isolation boundary ASCII art with a clean Mermaid flowchart diagram!
| ### Rule 2: Embedded String Interpolation | ||
| If a parameter token appears alongside other characters (e.g. `"Hello, ${userName}!"` or `"${dept} - ${code}"`): | ||
| - All tokens are replaced by their string representations. | ||
| - Evaluates to a native string. |
There was a problem hiding this comment.
Hmm. But what about the reactive UI client side of things? What if I want to use the formatString function to put a data model item into the string and have it be reactive if the data model item changes? Can I escape the string interpolation so that is possible?
There was a problem hiding this comment.
That is a great observation and highlights an inherent tension: in A2UI catalogs, the client runtime already uses ${/path} for reactive data model interpolation inside formatString(...). Using ${param} for server-side template expansion means any client-side expressions in template layouts would either need escaping (\${/path}) or risk colliding.
We plan to transition template substitution to standard double curly braces {{ param }} (like Jinja/Mustache/Helm). That cleanly separates the two scopes without requiring escaping:
{{ param }}is evaluated server-side at template expansion time.${/path}is untouched by the template engine and passes through for client-side reactive evaluation (e.g.formatString("Hello ${/user/name}, dept: {{ dept }}")).
For now, \${...} escapes any literal ${...} so it passes through to the client intact.
There was a problem hiding this comment.
Update: We have gone ahead and implemented this across the specification and all template examples! Double-curly Mustache syntax ({{ param }}) is now the canonical format for template parameter substitutions (with optional whitespace, e.g. {{ param }} or {{param}}).
This cleanly disambiguates compile-time template substitutions from client-side reactive expressions (${/data/path} and catalog functions like formatString(...)), ensuring client expressions pass through untouched without requiring any escaping.
| ## 9. Error Handling, Cycle Guards & Safety | ||
|
|
||
| ### Recursion & Circular Reference Detection | ||
| Templates can invoke other templates. However, circular references (`A` invokes `B`, which invokes `A`) must be caught immediately to prevent stack overflow. |
There was a problem hiding this comment.
What about nesting? If I have a "Card" with a "Carousel" inside of it, containing other "Card"s, I would think that should be allowed, since they're different instances of the Card template.
There was a problem hiding this comment.
Clarified this in Section 11! The cycle guard specifically prevents definition-level circular references (where a template's own layout unconditionally references itself in a cycle, causing infinite expansion).
In contrast, instance nesting—where a caller passes a Card instance into a slot of another Card instance (e.g. Card(child=Carousel(items=[Card(...)])))—is fully supported and encouraged, as each instance has a unique synthetic ID and is bounded by caller input.
|
|
||
| - **Call Stack Tracking**: The `TemplateProcessor` maintains an active `_call_stack: Set[str]` throughout expansion. | ||
| - **Cycle Guard**: Before expanding any template, if `template_id in _call_stack`, expansion terminates immediately with `TemplateCycleError: Circular template reference detected: A -> B -> A`. | ||
| - **Maximum Depth Guard**: An absolute limit (`MAX_EXPANSION_DEPTH = 32`) enforces termination even in non-identical runaway recursion. |
There was a problem hiding this comment.
We should standardize on the max depth defaults. I think in other cases, we're using 50.
There was a problem hiding this comment.
Updated MAX_EXPANSION_DEPTH default from 32 to 50 to standardize across A2UI!
2ea9b6b to
4c04267
Compare
…cursion, and max depth
|
I have addressed the feedback. Please take another look. |
| }, | ||
| "additionalProperties": false | ||
| }, | ||
| {"type": "array"}, |
There was a problem hiding this comment.
Should we limit this to be an array of NestedTemplateNode, rather than arbitrary array?
| Templates decouple their local invocation name from their optional global identity: | ||
|
|
||
| - **`name`** (Required): Component tag name used in layout trees and LLM prompts (`^[A-Za-z][A-Za-z0-9_]*$`). `templateId` is accepted as a backwards-compatible alias. | ||
| - **`id`** (Optional): Globally unique URI or URN string (e.g. `https://company.org/templates/card/v1.json`) for package distribution and version pinning. |
There was a problem hiding this comment.
How do we enforce or validate the global uniqueness of template IDs? Is there a plan for a centralized template registry for discovery and resolution?
|
|
||
| - **`name`** (Required): Component tag name used in layout trees and LLM prompts (`^[A-Za-z][A-Za-z0-9_]*$`). `templateId` is accepted as a backwards-compatible alias. | ||
| - **`id`** (Optional): Globally unique URI or URN string (e.g. `https://company.org/templates/card/v1.json`) for package distribution and version pinning. | ||
| - **`imports`** (Optional): List of global template IDs, or dictionary mapping local aliases to global template IDs (`imports: { VendorCard: "https://vendor.com/card.json" }`). |
There was a problem hiding this comment.
Do we allow remote network fetching at runtime, or must all imported template IDs be pre-loaded into a local registry ahead of time?
Summary
This PR introduces the authoritative A2UI Templates Specification, formal JSON Schema, and multi-document YAML test fixtures under
specification/proposals/templates/.Templates provide a declarative, human-readable mechanism for authoring reusable UI subtrees in nested YAML. At generation time, an LLM emits compact, high-level template signatures (such as
UserProfile("u1", "Alice")), which the backend expands into canonical Basic Catalog primitives in a single synchronous pass before emitting standard A2UI protocol messages (createSurface,updateComponents) to the client.Architectural Highlights
{parent}_{slot}_{index}_{type}) guaranteeing zero ID collisions when multiple template instances are placed on a single surface.{path: "/user/name"}) and path prefix plumbing.0.1): Enforces top-levelversion: "0.1"across all template definitions to support smooth schema evolution across future protocol releases.TemplateCycleError) andMAX_EXPANSION_DEPTH = 32recursion limits.Files Added
specification/proposals/templates/README.md: Complete, authoritative specification with pipeline diagrams, grammar rules, and multi-language conformance checklist.specification/proposals/templates/schema/template_definition.json: Canonical JSON Schema (Draft 2020-12) enforcing requiredversion: "0.1",templateId,parameters, and nestedlayout.specification/proposals/templates/examples/*.yaml: 11 multi-document YAML template fixtures and test suites (basic_cards,nested_lists,slot_composition,user_profile,salary_card,team_roster, etc.).Stack Context