Skip to content

feat(angular): native signals for v0.9 renderer#925

Draft
gspencergoog wants to merge 16 commits intogoogle:mainfrom
gspencergoog:angular_updates
Draft

feat(angular): native signals for v0.9 renderer#925
gspencergoog wants to merge 16 commits intogoogle:mainfrom
gspencergoog:angular_updates

Conversation

@gspencergoog
Copy link
Collaborator

Description

Refactor the A2UI v0.9 Angular renderer to use native Angular Signals directly, eliminating the overhead and complexity of translating from Preact signals. This change also decouples web_core from Preact-specific logic by introducing a ReactiveProvider interface.

Changes

  • web_core:
    • Introduced ReactiveProvider and GenericSignal abstractions to support multiple reactive engines.
    • Added PreactReactiveProvider as the default implementation for the web core.
    • Updated SurfaceModel and MessageProcessor to inject the reactive provider during initialization.
  • angular renderer:
    • Implemented AngularReactiveProvider using native Angular signal(), computed(), and effect().
    • Simplified the BoundProperty API: components now access values via prop() instead of prop.value() and update via prop.set(v) instead of prop.onUpdate(v).
    • Removed toAngularSignal utility as it is superseded by the direct provider integration.
    • Refactored all catalog components (Button, Card, List, etc.) to the new API.
    • Updated the unit test suite and ComponentBinder service to support signal-based property binding.
  • a2a_explorer:
    • Updated demo components and the AgentStubService to align with the unified BoundProperty structure.

Impact & Risks

  • Performance: Reduces CPU and memory overhead by eliminating redundant signal wrapping and translation layers in Angular environments.
  • Consistency: The BoundProperty API is now consistent across different reactive providers, simplifying cross-framework logic in web_core.
  • Breaking Change: Any external code relying on the v0.9 Angular BoundProperty.value or .onUpdate will need to be updated to the new function-call and .set() syntax.

Testing

  • Unit Tests: All 189 tests in renderers/angular pass successfully.
  • Integration Tests: All 199 tests in integration_tests_09 pass successfully.
  • Manual Verification: Verified component reactivity and action dispatching in the a2a_explorer application.

…date

- Updated `A2uiRendererService` and `RendererConfiguration` to use `A2uiClientAction` instead of `SurfaceGroupAction`.
- Modified `ComponentHostComponent` to accept and pass `componentId` to rendered components.
- Updated all v0.9 catalog components to include a required `componentId` input.
- Passing `sourceComponentId` in `SurfaceModel.dispatchAction` calls (e.g., in `ButtonComponent`).
- Updated all test specs and dummy components to support the new `componentId` input.

This fix aligns the Angular renderer with the client data model synchronization changes introduced in @a2ui/web_core.
…y API

This major refactor migrates the Angular v0.9 renderer to use native Angular
Signals instead of translating from Preact signals.

Key changes:
- Core: Introduced ReactiveProvider in web_core and AngularReactiveProvider
  in @a2ui/angular to allow the core logic to use the renderer's native
  reactive primitives.
- Components: Refactored all v0.9 catalog components to use signal-based
  property getters (this.props()['key']?()) instead of the .value() API.
- Inputs: Migrated all component inputs (props, surfaceId, componentId,
  dataContextPath) to use the Angular input() and input.required() Signal API.
- Protocol: Adopted the updated A2UI v0.9 Action protocol from main,
  moving from functionCall to named event name and context.
- Integration: Reconciled all merge conflicts with the main branch following
  the adoption of Signal inputs in both branches.
- Tests: Updated the comprehensive test suite and integration tests to support
  the new signal-based property and action structures.
Resolved conflicts in basic catalog components by keeping componentId as a required input.
Updated button.component.spec.ts to use more general action dispatch assertion.
Includes upstream documentation for A2UI over MCP.
…nding

Resolved a regression in the v0.9 demo where two-way data binding for
text fields and other interactive components was failing. The root
cause was that signal wrapper properties created by the reactive
providers were non-configurable by default, preventing the
ComponentBinder from augmenting them with DataModel setters.

Changes:
- Set `configurable: true` for all wrapped signal properties in both
  Angular and Preact reactive providers.
- Added explicit `.set(v)` method to Preact's signal wrapper for API
  consistency across renderers.
- Updated `GenericSignal` interface in `web_core` to include `.set()`.
- Verified fix in `a2a_explorer` Login Form example.
Previously, failures in defining the "name" property (used primarily
for debugging) were silently ignored. Added a console.warn to capture
unexpected redefinition errors.
- Introduce ReactiveProvider and GenericSignal abstractions to permit multiple reactive engines.
- Add isSignal type guard and toGenericSignal coercion method to ReactiveProvider.
- Implement AngularReactiveProvider to bridge native Angular signals.
- Update DataContext to use standardized signal resolution for both path-bindings and literals.
- Fix web_core test failures by providing proper reactive providers to mock surfaces.
- Support direct signal updates via prop.set(v) in ComponentBinder and Angular components.
gemini-code-assist[bot]

This comment was marked as resolved.

- Support `set()` method in `AngularReactiveProvider` to allow direct signal mutations.
- Update `ComponentBinder` to use standardized `GenericSignal` interface from `@a2ui/web_core`.
- Refactor test specs to utilize `PreactReactiveProvider` from `web_core/v0_9/testing`.
- Ensure `DataModel` notifications trigger Angular reactivity by properly updating wrapped signal values.
- Verified fix with the Login Form demo example; text input now correctly propagates to the data model and action context.
@gspencergoog gspencergoog marked this pull request as draft March 20, 2026 21:57
…Signal<T>

This aligns BoundProperty with GenericSignal and improves consistency.
Updated test mocks (createBoundProperty) to use a getter for .value.
Added missing BoundProperty imports in spec files.
Replaced z.object({}).passthrough() with explicit property definitions
for better type safety and validation in the demo catalog.
Updated the assertion to verify that sourceComponentId ('test-btn')
is correctly passed to mockSurface.dispatchAction.
gemini-code-assist[bot]

This comment was marked as resolved.

…ec files

- Extract `createBoundProperty`, `StubComponent`, and mock factories to `src/v0_9/testing.ts`.
- Refactor `button`, `simple-components`, `complex-components`, `column`, `row`, `text`, and `text-field` spec files to use the new helpers.
- Fix specific test assertions and service mocking in `button.component.spec.ts`.
- Verify all 192 tests pass in the Angular renderer.
- Add `name` property to `BoundProperty` type in `types.ts`.
- Refactor `ComponentBinder` to use `defineSafe` for `name` property.
- Update `wrapAngularSignal` and `createBoundProperty` mock to use `unknown` instead of `any` for safety.
- Update `createBoundProperty` mock to include `name` property.
- Deduplicate and simplify `setter` logic in `wrapAngularSignal`.
- Verified with 192/192 passing tests.
…dd defensive value getter

- Add `name` property to `BoundProperty` type in `types.ts`.
- Refactor `ComponentBinder` to use `defineSafe` for `name`, `raw`, `set`, and `value` properties.
- Add defensive `value` getter in `ComponentBinder.bind` to ensure reactive property access.
- Update `createBoundProperty` mock factory in `testing.ts` to include `name` property.
- Update type casts to use `unknown` instead of `any` for better type safety.
- Verified with 192/192 passing tests.
- Remove `update` method from `createBoundProperty` mock factory in `testing.ts`.
- Align mock object with the `BoundProperty` type definition.
- Verified with 192/192 passing tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant