Add Frontend Interaction to a Tool
Some Tools only need to run on the server and require no custom interface. Other Tools need the user to confirm, select, or edit arguments. In those cases, register a frontend card for the Tool with the same name.
A frontend card only handles ToolCall display and human interaction. It does not mean that the Tool's business logic must run in the browser.
If the card only displays options like suggestions and continues to the server-side invoke() after the user selects one, keep the default execution: 'backend'. Set execution: 'frontend' and implement a frontend invoke only when the Tool's actual logic must access the current browser page, FlowModel, or editor state.
Define arguments and execution logic on the server first
The built-in suggestions Tool is located at:
Its schema includes both the candidate options and the user's final selection:
According to the Tool description, the model should generate only options on the first call. Because this Tool does not set defaultPermission: 'ALLOW', its default permission is ASK, and the ToolCall pauses for user input.
After the user makes a selection, the frontend uses decisions.edit() to merge option into the original arguments and resume the ToolCall. The server-side invoke() then returns the selected content:
The built-in implementation also writes the selection back to aiMessages.toolCalls, so rerendered historical messages can still show which option the user selected.
Write the card component
A frontend card receives ToolsUIProperties:
This component demonstrates the general use of decisions.edit() and handles repeated clicks and JSON-string arguments. In production, you must also account for read-only conversations, the current active message, and historical selection state in the surrounding chat interface. See the complete implementation in packages/plugins/@nocobase/plugin-ai/src/client-v2/ai-employees/tools/SuggestionsOptionsCard.tsx.
decisions provides three operations:
The built-in SuggestionsOptionsCard.tsx also handles these details:
- Supports both array and JSON-string forms of
options - Displays a loading state while the ToolCall is still being generated
- Allows selection only for a ToolCall with the
interruptedstatus - Disables buttons immediately after a click to prevent duplicate submission
- Preserves and highlights the selected option in historical messages
- Allows actions only in the current editable conversation
Register it in the client plugin
The frontend registration name must exactly match the server-side Tool name:
If the server-side file is src/ai/tools/developerChoice.ts, register developerChoice here.
The built-in suggestions registration works the same way:
PluginAIClientV2.load() then calls registerPluginAIClientV2BuiltinTools(this.ai.toolsManager) to merge the card into the same-named Tool definition returned by the server.
Choose a card, modal, or frontend execution
Use a card
The following lists only the commonly used client-side ToolsOptions settings. See the complete type in packages/core/client-v2/src/ai/tools-manager/types.ts.
Use card first by default.
Use a modal
Add a modal only when the content is extensive or requires a large preview or complex argument editing.
Execute a Tool in the browser
If the server-side Tool sets execution: 'frontend', the client must also provide invoke. Such Tools are suitable for reading the current page context, editor content, or FlowEngine state. They are not suitable for data writes that require server-side permission enforcement.
Complete example: Add a selection card to a built-in AI employee
After completing Complete Example: Create a Built-in AI Employee, turn Dev Helper's follow-up question into clickable options by defining another Tool named developerChoice and registering a frontend card. Put the server-side file at:
This Tool declares the options and accepts the user's selection:
Because developerChoice.ts is in the welcome-developer Skill's tools/ directory, it is automatically bound to the current Skill. However, binding only means the model can use the Tool; it does not guarantee that the model will call it.
Also update the workflow in SKILLS.md, replacing the original steps 5–6 with:
Reuse the DeveloperChoiceCard defined above and save it to:
Finally, register it in src/client-v2/plugin.tsx:
After registering the card, rebuild the client. When a conversation reaches developerChoice, the ToolCall pauses and displays clickable options.
Related links
- Define a server-side Tool — Define the server-side Tool corresponding to a frontend card
- Complete example: Create a built-in AI employee — Complete the basic example without frontend code first
- Internationalization for AI employee plugins — Translate Tool and Skill management-interface text
- Client Plugin — Learn about the client plugin entry point and
load()

