Rich Chat Widgets
Rich chat widgets are interactive React components the LLM can drop into the chat during a response. They turn "here is a URL" into a clickable element link, "here are 15 cars I found" into an inline table, "I want to make these changes" into a proposal card with a diff modal. Widgets contain no server-side business logic: some render the arguments passed in the tool call directly, others (notably the proposal widgets) fetch their payload from the Studio Backend via RTK Query on mount — by design, so the LLM never has to relay large or sensitive payloads through the conversation.
This page is the canonical catalog of every widget that ships with the bundle. For how to add your own, see Extending → Rich Chat Widgets.
The widget catalog
Nine widgets ship today. The Triggered by column shows what makes the widget appear. Five are LLM-callable display tools — the model chooses whether and what to show:
| Widget | Widget type key | Triggered by | What the user sees |
|---|---|---|---|
| Open element | element-link | LLM tool pimcore_open_element | Clickable button that opens a data object, asset, or document in Studio. Icon varies by element type. |
| Switch agent | agent-switch | LLM tool pimcore_switch_agent | Pill button suggesting a different agent. One click switches — see Agents and Switching. |
| Asset preview | asset-preview | LLM tool show_asset_preview | Inline image gallery of asset thumbnails. Click to open in Studio. |
| Data-object preview | data-object-preview | LLM tool show_data_object_preview | Preview cards with a few key attributes and an "open" button. |
| Data table | data-table | LLM tool show_data_table | Interactive, sortable, searchable table for search results. |
The remaining four are server-emitted — they are not LLM tools. A freshly created proposal should
always be surfaced, so the agent-server emits the proposal widget automatically from the minted
proposalId the moment a propose_* tool succeeds (on tool.execution_complete). There is no
show_*_proposal tool and no widget YAML for these:
| Widget | Widget type key | Triggered by | What the user sees |
|---|---|---|---|
| Data-object proposal | proposal-data-object | Server, after propose_data_object_update | HITL proposal card with approve / reject / refine actions and a diff modal. See HITL Proposals. |
| Asset metadata proposal | proposal-asset-metadata | Server, after propose_asset_metadata_update | HITL proposal card for asset metadata edits. |
| Document proposal | proposal-document | Server, after propose_document_update | HITL proposal card for document edits. The diff modal carries Preview / Edit / Settings tabs and a target-group control when the personalization-bundle is installed — see Architecture → Document Schema → Target-group variants. |
| Tag proposal | proposal-tags | Server, after propose_tag_assignment | HITL proposal card for tag assignments. |
| Agent-template proposal | proposal-agent-template | Server, after propose_agent_template / …_deletion | HITL proposal card for agent Twig-template create / update / delete. |
Two further widgets are server-emitted outside the proposal flow:
| Widget | Widget type key | Triggered by | What the user sees |
|---|---|---|---|
| Ask user | ask-user | Server, on ask_user tool | Inline question with choice buttons and/or freeform input. See Interactive Input. |
| Proposal result | proposal-result | Server, after resolve | Read-only status chip showing whether a proposal applied, was rejected, or errored. |
Enabling widgets for an agent
The LLM-callable display widgets are opt-in per agent. In the YAML under richChatWidgets, list the
widgets the agent is allowed to trigger:
richChatWidgets:
- pimcore_open_element
- show_data_object_preview
- pimcore_switch_agent
If an agent calls a widget it is not configured for, the call is rejected. A widget not in the agent's list never appears in chat, regardless of what the LLM asks for.
The proposal widgets are not listed here — they are server-emitted, so simply granting an agent the
matching propose_* tool is enough for its review widget to appear automatically.
How widgets reach the screen
The mechanism — for when you are debugging why a widget didn't render — is briefly:
LLM-callable display widgets:
- LLM calls a widget tool (e.g.
show_data_table). - The agent-server intercepts the SDK's
tool.execution_startevent before the tool would actually run. - Server checks the tool name against the widget registry; on match, it emits a
widgetSSE event with the payload. - A confirmation string from the widget's
handlerTemplateis returned to the LLM as the tool result, so the LLM knows the widget rendered. - The frontend's widget renderer registry maps
widgetTypeto a React component and mounts it inline in the message stream.
Server-emitted proposal widgets:
- LLM calls a
propose_*tool, which mints proposalIds and stores the payload server-side. - The PHP propose tool embeds a server-only
widgetdirective (widgetType + proposalIds + summary) in its tool result, alongside an LLM-visible stop-signal. - The agent-server intercepts the SDK's
tool.execution_completeevent, parses the directive out of the result, and emits the samewidgetSSE event — no widget registry / YAML lookup involved. - The frontend renders it via the same
widgetType→ component registry. The widget fetches its diff from the Studio Backend by proposalId.
Either way the widget appears instantly, before the LLM continues, because the server short-circuits the normal tool-call path. The widget event is also persisted as a message part, so it re-renders on reopen.
Further reading
- Extending → Rich Chat Widgets — how to add a widget (YAML definition + React renderer) and the widget-registry DI wiring.
- HITL Proposals — how proposal widgets integrate with the review/resolve workflow.