Chat SDK

useChatContext

Access chat state and methods from any component within ChatProvider.

Usage

import { useChatContext } from 'react-chat-agent';

function MyComponent() {
  const {
    messages,
    sendMsg,
    isStreaming,
    isLoading,
    abort,
    messageManager,
    sessionId
  } = useChatContext();

  return <div>Chat Component</div>;
}

Return Value

interface ChatContextValue {
  // Messages
  messages: Message[];
  messageManager: MessageManager;
  
  // State
  isLoading: boolean;
  isStreaming: boolean;
  isResponseStarted: boolean;
  isInitialLoading: boolean;
  isLoadingMore: boolean;
  
  // Actions
  sendMsg: (params?: SendMessageParams) => Promise<void>;
  abort: () => void;
  retryLastMessage: () => Promise<void>;
  
  // History
  getHistory: () => Promise<void>;
  loadMoreMessages: () => Promise<void>;
  hasMoreMessages: boolean;
  enableHistory: boolean;
  
  // Errors
  error: any;
  streamError: any;
  clearStreamError: () => void;
  
  // Session
  sessionId: string | undefined;
  setSessionId: (id: string | undefined) => void;
  instanceId: string;
  
  // Configuration
  welcome: any;
  statusRegistry: StatusRegistry;
  markdownComponents: any;
  typingAnimation: TypingAnimationConfig;
  statusComponents?: any;
  loadingComponent?: ComponentType;
  headerComponent?: ReactNode;
  debug?: boolean;
  
  // Files
  currentSelectedFile: any;
  setCurrentSelectedFile: (file: any) => void;
}

Examples

Send Message

function SendButton() {
  const { sendMsg, isLoading } = useChatContext();

  const handleClick = async () => {
    await sendMsg({
      message: 'Hello, agent!',
      attachedFiles: []
    });
  };

  return (
    <button onClick={handleClick} disabled={isLoading}>
      Send
    </button>
  );
}

Display Messages

function MessageList() {
  const { messages } = useChatContext();

  return (
    <div>
      {messages.map(msg => (
        <div key={msg.id}>
          <strong>{msg.role}:</strong> {msg.content}
        </div>
      ))}
    </div>
  );
}

Stream Control

function StreamControls() {
  const { isStreaming, abort } = useChatContext();

  if (!isStreaming) return null;

  return (
    <button onClick={abort}>
      Stop Generation
    </button>
  );
}

Message History

function HistoryLoader() {
  const {
    hasMoreMessages,
    isLoadingMore,
    loadMoreMessages
  } = useChatContext();

  if (!hasMoreMessages) return null;

  return (
    <button onClick={loadMoreMessages} disabled={isLoadingMore}>
      {isLoadingMore ? 'Loading...' : 'Load More'}
    </button>
  );
}

Error Handling

function ErrorDisplay() {
  const { streamError, clearStreamError } = useChatContext();

  if (!streamError) return null;

  return (
    <div className="error">
      <p>{streamError.message}</p>
      <button onClick={clearStreamError}>Dismiss</button>
    </div>
  );
}

useForwarding

Intercept and forward streaming data to external components.

Signature

// Single handler
function useForwarding(
  action: string,
  handler: ForwardingHandler,
  options?: Partial<ForwardingHandlerConfig>
): UseForwardingReturn;

// Multiple handlers
function useForwarding(
  handlers: ForwardingHandlers
): UseForwardingReturn;

// Access manager only
function useForwarding(): UseForwardingReturn;

Handler Function

type ForwardingHandler = (
  incrementalText: string,
  fullText: string,
  metadata: {
    action: string;
    isLive: boolean;
    event: 'chunk' | 'end';
  }
) => void;

Options

interface ForwardingHandlerConfig {
  handler: ForwardingHandler;
  mode?: 'dual' | 'replace' | 'raw';
  animated?: boolean;
  subscriptionMode?: 'delta' | 'full';
}

Usage

Basic Forwarding

import { useForwarding } from 'react-chat-agent';

function Editor() {
  const editorRef = useRef();

  useForwarding('prompt_create', (incremental, full, meta) => {
    if (editorRef.current) {
      editorRef.current.setValue(full);
    }
  });

  return <div ref={editorRef} />;
}

