The Tool Builder replaces a raw JSON textarea with a card UI for defining mid-call function-calling tools. It is 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:
FieldHelp keyPurpose
Start From PresetRe-seed the card from a preset
Tool NamenameInternal snake_case name (sanitized on input)
When should the bot use this tool?triggerTrigger description (the tool description)
Success / Failure / Timeout / Missing-info guidancesuccess/failure/timeout/missingNatural-language LLM guidance, not fixed scripts
Calls External APIhas_api toggle; off = intent-capture only
TimingtimingWhen the hold message plays vs. when the API runs
Hold Message IntentpreMessageShown only for timing policies that require it; English intent the LLM localizes
Method + URLGET/POST and the request URL (supports {{...}} tokens)
Headers / Query ParamsKey/value rows
Body Template (JSON)Shown only for POST
Timeout (seconds)Blur-defaults to 8
ParametersparametersConversation values the LLM extracts

Presets

A preset bar at the top adds a pre-filled tool. Presets come from TOOL_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:
PolicyTimeline
immediateAPI runs → Bot replies
speak_then_runBot speaks → API runs → Bot replies
speak_and_run_parallelBot 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 passes botVariables (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 renderToolPreview against a synthetic context (sample args, call, crm, and sip values), showing resolved variables, the final method/URL/headers/params/body, and any unsupported placeholders.

Create Bot Wizard

Where the Tool Builder sits in step 5.

Bot Detail & Integration

How saved tools appear in view mode.