Skip to content

feat(python): implement A2UI synchronous template expansion engine with version 0.1 validation - #2381

Open
jacobsimionato wants to merge 16 commits into
a2ui-project:mainfrom
jacobsimionato:feat/python-sdk-templates
Open

feat(python): implement A2UI synchronous template expansion engine with version 0.1 validation#2381
jacobsimionato wants to merge 16 commits into
a2ui-project:mainfrom
jacobsimionato:feat/python-sdk-templates

Conversation

@jacobsimionato

@jacobsimionato jacobsimionato commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

[Part 2 of 4 in Templates Stack - Depends on #2380]

This PR implements the A2UI Server-Side Template Engine in the Python Agent SDK under experimental inference formats (agent_sdks/python/a2ui_agent/src/a2ui/inference_formats/experimental/template/).

It provides synchronous template expansion, synthetic component catalog synthesis for LLM prompt generators, support for static YAML templates, dynamic data-binding resolvers, and programmatic Python render functions.


Architectural Highlights

  • Experimental Inference Format: Housed in a2ui.inference_formats.experimental.template and decorated with @experimental to communicate preview status.
  • Matching Directory Structure: Both source code and unit tests follow the unified modular path under inference_formats/experimental/template/.
  • Catalog-Agnostic Engine: TemplateProcessor operates independently with zero hardcoded primitives or catalog fallbacks (base_catalog: Optional[CatalogSchema] = None). Primitives and catalog IDs are dynamically derived from the provided catalog or left empty for template-only generation.
  • Strong Semantic Type Aliases: Explicit type definitions for identifiers (TemplateId, InstanceId, ComponentId, ParamPath), template evaluation (TemplateParams, TemplateNodeDict), wire-format outputs (A2UIComponent, A2UIComponentList, A2UIMessage), and catalog schemas (CatalogSchema, JSONSchemaDict).
  • Private Helper Encapsulation: Private helpers (_resolve_param_path, _substitute_params, _validate_templates) with backward-compatible deprecation aliases.
  • Strict Template Versioning (0.1): Validates that all ingested templates declare version == "0.1" and serializes the version tag across dict and YAML outputs.
  • Polymorphic Dynamic Templates:
    • Data-Binding Mode: Secure server-side callbacks (resolver) query databases/APIs and inject sensitive data directly into presentation layouts, keeping confidential numbers out of prompt contexts.
    • Programmatic AST Mode: Developers write native Python functions returning component trees using arbitrary Python loops, math calculations, and conditionals.
  • Duck-Typing & Dataclass Normalization: normalize_node() automatically recognizes dataclasses or any class implementing .to_dict(), enabling seamless future integration with fluent builders.
  • Deterministic ID Synthesis: Flattens nested layout trees into canonical primitives with collision-free synthetic IDs ({parent}_{slot}_{index}_{type}).
  • Cycle & Recursion Guards: Call-stack tracking raises immediate ValueError on circular template references and enforces MAX_EXPANSION_DEPTH = 32.
  • Inference Integration: TemplateInferenceFormat bridges registered templates into system prompt instructions and parses LLM outputs synchronously.

Testing & Verification

  • Comprehensive unit test suite in agent_sdks/python/a2ui_agent/tests/inference_formats/experimental/template/test_template_format.py.
  • 29 pytest tests pass cleanly, verifying:
    • Multi-doc YAML loading and forward referencing
    • Exact parameter substitution with native type preservation (int, bool, dict)
    • Loop unrolling and nested collection components
    • Higher-order container slots (child, children)
    • Dynamic resolver execution
    • Programmatic render functions and duck-typing AST / dataclass normalization
    • Version validation (0.1 success vs. unsupported version rejection)
    • Completely optional base_catalog=None behavior and custom domain catalogs
    • End-to-end prompt generation and response parsing with Express DSL

Stack Context

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the a2ui.template package, providing a robust server-side UI template engine for the A2UI Python Agent SDK. It includes support for static YAML-based templates, dynamic resolvers, and programmatic render functions, along with a synthetic catalog generation system for LLM integration. The review identified several critical issues, including potential runtime errors with asynchronous resolver execution, incomplete dataclass normalization, inefficient helper function definitions, missing circular reference detection, and overly simplistic parameter inference logic. These issues have been addressed to ensure robustness and compliance with the project's specification.

Comment thread agent_sdks/python/a2ui_agent/src/a2ui/template/processor.py Outdated
@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch from a201012 to e51913e Compare August 25, 2026 04:05
@jacobsimionato

Copy link
Copy Markdown
Collaborator Author

Addressed reviewer feedback and synced with updated specification:

  1. Resolver Dict Return: Ensured DynamicTemplate.resolve() always falls back to an empty dict {} if the resolver returns None or non-dict, avoiding unpacking TypeError.
  2. A2UI Expressions in Primitive Parameters: Added expression guard (is_expression) in TemplateProcessor.expand_template so that dynamic DataBinding or format expressions (e.g. {"path": "..."}) passed to primitive string/number params pass validation.
  3. Lifted Recursive Helpers: Refactored _check_val and _check_path to class methods on StaticTemplate, and _map_id, _resolve_slot, and _map_child_list to class methods on TemplateProcessor to avoid inner closure reallocations.
  4. Defensive Kwarg Filtering: render_fn inspects signature parameters and filters extra parameters if the function does not accept **kwargs.
  5. Schema & Models: Synced updated schema and added 4 new unit tests (23 pytest tests passing).

@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch 4 times, most recently from b7597fd to 3f100c4 Compare August 25, 2026 04:42
@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch from 50fbca1 to 282c386 Compare August 26, 2026 02:52
@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch 3 times, most recently from f2e17c4 to bbcf39c Compare August 26, 2026 03:36
@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch from bbcf39c to d610be3 Compare August 26, 2026 03:52
@jacobsimionato
jacobsimionato force-pushed the feat/python-sdk-templates branch from d610be3 to 9ba72fc Compare August 26, 2026 03:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants