> ## 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.

# useAgentChat Hook

> React hook for AI chat interfaces with Agents

## 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.

```typescript theme={null}
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

```bash theme={null}
npm install @cloudflare/ai-chat
```

## Options

<ParamField path="options" type="UseAgentChatOptions" required>
  <ParamField path="agent" type="string" required>
    Name of the chat agent class
  </ParamField>

  <ParamField path="name" type="string" default="default">
    Name of the specific Agent instance
  </ParamField>

  <ParamField path="initialMessages" type="Message[]">
    Initial message history
  </ParamField>

  <ParamField path="onFinish" type="(message: Message) => void">
    Called when a message is complete
  </ParamField>

  <ParamField path="onError" type="(error: Error) => void">
    Called when an error occurs
  </ParamField>
</ParamField>

## Return Value

<ResponseField name="messages" type="Message[]" required>
  Array of chat messages (user + assistant)
</ResponseField>

<ResponseField name="input" type="string" required>
  Current input value
</ResponseField>

<ResponseField name="handleInputChange" type="(e: ChangeEvent<HTMLInputElement>) => void" required>
  Handler for input changes
</ResponseField>

<ResponseField name="handleSubmit" type="(e: FormEvent) => Promise<void>" required>
  Handler for form submission
</ResponseField>

<ResponseField name="isLoading" type="boolean" required>
  Whether a response is being generated
</ResponseField>

<ResponseField name="append" type="(message: Message) => Promise<void>" required>
  Append a message to the chat
</ResponseField>

<ResponseField name="reload" type="() => Promise<void>" required>
  Reload the last assistant message
</ResponseField>

<ResponseField name="stop" type="() => void" required>
  Stop the current streaming response
</ResponseField>

<ResponseField name="setMessages" type="(messages: Message[]) => void" required>
  Set the entire message history
</ResponseField>

## Basic Usage

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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>
  );
}
```

## Related

* [useAgent Hook](/api/use-agent-hook) - Base Agent hook
* [@cloudflare/ai-chat](https://www.npmjs.com/package/@cloudflare/ai-chat) - AI chat package
