What the backend must do
The library runs in the browser and ships no server code. The host brings its own backend. The backend’s part is small, because it is assistant-ui’s backend contract and nothing more.
Take system text and tools from the request
Section titled “Take system text and tools from the request”Every request carries the model context: system, the concatenated instructions and page note, and the tools, a JSON Schema for every lent tool. The backend passes system to the model and turns the schemas into tool definitions. That is two lines in a route handler or in an agent’s onChatMessage.
How the request gets there depends on the runtime. useChatRuntime’s transport adds system and tools to the body of every request by itself, and the route turns tools into definitions with frontendTools from @assistant-ui/ai-sdk. useAISDKRuntime over useAgentChat adds nothing, so the host wires two options of useAgentChat. A body function returns system. A tools object mirrors the runtime’s model context tools, and useAgentChat sends their schemas as clientTools with every user message and every tool result. The agent builds its tools from options.clientTools with Cloudflare’s createToolsFromClientSchemas. The library has no fields of its own on the wire.
createToolsFromClientSchemas does not unwrap assistant-ui’s model-content envelope as frontendTools does. A host tool that answers with model content, such as an image, reaches the model as JSON on this path. The library’s own tools answer with text and JSON only.
Let the browser run the tools
Section titled “Let the browser run the tools”The tools carry no server execute. The model calls one, the call streams to the browser, assistant-ui runs it, and the result goes back. The backend’s job is to continue the turn when the result arrives.
- On an AI SDK route, the client sends the result as a new request, with
sendAutomaticallyWhen. - On Cloudflare Agents,
useAgentChatsends the result over the socket and the agent continues by itself. The host leavessendAutomaticallyWhenout, or the turn would be requested twice.
The library’s tools never fail as errors. A failure is an answer like { error: "…" }, because an error result ends the turn on useAgentChat with no reply.
Nothing for confirmations
Section titled “Nothing for confirmations”A confirm card pauses the tool call in the browser through assistant-ui’s human(). The backend sees a tool call whose result comes late. It needs no approval endpoint and no state for the pause.
Threads are the runtime’s
Section titled “Threads are the runtime’s”The library keeps no threads. If users need several, the runtime needs a thread list adapter, and its backend keeps the list. The example keeps it in a ThreadHub agent on the Worker. The panel shows a picker only when the host says the runtime has a list.
What a continuation carries on Cloudflare Agents
Section titled “What a continuation carries on Cloudflare Agents”A continuation after a tool result reuses the body of the user’s last message, so its system text is as of that message. The tools are not in the body: each tool result carries them as they are when it is sent. When a tool changes the page mid-turn, through go_to_page or an action that opens a dialog, the model can use the new page’s tools on its very next step.
The page section of the system text still names the old page until the user writes again. The tool that changed the page answers with the new page’s note, and the universal instructions tell the model that a note in a tool result is newer than the page section. So the model knows where it is and can act there in the same turn.
An AI SDK route needs none of this: each continuation is a new request, built from the model context at that moment.