Repository navigation
feat(metadata): implement v1.0 extension metadata APIs across SDKs - #3757
Conversation
31c1839 to
472538a
Compare
Adds UAX 31 extension key validation, deep-frozen metadata snapshots, symmetric metadata property getters and setters, reactive ComponentNode and SurfaceModel metadata signals, outbound action metadata merging, catalog ComponentApi metadata preservation, Express extensions= compilation/decompilation, and cross-SDK conformance suites across TypeScript, Dart, Python, and Swift. Resolves a2ui-project#3708 Resolves a2ui-project#3468 Resolves a2ui-project#3469 Resolves a2ui-project#3560 Resolves a2ui-project#3103 Signed-off-by: Greg Spencer <gspencer@google.com>
472538a to
ec78bff
Compare
…ess map matching Guard inspect.signature in ComponentContext.dispatch_action against callables that lack signature metadata and support keyword-only metadata or **kwargs dispatch callbacks alongside positional ones. Pattern-match Map<Object?, Object?> in Dart ExpressCompiler._extensionsMap so dynamically typed maps validate cleanly.
Resolve conflicts in @a2ui/web_core with PR a2ui-project#3579 (DataContext.resolveAction delegation, MessageErrorMapper, and node-resolution conformance steps) while preserving ActionDispatchOptions and extension metadata propagation.
Resolve conflicts with a2ui-project#3712 (incremental Express streaming) in the Dart and TypeScript Express compilers and the compiler conformance suite. Carry surface(extensions=...) through the new buildUnits/_build_units and buildCreateMessages paths, including the streaming create path, and thread the target version into unit building in Python and TypeScript so surface() extension validation still has it.
nan-yu
left a comment
There was a problem hiding this comment.
Thanks for addressing all 10 findings from the earlier review across the React adapter, Python/Swift/Dart Core SDKs, and Express compilers! Left two optional follow-up notes on incremental Express streaming (ExpressScopeSession) from the #3712 merge. LGTM!
🤖 Agent-generated
|
FYI, here's a user guide for how to use these APIs: DetailsUsing Extension Metadata in A2UI v1.0In A2UI v1.0, protocol schemas reject unknown top-level fields. When you need to attach non-visual data such as telemetry tags, access control policies, or host hints, use the You can attach and read extension metadata in four places:
Core RulesEvery SDK enforces three rules when reading or writing metadata:
1. Authoring Metadata from an AgentA2UI Express DSLIn v1.0 A2UI Express, pass the surface("main", extensions={surfaceTheme: "dark", traceId: "req_42"})
header = Text("Welcome", extensions={role: "banner"})
root = Column([header])
Python Agent Builders (
|
Summary
Implements A2UI v1.0 extension metadata APIs across TypeScript, Dart, Python, and Swift. Also adds shared conformance suites, Express
extensions=authoring, and updated specification and blueprints.Resolves #3708
Resolves #3468
Resolves #3469
Resolves #3560
Resolves #3103
Reviewer Focus
typescript/core/web_core/src/common/metadata.ts,dart/a2ui_core/lib/src/core/metadata.dart,python/a2ui_core/src/a2ui/core/common/metadata.py, andswift/core/Sources/A2UICore/Validation/MetadataValidator.swift.ComponentNode.metadatais decoupled fromComponentNode.propsinNodeResolveracross TypeScript, Dart, Python, and Swift. Metadata-only updates do not re-render components that read onlyprops.mergeActionMetadata) inSurfaceModel.dispatchActionandGenericBinder, where call-site keys take precedence over keys on the action payload.ComponentHostComponent(typescript/renderers/angular/src/core/component-host.component.ts). It inspectsreflectComponentTypebefore settingmetadatato avoidNG0303errors on plain custom components.python/a2ui_core/src/a2ui/core/schema/v1_0/renderer_to_agent.py) andCHANGELOG.mdentries can be skimmed quickly.Changes
validateMetadata), deep-frozen snapshots (cloneMetadata), and structural equality (metadataEquals/sameMetadata). Empty envelopes ({}and{extensions: {}}) normalize to nullish values.metadatagetters and setters (model.metadata = ...),extensionsviews,setExtension,removeExtension, andonMetadataChangedstreams onSurfaceModelandComponentModel. Swift usessetMetadata(_:) throws.applyUpdate/apply_updatehandling duringupdateComponentssoMessageProcessorupdatespropertiesandmetadatatogether before emitting change notifications.metadatasignal onComponentNodein TypeScript and Dart,ComponentNode.metadataandon_metadata_changedin Python, and reactiveNode.metadatain Swift alongsideSurfaceModel.metadataSignal.@a2ui/web_coreuniversal elements (A2uiControllerandA2uiLitElement),@a2ui/react,@a2ui/angular,a2ui_flutter, andA2UISwiftUI(@Environment(\.a2uiSurfaceMetadata)).ComponentDefinition.metadataonComponentApiacrossCatalog.fromJsonandCatalog.toJsonin TypeScript, Dart, and Python. Updated Pydantic codegen to emitActionMetadatainstead of colliding withExtensions.ActionDispatchOptions(metadata) toNodeAction,ComponentContext.dispatchAction, andSurfaceModel.dispatchActionacross all four Core SDKs.ComponentBuilderNode.metadata,with_extension,CreateSurface(extensions=...), andset_surface_extensions). Added reservedextensions=keyword compilation and decompilation in v1.0 A2UI Express.conformance/core/message_processor_v1_0.yaml,conformance/core/node_resolution.yaml,conformance/core/actions.yaml,conformance/core/catalog.yaml, andconformance/agent/express/compiler.yaml.Impact & Risks
a2ui_core,ComponentModelnow strips envelopemetadataout ofcomponent.propertiesintocomponent.metadatafor v1.0 components, matching TypeScript, Dart, and Swift.A2uiRendererAction.metadatafromExtensions | NonetoActionMetadata | None.node.propsincur zero extra renders when component metadata changes because metadata subscriptions are lazy across React, Lit, Angular, and Flutter.Testing
yarn --cwd typescript/core/web_core testandyarn --cwd typescript/core/web_core test:conformanceyarn --cwd typescript/renderers/angular testyarn --cwd typescript/renderers/react testyarn --cwd typescript/agents/a2ui_agent testcd dart/a2ui_core && dart analyze && dart testcd dart/a2ui_agent && dart analyze && dart testcd dart/a2ui_flutter && flutter analyze && flutter testcd python/a2ui_core && uv run pytestcd python/a2ui_agent && uv run pytestcd swift/core && swift testcd swift/swiftui && swift test