@kedge-agentic/react-sdk
v0.2.0
Published
React hooks and utilities for integrating with Claude-Code-as-a-Service backend
Maintainers
Readme
@kedge-agentic/react-sdk
React SDK for building KedgeAgentic solutions with chat UI, real-time updates, and agent status tracking.
Features
- Chat Components: Pre-built ChatPanel, MessageBubble, AgentActivityLine
- React Hooks: Modular hooks for connection, chat, status, and layout
- Real-time Updates: SSE (Server-Sent Events) integration with automatic reconnection
- Agent Tracking: Monitor tool execution, subagents, thinking, and todos
- Form Sync: Output update protocol for AI-suggested form changes
- Layout Controls: Multiple chat modes (default, overlay, expanded)
- Type Safe: Full TypeScript support with types from @kedge-agentic/common
Installation
npm install @kedge-agentic/react-sdk @kedge-agentic/commonQuick Start
import {
useAgentConnection,
useAgentChat,
useAgentStatus,
ChatPanel
} from '@kedge-agentic/react-sdk'
function App() {
const connection = useAgentConnection({
serverUrl: 'http://localhost:3001',
tenantId: 'my-app' // Enables conversation persistence
})
const chat = useAgentChat({ connection, tenantId: 'my-app' })
const status = useAgentStatus({ connection })
if (chat.isLoadingHistory) {
return <div>Loading conversation...</div>
}
return (
<>
<button onClick={() => chat.clearConversation()}>New Conversation</button>
<ChatPanel
messages={chat.messages}
isProcessing={status.isProcessing}
connected={connection.connected}
activeTools={status.activeTools}
onSendMessage={chat.sendMessage}
/>
</>
)
}Terminology Guide
This table clarifies terms used across documentation, code, and user interfaces:
| User-Facing Term | Technical Term | Type/Interface | Format/Example | Notes |
|------------------|----------------|----------------|----------------|-------|
| Conversation | Session | Session | - | Same entity, different perspectives |
| Conversation ID | sessionId | string | conv_a1b2c3d4-... | Format: conv_{uuid} when using tenantId |
| Chat message | Message | Message | - | Single utterance from user or assistant |
| Exchange | Turn | Turn | - | One Q&A pair (user message + assistant response) |
| Message history | messages | Message[] | - | All messages in a conversation |
| Session ID | sessionId | string | conv_{uuid} or {prefix}_{id} | Unique conversation identifier |
| Client ID | clientId | string | Auto-assigned | WebSocket client identifier |
Common Confusion Points
Q: What's the difference between "conversation" and "session"? A: They're the same thing. "Conversation" is user-facing term, "Session" is the technical database entity.
Q: Is conversationId the same as sessionId?
A: Yes. localStorage uses ccaas_session_{tenantId} as the key, but the value stored is the sessionId (format: conv_{uuid}).
Q: What's a Turn? A: A Turn represents one complete exchange: user message → assistant response. Used for analytics and per-turn cost tracking.
Q: Why messageIndex instead of createdAt for sorting?
A: messageIndex is a 0-based sequential number that guarantees message order, even if createdAt timestamps are identical.
Documentation
Comprehensive Guides
- API Reference - Complete API documentation for all hooks and components
- Advanced Patterns - Custom hooks, error handling, state management integration
- Troubleshooting - Common issues, debugging techniques, and FAQ
- Performance Optimization - Performance best practices and optimization strategies
- Chat Integration Guide - Step-by-step integration guide
SDK Comparison
- SDK Comparison - Feature comparison between React and Vue SDKs
- Choosing an SDK - Decision guide for selecting the right SDK
- Migration Guide - Upgrading and migrating between SDKs
Core Hooks
useAgentConnection
Manages connection to KedgeAgentic backend (SSE by default) with optional conversation persistence.
const connection = useAgentConnection({
serverUrl: 'http://localhost:3001',
tenantId: 'my-solution', // Enables conversation persistence via localStorage
autoConnect: true,
// sessionPrefix: 'legacy', // Legacy option (no persistence), use tenantId instead
// forceNewConversation: true, // Always start fresh, ignore saved conversationId
})
// Returns:
// - connected: boolean
// - sessionId: string // conv_${uuid} when tenantId provided
// - socket: Socket | null
// - connect: () => void
// - disconnect: () => void
// - startNewConversation: () => void // Clear storage, new ID, reconnectConversation persistence: When tenantId is provided, the sessionId is persisted in localStorage under ccaas_session_{tenantId}. On page refresh, the same sessionId is recovered, enabling message history loading.
useAgentChat
Handles chat messages, user input, and conversation lifecycle.
const chat = useAgentChat({
connection,
tenantId: 'my-solution'
})
// Returns:
// - messages: Message[]
// - isProcessing: boolean
// - isLoadingHistory: boolean // True while loading saved messages
// - currentStreamContent: string
// - sendMessage: (content: string) => void
// - clearMessages: () => void // Clear UI only, keep same conversation
// - clearConversation: () => void // Clear UI + new conversationId + reconnect
// - cancelProcessing: () => voidMessage history: On connection, useAgentChat automatically fetches message history from GET /api/v1/sessions/{sessionId}/messages?limit=100. Use isLoadingHistory to show a loading indicator.
New conversation: Call clearConversation() to start a fresh conversation. This clears messages, removes the saved conversationId from localStorage, generates a new conv_${uuid}, and reconnects.
useAgentStatus
Tracks agent execution status.
const status = useAgentStatus({ connection })
// Returns:
// - isProcessing: boolean
// - activeTools: Map<string, ToolActivity>
// - activeSubAgents: ActiveSubAgent[]
// - isThinking: boolean
// - thinkingContent: string
// - todoItems: TodoItem[]
// - todoStats: TodoStats | nulluseChatLayout
Manages chat UI layout state.
const layout = useChatLayout()
// Returns:
// - mode: 'default' | 'overlay' | 'expanded'
// - isCollapsed: boolean
// - setMode: (mode) => void
// - setCollapsed: (collapsed: boolean) => void
// - toggleCollapsed: () => voiduseSkills
Manages solution skills (CRUD operations).
const { skills, enabledSkills, toggleSkill, createSkill, deleteSkill } =
useSkills({ tenantId: 'default' })Chat Components
ChatPanel
Main chat interface with message list, input, and activity line.
<ChatPanel
messages={messages}
isProcessing={isProcessing}
connected={connected}
activeTools={activeTools}
activeSubAgents={activeSubAgents}
isThinking={isThinking}
thinkingContent={thinkingContent}
todoItems={todoItems}
todoStats={todoStats}
onSendMessage={sendMessage}
onCancel={() => socket?.emit('cancel')}
renderMessage={(msg) => (
<MessageBubble message={msg}>
{/* Custom content */}
</MessageBubble>
)}
renderQuickActions={() => (
<QuickActions actions={actions} onAction={sendMessage} />
)}
/>MessageBubble
Individual message display with role-based styling.
<MessageBubble
message={message}
colorScheme="blue" // or "purple", "green", etc.
>
{/* Optional children for custom content */}
</MessageBubble>AgentActivityLine
Status bar showing tool execution, thinking, todos, and subagents.
<AgentActivityLine
isProcessing={isProcessing}
isThinking={isThinking}
thinkingContent={thinkingContent}
activeTools={activeTools}
activeSubAgents={activeSubAgents}
todoItems={todoItems}
todoStats={todoStats}
onCancel={() => socket?.emit('cancel')}
/>Features:
- Expandable details panel
- Task hierarchy visualization
- Live subagent tracking with duration timers
- Todo list with status indicators
- Thinking content display
- Cancel button
OutputUpdateCard
Display AI-suggested content updates with sync/discard actions.
<OutputUpdateCard
field="title"
fieldLabel="Title"
preview="Suggested title..."
synced={false}
icon="sync" // or "download", "attach", or ReactNode
syncLabel="Sync to Form"
onSync={() => handleSync('title')}
onDiscard={() => handleDiscard('title')}
/>QuickActions
Quick action buttons for common prompts.
<QuickActions
actions={[
{ id: 'summarize', label: 'Summarize', prompt: 'Summarize this' },
{ id: 'translate', label: 'Translate', prompt: 'Translate to English' }
]}
onAction={(prompt) => sendMessage(prompt)}
renderAction={(action, onClick) => (
<button onClick={onClick}>{action.label}</button>
)}
/>SubAgentCard
Display individual subagent progress.
<SubAgentCard
subAgent={{
subAgentId: 'agent-123',
agentType: 'Explore',
status: 'running',
description: 'Exploring codebase...',
startedAt: new Date().toISOString()
}}
/>ChatLayoutControls
UI controls for switching chat layout modes.
<ChatLayoutControls
mode={mode}
onModeChange={setMode}
isCollapsed={isCollapsed}
onToggleCollapse={toggleCollapsed}
colorScheme="blue"
/>Advanced Usage
Custom Hook Pattern
import {
useAgentConnection,
useAgentChat,
useAgentStatus,
useChatLayout
} from '@kedge-agentic/react-sdk'
const TENANT_ID = 'my-solution'
export function useMySession() {
const connection = useAgentConnection({
serverUrl: process.env.REACT_APP_BACKEND_URL,
tenantId: TENANT_ID,
})
const chat = useAgentChat({ connection, tenantId: TENANT_ID })
const status = useAgentStatus({ connection })
const layout = useChatLayout()
// Add solution-specific logic
const [customState, setCustomState] = useState(...)
return {
...connection,
...chat,
...status,
...layout,
customState,
setCustomState
}
}Custom Message Rendering
<ChatPanel
{...props}
renderMessage={(msg) => (
<MessageBubble message={msg}>
{/* Render output updates */}
{msg.outputUpdates?.map(update => (
<OutputUpdateCard
key={update.field}
field={update.field}
fieldLabel={FIELD_LABELS[update.field]}
preview={update.preview}
onSync={() => syncToForm(update.field)}
onDiscard={() => discardUpdate(update.field)}
/>
))}
{/* Render file attachments */}
{msg.attachments?.map(file => (
<FileCard key={file.id} file={file} />
))}
</MessageBubble>
)}
/>Form Synchronization
function useFormSync<T>(initialForm: T) {
const connection = useAgentConnection({...})
const [formData, setFormData] = useState(initialForm)
const [pendingUpdates, setPendingUpdates] = useState(new Map())
useEffect(() => {
if (!connection.socket) return
const handleOutputUpdate = (event: OutputUpdateEvent) => {
const { field, value, preview } = event.payload.data
setPendingUpdates(prev => new Map(prev).set(field, { value, preview }))
}
connection.socket.on('output_update', handleOutputUpdate)
return () => connection.socket.off('output_update', handleOutputUpdate)
}, [connection.socket])
const syncToForm = (field: string) => {
const update = pendingUpdates.get(field)
if (update) {
setFormData(prev => ({ ...prev, [field]: update.value }))
setPendingUpdates(prev => {
const next = new Map(prev)
next.delete(field)
return next
})
}
}
return { formData, pendingUpdates, syncToForm }
}TypeScript Support
All components and hooks are fully typed. Import types from @kedge-agentic/common:
import type {
Message,
ToolActivity,
ActiveSubAgent,
TodoItem,
OutputUpdateEvent
} from '@kedge-agentic/common'
import type {
AgentConnectionConfig,
ChatLayoutMode
} from '@kedge-agentic/react-sdk'Testing
The SDK includes both unit and integration tests to ensure reliability.
Running Tests
# Run all tests (unit + integration)
npm test
# Run only unit tests (fast, no backend required)
npm run test:unit
# Run only integration tests (requires backend running)
npm run test:integration
# Watch mode for development
npm run test:watchIntegration Tests
Integration tests verify the SDK works correctly with a real KedgeAgentic backend. They test:
- WebSocket connection establishment
- REST API endpoints (
/api/v1/sessions/:id/completion) - Message flow (send message → receive events)
- Multi-session concurrency
- Real-time event streaming
Prerequisites:
Before running integration tests, start the KedgeAgentic backend:
cd packages/backend
npm run start:devThe backend must be running on http://localhost:3001 for integration tests to pass.
Integration Test Coverage:
| Test Suite | Coverage |
|------------|----------|
| backend.test.ts | Backend availability, endpoint existence |
| websocket.test.ts | WebSocket connections, client IDs, concurrent connections |
| completion.test.ts | REST endpoint validation, DTO validation, parameters |
| message-flow.test.ts | Complete message lifecycle, event streaming, follow-ups |
CI/CD Setup:
For CI pipelines, ensure the KedgeAgentic backend is started before running integration tests:
- name: Start KedgeAgentic Backend
run: |
cd packages/backend
npm run start:dev &
sleep 5
- name: Run Integration Tests
run: |
cd packages/react-sdk
npm run test:integrationEvents
The SDK handles these standard events from the backend (delivered via SSE stream or Socket.IO):
chat_message- New assistant messagetext_delta- Streaming text updatesoutput_update- AI-suggested form updatestool_activity- Tool execution trackingagent_status- Agent completion/errorsubagent_started- SubAgent execution startedsubagent_completed- SubAgent execution completedagent_thinking- Thinking contenttodo_created,todo_updated- Todo tracking
Examples
See complete examples in:
solutions/ccaas-demo- Basic chat with file trackingsolutions/lesson-plan-designer- Form sync with output updates
Documentation
- Chat Integration Guide - Complete integration tutorial
- Conversation Persistence - Conversation recovery architecture and integration guide
- Understanding the Messaging Model - Conceptual overview of Session, Message, Turn entities with diagrams
- Solution Template - Template for new solutions
- Backend Events - Backend event reference
Contributing
When adding new components or hooks:
- Add TypeScript types to
@kedge-agentic/commonif shared - Document props with JSDoc comments
- Add examples to this README
- Update CHAT_INTEGRATION_GUIDE.md if needed
- Run
npm run buildto verify
License
See repository root LICENSE file.
