npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kedge-agentic/react-sdk

v0.2.0

Published

React hooks and utilities for integrating with Claude-Code-as-a-Service backend

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/common

Quick 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

SDK Comparison

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, reconnect

Conversation 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: () => void

Message 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 | null

useChatLayout

Manages chat UI layout state.

const layout = useChatLayout()

// Returns:
// - mode: 'default' | 'overlay' | 'expanded'
// - isCollapsed: boolean
// - setMode: (mode) => void
// - setCollapsed: (collapsed: boolean) => void
// - toggleCollapsed: () => void

useSkills

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:watch

Integration 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:dev

The 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:integration

Events

The SDK handles these standard events from the backend (delivered via SSE stream or Socket.IO):

  • chat_message - New assistant message
  • text_delta - Streaming text updates
  • output_update - AI-suggested form updates
  • tool_activity - Tool execution tracking
  • agent_status - Agent completion/error
  • subagent_started - SubAgent execution started
  • subagent_completed - SubAgent execution completed
  • agent_thinking - Thinking content
  • todo_created, todo_updated - Todo tracking

Examples

See complete examples in:

  • solutions/ccaas-demo - Basic chat with file tracking
  • solutions/lesson-plan-designer - Form sync with output updates

Documentation

Contributing

When adding new components or hooks:

  1. Add TypeScript types to @kedge-agentic/common if shared
  2. Document props with JSDoc comments
  3. Add examples to this README
  4. Update CHAT_INTEGRATION_GUIDE.md if needed
  5. Run npm run build to verify

License

See repository root LICENSE file.