Frontend Tools
Let your agent interact with and update your application's UI.
Open your coding agent in your project's folder, or in an empty folder for a new app.This runs in a coding agent on your computer.
See this in Inspector
Open Inspector on localhost. Go to Agents, then Frontend Tools. Your tool and its schema are listed.
More detail: Inspector.
What is this?#
Frontend tools let your agent define and invoke client-side functions that run entirely in the user's browser. Because the handler executes on the frontend, it has direct access to component state, browser APIs, and any third-party UI library the page already uses. That's how an agent can "reach into" the app: update React state, trigger animations, read localStorage, pop a toast, or steer the user's view.
This page covers the "agent drives the UI" shape of frontend tools. The same primitive also powers Generative UI and Human-in-the-loop; see those pages for interaction patterns.
When should I use this?#
Use frontend tools when your agent needs to:
- Read or modify React component state
- Access browser APIs like
localStorage,sessionStorage, or cookies - Trigger UI updates, animations, or transitions
- Show alerts, toasts, or notifications
- Interact with third-party frontend libraries
- Perform anything that requires the user's immediate browser context
How it works in code#
Register a frontend tool with useFrontendTool. Give it a name, a Zod schema for parameters, and a handler. The agent can then call it like any other tool and your frontend runs it in the browser.
a2a::frontend-tools. Known demos are bundled from manifest demos[i]; check the cell id and framework slug.The handler receives the parsed, type-safe parameters and can do anything the browser can: update state, call an API, touch the DOM. Its return value is sent back to the agent as the tool result so the model can reason about what happened.
a2a::frontend-tools. Known demos are bundled from manifest demos[i]; check the cell id and framework slug.Registering a list of tools#
useFrontendTool registers one tool per call, so it cannot be called in a loop
over a list whose length changes between renders. When the set of tools comes
from state, from props, or from a backend response, use
useFrontendTools instead. It takes an
array and runs a single effect over it, so the array can be empty on one render
and hold twenty entries on the next.
useFrontendTools(
reports.map((report) => ({
name: `open_${report.id}`,
description: `Open the ${report.title} report`,
handler: async () => navigate(`/reports/${report.id}`),
})),
[navigate],
);Tools that leave the array are unregistered, tools that join it are registered,
and a re-render that produces an equal list does not re-register anything. A
description built from your data stays current on its own. The second argument
is for values a handler closes over, such as navigate above.