Skip to content

useConversations

useConversations manages the full lifecycle of multi-turn conversations: listing conversations, selecting one, sending messages, creating new conversations, and deleting conversations. It is used internally by ConversationPanel.

Import

import { useConversations } from "@modernpath/agent-ui-react";

Options

interface UseConversationsOptions {
  /** Backend instance for conversation operations */
  backend: ConversationBackend;

  /** Default agent name used when creating new conversations */
  defaultAgentName?: string;

  /** Default parameters sent with each message */
  defaultParameters?: Record<string, unknown>;
}

Return Value

interface UseConversationsReturn {
  /** Array of conversation summaries */
  conversations: ConversationUI[];

  /** ID of the currently selected conversation, or null */
  selectedId: string | null;

  /** Messages in the currently selected conversation */
  messages: ConversationMessageUI[];

  /** Whether a list fetch or message send is in progress */
  isLoading: boolean;

  /** Whether a message send is specifically in progress */
  isSending: boolean;

  /** Error from the last failed operation, or null */
  error: Error | null;

  /** Select a conversation by ID. Fetches its messages. */
  select: (id: string) => void;

  /** Create a new conversation. Selects it after creation. */
  create: () => void;

  /**
   * Send a message in the selected conversation.
   * Appends the user message and the assistant response.
   */
  send: (content: string) => void;

  /** Delete a conversation by ID. Deselects if it was selected. */
  remove: (id: string) => void;

  /** Refresh the conversation list from the backend */
  refreshList: () => void;
}

ConversationUI Type

interface ConversationUI {
  /** Unique conversation identifier */
  id: string;

  /** Conversation title (auto-generated or user-defined) */
  title: string;

  /** Agent name associated with this conversation */
  agentName?: string;

  /** Creation timestamp (ISO 8601) */
  createdAt: string;

  /** Last update timestamp (ISO 8601) */
  updatedAt: string;
}

ConversationMessageUI Type

interface ConversationMessageUI {
  /** Message role */
  role: ConversationRole; // "user" | "assistant" | "system"

  /** Message text content */
  content: string;

  /** Message timestamp (ISO 8601) */
  timestamp: string;

  /** Trace ID associated with the assistant response */
  traceId?: string;

  /** Additional metadata */
  metadata?: Record<string, unknown>;
}

Behavior

Initial Load

On mount, the hook fetches the conversation list from backend.listConversations(). The list is sorted by updatedAt in descending order (most recent first).

Selecting a Conversation

Calling select(id) sets selectedId and fetches the conversation's messages from backend.getMessages(id). The messages are stored in the messages return value.

Sending a Message

Calling send(content) performs the following:

  1. Sets isSending to true.
  2. Calls backend.sendMessage(selectedId, { content, agentName, parameters }).
  3. Appends the user message and assistant response to messages.
  4. Refreshes the conversation list (to update updatedAt ordering).
  5. Sets isSending to false.

Creating a Conversation

Calling create() calls backend.createConversation({ agentName: defaultAgentName, parameters: defaultParameters }), adds the new conversation to the list, and selects it.

Deleting a Conversation

Calling remove(id) calls backend.deleteConversation(id) and removes it from the local list. If the deleted conversation was selected, selectedId is set to null and messages is cleared.

Cleanup

The hook cancels in-flight requests when the component unmounts.

Usage

Complete Custom Conversation UI

import {
  useConversations,
  createHttpConversationBackend,
} from "@modernpath/agent-ui-react";

const backend = createHttpConversationBackend({
  baseUrl: "/api",
  getHeaders: () => ({
    Authorization: `Bearer ${getToken()}`,
  }),
});

function CustomConversations() {
  const {
    conversations,
    selectedId,
    messages,
    isLoading,
    isSending,
    error,
    select,
    create,
    send,
    remove,
    refreshList,
  } = useConversations({
    backend,
    defaultAgentName: "qa-chat",
  });

  const [input, setInput] = React.useState("");

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      {/* Sidebar */}
      <div style={{ width: 280, borderRight: "1px solid #e0e0e0" }}>
        <button onClick={create}>New Conversation</button>
        <button onClick={refreshList}>Refresh</button>
        {conversations.map((conv) => (
          <div
            key={conv.id}
            onClick={() => select(conv.id)}
            style={{
              padding: 12,
              background: conv.id === selectedId ? "#e8f0fe" : "transparent",
              cursor: "pointer",
            }}
          >
            <div>{conv.title}</div>
            <small>{new Date(conv.updatedAt).toLocaleDateString()}</small>
            <button
              onClick={(e) => {
                e.stopPropagation();
                remove(conv.id);
              }}
            >
              Delete
            </button>
          </div>
        ))}
      </div>

      {/* Chat area */}
      <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
        <div style={{ flex: 1, overflow: "auto", padding: 16 }}>
          {messages.map((msg, i) => (
            <div key={i} style={{ marginBottom: 12 }}>
              <strong>{msg.role}:</strong>
              <p>{msg.content}</p>
              {msg.traceId && (
                <small>Trace: {msg.traceId}</small>
              )}
            </div>
          ))}
          {isSending && <div>Sending...</div>}
        </div>

        {selectedId && (
          <form
            onSubmit={(e) => {
              e.preventDefault();
              send(input);
              setInput("");
            }}
            style={{ padding: 16, borderTop: "1px solid #e0e0e0" }}
          >
            <input
              value={input}
              onChange={(e) => setInput(e.target.value)}
              disabled={isSending}
              placeholder="Type a message..."
              style={{ width: "80%" }}
            />
            <button type="submit" disabled={isSending || !input.trim()}>
              Send
            </button>
          </form>
        )}

        {error && <div style={{ color: "red", padding: 16 }}>{error.message}</div>}
      </div>
    </div>
  );
}

Minimal Usage with ConversationList

import {
  useConversations,
  ConversationList,
} from "@modernpath/agent-ui-react";

function ConversationSidebar() {
  const { conversations, selectedId, isLoading, select, create, remove } =
    useConversations({ backend });

  return (
    <ConversationList
      conversations={conversations}
      selectedId={selectedId}
      isLoading={isLoading}
      onSelect={select}
      onCreate={create}
      onDelete={remove}
    />
  );
}