# Build the "Agent-selected components" pattern: `RegisteredComponentRenderer`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
The agent chooses from a typed library of components and populates them; it cannot invent primitives.

Use it when: The default safe shape of generative UI in a product with an existing design system.

## What to build
Renders an agent's UI request by looking up the requested component name in a typed registry from the design system and validating the props against that component's schema. Anything unregistered or invalid falls back to plain text, never to agent-written markup. It renders inside a chat message or any slot that shows agent output.

### Props
- `call`: { id: string; name: string; args: unknown }, the agent's render or tool call.
- `registry`: Record<string, { component: ComponentType<P>; validate: (args: unknown) => { ok: true; props: P } | { ok: false; errors: string[] }; label: string; skeleton?: ReactNode }>, the only components the agent may use.
- `status`: "streaming" | "ready", whether `args` is still arriving.
- `showCall?`: boolean, reveals the raw call (name and arguments) for inspection.
- `fallbackText?`: string, the agent's plain-text answer to show when the call can't render.
- `onRejected?(call, reason: "unknown" | "invalid", errors?: string[])`: reports refusals for monitoring.
- `onComponentAction?(callId, action)`: passes events from the rendered component (e.g. a button inside a card) back to the agent.

### States it must render
- Streaming: the registered component's skeleton, sized like the real thing; unknown names show a neutral placeholder.
- Rendered: the design-system component with validated props.
- Invalid props: the text fallback with a quiet note ("Couldn't show this as an invoice table"); errors go to `onRejected`.
- Unknown component: "PieChart isn't available here" plus the text fallback; nothing is improvised.
- Call shown: a disclosure under the output with the component name and formatted arguments.

### Interactions
- The show-call toggle opens and closes the inspection panel.
- Actions inside the rendered component are forwarded with `onComponentAction`, tagged with the call id.
- Rejections fire `onRejected` once per call, not on every streamed chunk.

### Edge cases
- Arguments containing HTML or script are rendered as text; `dangerouslySetInnerHTML` is never used.
- Unknown extra props are stripped by validation, not passed through.
- A name that differs only in case or spelling from a registered one is still rejected, not guessed.
- Arguments still streaming: validate only once `status` is ready; don't flash errors on partial data.

## Must avoid
Letting the model emit arbitrary markup, producing off-system UI nobody can maintain.

## Engineering constraint
AG-UI is supported across LangGraph, CrewAI, Google ADK, AWS Strands and more — render by tool name.

## Accessibility
- The rendered component keeps its own semantics; the fallback is announced like any other message.
- The show-call control is a disclosure button with `aria-expanded`.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
