Skip to content

useChat Hook ​

The useChat hook provides direct access to the chat state and methods. Use this hook in any component within your CyborgProvider to interact with the chat functionality.

Overview ​

The useChat hook returns an object containing the current chat state and methods to manipulate it. It can only be used within a component that is wrapped by CyborgProvider.

Basic Usage ​

tsx
import { useChat } from '@cyborg-sdk/react';

function MyChatComponent() {
  const { messages, isLoading, error, sendMessage, clearMessages } = useChat();

  return (
    <div>
      {/* Display messages */}
      {messages.map(msg => (
        <div key={msg.id}>{msg.content}</div>
      ))}

      {/* Show loading state */}
      {isLoading && <p>Loading...</p>}

      {/* Show errors */}
      {error && <p>Error: {error.message}</p>}

      {/* Send messages */}
      <button onClick={() => sendMessage('Hello!')}>Send</button>
    </div>
  );
}

Return Value ​

The hook returns an object with the following properties and methods:

typescript
interface CyborgChatContextValue {
  // State
  messages: Message[];
  isLoading: boolean;
  error: Error | null;
  conversationId: string | null;
  isOpen: boolean;
  hasUniqueIdentifier: boolean;
  isLoadingConversation: boolean;

  // Methods
  sendMessage: (content: string) => Promise<void>;
  clearMessages: () => void;
  startNewConversation: () => void;
  loadConversation: (conversationId: string) => Promise<void>;
  listConversations: () => Promise<ConversationSummary[]>;
  openChat: () => void;
  closeChat: () => void;
  triggerPrompt: (prompt: string, options?: TriggerPromptOptions) => Promise<void>;
}

Properties ​

messages ​

Array of all chat messages in the conversation.

Type: Message[]

Message structure:

typescript
interface Message {
  id: string;
  content: string;
  role: 'user' | 'assistant' | 'system' | 'tool';
  timestamp: Date;
  toolCallId?: string;
  metadata?: Record<string, unknown>;
}

Example:

tsx
function ChatHistory() {
  const { messages } = useChat();

  return (
    <div>
      {messages.map(message => (
        <div key={message.id} className={`msg-${message.role}`}>
          {message.content}
          <small>{message.timestamp.toLocaleTimeString()}</small>
        </div>
      ))}
    </div>
  );
}

isLoading ​

Boolean indicating whether a message is currently being sent or received.

Type: boolean

error ​

Error object if something went wrong, or null if no error.

Type: Error | null

conversationId ​

Unique identifier for the current conversation.

Type: string | null

isOpen ​

Whether the chat modal is currently open.

Type: boolean

hasUniqueIdentifier ​

Whether uniqueIdentifier is configured (enables server-side conversation history).

Type: boolean

isLoadingConversation ​

Loading state specifically for conversation operations (load/list).

Type: boolean

Methods ​

sendMessage(content: string): Promise<void> ​

Send a message to the chat assistant.

tsx
function ChatInput() {
  const [input, setInput] = useState('');
  const { sendMessage, isLoading } = useChat();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (input.trim()) {
      await sendMessage(input);
      setInput('');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        disabled={isLoading}
      />
      <button type="submit" disabled={isLoading}>Send</button>
    </form>
  );
}

clearMessages(): void ​

Clear all messages from the conversation.

tsx
const { clearMessages } = useChat();

<button onClick={clearMessages}>Clear Chat</button>

startNewConversation(): void ​

Start a new conversation (clears messages and resets conversationId locally).

tsx
const { startNewConversation } = useChat();

<button onClick={startNewConversation}>New Chat</button>

openChat(): void ​

Open the chat widget.

tsx
const { openChat } = useChat();

<button onClick={openChat}>Open Chat</button>

closeChat(): void ​

Close the chat widget.

tsx
const { closeChat } = useChat();

<button onClick={closeChat}>Close Chat</button>

triggerPrompt(prompt: string, options?: TriggerPromptOptions): Promise<void> ​

Open the chat with a pre-filled prompt, optionally starting a new conversation.

tsx
const { triggerPrompt } = useChat();

// Basic usage
triggerPrompt('How do I reset my password?');

// With options
triggerPrompt('Help me upgrade my plan', {
  startNew: true,  // Start a new conversation (default: true)
  instruction: 'Focus on pricing and plan differences'
});

Options:

typescript
interface TriggerPromptOptions {
  startNew?: boolean;   // Whether to start a new conversation. Default: true
  instruction?: string; // Additional instruction for this prompt
}

Example: Help Buttons

tsx
function HelpButton({ topic }) {
  const { triggerPrompt } = useChat();

  const handleHelp = () => {
    triggerPrompt(`Help me understand ${topic}`, {
      startNew: true,
      instruction: `Focus on explaining ${topic} clearly`
    });
  };

  return (
    <button onClick={handleHelp}>
      Get help with {topic}
    </button>
  );
}

