Skip to content

feat(cli): introduce @a2ui/cli and basic catalog python builders - #2425

Open
jacobsimionato wants to merge 24 commits into
mainfrom
feat/cli-typescript-codegen
Open

feat(cli): introduce @a2ui/cli and basic catalog python builders#2425
jacobsimionato wants to merge 24 commits into
mainfrom
feat/cli-typescript-codegen

Conversation

@jacobsimionato

Copy link
Copy Markdown
Collaborator

Summary

Introduces the @a2ui/cli developer tooling package in TypeScript and pre-generated Basic Catalog Python builders.

Part 2 of the Programmatic Macros & Typesafe Builders stack.

Key Changes

  • @a2ui/cli Package: Built with Commander, registered in the root Yarn Berry monorepo workspace under "javascript/*".
  • a2ui codegen Command: Ingests any catalog schema (via @a2ui/web_core's Catalog.fromJson) and emits a clean, type-annotated single-file Python module containing:
    • Literal string enums colocated with component schemas.
    • Typed @dataclass component builder classes with automatic ID allocation and serialization.
    • Catalog function wrappers with keyword-only arguments.
    • Module __all__ exports.
  • Runtime Foundation (builder/base.py): Defines ComponentBuilderNode, Surface, bind, Action, and tree flattening logic.
  • Pre-Generated Basic Catalog Builders (builder/basic.py): Generated directly by @a2ui/cli for protocol version v0.9.1.

Stack Overview

  • PR 1: feat(web_core): introduce Catalog.fromJson schema ingestion engine (feat(web_core): introduce Catalog.fromJson schema ingestion engine #2424)
  • ➡️ PR 2 (This PR): feat(cli): introduce @a2ui/cli and basic catalog python builders
  • PR 3: feat(a2ui_agent): add programmatic macro runtime and test suite
  • PR 4: feat(samples): add community macros demo server and react client
  • PR 5: docs(proposals): add programmatic macros and typesafe builders proposal

Verification

  • Built CLI: yarn --cwd javascript/a2ui_cli run build
  • CLI Unit & E2E Tests: yarn --cwd javascript/a2ui_cli run test (5 tests passed)
  • Linter & Formatting: yarn --cwd javascript/a2ui_cli run lint && yarn --cwd javascript/a2ui_cli run format:check

- Add static Catalog.fromJson factory to ingest raw A2UI JSON catalog schemas into typed Catalog instances.
- Reconstruct ComponentDefinition, SlotDefinition, and parameter bindings dynamically with canonical Zod common types.
- Export JsonSchemaCatalogLoader and add comprehensive unit test suite.
- Add @a2ui/cli TypeScript package registered in Yarn monorepo workspaces.
- Provide codegen command powered by CatalogAnalyzer and PythonEmitter.
- Emit single-file consolidated Python modules with types, dataclasses, and functions.
- Add builder base runtime foundation (base.py) and pre-generated Basic Catalog builders (basic.py).

@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/cli package, a developer tool and typesafe component generator that analyzes catalog schemas and generates typesafe Python builder classes. It also includes the generated Python builders and base runtime classes. The review feedback highlights critical issues in recursive traversal and serialization: both assign_ids and serialize_node in base.py fail to traverse Mapping values, which prevents nested components (like those in Tabs) from being correctly processed. Similarly, the generated _serialize_prop helper in python-emitter.ts needs to recursively serialize dictionaries to avoid runtime TypeErrors. Finally, catalog-analyzer.ts should match refMatch against the accumulated description variable rather than current.description to correctly resolve REF: pointers on optional or default fields.

Comment thread agent_sdks/python/a2ui_agent/src/a2ui/builder/base.py
Comment thread javascript/a2ui_cli/src/emitters/python/python-emitter.ts
Comment thread javascript/a2ui_cli/src/analyzer/catalog-analyzer.ts Outdated
- Make json_schema_loader internal by removing its re-export from index.ts.
- Default protocol version to v0.9 per specification when omitted instead of requiring explicit options.
- Support data.id and data.protocolVersion in extractCatalogMetadata.
- Fix allOf and properties merging by evaluating both instead of using else-if.
- Resolve required fields across schemas using a two-pass collection.
- Stricten integer schema type parsing to z.number().int().
- Add convertEnumToZod helper to safely parse string, literal, and mixed enums without throwing in z.enum.
- Add defensive checks for non-object propSchema.
- Format modified files with Prettier.
- Add comprehensive unit tests covering all edge cases.
- Remove CatalogJsonLoaderOptions interface.
- Simplify Catalog.fromJson to accept only catalogJson and rely on catalog metadata and spec defaults.
- Support nested component traversal inside mappings in assign_ids and serialize_node
- Support dict recursion in python emitter _serialize_prop
- Match refMatch against unwrapped description in CatalogAnalyzer
- Restore third_party to IGNORE_PATTERNS in fix_licenses.py
- Format python builder files with pyink
# =============================================================================

TextVariant = Literal["h1", "h2", "h3", "h4", "h5", "caption", "body"]
ImageFit = Literal["contain", "cover", "fill", "none", "scaleDown"]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this needs to handle future and previous versions of the basic catalog

if we like the setup here https://docs.google.com/document/d/1ACOeNwMxSOZ2UFQdZfi80eAd8EET9CXiH5de2Apfr5w/edit?resourcekey=0-BunpI_b9qriYqpjbl1hY0w&tab=t.y0y8446q3tdb#bookmark=id.s0pb0dnj7k8m maybe just ask the LLM to support it?

here I think we need open enums

IconSize = Literal["small", "medium", "large"] | str

d["label"] = _serialize_prop(self.label)
if self.id is not None:
d["id"] = self.id
return d

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

can we try to get these builders working as the deserialization engine too?

there are some extra properties we want like unknown field preservation, eg

Component = Annotated[
Union[MaterialIcon, UnknownComponent],
Field(discriminator="type"),
]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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



@dataclass(kw_only=True)
class DateTimeInput(ComponentBuilderNode):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why not use pydantic? it has some options we want like preserve extra fields, eg

class MaterialIcon(BaseModel):
model_config = ConfigDict(
extra="allow", # Preserves unknown fields for round-tripping
populate_by_name=True,
)

Base automatically changed from feat/web-core-catalog-json-loader to main August 30, 2026 21:35
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