Managing Messages
useChat returns a setMessages function — the standard React state setter for the messages array. Use it for any programmatic manipulation beyond what the streaming lifecycle provides.
Clearing the Conversation
Section titled “Clearing the Conversation”Reset the chat to an empty state:
const { messages, setMessages, sendMessage } = useChat({ api: "/chat" });
function handleNewChat() { setMessages([]);}<button onClick={handleNewChat}>New Chat</button>Deleting a Message
Section titled “Deleting a Message”Remove a specific message by filtering it out:
function handleDelete(messageId: string) { setMessages((prev) => prev.filter((msg) => msg.id !== messageId));}{messages.map((msg) => ( <div key={msg.id}> {msg.parts.map((part, i) => { switch (part.type) { case "text": return <span key={i}>{part.text}</span>; default: return null; } })} <button onClick={() => handleDelete(msg.id)}>Delete</button> </div>))}Editing a Message
Section titled “Editing a Message”Update the parts of a specific message:
function handleEdit(messageId: string, newText: string) { setMessages((prev) => prev.map((msg) => msg.id === messageId ? { ...msg, parts: [{ type: "text", text: newText }] } : msg, ), );}Prepending a System-Style Message
Section titled “Prepending a System-Style Message”Insert a message at the beginning of the conversation:
function addWelcomeMessage() { setMessages((prev) => [ { id: "welcome", role: "assistant", parts: [{ type: "text", text: "Hello! How can I help you today?" }], }, ...prev, ]);}Functional Updates
Section titled “Functional Updates”setMessages supports functional updates — the same pattern as React’s useState setter. Always use functional updates when the new state depends on the previous state:
// Good — uses previous statesetMessages((prev) => prev.filter((msg) => msg.role !== "assistant"));
// Bad — may use stale statesetMessages(messages.filter((msg) => msg.role !== "assistant"));Important Notes
Section titled “Important Notes”setMessagestriggers a re-render with the new messages array- Changes made via
setMessagesare not sent to the backend — it only modifies local state sendMessageis a no-op while a stream is in progress. If you need to clear messages and send a new one, callstop()first, thensetMessages([]), thensendMessage(text)on the next render- The
onMessageandonFinishcallbacks are not triggered bysetMessages— they only fire during the streaming lifecycle