Status: Accepted · Issue: #294
BeautifulUI is not a semver npm library — it is distributed as shadcn-style
registry components that are copied into the consuming repo. PraisonAIUI must
integrate it without leaking upstream types or import paths across the codebase,
and without breaking when either side updates.
Introduce a single adapter boundary between transport payloads and the UI,
and vendor BeautifulUI components behind that boundary.
Rule: BeautifulUI / upstream prop types must never be imported outside
src/agent-ui/. Consumers depend on contracts.ts only, so the vendored
src/agent-ui/
contracts.ts
implementation can be swapped later without touching call sites.
Internal, transport-agnostic types live in contracts.ts:
AgentStreamEvent
chat.js (run_started, run_content, tool_call_started, …). Unknown
chat.js
run_started
run_content
tool_call_started
frame types degrade to kind: 'unknown' with rawType preserved instead
type
kind: 'unknown'
rawType
of throwing, so new upstream events never break the UI.
ToolCallChipModel
ApprovalPromptModel
/api/approvals/pending REST payload.
/api/approvals/pending
Mappers (adapter.ts): mapChatEventToUi(frame) and
adapter.ts
mapChatEventToUi(frame)
mapApprovalToCardProps(item). Both are pure and unit tested.
mapApprovalToCardProps(item)
| Mechanism | Purpose |
|-----------|---------|
| BEAUTIFULUI_UPSTREAM.md | Record git SHA, date, registry base URL for every vendored component |
BEAUTIFULUI_UPSTREAM.md
| shadcn registry URLs | Per-component install, pinned in the upstream doc |
| No dependencies.beautiful-ui in package.json | Avoid a phantom npm package |
dependencies.beautiful-ui
package.json
Upgrade rule: bump upstream only via a PR that updates
BEAUTIFULUI_UPSTREAM.md and passes the frontend CI gate (issue #295). Icons
stay on lucide-react; do not vendor paid Central icons.
lucide-react
Integration is gated so the existing vanilla-JS chat/approvals plugins remain
the fallback until migration milestones (#296, #297) complete.
AIUI_BEAUTIFULUI
src/agent-ui
off and the vanilla path renders. No user-facing regression when off.
Scope agent-UI primitives under an .aiui-agent-ui { … } CSS layer (or extend
.aiui-agent-ui { … }
the existing shadcn presets in themes.py) so vendored component tokens cannot
themes.py
collide with the global dashboard theme.
Vendored code stays MIT-licensed in-tree. Because consumers depend only on the
contracts.ts view models, a future first-party implementation can satisfy the
same contracts and replace the vendored components with no call-site churn.