Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .kiro/specs/a2ui-standard-renderers/.config.kiro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "9bd88caa-9d12-4a17-b2c0-e2f0117c1747", "workflowType": "requirements-first", "specType": "feature"}
361 changes: 361 additions & 0 deletions .kiro/specs/a2ui-standard-renderers/design.md

Large diffs are not rendered by default.

98 changes: 98 additions & 0 deletions .kiro/specs/a2ui-standard-renderers/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Requirements Document

## Introduction

This feature replaces the custom A2UI parsing logic (`a2ui-parser.ts`) in the generative-angular sample with the official `@a2ui/angular` renderer package (backed by `@a2ui/web_core`). The goal is to drastically reduce custom code, leverage the standard A2UI renderer's built-in state management and component resolution, and align with the A2UI ecosystem for easier future extensibility.

## Glossary

- **Renderer_Service**: The `A2uiRendererService` provided by `@a2ui/angular` — processes A2UI operation messages and manages reactive surface state via Angular Signals.
- **Component_Host**: The `a2ui-v09-component-host` / `SurfaceComponent` from `@a2ui/angular` that dynamically renders surfaces by resolving component types from registered catalogs.
- **Renderer_Config**: The `A2UI_RENDERER_CONFIG` injection token from `@a2ui/angular` used to supply catalogs and action handlers at the Angular module/provider level.
- **Basic_Catalog**: The standard catalog shipped with `@a2ui/angular` containing generic layout, content, and input components.
- **Commerce_Catalog**: A custom catalog defined in the sample app that maps commerce-specific A2UI component types (ProductCarousel, ComparisonTable, ComparisonSummary, BundleDisplay, NextActionsBar) to Angular components.
- **Activity_Snapshot**: An SSE event from the Coveo converse API with `type: "ACTIVITY_SNAPSHOT"` and `activityType: "a2ui-surface"` whose `content.operations` array contains A2UI v0.8 operations.
- **Operations_Array**: The `content.operations` field of an Activity_Snapshot containing `beginRendering`, `surfaceUpdate`, and `dataModelUpdate` operation objects.
- **Conversation_Service**: The Angular service (`ConversationService`) that manages conversation state, subscribes to `ConverseController`, and exposes reactive signals consumed by UI components.
- **Surface_Outlet**: The existing `SurfaceOutletComponent` that maps typed surfaces to Angular components via `NgComponentOutlet`.
- **Custom_Parser**: The existing `a2ui-parser.ts` module (~300 lines) that manually transforms raw A2UI surfaces into typed `RenderableCommerceSurface` objects.

## Requirements

### Requirement 1: Install and configure the A2UI Angular renderer packages

**User Story:** As a developer maintaining the generative-angular sample, I want to install the official `@a2ui/angular` and `@a2ui/web_core` packages, so that I can leverage the standard renderer infrastructure instead of custom parsing logic.

#### Acceptance Criteria

1. THE generative-angular sample SHALL declare `@a2ui/angular` and `@a2ui/web_core` as dependencies in its `package.json`.
2. WHEN the application bootstraps, THE App SHALL provide `A2UI_RENDERER_CONFIG` via Angular's dependency injection with at least the Commerce_Catalog registered.
3. THE Renderer_Config SHALL include an action handler that triggers new prompts through the Conversation_Service when a NextActionsBar action is selected.

### Requirement 2: Register a custom Commerce_Catalog

**User Story:** As a developer, I want to register the existing commerce Angular components (ProductCarousel, ComparisonTable, ComparisonSummary, BundleDisplay, NextActionsBar) as a custom A2UI catalog, so that the standard renderer can resolve and instantiate them by component type name.

#### Acceptance Criteria

