Tool picker

Choosing what an agent can use: tools grouped by app with a permission for each, a quick tools menu from the composer, and a permissions table for settings.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/tool-picker-grouped.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/tool-picker-grouped.json

Usage & API

Example

tool-picker-grouped.tsx
import { ToolPickerGrouped } from "@/components/ai/tool-picker-grouped"

<ToolPickerGrouped
  apps={[]}
  permissions={permissions}
  onPermissionChange={() => {}}
  onPermissionsChange={() => {}}
  onConnect={() => {}}
  query="…"
  onQueryChange={() => {}}
  expanded={[]}
  onExpandedChange={() => {}}
/>

Props ToolPickerGrouped

PropType & descriptionRequired
appsToolApp[]Required
permissionsRecord<string, ToolPermission>Required
onPermissionChange(toolId: string, value: ToolPermission) => voidRequired
onPermissionsChange(changes: Record<string, ToolPermission>) => voidRequired
onConnect(appId: string) => voidRequired
connectingstring | nullOptional
querystringRequired
onQueryChange(query: string) => voidRequired
expandedstring[]Required
onExpandedChange(ids: string[]) => voidRequired

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

By app starts with a Search tools field and a count of tools that are on, counting only connected apps whose permission is not Off. Each app row has an icon, the account or Connected, or Not connected, a chevron, and either an n of n tools count plus a group checkbox, or Connect. The checkbox is mixed when only some tools are on. Expanded, every tool shows its name, a description on wider screens, and a segmented control labelled with the tool name: Allow, Ask, Off. Arrow keys move that control. Disconnected apps still list their tools, but the segments stay disabled. Write tools are the ones marked writes. They are the ones that land on Ask when the group is switched on from empty.

Choosing a layout

Use the grouped picker while someone is setting up an agent and still deciding which apps to connect. The per-tool Allow, Ask and Off control is the right grain there, because a write such as merging a pull request should not inherit the same permission as a search. Use the permissions table later, on a settings page, when the tools already exist and the question is risk: what may run alone, what must stop for a person, and what must never run. The risk headings are part of the layout, so pass a risk on each tool.

Use the composer menu on the message box, for the duration of one chat, when the person is turning Web search or a single repo on without opening settings. Manage connectors closes the menu and calls onManage, which is where you would send them to the grouped picker or the permissions table. Do not use the composer menu as the only place write tools can be gated. It has a check or a switch, not Ask. Pair it with the permissions table if a tool can change data. Memory and MCP servers are separate screens. This picker does not store memories or edit a server command.

What is the difference between Ask and Never?

In the grouped picker, Ask means the tool is on but should check first, and Off means it is not available. In the permissions table the three choices are Always allow, Ask every time and Never. Never is the strong refusal. Off and Never are not stored as the same value. Each variant has its own union, and you map them when you save.

Does Connect sign the user into an app?

No. Connect calls onConnect with the app id and shows a spinner while you pass that id as connecting. The picker never opens a login window. When you set the app's connected flag and account, the row swaps the button for the Allow, Ask and Off controls.