@vikaskalla/sentra-chat-widget
v1.0.5
Published
Reusable chat widget for Sentra Platform - Embed Sentra AI chat interface in your applications
Maintainers
Readme
@vikaskalla/sentra-chat-widget
A reusable React chat widget for integrating Sentra Platform's AI chat into your applications. It provides a full chat UI with message history, execution timeline, optional HITL, and workflow UI nodes in a full-screen modal.
Features
- Easy integration: Pass
sentraUrl,userId, andprojectId. - Chat UI aligned with Sentra app: Message list, typing indicator, execution timeline, and HITL inline card match packages/ui.
- New conversation: Header button starts a fresh session; optional
onNewConversation(newConversationId)for the host to update session/conversation display. - Stream auth: When using
accessToken, the widget appends it as a query param for the EventSource stream URL so the API gateway can authenticate GET stream requests. - Full theming: All components use semantic tokens (no hardcoded colors); host provides CSS variables for light/dark and brand.
- Rich responses: Tables, cards, lists, markdown, HTML, and JSON.
- Workflow UI: Full-screen modal for workflow UI nodes via SSE.
- TypeScript: Full type support and exported types.
Alignment with Sentra UI
The chat UI matches packages/ui (main Sentra app):
- Message list: Scroll-to-bottom, empty state, message ordering.
- Typing indicator: Left-aligned bubble with "Thinking..." and bouncing dots.
- Execution timeline: Per-message collapsible timeline (routing, tool calls, completion) from the query stream.
- HITL: Inline amber card with "Respond"; use
onHITLRespondto handle (e.g. open modal and call HITL API).
MessageList and MessageBubble use the same props and event shapes as the UI package (messageEvents, executionEvents, onHITLRespond).
Installation
npm install @vikaskalla/sentra-chat-widget
# or
yarn add @vikaskalla/sentra-chat-widget
# or
pnpm add @vikaskalla/sentra-chat-widgetQuick Start
import { ChatWidget } from '@vikaskalla/sentra-chat-widget';
function App() {
return (
<div style={{ height: '100vh' }}>
<ChatWidget
config={{
sentraUrl: 'http://localhost:3011',
userId: 'user-123',
projectId: 'project-456',
sessionId: 'session-789',
features: { chatHistory: true, workflowUI: true, hitl: true },
}}
/>
</div>
);
}The widget connects to the workflow SSE stream automatically when userId is set and the gateway reports workflow events capability (GET /health/ready → capabilities.workflowEvents). If the workflow service is not running, the widget skips the relay and continues without workflow UI updates (no user-facing error). Set features.workflowUI: false to disable workflow events entirely.
ChatConfig
The widget accepts a single config prop of type ChatConfig:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| sentraUrl | string | required | Base URL of Sentra (e.g. API gateway). |
| userId | string | required | User identifier. |
| projectId | string | required | Project ID. |
| sessionId | string | sess_${Date.now()} | Session for conversation grouping. |
| accessToken | string | - | Bearer token for API auth (see Authentication). |
| features | ChatFeatures | see below | Feature flags for optional UI. |
| className | string | '' | Extra CSS classes for the container. |
| onError | (error: Error) => void | - | Error callback. |
| workflowUIContainer | HTMLElement or null | - | Container for workflow UI. |
| workflowUIRightOffset | number | 500 | Right offset in px for workflow UI. |
| workflowUIDisplayMode | 'carousel' or 'vertical' | 'vertical' | UI nodes: carousel or vertical list. |
| onHITLRespond | (hitlRequestId, agentId, eventData?) => void | - | Called when user clicks "Respond" on HITL card (when features.hitl is false or for custom handling). |
| onNewConversation | (newConversationId?: string) => void | - | Called when user starts a new conversation (e.g. host can update sessionId for display). |
| timelineAutoCollapse | boolean | false | When true, auto-collapse execution timeline when loading completes (matches packages/ui). |
Feature flags (features)
| Flag | Default | Description |
|------|---------|-------------|
| chatHistory | true | Show chat history panel (conversation list). |
| workflowUI | true | Enable workflow events relay and full-screen workflow modal. |
| hitl | true | Use built-in HITL modal; when false, use onHITLRespond callback only. |
| debugPanel | false | Show execution debug panel (future). |
| documents | false | Show documents panel (future). |
| voice | false | Enable voice assistant (future). |
The widget header includes a New conversation button. Clicking it starts a fresh session: creates a new conversation via the API, clears the message list, and optionally notifies the host via onNewConversation(newConversationId) so the host can update session/conversation display (aligned with main Sentra Chat UI).
Recent updates (gaps addressed)
- API gateway only: All traffic (chat, query stream, workflow events relay) is routed via
sentraUrl(API gateway). TheworkflowServiceUrlprop was removed; the widget no longer connects directly to any backend service. - Theming: Replaced all hardcoded gray/blue/red/white with semantic tokens (
bg-card,border-border,text-foreground,text-muted-foreground,bg-primary,text-destructive, etc.) in ChatWidget, MessageList, MessageBubble, TypingIndicator, ResponseRenderer, TableResponse, ListResponse, CardResponse, ErrorBoundary, WorkflowFullScreenModal, and UINodeRenderer. - New conversation: Header "New conversation" button;
onNewConversation(newConversationId)callback for host to refresh session/conversation display. - Stream auth: EventSource cannot send
Authorization; widget appendsaccess_tokento the stream URL whenaccessTokenis set so the API gateway can authenticate the GET stream (gateway must accept token from query for/api/v1/query/stream/*). - Conversation/session display: Header shows truncated conversation ID and session ID for parity with main Sentra Chat UI.
Authentication
- Same origin: Omit
accessToken; cookies are sent automatically. - Cross-origin or PAT: Set
accessToken; the widget sendsAuthorization: Bearer <token>. The query stream (EventSource) cannot send custom headers; use same-origin or a proxy for token-based streaming.
Env example (Vite):
VITE_SENTRA_ACCESS_TOKEN=your-token
VITE_SENTRA_URL=https://api.sentra.example.com<ChatWidget
config={{
sentraUrl: import.meta.env.VITE_SENTRA_URL,
userId: 'user-123',
projectId: 'project-456',
accessToken: import.meta.env.VITE_SENTRA_ACCESS_TOKEN,
features: { chatHistory: true, workflowUI: true, hitl: true },
}}
/>Use REACT_APP_* or NEXT_PUBLIC_* for CRA/Next.js. Prefer server-side or build-time injection in production.
Usage Examples
With error handling:
<ChatWidget
config={{
sentraUrl: 'https://api.sentra.example.com',
userId: 'user-123',
projectId: 'project-456',
onError: (err) => console.error(err),
}}
/>How It Works
Chat messages
Messages are rendered by MessageList and MessageBubble. The widget streams queries when possible; stream events are pushed into messageEvents so the execution timeline and typing state stay in sync with packages/ui.
Routing
All API traffic (chat, query stream, workflow events) is sent to sentraUrl (the API gateway). The gateway proxies to the appropriate backend services. Set sentraUrl to your API gateway base URL (e.g. http://localhost:3011).
Required vs optional services
Core chat requires the API gateway, execution service, agent service, and (if using PAT) configuration service. The workflow service is optional: when it is not running, chat works but workflow UI events (e.g. node completion modal) are unavailable. The widget uses the gateway’s readiness endpoint (GET /health/ready) to discover capabilities.workflowEvents and only connects to the workflow events relay when available, avoiding 500s or connection errors for that optional feature.
Workflow UI nodes
When workflow events are enabled and the gateway reports workflowEvents: true, the widget opens an SSE connection to {sentraUrl}/api/v1/workflows/events/relay?userId={userId}. It listens for ui.node.started, ui.node.completed, and node.completed, and opens the full-screen workflow modal when UI node events arrive. Node results are kept for data binding (e.g. ${tool-xxx.output}). If the connection fails, the widget retries with exponential backoff (up to 5 attempts) then continues without workflow UI updates.
Response formats
Assistant content can be plain text, markdown, HTML, or JSON. Structured JSON with type: table, list, or card is rendered with the corresponding component.
Using Individual Components
Contracts match packages/ui:
- MessageList:
messages,isLoading, optionalmessageEvents(Map<id, ExecutionEvent[]>), optionalonHITLRespond. - MessageBubble:
message, optionalexecutionEvents, optionalonHITLRespond.
import {
MessageList,
MessageBubble,
TypingIndicator,
ResponseRenderer,
WorkflowFullScreenModal,
ChatService
} from '@vikaskalla/sentra-chat-widget';
function CustomChat() {
const [messages, setMessages] = useState([]);
const [messageEvents, setMessageEvents] = useState(new Map());
return (
<MessageList
messages={messages}
isLoading={loading}
messageEvents={messageEvents}
onHITLRespond={(id, agentId, data) => {}}
/>
);
}Service only:
import { ChatService } from '@vikaskalla/sentra-chat-widget';
const service = new ChatService('https://api.sentra.example.com');
const result = await service.sendQuery('Hello', 'user-123', 'project-456');
const messages = await service.getMessages(conversationId);Styling / Theming
The widget is fully themeable via CSS variables. The host app must use Tailwind and define the same design tokens as the Sentra app (or shadcn-style theme):
- Surfaces:
--background,--card,--foreground,--card-foreground - Borders / inputs:
--border,--input,--ring - Primary:
--primary,--primary-foreground - Muted:
--muted,--muted-foreground - Accent:
--accent,--accent-foreground - Destructive:
--destructive,--destructive-foreground
All widget components (ChatWidget, MessageList, MessageBubble, TypingIndicator, ResponseRenderer, TableResponse, ListResponse, CardResponse, ErrorBoundary, WorkflowFullScreenModal, UINodeRenderer) use these semantic classes only (e.g. bg-primary, bg-card, border-border, text-muted-foreground, bg-destructive/10). No hardcoded gray/blue/red; the widget inherits the host’s theme and works with light/dark when the host toggles the token values.
TypeScript
import type {
ChatConfig,
ChatFeatures,
ChatMessage,
Conversation,
WorkflowDataItem,
ExecutionEvent
} from '@vikaskalla/sentra-chat-widget';Requirements
- React 18+
- Sentra Platform instance
API Endpoints
POST /api/v1/query– send queryPOST /api/v1/query/stream/init– start query streamGET /api/v1/chat/conversations,POST /api/v1/chat/conversationsGET /api/v1/chat/conversations/:id/messagesPOST /api/v1/chat/conversations/:id/endGET /api/v1/workflows/events/relay?userId={userId}– workflow SSE (auto-connected)
Error Handling
- Network and API errors surface in the chat and trigger
onErrorwhen provided. - Error messages are appended to the conversation.
Browser Support
Chrome, Firefox, Safari, Edge (latest).
Development
pnpm install
pnpm build
pnpm dev
pnpm type-check
pnpm lintLicense
MIT
Support
Contributing
See the main repository for guidelines.
