Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9393bf7
feat(spec): add core A2UI templates specification, version 0.1 schema…
jacobsimionato Aug 25, 2026
5950f4c
style(templates): add license headers and format specification files
jacobsimionato Aug 26, 2026
4c04267
feat(templates): specify name, id, catalogs, and imports in template …
jacobsimionato Aug 26, 2026
65145a0
docs(templates): address review comments on diagrams, terminology, re…
jacobsimionato Aug 26, 2026
650a511
feat(spec): adopt double-curly Mustache syntax for template parameter…
jacobsimionato Aug 26, 2026
ce45806
feat(python): implement A2UI synchronous template expansion engine wi…
jacobsimionato Aug 25, 2026
1147970
test(templates): add declarative conformance test suite and boundary …
jacobsimionato Aug 25, 2026
615c4c0
refactor(templates): remove unused manager.py placeholder
jacobsimionato Aug 25, 2026
58b2c5f
test(templates): modularize Python unit tests into test_models, test_…
jacobsimionato Aug 25, 2026
78f89e6
refactor(templates): refer to template_definition.json from specifica…
jacobsimionato Aug 25, 2026
93e2ee3
style(templates): add license headers to conformance YAML files, form…
jacobsimionato Aug 26, 2026
45e68cd
feat(python-sdk): require explicit catalogs and support name, id, cat…
jacobsimionato Aug 26, 2026
6eb9ff1
feat(python-sdk): add @dynamic_template decorator and __call__ invoca…
jacobsimionato Aug 26, 2026
ee2885e
feat(python-sdk): standardize MAX_EXPANSION_DEPTH default to 50
jacobsimionato Aug 26, 2026
9ba72fc
feat(python-sdk): support double-curly Mustache syntax for template s…
jacobsimionato Aug 26, 2026
3ec3f85
style(python-sdk): format test_processor with pyink
jacobsimionato Aug 26, 2026
6a1e832
feat(samples): add community templates sample app with version 0.1 te…
jacobsimionato Aug 25, 2026
f0b926a
style(samples): add license headers to community template sample YAML…
jacobsimionato Aug 26, 2026
194bf10
feat(samples): declare catalogs and name in community sample templates
jacobsimionato Aug 26, 2026
b883657
feat(samples): use @dynamic_template decorator in community sample se…
jacobsimionato Aug 26, 2026
d745da8
feat(samples): adopt double-curly Mustache syntax in community templates
jacobsimionato Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions agent_sdks/python/a2ui_agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ The following directories contain the base protocol logic, parsing, and schema o
- **`provider.py`**: Implementation of `BasicCatalog` for handling the basic
A2UI components.

## Experimental Templates (`src/a2ui/inference_formats/experimental/template`)

- **`models.py`**: Typed models (`StaticTemplate`, `DynamicTemplate`, `Param`, `ParamType`, AST expressions) and signature-based parameter inference.
- **`processor.py`**: `TemplateProcessor` for generating synthetic inference catalogs and expanding template invocations into A2UI primitives.
- **`format.py`**: `TemplateInferenceFormat` integrating template-aware prompt generation and synchronous parsing.
- Reference schema: Located at `specification/proposals/templates/schema/template_definition.json`.

## A2A (`src/a2ui/a2a`)

- **`extension.py`**: Utilities for managing the A2UI extension URI and activation logic.
Expand Down
5 changes: 4 additions & 1 deletion agent_sdks/python/a2ui_agent/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ dependencies = [
"google-adk>=1.28.1",
"google-genai>=1.27.0",
"httpx>=0.27.0",
"jsonschema>=4.0.0"
"jsonschema>=4.0.0",
"nest-asyncio>=1.6.0",
"pyyaml>=6.0"
Comment thread
jacobsimionato marked this conversation as resolved.
]