1. THE Commerce_Catalog SHALL map the component type `"ProductCarousel"` to the `ProductCarouselComponent`.
2. THE Commerce_Catalog SHALL map the component type `"ComparisonTable"` to the `ComparisonTableComponent`.
3. THE Commerce_Catalog SHALL map the component type `"ComparisonSummary"` to the `ComparisonSummaryComponent`.
4. THE Commerce_Catalog SHALL map the component type `"BundleDisplay"` to the `BundleDisplayComponent`.
5. THE Commerce_Catalog SHALL map the component type `"NextActionsBar"` to the `NextActionsBarComponent`.
6. WHEN the Renderer_Service encounters a component type present in the Commerce_Catalog, THE Component_Host SHALL instantiate the corresponding Angular component.

### Requirement 3: Feed raw operations to the Renderer_Service

**User Story:** As a developer, I want the Conversation_Service to pass raw A2UI operations directly to the Renderer_Service instead of the Custom_Parser, so that the standard renderer handles state management and component resolution.

#### Acceptance Criteria

1. WHEN the ConverseController emits a turn containing `agentResponse.surfaces`, THE Conversation_Service SHALL extract the Operations_Array from each Activity_Snapshot surface and pass it to `Renderer_Service.processMessages()`.
2. WHEN an Activity_Snapshot has `replace: true`, THE Conversation_Service SHALL reset the Renderer_Service state before processing the new operations.
3. WHILE a turn has status `"streaming"`, THE Renderer_Service SHALL reflect loading states (e.g., `isLoading: true`) as conveyed by the incoming component data.
4. WHEN a turn completes (status transitions from `"streaming"` to `"complete"`), THE Renderer_Service SHALL clear all loading indicators from rendered surfaces.

### Requirement 4: Replace Surface_Outlet with Component_Host

**User Story:** As a developer, I want the transcript panel to use the standard A2UI Component_Host for rendering surfaces instead of the custom Surface_Outlet and `NgComponentOutlet` dispatch logic, so that surface rendering is fully delegated to the A2UI renderer.

#### Acceptance Criteria

1. THE transcript panel template SHALL use `a2ui-v09-component-host` (or equivalent Component_Host directive) to render each active surface from the Renderer_Service state.
2. WHEN the Renderer_Service state contains multiple surfaces, THE transcript panel SHALL render them in the order provided by the Renderer_Service.
3. THE Component_Host SHALL pass resolved component data (products, headings, attributes, actions) to each commerce component through the standard A2UI data binding mechanism.

### Requirement 5: Remove the Custom_Parser and associated custom types

**User Story:** As a developer, I want to delete the `a2ui-parser.ts` file and the A2UI-specific type definitions from `models.ts`, so that the codebase no longer carries redundant custom parsing logic.

#### Acceptance Criteria

1. WHEN the migration is complete, THE generative-angular sample SHALL NOT contain the file `a2ui-parser.ts`.
2. WHEN the migration is complete, THE `models.ts` file SHALL NOT export the types `A2UIOperation`, `ActivitySnapshotContent`, `BeginRenderingOperation`, `SurfaceUpdateOperation`, `DataModelUpdateOperation`, `SurfaceComponentPayload`, `CommerceSurfaceComponentType`, or `RenderableCommerceSurface`.
3. WHEN the migration is complete, THE Conversation_Service SHALL NOT import from `a2ui-parser.ts`.
4. THE generative-angular sample SHALL continue to export shared domain types (`ProductRecord`, `NextAction`, `BundleDisplayTier`, `BundleSlotConfig`) that the commerce components require for their inputs.

### Requirement 6: Preserve existing commerce component behavior

**User Story:** As a user of the generative-angular sample, I want the rendered commerce surfaces (product carousels, comparison tables, comparison summaries, bundle displays, and next-actions bars) to behave identically after the migration, so that no user-facing functionality is lost.

#### Acceptance Criteria

