Skip to main content

Overview

The useChat hook is the core state management hook for PolyChat-AI, built with Zustand. It manages chat sessions, message streaming, multi-model support (up to 3 models simultaneously), and conversation templates.

Import

import { useChat } from '@/hooks/useChat';

Usage

const {
  activeSessions,
  currentSessionId,
  selectedModels,
  isAnyLoading,
  sendMessageToAll,
  createNewSession,
  deleteMessage,
  regenerateMessage,
  stopStreaming,
} = useChat();

State Properties

activeSessions
ChatSession[]
Array of currently active chat sessions (max 3). Each session represents a conversation with a specific AI model.
allSessions
ChatSession[]
All saved chat sessions, including inactive ones. Used for session history and switching between conversations.
currentSessionId
string | null
ID of the currently active/focused session. Used for single-window mode.
selectedModels
string[]
Array of currently selected model IDs (max 3). Corresponds to the models in activeSessions.
isAnyLoading
boolean
True if any session is currently loading or streaming a response.
abortControllers
Record<string, AbortController>
Map of session IDs to AbortControllers for canceling streaming responses.
streamingProgress
Record<string, { chars: number; start: number; lastUpdate: number }>
Tracks streaming progress for each session, including character count and timing metrics.
pendingTemplate
ConversationTemplate | null
Template waiting to be applied to the conversation.
isInitialized
boolean
Whether the chat store has been initialized with saved data.

Core Methods

sendMessageToAll

Sends a message to all active sessions simultaneously.
await sendMessageToAll(content: string): Promise<void>
content
string
required
The message content to send to all active models.
Features:
  • Validates content before sending
  • Filters out pending sessions (not yet assigned a model)
  • Handles image generation detection and routing
  • Integrates with RAG (Retrieval-Augmented Generation) when enabled
  • Applies system prompts and tone settings
  • Streams responses in real-time
  • Sends notifications when complete
Example:
const { sendMessageToAll, activeSessions } = useChat();

// Send a message to all active models
await sendMessageToAll('Explain quantum computing in simple terms');

// Automatically detects image generation requests
await sendMessageToAll('Génère une image d\'un coucher de soleil');

regenerateMessage

Regenerates a specific assistant message.
await regenerateMessage(sessionId: string, messageId: string): Promise<void>
sessionId
string
required
ID of the session containing the message.
messageId
string
required
ID of the assistant message to regenerate.
Example:
const { regenerateMessage } = useChat();

// Regenerate a specific response
await regenerateMessage('session-123', 'message-456');

deleteMessage

Deletes a message from a session.
deleteMessage(sessionId: string, messageId: string): void
sessionId
string
required
ID of the session containing the message.
messageId
string
required
ID of the message to delete.

stopStreaming

Stops streaming for one or all sessions.
stopStreaming(sessionId?: string): void
sessionId
string
Optional session ID. If not provided, stops streaming for all sessions.
Example:
const { stopStreaming, activeSessions } = useChat();

// Stop a specific session
stopStreaming('session-123');

// Stop all streaming
stopStreaming();

Session Management

initializeChat

Initializes the chat store, loading saved sessions and creating a temporary session.
initializeChat(): void
Called automatically on app load. Loads chat history from localStorage and creates a new temporary session.

createNewSession

Creates a new chat session with the currently selected model.
createNewSession(): void

deleteSession

Deletes a session from history.
deleteSession(sessionId: string): void
sessionId
string
required
ID of the session to delete.

setActiveSession

Switches to a different saved session.
setActiveSession(sessionId: string): void
sessionId
string
required
ID of the session to activate.

clearAllChats

Clears all messages from the current session.
clearAllChats(): void

Multi-Model Management

addModel

Adds a new model to active sessions (max 3).
addModel(modelId: string): void
modelId
string
required
ID of the model to add (e.g., ‘anthropic/claude-3.5-sonnet’).
Example:
const { addModel, selectedModels } = useChat();

if (selectedModels.length < 3) {
  addModel('openai/gpt-4-turbo');
}

removeModel

Removes a model from active sessions.
removeModel(modelId: string): void
modelId
string
required
ID of the model to remove.

setWindowCount

Sets the number of active chat windows (1-3).
setWindowCount(count: number): void
count
number
required
Number of windows (clamped to 1-3).

setSessionModel

Assigns a model to a pending session.
setSessionModel(sessionId: string, modelId: string): void
sessionId
string
required
ID of the pending session.
modelId
string
required
ID of the model to assign.

