Remote Component Plugins
This guide explains how to build a newremote_component plugin for the Assistant Workbench. remote_component is a View Extension view schema, not a trigger type: it can be listed from a normal view slot, or it can be opened explicitly by a tool result with xpert.extension_view. All data access and mutations still go through the platform’s authenticated View Extension APIs.
Use this pattern when a plugin needs a full custom UI rather than a declarative table, list, stats, or detail view.
Architecture
A remote component plugin has at least two pieces. Add a tool entry only when the view should be opened on demand by an Agent conversation:- ViewExtensionProvider: provides the manifest, data, parameter options, actions, and remote component HTML entry.
- Remote React page: runs inside a sandboxed iframe and communicates with the host through
postMessage. - Optional tool entry: returns
_meta['xpertai/visualization']withtype: 'xpert.extension_view'for tool-triggered scenarios.
- access token
- API base URL
assistantIdhostIdhostType- permission information
- data-xpert Web attaches the current user’s OIDC token through
authenticatedFetch. - data-xpert API verifies the current user and resolves
assistantCodeto the effective assistant. - data-xpert API always forwards to
hostType=agentandhostId=<assistant.assistantId>. - xpert-pro checks view host access, manifest visibility, and action permissions before invoking the provider.
Define Stable Keys
Use stable keys because they are part of the contract between the view host, Workbench canvas, optional tool result, and provider.Choose a Trigger Mode
remote_component can enter the host UI in two ways:
- Slot-listed view: the host calls
GET /api/view-hosts/:hostType/:hostId/slots/:slot/views, receives the view manifest, and renders the remote component for that slot. - Tool-triggered view: the tool result carries
_meta['xpertai/visualization'], and the host opens the view only after that tool is used.
Optional: Return a Tool-Triggered View
The tool should only open the view. It should not return the full page data.Provide a Remote Component Manifest
Register aViewExtensionProvider and return a remote_component + react + iframe manifest from the agent.workbench.main slot.
permissions when mutations require stronger permissions than reading the view.
Return the Iframe HTML Entry
The provider returns a single HTML document for the iframe. UserenderRemoteReactIframeHtml() from @xpert-ai/plugin-sdk so all plugins share the same shell, reset, theme variables, and .xui-* UI classes.
entry value is a provider-local key, not a browser URL. The ViewExtension API rejects unsafe values such as absolute URLs, .., and backslashes.
Implement the Remote Bridge Client
The iframe page sends requests to the parent window and waits for matchingrequestId responses.
contentWindow and checks the instanceId.
Example: Load the Metric List
The remote page does not callfetch. It asks the host for view data:
Example: Save One Metric
Create and edit can share one form. The remote page submits an action request:refresh: true on success so the host can invalidate cache and the remote page can reload the current query.
Parameter Options
UserequestParameterOptions for select boxes and dependent fields.
Styling
Remote components should use the shared.xui-* classes provided by renderRemoteReactIframeHtml():
.xui-app.xui-toolbar.xui-control.xui-input.xui-button.xui-button-primary.xui-table.xui-modal.xui-notice
init.theme.tokens, and the helper maps them to --xui-* CSS variables. Plugin CSS should only add business layout and should not redefine the base control visuals.
Build Assets
If the remote script is stored under the plugin source directory, make sure the package build copies it to the production output.Test Checklist
Before shipping, verify:- the tool returns a valid
xpert.extension_viewpayload - the public view key matches
<providerKey>__<manifestKey> - the manifest returns
remote_component + react + iframe getRemoteComponentEntryreturns HTML without token, API URL,assistantId, orhostId- list loading uses
requestData - saving uses
executeAction - parameter options work for both standalone and dependent fields
- unauthorized users cannot access the view host
- mutation actions have stricter permissions when needed
- the iframe works with
sandbox="allow-scripts"and no direct network credentials