1. WHEN a ProductCarousel surface is rendered, THE ProductCarouselComponent SHALL display the heading and product list as before the migration.
2. WHEN a ComparisonTable surface is rendered, THE ComparisonTableComponent SHALL display the heading, attribute columns, and product rows as before the migration.
3. WHEN a ComparisonSummary surface is rendered, THE ComparisonSummaryComponent SHALL display the summary text as before the migration.
4. WHEN a BundleDisplay surface is rendered, THE BundleDisplayComponent SHALL display the title, tier labels, and slot products as before the migration.
5. WHEN a NextActionsBar action button is clicked, THE NextActionsBarComponent SHALL invoke the action handler configured in the Renderer_Config, which triggers a new prompt submission through the Conversation_Service.
6. WHILE any commerce surface has `isLoading: true`, THE corresponding component SHALL display its loading/skeleton state.

### Requirement 7: Maintain application build and serve integrity

**User Story:** As a developer, I want the generative-angular sample to compile and serve without errors after the migration, so that the sample remains a functional reference implementation.

#### Acceptance Criteria

1. WHEN `ng build` is executed, THE generative-angular sample SHALL produce a successful build with zero compilation errors.
2. WHEN `ng serve` is executed, THE generative-angular sample SHALL serve without runtime errors related to the A2UI renderer integration.
3. THE generative-angular sample SHALL NOT introduce circular dependency warnings related to the Renderer_Service or Commerce_Catalog registration.
179 changes: 179 additions & 0 deletions .kiro/specs/a2ui-standard-renderers/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Implementation Plan: A2UI Standard Renderers

## Overview

Replace the custom `a2ui-parser.ts` and `SurfaceOutletComponent` in the generative-angular sample with the official `@a2ui/angular` renderer package. This involves installing packages, creating a Commerce Catalog, building a thin adapter service, reconfiguring the transcript panel to use `a2ui-v09-component-host`, adapting commerce component inputs, and cleaning up obsolete code.

## Tasks

- [ ] 1. Install packages and create Commerce Catalog
- [ ] 1.1 Add `@a2ui/angular` and `@a2ui/web_core` dependencies to `samples/thermidor/generative-angular/package.json`
- Add both packages to the `dependencies` section
- Run `pnpm install` to update the lockfile
- _Requirements: 1.1_

- [ ] 1.2 Create the Commerce Catalog at `src/app/a2ui/commerce-catalog.ts`
- Define and export `COMMERCE_CATALOG` as an `A2uiCatalog` object
- Map `ProductCarousel` → `ProductCarouselComponent`
- Map `ComparisonTable` → `ComparisonTableComponent`
- Map `ComparisonSummary` → `ComparisonSummaryComponent`
- Map `BundleDisplay` → `BundleDisplayComponent`
- Map `NextActionsBar` → `NextActionsBarComponent`
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_

- [ ] 2. Create the A2uiAdapterService
- [ ] 2.1 Create `src/app/services/a2ui-adapter.service.ts`
- Inject `A2uiRendererService` from `@a2ui/angular`
- Implement `processSurfaces(surfaces: A2UISurface[])` method that iterates over surfaces, checks for `replace: true` (calling `renderer.reset()` if found), extracts `operations` arrays, and forwards them to `renderer.processMessages()`
- Implement `reset()` method that calls `renderer.reset()`
- Wrap `processMessages()` in a try/catch to log errors without propagating
- _Requirements: 3.1, 3.2_

- [ ]\* 2.2 Write property test for operations extraction (Property 1)
- **Property 1: Operations extraction preserves content**
- Use `fast-check` to generate random arrays of objects with varying `operations` arrays (empty, nested, large)
- Verify all operations are forwarded to `processMessages()` without modification, in order
- **Validates: Requirements 3.1**

- [ ]\* 2.3 Write unit tests for `A2uiAdapterService`
- Test that surfaces without `operations` are skipped silently
- Test that `replace: true` triggers a reset before processing
- Test that errors in `processMessages()` are caught and logged
- _Requirements: 3.1, 3.2_

