src/components/bot/ToolBuilder.tsx, rendered inside the Custom Tools section of StepToolsIntegrations.tsx.
Where It Lives
StepToolsIntegrations passes the current form.custom_tools, an onChange that writes back to the form, the custom_tools validation error, and a botVariables list derived from the bot’s prompts/opening message via deriveBotToolVariables (in toolDraftUtils.ts).
Tool Card Anatomy
Each tool is a collapsible card. Expanded, it exposes these fields:| Field | Help key | Purpose |
|---|---|---|
| Start From Preset | — | Re-seed the card from a preset |
| Tool Name | name | Internal snake_case name (sanitized on input) |
| When should the bot use this tool? | trigger | Trigger description (the tool description) |
| Success / Failure / Timeout / Missing-info guidance | success/failure/timeout/missing | Natural-language LLM guidance, not fixed scripts |
| Calls External API | — | has_api toggle; off = intent-capture only |
| Timing | timing | When the hold message plays vs. when the API runs |
| Hold Message Intent | preMessage | Shown only for timing policies that require it; English intent the LLM localizes |
| Method + URL | — | GET/POST and the request URL (supports {{...}} tokens) |
| Headers / Query Params | — | Key/value rows |
| Body Template (JSON) | — | Shown only for POST |
| Timeout (seconds) | — | Blur-defaults to 8 |
| Parameters | parameters | Conversation values the LLM extracts |
Presets
A preset bar at the top adds a pre-filled tool. Presets come fromTOOL_PRESET_OPTIONS in toolDraftUtils.ts (the blank option is filtered out of the bar). Inside a card, the “Start From Preset” select can re-seed an existing tool via createToolFromPreset, or reset it with createEmptyTool.
Timing Policies
TIMING_POLICY_OPTIONS drives the timing select. The builder renders a small timeline of steps for the chosen policy:
| Policy | Timeline |
|---|---|
immediate | API runs → Bot replies |
speak_then_run | Bot speaks → API runs → Bot replies |
speak_and_run_parallel | Bot speaks → API runs → Bot replies |
| (run-then-end) | Bot speaks → API runs → Call ends |
requiresPreMessage(policy) decides whether the Hold Message Intent field appears.
Hold Message Intent is plain-English intent, not a verbatim script. The bot translates it into the customer’s language at runtime. The help text explicitly warns against writing the literal sentence.
Variables & Token Insertion
When a tool has an API, a Variables panel shows insertable tokens. If the parent passesbotVariables (derived from prompts), those are the simple chips; otherwise the builder falls back to TOOL_VARIABLES split into simple and advanced (“Technical names”) groups. Each chip has URL and Body buttons that call insertToken, appending the token (e.g. {{args.customer_id}}, {{call.session_id}}, {{crm.due_amount}}) into the URL or body template.
Parameter Auto-Detect
When the URL, body, headers, or query params change,updateTool re-runs autoDetectParameters to keep the parameter list in sync with {{args.<name>}} placeholders. If a user hand-edits a parameter, it is marked auto_managed: false so it survives later auto-detect pruning even when its placeholder disappears.
Validation & Preview
getToolValidationIssues([tool])surfaces per-tool problems inline when the tool has an API.- The Preview Request button renders the resolved request via
renderToolPreviewagainst a synthetic context (sampleargs,call,crm, andsipvalues), showing resolved variables, the final method/URL/headers/params/body, and any unsupported placeholders.
Related Docs
Create Bot Wizard
Where the Tool Builder sits in step 5.
Bot Detail & Integration
How saved tools appear in view mode.