With Options

useForwarding('stream_data', handler, {
  mode: 'replace',           // Don't show in chat
  subscriptionMode: 'delta', // Get incremental updates
  animated: false            // No typing animation
});

Multiple Actions

useForwarding({
  prompt_create: {
    handler: (inc, full, meta) => updateEditor(full),
    mode: 'replace'
  },
  code_generation: {
    handler: (inc, full, meta) => updateCodeBlock(full),
    mode: 'dual'
  }
});

Manager API

const forwarding = useForwarding();

// Register dynamically
forwarding.register('custom_action', handler, options);

// Unregister
forwarding.unregister('custom_action');

// Get active sessions
const activeSessions = forwarding.getActiveSessions();

useStatusSubscription

Listen to agent events, tool executions, and status updates.

Signature

// Single action
function useStatusSubscription(
  action: string,
  handler: StatusHandler,
  options?: { instanceId?: string }
): void;

// Multiple actions
function useStatusSubscription(
  handlers: StatusHandlers,
  handler?: never,
  options?: { instanceId?: string }
): void;

Handler Function

type StatusHandler = (statusData: any) => void;

Usage

Single Action

import { useStatusSubscription } from 'react-chat-agent';

function ToolMonitor() {
  useStatusSubscription('tool_call', (statusData) => {
    console.log('Tool:', statusData.tool_name);
    console.log('State:', statusData.status.state);
    console.log('Result:', statusData.result);
  });

  return <div>Monitoring tools...</div>;
}

Multiple Actions

function EventMonitor() {
  useStatusSubscription({
    tool_call: (data) => {
      console.log('Tool executed:', data.tool_name);
    },
    edit_file: (data) => {
      console.log('File edited:', data.file_path);
    },
    error: (data) => {
      console.error('Error:', data.error);
    }
  });

  return <div>Monitoring events...</div>;
}

Global Listener

useStatusSubscription('*', (statusData) => {
  // Receives all status messages
  console.log('Status:', statusData);
});

Multi-Instance

// Listen to specific agent instance
useStatusSubscription('tool_call', handler, {
  instanceId: 'agent-123'
});

UI Updates

function ToolStatus() {
  const [currentTool, setCurrentTool] = useState(null);

  useStatusSubscription('tool_call', (data) => {
    if (data.statusType === 'started') {
      setCurrentTool(data.tool_name);
    } else if (data.statusType === 'finished') {
      setCurrentTool(null);
    }
  });

  return currentTool ? (
    <div>Executing: {currentTool}</div>
  ) : null;
}

Message Manager

Manipulate messages programmatically.

API

interface MessageManager {
  messages: Message[];
  subscribers: Set<(messages: Message[]) => void>;
  
  addMessage(msg: Partial<Message>): Message;
  updateMessage(id: string, updates: Partial<Message>, options?: { silent?: boolean }): Message;
  removeMessage(id: string): boolean;
  getMessage(id: string): Message | undefined;
  insertMessages(messages: Message[], position?: 'start' | 'end'): void;
  subscribe(callback: (messages: Message[]) => void): () => void;
  clear(): void;
  
  get count(): number;
}

Usage

function MessageControls() {
  const { messageManager } = useChatContext();

  const addCustomMessage = () => {
    messageManager.addMessage({
      role: 'assistant',
      content: 'This is a custom message'
    });
  };

  const clearAllMessages = () => {
    messageManager.clear();
  };

  const updateMessage = (msgId: string) => {
    messageManager.updateMessage(msgId, {
      content: 'Updated content'
    });
  };

  return (
    <div>
      <button onClick={addCustomMessage}>Add Message</button>
      <button onClick={clearAllMessages}>Clear All</button>
      <p>Total: {messageManager.count}</p>
    </div>
  );
}

Typing Animation Config

Configure how responses appear.

<ChatProvider
  authConfig={authConfig}
  typingAnimation={{
    mode: 'char',     // 'char' | 'word' | 'batch' | 'instant'
    speed: 50,        // units per second
    batchSize: 10     // for 'batch' mode
  }}
>
  <ChatPanel />
</ChatProvider>

Next Steps