[project.scripts]
Expand Down Expand Up @@ -65,4 +67,5 @@ dev = [
"antlr4-tools>=0.2.1",
"hatchling>=1.30.1",
"types-jsonschema",
"types-pyyaml",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# A2UI Python Template Engine (`a2ui.inference_formats.experimental.template`)

The `a2ui.inference_formats.experimental.template` package provides server-side UI template expansion and synthetic catalog compilation for the A2UI Python Agent SDK.

For the language-agnostic protocol specification, JSON schemas, and multi-platform design guidelines, see:
👉 **[`specification/proposals/templates/README.md`](../../../../../../../../specification/proposals/templates/README.md)**

---

## Python API Reference

### 1. `StaticTemplate`

Represents a declarative, immutable UI template parsed from YAML or a dictionary.

```python
from a2ui.inference_formats.experimental.template import StaticTemplate

# Load from single or multi-document ('---') YAML files
templates = StaticTemplate.from_yaml_file("path/to/templates.yaml")

# Load directly from a YAML string
single_template = StaticTemplate.from_yaml(yaml_string)
```

### 2. `DynamicTemplate`

Extends templates with server-side execution. Supports two modes:

#### A. Data-Binding Mode (`resolver + layout`)

Takes a lookup argument (e.g. `employeeId`), runs a resolver callback, and injects the result into a static YAML presentation layout:

```python
from a2ui.inference_formats.experimental.template import DynamicTemplate, StaticTemplate

layout = StaticTemplate.from_yaml_file("salary_card.yaml")[0]

def resolve_compensation(employeeId: str) -> dict:
return db.fetch_employee_salary(employeeId)

dynamic_salary = DynamicTemplate(
template_id="EmployeeSalaryCard",
resolver=resolve_compensation,
layout=layout,
description="Verified compensation. Pass only employeeId.",
sample_data={"employeeId": "emp_101"},
)
```

#### B. Programmatic Render Mode (`render`)

Bypasses static layouts and runs native Python logic (loops, arithmetic, conditionals) returning a component AST:

```python
from a2ui.inference_formats.experimental.template import DynamicTemplate

def render_server_health(serverId: str, includeDisks: bool = True) -> dict:
status_icon = "check_circle" if serverId == "srv_01" else "warning"
return {
"component": "Card",
"child": {
"component": "Column",
"children": [
{"component": "Text", "text": f"Server {serverId}", "variant": "h3"},
{"component": "Icon", "name": status_icon},
]
}
}

server_template = DynamicTemplate(
template_id="ServerHealthCard",
render=render_server_health,
description="Live server diagnostics.",
sample_data={"serverId": "srv_01", "includeDisks": True},
)
```

### 3. `TemplateProcessor`

The core synchronous template expansion and catalog generation engine.

```python
from a2ui.inference_formats.experimental.template import (
TemplateProcessor,
TemplateId,
A2UIComponentList,
)

processor = TemplateProcessor(templates=[user_profile, dynamic_salary, server_template])

# 1. Synthesize virtual A2UI component catalog for LLMs
synthetic_catalog = processor.generate_inference_catalog()

# 2. Synchronously expand template invocations into standard A2UI primitives
expanded_components: A2UIComponentList = processor.expand_template(
instance_id="root",
template_id="ServerHealthCard",
passed_params={"serverId": "srv_01", "includeDisks": True},
)
```

### 4. `TemplateInferenceFormat`

Integrates templates seamlessly with LLM prompting and parsing.

```python
from a2ui.inference_formats.experimental.template import TemplateInferenceFormat

format_instance = TemplateInferenceFormat(
templates=[user_profile, dynamic_salary],
surface_id="main",
version="0.9.1",
)

# Generate system prompt instructions with template signatures
system_prompt = format_instance.prompt_generator.generate(
role_description="You are an A2UI assistant.",
include_schema=True,
)

# Parse response & synchronously expand templates to standard A2UI messages
messages = format_instance.parser.parse_response(llm_response_text)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A2UI Template module providing parameterized component expansion and dynamic resolvers."""

from .models import (
Template,
StaticTemplate,
DynamicTemplate,
dynamic_template,
BaseTemplate,
Param,
ParamType,
ParamRef,
Concat,
FormatExpr,
TemplateLoop,
TemplateComponent,
normalize_a2ui_type_to_jsonschema,
flatten_nested_layout,
normalize_node,
)
from .processor import (
TemplateProcessor,
TemplateId,
InstanceId,
ComponentId,
ParamPath,
TemplateParams,
TemplateNodeDict,
A2UIComponent,
A2UIComponentList,
A2UIMessage,
CatalogSchema,
JSONSchemaDict,
)
from .format import TemplateInferenceFormat, A2uiTemplateManager, TemplateParser

__all__ = [
"Template",
"StaticTemplate",
"DynamicTemplate",
"dynamic_template",
"BaseTemplate",
"Param",
"ParamType",
"ParamRef",
"Concat",
"FormatExpr",
"TemplateLoop",
"TemplateComponent",
"normalize_a2ui_type_to_jsonschema",
"flatten_nested_layout",
"normalize_node",
"TemplateProcessor",
"TemplateId",
"InstanceId",
"ComponentId",
"ParamPath",
"TemplateParams",
"TemplateNodeDict",
"A2UIComponent",
"A2UIComponentList",
"A2UIMessage",
"CatalogSchema",
"JSONSchemaDict",
"TemplateInferenceFormat",
"A2uiTemplateManager",
"TemplateParser",
]
Loading
Loading