DeltaKitDeltaKit
Agno Agents

Manage Messages

Recipe for implementing clear, delete, edit, resend, and insert operations on chat messages with Agno agents.

This recipe shows how to implement common message management operations using the setMessages API when using Agno agents on the backend. You'll build UI controls for clearing conversations, deleting messages, editing content, and resending failed messages.

Clearing the Conversation

const { setMessages } = useStreamChat({ api: "/api/chat-agno" });

function handleClear() {
  setMessages([]);
}

If your Agno backend tracks conversation state, clear it too:

async function handleClear() {
  await fetch("/api/chat-agno/clear", { method: "POST" });
  setMessages([]);
}

Backend Clear Endpoint (FastAPI + Agno)

from fastapi import APIRouter
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openrouter import OpenRouter

router = APIRouter()

SESSION_ID = "default-agno"

storage = SqliteDb(
    session_table="agno_agent_sessions",
    db_file="./dev.db",
)

@router.post("/api/chat-agno/clear")
async def clear_history():
    agent = Agent(
        model=OpenRouter(id="moonshotai/kimi-k2.5"),
        db=storage,
        session_id=SESSION_ID,
    )
    agent.db.delete_session(session_id=SESSION_ID)
    return {"status": "cleared"}

Removing a Message

Remove a specific message by ID:

function handleDelete(messageId: string) {
  setMessages((prev) => prev.filter((msg) => msg.id !== messageId));
}

Remove the last message:

function handleRemoveLast() {
  setMessages((prev) => prev.slice(0, -1));
}

Editing a Message

Replace a message's content:

function handleEdit(messageId: string, newText: string) {
  setMessages((prev) =>
    prev.map((msg) =>
      msg.id === messageId
        ? { ...msg, parts: [{ type: "text", text: newText }] }
        : msg,
    ),
  );
}

Resending a Message

A common pattern is editing the last user message and re-triggering the response. Remove the last assistant message, then send again:

const { messages, setMessages, sendMessage } = useStreamChat({
  api: "/api/chat-agno",
});

function handleResend() {
  const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
  if (!lastUserMsg) return;

  const lastUserText = lastUserMsg.parts
    .filter((p) => p.type === "text")
    .map((p) => p.text)
    .join("");

  // Remove the last assistant response (and optionally the user message)
  setMessages((prev) => {
    const idx = prev.findLastIndex((m) => m.role === "user");
    return prev.slice(0, idx);
  });

  // Re-send (triggers a new stream)
  sendMessage(lastUserText);
}

Inserting a System-Style Message

You can programmatically insert messages without triggering a stream:

function addNotice(text: string) {
  setMessages((prev) => [
    ...prev,
    {
      id: `notice_${Date.now()}`,
      role: "assistant" as const,
      parts: [{ type: "text" as const, text }],
    },
  ]);
}

// Usage
addNotice("The model has been switched to GPT-4.");

Functional Updates

setMessages supports functional updates just like React's useState. Always use the functional form when your update depends on the current state:

// Correct - uses the latest state
setMessages((prev) => prev.filter((msg) => msg.id !== id));

// Avoid - may use stale state
setMessages(messages.filter((msg) => msg.id !== id));

On this page