- [ ] 3. Configure A2UI_RENDERER_CONFIG provider
- [ ] 3.1 Modify `src/app/app.config.ts` to provide `A2UI_RENDERER_CONFIG`
- Import `A2UI_RENDERER_CONFIG` and `BasicCatalog` from `@a2ui/angular`
- Import `COMMERCE_CATALOG` from `./a2ui/commerce-catalog`
- Register both catalogs: `[BasicCatalog, COMMERCE_CATALOG]`
- Configure the `actionHandler` to forward action payloads to `ConversationService.submit()` (use lazy injection or an intermediate bridge to avoid circular dependencies)
- _Requirements: 1.2, 1.3, 6.5_

- [ ]\* 3.2 Write property test for action handler forwarding (Property 2)
- **Property 2: Action handler forwarding**
- Use `fast-check` to generate arbitrary non-empty strings
- Verify the action handler calls `ConversationService.submit()` with the exact string
- **Validates: Requirements 1.3, 6.5**

- [ ] 4. Checkpoint - Ensure foundation compiles
- Ensure all tests pass, ask the user if questions arise.

- [ ] 5. Modify ConversationService to use the adapter
- [ ] 5.1 Update `src/app/services/conversation.service.ts`
- Remove `import {parseSurfaces} from '../a2ui-parser'`
- Remove the `surfaces` signal
- Inject `A2uiAdapterService`
- Replace the `buildSurfaces()` method with `collectSurfaces(turns: Turn[]): A2UISurface[]` that returns the latest turn's surfaces array
- Call `this.adapter.processSurfaces(this.collectSurfaces(state.turns))` inside `applyState()`
- _Requirements: 3.1, 3.2, 3.3, 3.4, 5.3_

- [ ]\* 5.2 Write unit tests for modified ConversationService
- Verify `parseSurfaces` is no longer called
- Verify `A2uiAdapterService.processSurfaces()` is called on state updates
- Verify streaming/complete transitions are handled correctly
- _Requirements: 3.1, 3.3, 3.4_

- [ ] 6. Modify TranscriptPanelComponent to use a2ui-v09-component-host
- [ ] 6.1 Update `src/app/components/transcript-panel.component.ts`
- Remove `SurfaceOutletComponent` import
- Import the `a2ui-v09-component-host` component/directive from `@a2ui/angular`
- Inject `A2uiRendererService` to access reactive surface state (or receive surfaces from the renderer as a signal input)
- Replace the `surfaces` input of type `RenderableCommerceSurface[]` with the renderer's surface signal
- Replace the `<app-surface-outlet>` loop with `<a2ui-v09-component-host [surface]="surface" />` iterating over renderer surfaces
- Remove the `quickAction` output (action handling is now via `A2UI_RENDERER_CONFIG`)
- _Requirements: 4.1, 4.2, 4.3_

- [ ]\* 6.2 Write property test for surface render order (Property 3)
- **Property 3: Surface render order preservation**
- Use `fast-check` to generate random-length arrays of surface objects
- Verify DOM order of `a2ui-v09-component-host` instances matches the renderer's surface order
- **Validates: Requirements 4.2**

- [ ] 7. Adapt commerce component inputs
- [ ] 7.1 Adapt `ProductCarouselComponent` inputs
- Replace `surface = input.required<ProductCarouselSurface>()` with individual inputs: `heading = input<string>('')`, `products = input<ProductRecord[]>([])`, `isLoading = input<boolean>(false)`
- Update template references from `surface().heading` to `heading()`, etc.
- _Requirements: 6.1, 6.6_

- [ ] 7.2 Adapt `ComparisonTableComponent` inputs
- Replace `surface` input with individual inputs: `heading`, `attributes`, `products`, `isLoading`
- Update template references accordingly
- _Requirements: 6.2, 6.6_

