defineBotTool
Define a typed BotTool — a frontend tool the agent can call whose handler runs in the bot with a Thread in scope.
Overview
defineBotTool defines a BotTool with full type inference: the handler's args are inferred from the parameters schema. A BotTool is forwarded to the agent as a frontend tool; when the agent calls it, the handler runs in the bot, with the conversation's Thread in scope — so a tool can read the thread, post JSX cards, or block on a human choice.
Signature
import { defineBotTool } from "@copilotkit/bot";
function defineBotTool<Schema extends ObjectSchema>(
tool: BotTool<Schema>,
): BotTool<Schema>;Parameters
Prop
Type
BotToolContext
The single shared context every handler receives — there are no per-adapter generics:
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Usage
A data tool
import { defineBotTool } from "@copilotkit/bot";
import { z } from "zod";
const readThread = defineBotTool({
name: "read_thread",
description: "Read the messages in the current conversation.",
parameters: z.object({}),
async handler(_args, { thread }) {
return await thread.getMessages();
},
});A render tool (posts JSX)
A common pattern: the component's prop schema doubles as the tool's input schema, and the agent "renders" by calling the tool.
const issueCard = defineBotTool({
name: "issue_card",
description: "Render one issue as a rich card.",
parameters: issueCardSchema,
async handler(props, { thread }) {
await thread.post(<IssueCard {...props} />);
return "Displayed the issue card to the user.";
},
});A blocking human-in-the-loop tool
const confirmWrite = defineBotTool({
name: "confirm_write",
description: "Ask the user to approve a write before performing it.",
parameters: z.object({ action: z.string() }),
async handler({ action }, { thread }) {
const choice = await thread.awaitChoice<{ confirmed: boolean }>(
<ConfirmWrite action={action} />,
);
return choice ?? { confirmed: false }; // serialized for the agent automatically
},
});Behavior
- Validation — args coming back from the model are validated against
parameters; invalid args don't reach your handler. - Registration — pass tools via
createBot({ tools })orbot.tool(t); per-run extras go throughthread.runAgent({ tools }). Tools must be registered beforestart(). - Portability — handlers receive the same
BotToolContexton every platform; a tool written againstthreadmethods runs unchanged on any adapter that supports them.
Related
- Thread — the handle in
ctx.thread - createBot — registering tools
- defineBotCommand — the command analog