Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt

Use this file to discover all available pages before exploring further.

Overview

useAgentChat is a specialized React hook for building AI chat interfaces with Agents. It’s part of the @cloudflare/ai-chat package and provides message history, streaming responses, and tool calling.
import { useAgentChat } from "@cloudflare/ai-chat/react";

function Chat() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } =
    useAgentChat({
      agent: "ChatAgent",
      name: "default"
    });

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          <strong>{m.role}:</strong> {m.content}
        </div>
      ))}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading}>
          Send
        </button>
      </form>
    </div>
  );
}

Installation

npm install @cloudflare/ai-chat

Options

options
UseAgentChatOptions
required
agent
string
required
Name of the chat agent class
name
string
default:"default"
Name of the specific Agent instance
initialMessages
Message[]
Initial message history
onFinish
(message: Message) => void
Called when a message is complete
onError
(error: Error) => void
Called when an error occurs

Return Value

messages
Message[]
required
Array of chat messages (user + assistant)
input
string
required
Current input value
handleInputChange
(e: ChangeEvent<HTMLInputElement>) => void
required
Handler for input changes
handleSubmit
(e: FormEvent) => Promise<void>
required
Handler for form submission
isLoading
boolean
required
Whether a response is being generated
append
(message: Message) => Promise<void>
required
Append a message to the chat
reload
() => Promise<void>
required
Reload the last assistant message
stop
() => void
required
Stop the current streaming response
setMessages
(messages: Message[]) => void
required
Set the entire message history

Basic Usage

import { useAgentChat } from "@cloudflare/ai-chat/react";

function ChatInterface() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } =
    useAgentChat({
      agent: "ChatAgent",
      name: "conversation-123"
    });

  return (
    <div className="chat">
      <div className="messages">
        {messages.map((message) => (
          <div key={message.id} className={message.role}>
            {message.content}
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Type a message..."
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? "Sending..." : "Send"}
        </button>
      </form>
    </div>
  );
}

Initial Messages

function ChatWithHistory() {
  const chat = useAgentChat({
    agent: "ChatAgent",
    name: "default",
    initialMessages: [
      {
        id: "1",
        role: "system",
        content: "You are a helpful assistant."
      },
      {
        id: "2",
        role: "user",
        content: "Hello!"
      },
      {
        id: "3",
        role: "assistant",
        content: "Hi! How can I help you today?"
      }
    ]
  });

  return <ChatUI {...chat} />;
}

Streaming Responses

function StreamingChat() {
  const { messages, isLoading, stop } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  const latestMessage = messages[messages.length - 1];
  const isStreaming = isLoading && latestMessage?.role === "assistant";

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          {m.content}
          {m.id === latestMessage?.id && isStreaming && (
            <span className="cursor">β–Š</span>
          )}
        </div>
      ))}
      {isStreaming && (
        <button onClick={stop}>Stop generating</button>
      )}
    </div>
  );
}

Programmatic Messages

function ChatWithActions() {
  const { messages, append } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  const handleQuickAction = async () => {
    await append({
      role: "user",
      content: "Tell me a joke"
    });
  };

  return (
    <div>
      <MessageList messages={messages} />
      <button onClick={handleQuickAction}>Quick Action: Tell a Joke</button>
    </div>
  );
}

Error Handling

function ResilientChat() {
  const [error, setError] = useState<string | null>(null);

  const chat = useAgentChat({
    agent: "ChatAgent",
    name: "default",
    onError: (err) => {
      console.error("Chat error:", err);
      setError(err.message);
    }
  });

  return (
    <div>
      {error && (
        <div className="error">
          {error}
          <button onClick={() => setError(null)}>Dismiss</button>
        </div>
      )}
      <ChatUI {...chat} />
    </div>
  );
}

Completion Callbacks

function ChatWithAnalytics() {
  const chat = useAgentChat({
    agent: "ChatAgent",
    name: "default",
    onFinish: (message) => {
      console.log("Message complete:", message);
      // Track analytics, save to database, etc.
      analytics.track("message_sent", {
        messageId: message.id,
        length: message.content.length
      });
    }
  });

  return <ChatUI {...chat} />;
}

Reload Last Message

function ChatWithReload() {
  const { messages, reload, isLoading } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  const lastMessage = messages[messages.length - 1];
  const canReload = lastMessage?.role === "assistant" && !isLoading;

  return (
    <div>
      <MessageList messages={messages} />
      {canReload && (
        <button onClick={reload}>Regenerate Response</button>
      )}
    </div>
  );
}

Clear Chat

function ChatWithClear() {
  const { messages, setMessages } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  const handleClear = () => {
    setMessages([]);
  };

  return (
    <div>
      <MessageList messages={messages} />
      <button onClick={handleClear}>Clear Chat</button>
    </div>
  );
}

Custom Message Rendering

function ChatWithRichMessages() {
  const { messages } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  return (
    <div>
      {messages.map((message) => (
        <div key={message.id} className={`message ${message.role}`}>
          {message.role === "assistant" && <Avatar src="/bot.png" />}
          {message.role === "user" && <Avatar src="/user.png" />}
          <div className="content">
            <ReactMarkdown>{message.content}</ReactMarkdown>
          </div>
          <div className="timestamp">
            {new Date(message.createdAt).toLocaleTimeString()}
          </div>
        </div>
      ))}
    </div>
  );
}

Best Practices

Extract to Custom Hook

function useChatInterface(conversationId: string) {
  return useAgentChat({
    agent: "ChatAgent",
    name: conversationId,
    onFinish: (message) => {
      // Save to database
      saveMessage(conversationId, message);
    },
    onError: (error) => {
      // Log errors
      console.error("Chat error:", error);
    }
  });
}

function Chat({ conversationId }: { conversationId: string }) {
  const chat = useChatInterface(conversationId);
  return <ChatUI {...chat} />;
}

Persist Messages

function PersistentChat() {
  const [initialMessages, setInitialMessages] = useState<Message[]>([]);

  useEffect(() => {
    // Load from localStorage
    const saved = localStorage.getItem("chat-messages");
    if (saved) {
      setInitialMessages(JSON.parse(saved));
    }
  }, []);

  const chat = useAgentChat({
    agent: "ChatAgent",
    name: "default",
    initialMessages,
    onFinish: (message) => {
      // Save to localStorage
      const messages = [...chat.messages, message];
      localStorage.setItem("chat-messages", JSON.stringify(messages));
    }
  });

  return <ChatUI {...chat} />;
}

Auto-scroll to Bottom

function AutoScrollChat() {
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const { messages } = useAgentChat({
    agent: "ChatAgent",
    name: "default"
  });

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages]);

  return (
    <div className="messages">
      {messages.map((m) => (
        <div key={m.id}>{m.content}</div>
      ))}
      <div ref={messagesEndRef} />
    </div>
  );
}

Build docs developers (and LLMs) love