- [ ] 7.3 Adapt `ComparisonSummaryComponent` inputs
- Replace `surface` input with individual input: `text = input<string>('')`
- Update template references accordingly
- _Requirements: 6.3_

- [ ] 7.4 Adapt `BundleDisplayComponent` inputs
- Replace `surface` input with individual inputs: `title`, `bundles`, `isLoading`
- Update template references accordingly
- _Requirements: 6.4, 6.6_

- [ ] 7.5 Adapt `NextActionsBarComponent` inputs
- Replace `surface` input with individual inputs: `actions`, `isLoading`
- Remove `onSelectAction` callback input (actions are now handled by the A2UI action handler config)
- Update template to dispatch actions through the A2UI mechanism
- _Requirements: 6.5, 6.6_

- [ ]\* 7.6 Write unit tests for commerce component input adaptation
- Verify each component renders correctly with individual inputs
- Verify loading states display skeleton UI
- _Requirements: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6_

- [ ] 8. Checkpoint - Ensure adapted components compile and render
- Ensure all tests pass, ask the user if questions arise.

- [ ] 9. Clean up obsolete code
- [ ] 9.1 Remove obsolete types from `src/app/models.ts`
- Delete types: `A2UIOperation`, `ActivitySnapshotContent`, `BeginRenderingOperation`, `SurfaceUpdateOperation`, `DataModelUpdateOperation`, `SurfaceComponentPayload`, `CommerceSurfaceComponentType`, `RenderableCommerceSurface`, `ProductCarouselSurface`, `ComparisonTableSurface`, `ComparisonSummarySurface`, `BundleDisplaySurface`, `NextActionsBarSurface`, `ValueMapEntry`, `ValueMapItem`
- Retain: `ProductRecord`, `NextAction`, `BundleDisplayTier`, `BundleDisplaySlot`, `BundleSlotConfig`, `BundleTierConfig`
- _Requirements: 5.2, 5.4_

- [ ] 9.2 Delete `src/app/a2ui-parser.ts`
- Remove the file entirely
- _Requirements: 5.1, 5.3_

- [ ] 9.3 Delete `src/app/components/surface-outlet.component.ts`
- Remove the file entirely
- Verify no remaining imports reference this file
- _Requirements: 4.1_

- [ ] 10. Final verification
- [ ] 10.1 Verify build integrity
- Run `ng build` and confirm zero compilation errors
- Confirm no circular dependency warnings in build output
- Confirm `a2ui-parser.ts` and `surface-outlet.component.ts` no longer exist
- Confirm `package.json` includes `@a2ui/angular` and `@a2ui/web_core`
- _Requirements: 7.1, 7.2, 7.3_

- [ ] 11. Final checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.

## Notes

- Tasks marked with `*` are optional and can be skipped for faster MVP
- Each task references specific requirements for traceability
- Checkpoints ensure incremental validation
- Property tests validate universal correctness properties from the design document
- Unit tests validate specific examples and edge cases
- The existing commerce component templates and styles remain unchanged — only the input binding interface shifts
- The `@a2ui/angular` package handles all surface state management internally via Angular Signals

## Task Dependency Graph

```json
{
"waves": [
{"id": 0, "tasks": ["1.1"]},
{"id": 1, "tasks": ["1.2", "2.1"]},
{"id": 2, "tasks": ["2.2", "2.3", "3.1"]},
{"id": 3, "tasks": ["3.2", "5.1"]},
{"id": 4, "tasks": ["5.2", "6.1"]},
{"id": 5, "tasks": ["6.2", "7.1", "7.2", "7.3", "7.4", "7.5"]},
{"id": 6, "tasks": ["7.6", "9.1"]},
{"id": 7, "tasks": ["9.2", "9.3"]},
{"id": 8, "tasks": ["10.1"]}
]
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "9bd88caa-9d12-4a17-b2c0-e2f0117c1747", "workflowType": "requirements-first", "specType": "feature"}
Loading
Loading