loadConversation(conversationId: string): Promise<void> ​

Load a previous conversation from the backend. Requires uniqueIdentifier to be set.

tsx
const { loadConversation } = useChat();

await loadConversation('conv_abc123');

listConversations(): Promise<ConversationSummary[]> ​

List all conversations for the current user. Requires uniqueIdentifier to be set.

tsx
const { listConversations, loadConversation } = useChat();

const conversations = await listConversations();
// Returns: [{ id, title, createdAt, updatedAt }]

// Load a specific conversation
await loadConversation(conversations[0].id);

ConversationSummary type:

typescript
interface ConversationSummary {
  id: string;
  title?: string;
  createdAt: Date;
  updatedAt: Date;
}

Conversation History ​

When uniqueIdentifier is set in config, conversation history is enabled:

tsx
function ConversationList() {
  const { listConversations, loadConversation, hasUniqueIdentifier } = useChat();
  const [conversations, setConversations] = useState([]);

  useEffect(() => {
    if (hasUniqueIdentifier) {
      listConversations().then(setConversations);
    }
  }, [hasUniqueIdentifier]);

  if (!hasUniqueIdentifier) {
    return <p>Sign in to see conversation history</p>;
  }

  return (
    <ul>
      {conversations.map(conv => (
        <li key={conv.id} onClick={() => loadConversation(conv.id)}>
          {conv.title || 'Untitled'} - {conv.updatedAt.toLocaleDateString()}
        </li>
      ))}
    </ul>
  );
}

Complete Example: Custom Chat Panel ​

tsx
import React, { useState } from 'react';
import { useChat } from '@cyborg-sdk/react';

function CustomChatPanel() {
  const [input, setInput] = useState('');
  const {
    messages,
    isLoading,
    error,
    sendMessage,
    clearMessages,
    startNewConversation,
    openChat,
    closeChat,
    isOpen
  } = useChat();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!input.trim() || isLoading) return;

    try {
      await sendMessage(input);
      setInput('');
    } catch (err) {
      console.error('Failed to send message:', err);
    }
  };

  return (
    <div className="chat-panel">
      {/* Chat Toggle */}
      <button onClick={isOpen ? closeChat : openChat}>
        {isOpen ? 'Close' : 'Open'} Chat
      </button>

      {/* Error Display */}
      {error && (
        <div className="error-banner">
          Error: {error.message}
        </div>
      )}

      {/* Messages */}
      <div className="messages">
        {messages.length === 0 ? (
          <p className="placeholder">Start a conversation...</p>
        ) : (
          messages.map(msg => (
            <div key={msg.id} className={`message message-${msg.role}`}>
              <p>{msg.content}</p>
              <small>
                {msg.role === 'user' ? 'You' : 'Assistant'} •
                {msg.timestamp.toLocaleTimeString()}
              </small>
            </div>
          ))
        )}

        {isLoading && (
          <div className="message message-system">
            <p>Typing...</p>
          </div>
        )}
      </div>

      {/* Input Form */}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Type your message..."
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading || !input.trim()}>
          Send
        </button>
        <button type="button" onClick={startNewConversation}>
          New Chat
        </button>
        <button type="button" onClick={clearMessages}>
          Clear
        </button>
      </form>
    </div>
  );
}

TypeScript Support ​

Full TypeScript support is built-in:

tsx
import { useChat, Message, CyborgChatContextValue } from '@cyborg-sdk/react';

function TypedChatComponent() {
  const chat: CyborgChatContextValue = useChat();

  const renderMessage = (msg: Message) => {
    switch (msg.role) {
      case 'user':
        return <div className="user-msg">{msg.content}</div>;
      case 'assistant':
        return <div className="ai-msg">{msg.content}</div>;
      case 'system':
        return <div className="system-msg">{msg.content}</div>;
      case 'tool':
        return <div className="tool-msg">{msg.content}</div>;
    }
  };

  return (
    <div>
      {chat.messages.map(msg => (
        <div key={msg.id}>{renderMessage(msg)}</div>
      ))}
    </div>
  );
}

Context Requirement ​

The hook must be used within a component wrapped by CyborgProvider. Using it outside will throw an error:

tsx
// ❌ This will fail - not inside CyborgProvider
function InvalidUsage() {
  const chat = useChat(); // Error: useChat must be used within a CyborgProvider
  return null;
}

// ✅ This works - inside CyborgProvider
function App() {
  return (
    <CyborgProvider config={{ publishableKey: 'YOUR_API_KEY' }}>
      <ValidUsage />
    </CyborgProvider>
  );
}

function ValidUsage() {
  const { messages } = useChat(); // ✅ Works
  return <div>{messages.length} messages</div>;
}

Built with VitePress