Chat
There is one chat component. ChatWidget is the full-control component: streaming text, tool-call cards, confirmations, ask-user cards, session history, theming, and an imperative handle. AmodalChat (in the package root) is a preset of the same component: ChatWidget with position="inline" and serverUrl defaulted from the nearest AmodalProvider. Pick the entry point, not a different widget.
ChatWidget is exported from both the package root and the @amodalai/react/widget subpath; the subpath exists so a chat-only embed doesn't import the whole SDK, and it also ships the widget's building blocks for composing a custom chat surface (see Building blocks).
Installation
npm install @amodalai/reactQuick start
Inside an AmodalProvider, the preset is enough:
import { AmodalChat } from "@amodalai/react";
import "@amodalai/react/style.css";
<AmodalChat user={{ id: userId }} />;For any other position, or outside a provider, use ChatWidget directly:
import { ChatWidget } from "@amodalai/react/widget";
import "@amodalai/react/widget/style.css";
<ChatWidget
serverUrl="https://your-agent.example.com"
user={{ id: userId }}
position="floating"
historyEnabled
/>;Props
AmodalChat accepts every ChatWidget prop except position (pinned to inline); its serverUrl is optional and defaults to the provider's runtimeUrl.
Connection and identity
| Prop | Default | Meaning |
|---|---|---|
serverUrl | required | Base URL of the agent's runtime server. |
user | required | { id: string }; attributed to the session. |
getToken | none | Returns a bearer token for authenticated requests (sync or async). |
scopeId | none | Multi-tenant isolation: scopes sessions, memory, and stores per value. |
scopeContext | none | Key-value pairs injected into connection API calls via contextInjection. |
Behavior
| Prop | Default | Meaning |
|---|---|---|
position | floating | See Positions. |
defaultOpen | false | Start open (togglable positions only). |
historyEnabled | false | Session history drawer. |
showHeader / showInput / showFeedback | true / true / false | Header bar; input bar; thumbs up/down on assistant messages. |
sessionType | none | Which curated surface (skills, tools, knowledge) loads into the session. |
deployId | active deploy | Pin a specific deployment. |
initialMessage | none | Auto-sent once on mount. |
resumeSessionId | none | Load an existing session as read-only history; takes precedence over initialMessage. |
Callbacks
| Prop | Meaning |
|---|---|
onToolCall(call) | A tool call completed; receives the full ToolCallInfo. |
onKBProposal(proposal) | The agent proposed a knowledge-base update. |
onEvent(event) | Every widget event (agent-driven and interaction). |
onSessionCreated(sessionId) | First stream init returned a session id. |
onStreamEnd() | The SSE stream ended. |
onStateChange({ sessionId, messages }) | Session state changed (for external persistence). |
Extension points
| Prop | Meaning |
|---|---|
theme | See Theming. |
widgets | WidgetRegistry of custom renderers for rich inline widgets. |
inlineBlockRenderers | Renderers for block types the widget doesn't render natively; native types (text, ask_choice, proposal) cannot be overridden. |
streamFn | Custom transport ((text, signal, images?) => AsyncIterable<SSEEvent>); replaces the built-in chat API call for non-standard endpoints. |
entityExtractors | Replaces the default entity extractor for entity events. |
Imperative handle
The ref exposes ChatWidgetHandle:
const chat = useRef<ChatWidgetHandle>(null);
chat.current?.sendMessage("Summarize today's alerts"); // as if the user typed it
chat.current?.getSessionId();Positions
| Position | Behavior |
|---|---|
inline | Renders in-place within your layout |
floating | Floating button that expands into a chat panel |
right | Fixed panel on the right side |
bottom | Fixed panel at the bottom |
Theming
The theme prop covers the common cases:
<ChatWidget
serverUrl={serverUrl}
user={{ id: userId }}
theme={{
mode: "auto", // 'light' | 'dark' | 'auto' (follows prefers-color-scheme)
primaryColor: "#6e56cf",
borderRadius: "12px",
headerText: "Ask the agent",
placeholder: "Type a message…",
verboseTools: true, // full tool-call params, results, timing
}}
/>Other ChatTheme fields: backgroundColor, fontFamily, fontSize, userBubbleColor, agentBubbleColor, toolCallColor, emptyStateText.
For anything the prop doesn't cover, override the CSS custom properties (no Tailwind dependency):
.pcw-widget {
--pcw-primary: #6e56cf;
--pcw-bg: #ffffff;
--pcw-text: #1a1a1a;
--pcw-border: #e5e5e5;
--pcw-radius: 12px;
}SSE events
The widget handles these event types from the runtime:
| Event | Description |
|---|---|
text_delta | Streaming text output |
tool_call_start | Tool execution beginning |
tool_call_result | Tool execution complete |
skill_activated | Skill activation |
widget | Widget rendered inline |
confirmation_required | Write operation needs approval |
done | Response complete |
Building blocks
For a custom chat surface, the /widget subpath exports the pieces ChatWidget is made of:
- Components:
MessageList,InputBar,SessionHistory,StreamingIndicator,ToolCallCard,AskUserCard,KBProposalCard,SkillPill,TagEditor,FormattedText, andWidgetRenderer(with itsWidgetRegistrytype). - Hooks:
useChat(the widget's chat state machine),useWidgetEvents,useSessionHistory. - Chat API:
listSessions,getSessionHistory,createSession. - Theme utilities:
defaultTheme,applyTheme,mergeTheme.
The provider-based hooks and headless clients live in the package root; see @amodalai/react.