Template & Quick Actions

applyTemplate

Applies a conversation template to all active sessions.
applyTemplate(template: ConversationTemplate): void
template
ConversationTemplate
required
Template to apply, containing systemPrompt and userMessage.
Example:
const template: ConversationTemplate = {
  id: 'code-review',
  name: 'Code Review',
  category: 'programming',
  description: 'Review code for quality and bugs',
  systemPrompt: 'You are an expert code reviewer...',
  userMessage: 'Please review this code: {code}',
  tags: ['code', 'review'],
  isCustom: false,
};

applyTemplate(template);

prepareTemplate

Prepares a template for editing before application.
prepareTemplate(template: ConversationTemplate | null): void
template
ConversationTemplate | null
required
Template to prepare, or null to clear.

executeQuickAction

Executes a quick action on selected text.
executeQuickAction(action: QuickAction, selectedText?: string): void
action
QuickAction
required
Quick action to execute (explain, optimize, debug, etc.).
selectedText
string
Text to apply the action to (required if action.requiresSelection is true).
Example:
const action: QuickAction = {
  id: 'explain',
  name: 'Explain',
  icon: '📖',
  action: 'explain',
  description: 'Explain selected code',
  requiresSelection: true,
  systemPrompt: 'You are a helpful programming tutor.',
  userMessageTemplate: 'Explain this code: {selectedText}',
};

executeQuickAction(action, 'const x = 5;');

Helper Methods

createNewTemporarySession

Creates a new temporary session (not saved until first message).
createNewTemporarySession(modelId?: string): ChatSession
modelId
string
Model ID for the session. Defaults to ‘default’ if not provided.

Types

ChatSession

interface ChatSession {
  id: string;
  modelId: string;
  modelName: string;
  messages: Message[];
  isLoading: boolean;
  error: string | null;
  isTemporary?: boolean;
}

Message

interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string | MessageContent[];
  timestamp: Date;
  modelId?: string;
  streaming?: boolean;
  imageData?: GeneratedImage;
}

MessageContent

interface MessageContent {
  type: 'text' | 'image_url';
  text?: string;
  image_url?: {
    url: string;
    detail?: 'low' | 'high' | 'auto';
  };
}

Features

Image Generation Detection

The hook automatically detects image generation requests in multiple languages (English, French) using keyword matching:
const keywords = ['génér', 'créer', 'dessin', 'image', 'photo', 'illustration', ...];
When detected with a compatible model, routes to image generation instead of text streaming.

RAG Integration

When RAG is enabled in settings, the hook automatically retrieves relevant context from conversation history:
if (ragEnabled) {
  const relevantHistory = await getRelevantContext(content, sessionMessages);
  contextMessages = [...relevantHistory, lastUserMessage];
}

Streaming Progress Tracking

Tracks real-time streaming metrics for each session:
streamingProgress: {
  'session-123': {
    chars: 1024,
    start: 1234567890,
    lastUpdate: 1234567900
  }
}

Auto-Save

Sessions are automatically saved to localStorage whenever the state changes, excluding empty sessions.

Example: Complete Chat Flow

import { useChat } from '@/hooks/useChat';
import { useSettings } from '@/hooks/useSettings';

function ChatComponent() {
  const {
    activeSessions,
    selectedModels,
    isAnyLoading,
    sendMessageToAll,
    addModel,
    stopStreaming,
  } = useChat();
  
  const { apiKey } = useSettings();

  const handleSend = async (message: string) => {
    if (!apiKey) {
      console.error('API key required');
      return;
    }
    
    await sendMessageToAll(message);
  };

  const handleAddModel = () => {
    if (selectedModels.length < 3) {
      addModel('anthropic/claude-3.5-sonnet');
    }
  };

  return (
    <div>
      {activeSessions.map((session) => (
        <div key={session.id}>
          <h3>{session.modelName}</h3>
          {session.messages.map((msg) => (
            <div key={msg.id}>
              <strong>{msg.role}:</strong> {msg.content}
            </div>
          ))}
        </div>
      ))}
      
      <button onClick={handleAddModel} disabled={selectedModels.length >= 3}>
        Add Model
      </button>
      
      {isAnyLoading && (
        <button onClick={() => stopStreaming()}>Stop</button>
      )}
    </div>
  );
}

Build docs developers (and LLMs) love