Skip to Content
    QAFKA
    CTRL K
    CTRL K
    • Introduction
      • Quick Start
      • Configuration
      • React Native Widget
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Invitations
      • Settings
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Configuration
        • Members
        • Documents
        • Tools
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • API Keys
      • API Key Security
    • Introduction
      • Quick Start
      • Configuration
      • React Native Widget
      • Theming
      • Context
      • Navigation
      • External Navigation
      • Handling Tools
      • Voice Chat
      • Sub-Projects
      • Error Handling
      • CLI
      • Dashboard
      • Invitations
      • Settings
        • Project
        • Overview
        • Conversations
        • Chat Test
        • Sub-Projects
        • Analysis
        • Configuration
        • Members
        • Documents
        • Tools
        • Action Logs
        • Navigation Rules
        • External Destinations
        • Chat Theme
        • API Keys
      • API Key Security

    On This Page

    • Creating a Tool
    • Identity & Matching
    • Description vs When-to-use
    • Parameters
    • Template Variables
    • Endpoint (Optional)
    • Execution Mode
    • Multi-Step Flows
    • File Input & Document Extraction
    • Backend Actions
    • Email
    • Webhook
    • URL & Method
    • Custom Headers
    • Auto-Set Qafka Headers
    • Payload
    • File Delivery Format
    • User Info
    • HMAC Signing Secret (optional)
    • Action Condition
    • Conditional Actions
    • Multi-Target Email Routing
    • UI Rendering
    • Common settings
    • Item renderer — pick one
    • Card mode
    • Tracking ID Format
    • Examples
    • Where it shows up
    • Uniqueness
    • Risk & Confirmation
    • Custom Data
    • Loading Message
    • Enabled
    Question? Give us feedback Edit this page 
    DashboardInside a ProjectTools

    Tools

    The Tools section of the project is where you define what the AI can do — fetch data, fire backend actions, ask the user to upload a file, render a card. Each tool you create here becomes available to the AI for matching against user messages.

    This page is a field-by-field reference for the tool builder form. For the runtime side — how your mobile app handles a tool the AI invoked — see the Handling Tools guide.

    Creating a Tool

    1. Open Project → Tools
    2. Click New Tool
    3. Fill in at minimum: Name, Description, Execution mode
    4. Save — the tool is enabled by default and immediately eligible for AI matching

    The form is grouped into the sections below. Every field maps directly to runtime behavior described in the Handling Tools guide.

    Identity & Matching

    Form fieldWhat it does
    NameUnique key per project. The AI emits this back to the SDK to identify which tool was invoked.
    DescriptionThe full behavioral specification of the tool — read by the chat LLM after the tool has been selected. Include what the tool does, multi-stage flows, parameter rules, response phrasing, anything the AI needs to use the tool correctly. Up to 2000 characters. The single most important field — vague descriptions cause both false matches and incorrect execution.
    When to useOptional short intent hint (max 500 chars) read only by the selector (the lightweight LLM that decides which tool to invoke). Use it when the full Description is long and you want a concise signal for tool routing. Leave empty if Description’s first lines already make intent clear. The chat LLM never sees this field.
    CategoryGrouping label — purely organizational, not seen by the AI.
    TagsFree-form tags the AI sees alongside the description. Useful for adding extra matching signals.
    Usage examplesExample user phrasings that should fire this tool. Treated as positive training signals at matching time.

    Description vs When-to-use

    Tool invocation runs in two LLM phases, and the two fields target different phases:

    PhaseWhat runsReads description?Reads whenToUse?
    SelectorA small, fast LLM picks which tool (if any) fits the user’s message.First line only (fallback)Full text (preferred when set)
    ChatThe main LLM runs the selected tool — extracts parameters, follows your protocol, writes the user-facing reply.Full textNot used

    Practical guidance:

    • Always fill Description thoroughly. This is what governs how the tool actually behaves at runtime — multi-stage approval flows, “ask for missing detail before confirming” rules, response wording, etc.
    • Fill When to use only when the Description is too long for the selector to skim quickly. Two-three short bullet-style lines of “fire when…” / “skip when…” are ideal. Adding whenToUse does not change chat-phase behavior — it only sharpens the selector.
    • A common mistake is treating whenToUse as additive context for the main chat LLM. It isn’t. If the chat LLM needs to know something, it goes in Description.

    Parameters

    In the Parameters section, declare each input the AI should extract for this tool. For every parameter:

    Form fieldWhat it does
    NameThe key the AI emits back when calling the tool (e.g. productId). Used as-is in the SDK’s onToolSuggested callback under tool.params.
    Typestring, number, or boolean.
    RequiredIf on, and the AI can’t extract a value, the AI will ask the user a follow-up question to get it.
    DescriptionTells the AI what to extract or generate. The single most important field after Name — be specific.
    Default valueUsed when the AI doesn’t extract a value. A required parameter skips the follow-up prompt if it has a default. Supports template variables — see Template Variables below.
    LabelHuman-readable display name shown in the dashboard and used by email actions. Falls back to Name when empty.

    The AI pulls parameters from two places: the user’s message and whatever the SDK passes in its runtime context object. There’s no per-parameter “pull this key from context” wiring — if a value lives in context with a clear name, the AI will pick it up automatically.

    Template Variables

    Some parameters need values the AI shouldn’t generate — random tracking numbers, IDs, timestamps, fields pulled from the SDK’s userContext. Writing rules like “generate a random 10-digit number” in the description doesn’t work well: LLMs have heavy sample bias when asked for random values (you’ll see the same digit prefixes recurring). For these cases, write a template variable in the parameter’s Default value field — the server resolves it at runtime, then injects the resolved value into the AI’s prompt with a “use exactly this value” instruction.

    Syntax: {{namespace.key}} (mustache style — distinct from the single-brace {paramName} substitution used in endpoint URLs).

    TokenResolves to
    {{system.uuid}}UUID v4 (e.g. 9f3e2c1b-...)
    {{system.id10}}10-character URL-safe nanoid (e.g. k7d2N9mPxQ)
    {{system.digits10}}10 random digits (e.g. 4829105736)
    {{system.trackingDefault}}Default tracking ID format TRK-<base36 epoch>-<4 hex> (e.g. TRK-LM3K8F2A-9C2F) — time-prefixed, CX-friendly, used as the fallback when Tracking ID Format is left empty.
    {{system.timestamp}}ISO 8601 timestamp
    {{system.ymd}}Date in YYYY-MM-DD format
    {{user.<key>}}Any field from the SDK’s runtime userContext (e.g. {{user.firstName}}, {{user.userId}})
    {{tool.trackingId}}The tool’s resolved tracking ID for this invocation — see Tracking ID Format. The same value is reused everywhere it’s referenced (description, email subject prefix, webhook URL, headers, body) so a single complaint carries one ID end-to-end.

    Example: A complaint-tracking tool needs a stable reference number that’s unique per case and shown to the user in the chat reply. Set the parameter:

    Name: trackingNo Type: string Default value: {{system.digits10}}

    At runtime the server generates 4829105736, tells the AI “trackingNo is set to 4829105736 — use this exact value”, and the AI emits the same value in params.trackingNo plus naturally references it in the user-facing reply (“Your tracking number is 4829105736”). The same value is reused across all turns of the conversation (memoized per session) so the user never sees it change.

    Use sites: Template variables work in any string field admins write — currently the parameter Default value, the email action’s Subject prefix, and the endpoint URL. More fields (webhook bodies, headers, deep links, loading messages) gain support as the system rolls out.

    What to know:

    • Recursion is disabled — values produced by token resolution aren’t re-scanned for tokens. Users can’t smuggle template syntax through their chat messages.
    • {{user.*}} only reads keys the SDK already passed in userContext — no extra DB lookups, so adding a template token never widens the data the server can see.
    • If the AI emits a different value than the server-generated one, the server silently overrides with its own value (and logs a warning so prompt drift can be detected).

    Endpoint (Optional)

    If the tool maps to a backend HTTP call, switch on Endpoint and fill in:

    Form fieldWhat it does
    MethodGET, POST, PUT, DELETE, or PATCH.
    URLThe endpoint URL. Parameter names in {curly} braces get substituted from the extracted parameters (e.g. https://api.example.com/products/{productId}).
    Body templateFor POST/PUT, the JSON shape to send. Same {paramName} substitution rules apply.
    Required contextA list of keys that must exist in the SDK’s runtime context for this tool to be eligible. Acts as a gate — if any required key is missing, the AI never sees the tool that turn. Useful for tools that only make sense on certain screens (e.g. require productId so the tool only fires on a product detail page).

    Execution Mode

    The biggest behavioral choice — pick the mode based on where the tool actually runs and who writes the final reply.

    ModeWho runs the toolWho writes the final replyUse when
    Custom (default)The mobile app, in onToolSuggestedThe mobile app, via addResponse(data, tool)The tool result is purely a UI render — show a card, open a modal, navigate. AI doesn’t need to know what came back.
    ServerQafka backendAI, in a follow-up turnTool needs a real backend (DB, third-party API) and the AI should weave the result into prose. The SDK shows a one-line bridge (“On it…”) while the backend works.
    Custom with AIThe mobile app, in onToolSuggestedAI, in a follow-up turnData lives only on the client (e.g. local DB, user-entered form) but you want the AI to summarize it into a natural reply. SDK posts your result back to the backend for a second LLM turn.

    The chosen mode is injected into the system prompt so the AI knows whether to write a final reply itself or just a bridge sentence.

    Multi-Step Flows

    Some tools collect data over several turns (e.g. “book an appointment” needs date, then service, then user confirmation). In the Steps section, add a row per milestone:

    Form fieldWhat it does
    KeyStep identifier (e.g. date_selected, service_selected, complete).
    DescriptionWhat this step represents. The AI uses it to decide when to emit the step.
    Required fieldsParameter names that must be collected for this step to fire. The step triggers as soon as the AI has all of them.
    ActionsOptional side-effects to run when this step completes — same action types as below (email / webhook). Useful for “send a confirmation email when complete fires”.

    Step completion is reported to the SDK via the onStepCompleted callback.

    File Input & Document Extraction

    If the tool needs a file from the user (receipt photo, PDF invoice, etc.), switch on File Input and fill in:

    Form fieldWhat it does
    Accepted MIME typesWhich file types are allowed (e.g. image/jpeg, image/png, application/pdf).
    Max sizeUpper bound in bytes.
    SourcesWhich pickers the SDK should offer — any combination of camera, gallery, file.
    Webhook delivery formatDefault file delivery format for webhook actions: url (signed URL), base64 (inlined), or formdata (multipart). The webhook action’s own File Delivery Format setting overrides this; this field is the project-wide fallback.

    To run AI extraction on the uploaded file, also switch on Document Extractor and add:

    Form fieldWhat it does
    PromptFree-form instruction to the extraction LLM (e.g. “Extract invoice fields from this document”).
    FieldsThe structured fields you want pulled out — name, type (string / number / boolean), and whether each is required.

    After upload, the backend runs the extraction LLM and emits structured data via the SDK’s onExtractionResult callback.

    Backend Actions

    In the Actions section, add side-effects that fire when the tool completes (or when a specific step completes — see Multi-Step Flows). Two action types:

    Email

    Form fieldWhat it does
    TargetsOne or more email + condition rows. Single target with no condition behaves like the simple “send to one address” case. Add multiple targets to route the same email to different inboxes based on per-target conditions — see Conditional Actions below.
    Subject prefixPrefix added to the auto-generated subject line.
    Include conversationAppend the chat transcript to the email body.
    Attach fileIf the tool collected a file, attach it.
    User context keys to includeExplicit allow-list of keys from the SDK’s runtime context to render as a “User Info” section. Anything not on this list never leaves the system — KVKK / GDPR boundary. Default: empty (nothing forwarded).
    LabelsOptional human-readable display labels for those keys (e.g. firstName → "Name").
    Action conditionOptional natural-language condition. When set, the AI decides whether the entire action should fire. See Conditional Actions.

    When the tool has a Tracking ID Format set (or the legacy params.no parameter), the email body’s details block auto-renders a tracking-number row with the resolved value at the top — no admin config required. To surface it in the inbox listing as well, include {{tool.trackingId}} in the Subject prefix.

    Webhook

    Webhook actions POST a JSON (or multipart) payload to a partner endpoint — typically a CRM, ticketing system, or workflow automation. Every webhook delivery is recorded in Action Logs with a full request/response snapshot so you can audit, debug, and reproduce locally.

    URL & Method

    Form fieldWhat it does
    URLEndpoint to call. Supports template tokens — {{tool.trackingId}}, {{user.userId}}, etc. — resolved at runtime. So https://crm.example.com/cases/{{tool.trackingId}} becomes https://crm.example.com/cases/SHK-8984690258 for that specific complaint.
    MethodPOST or PUT.

    Custom Headers

    Add arbitrary headers as key/value pairs. Three common uses:

    • Authentication — Authorization: Bearer xxx, X-API-Key: sk_live_.... Required for almost every real CRM.
    • Routing metadata — X-Source: qafka, X-Environment: production. Helps the receiver classify or filter incoming requests.
    • Tokenized values — header values support the same template tokens as the URL. Writing X-CRM-Reference: {{tool.trackingId}} puts the per-invocation tracking ID in a header so the receiver can route or de-duplicate without parsing the body.

    Custom headers always win over the auto-set Qafka headers below — useful when you need to override User-Agent or replace the auto-attached metadata.

    Auto-Set Qafka Headers

    Every webhook request also carries these headers without admin config — receivers can rely on them for identification, idempotency, and signature verification:

    HeaderValuePurpose
    User-AgentQafka-Webhook/1.0Standard identification in the receiver’s access log.
    X-Qafka-ToolThe tool’s nameLets the receiver branch by tool without parsing the body.
    X-Qafka-Tracking-IdThe tool’s tracking ID for this invocationMirrors the body’s trackingId field — useful for routing layers (load balancers, edge functions) that don’t read the body.
    X-Qafka-Delivery-IdA fresh UUID per requestIdempotency key. If your receiver retries downstream work, key it on this value to avoid duplicating cases when Qafka itself retries.
    X-Qafka-TimestampUnix secondsReplay-window check. Reject requests older than your tolerance.
    X-Qafka-Session-IdThe chat session IDCorrelate multiple invocations from the same user session.
    X-Qafka-Signaturesha256=<hex>Only sent when an HMAC secret is configured — see below.

    Payload

    Form fieldWhat it does
    Include extraction dataSends the AI-extracted fields under the extraction key (e.g. { category, brief_summary, severity }). On by default.
    Include uploaded fileSends the file the tool collected. Effect depends on the File Delivery Format below. No-op when the tool has no file input or no file was uploaded.
    Include conversation historySends the full chat transcript under conversation. Useful for support tools where the receiver needs to read what the user said; verbose otherwise.

    The payload always includes a top-level trackingId field when the tool has a tracking ID set, regardless of these toggles. Receivers should rely on it for case correlation rather than parsing extraction.no (the legacy field).

    File Delivery Format

    When Include uploaded file is on, this dropdown picks how the file is sent:

    FormatWhat goes on the wireWhen to use
    url (default)JSON body with file: { url, fileName, mimeType, size }. The url is a signed GCS URL the receiver downloads from.Smallest payload; the receiver fetches the file asynchronously. Recommended for most CRMs.
    base64JSON body with file: { data: "<base64>", fileName, mimeType, size }. The whole file is inlined.Self-contained — no second HTTP round-trip. Cost: ~33% size overhead and no streaming. Use only for small files or receivers that can’t make outbound calls.
    formdatamultipart/form-data body. The file is a binary part; extraction, userContext, conversation, and trackingId ship as JSON-string parts.Legacy receivers (PHP, classic web frameworks) that expect form upload semantics.

    User Info

    Form fieldWhat it does
    User context keysAllow-list of keys from the SDK’s runtime userContext to include in the webhook payload as a userContext object (e.g. { userId: "1825", currentShoppingMallName: "..." }). Empty by default — without this, the receiver knows what was complained about but not who complained. Same KVKK / GDPR boundary as the email action.

    Unlike the email action, webhook user context uses the raw key names (no localized labels) — receivers code against stable identifiers.

    HMAC Signing Secret (optional)

    When set, the runtime computes sha256(secret, payload) and sends the result in the X-Qafka-Signature header. The receiver verifies with the same secret to detect tampering and replay attacks. Recommended for any public-facing webhook; optional for internal CRMs.

    The signed bytes are the JSON body for JSON-mode requests; for multipart requests the runtime signs a canonical formdata:<deliveryId>:<json-of-fields> string the receiver can recreate from the parsed parts. Implementation example for receivers:

    const expected = 'sha256=' + createHmac('sha256', SHARED_SECRET) .update(rawRequestBody) .digest('hex'); if (req.headers['x-qafka-signature'] !== expected) { return res.status(401).end(); }

    Rotate the secret periodically and prefer per-target secrets over a global one if the same Qafka project sends webhooks to multiple receivers.

    Action Condition

    Optional natural-language condition. AI decides whether to trigger this webhook based on the request context. See Conditional Actions.


    Action results — success / failure / message — are delivered to the SDK via onActionResult. The full request and response snapshots (including masked auth headers, response status, response body) are captured in Action Logs for forensic auditing.

    Conditional Actions

    Both action types support an Action condition — free-form natural-language text the AI evaluates against the tool’s parameters, the SDK’s userContext, and the conversation. If the condition isn’t met, the action is skipped and an entry is written to Action Logs with the AI’s reasoning. Examples:

    • "Only for complaint messages" — fire only when the AI judges the user is complaining
    • "currentRegion = Europe" — deterministic field-equality form (admin friendly)
    • "For users on the premium plan" — fuzzy semantic condition the AI resolves from userContext

    The same evaluation happens in the same LLM call that produces the tool parameters — no extra round-trip, no extra latency. When no actions on a tool have conditions (and email actions are single-target), the condition decision payload is omitted from the prompt entirely, so cost is zero for tools that don’t use the feature.

    Multi-Target Email Routing

    A common case for email actions: route a single tool to different inboxes based on tenant or context. Add multiple Targets with per-target conditions; AI picks the matching ones at runtime. Single tool, single action, N inboxes.

    Example — one support tool routing to different teams:

    Target emailTarget condition
    billing@example.com”User is asking about billing or invoices”
    tech@example.com”User is reporting a technical issue”
    sales@example.com”User is asking about pricing or upgrading”
    … (more)…

    Targets are evaluated independently — write mutually-exclusive conditions for routing-style cases (one inbox), inclusive conditions for fan-out cases (notify multiple teams). When the AI cannot match any target on a multi-target email, the action is skipped (no broadcast) and the skip is logged. This is intentional KVKK behavior — empty conditions cannot leak data to all recipients by accident.

    Per-target conditions also work with a single target: the AI decides whether that one address gets the email, equivalent to setting an action-level condition. Use whichever placement is more readable for the admin.

    UI Rendering

    The Response Configuration section tells the chat widget how to render the tool’s response. The outer settings (response type, data path, max items, layout, position) apply to BOTH renderer modes; the only choice is which renderer draws each item.

    Common settings

    Form fieldWhat it does
    Response typelist, detail, card, table, or summary — controls iteration. list plus an array payload renders one card per item.
    Data pathDot-path into the response payload to find the actual items (e.g. data.stores). Leave empty when the array is at the root.
    Max itemsCap for list mode — extra items render as a “…and N more” footer.
    Layoutvertical (stack) or horizontal (scrollable row).
    Positionbefore (above the assistant message) or after (below).

    Item renderer — pick one

    ModeWhen to use
    Component (rendered in app)Your React Native app already has a polished component (StoreCard, ProductRow, …). Set “Item component” to its registry key and the SDK looks it up at render time. See Customizing Components for the SDK-side wiring, or run qafka sync to auto-generate a stub file with the right data shape, doc comment, and <Qafka components> registration.
    Card (designed here)No app code needed. Visually compose a layout from the primitive whitelist (QView, QText, QImage, QIcon, QDivider, QButton) using the JSON editor. AI generate + Modify + iPhone-frame live preview keep the loop fast.

    Card mode

    ⚠️ Requires @qafka/react-native v1.1.0 or newer. Older SDK versions don’t know how to render a card and will silently fall through to the default renderer (plain text or basic list). Make sure your mobile app ships at least v1.1.0 before flipping a tool to Card mode in production.

    Selecting Card opens an inline editor inside the section:

    • Slug + Label — internal identifier and human-readable name. Slug is unique per tool.
    • Card definition (JSON) — the schema is { schemaVersion: 1, root: <node> }. Each node has component plus its props at the same level (no props: {…} wrapping). Use fieldName to bind text/image leaves to fields in your tool result. Conditionally show ornaments with showIf.
    • Sample data — paste a real example of what your tool returns. The preview binds against this; when you save the tool, the sample data persists alongside the card definition so the editor re-hydrates next session and the AI generate flow has a real shape to design around.
    • Live preview — wrapped in an iPhone 16 Pro chrome so you see the card in roughly the same proportions partners will. Buttons inside the preview are inert; click handlers fire only inside the SDK.
    • AI designer — Generate produces 2 variants (Compact + Detailed) from the tool description and sample data; Modify applies a natural-language change to the current JSON; ↶ Undo walks back through the last 10 AI edits.

    Card buttons can fire one of seven CTA types: external_navigation, deep_link, suggest_message, copy, dismiss, share, tool_trigger. The SDK handles copy, dismiss, share, suggest_message, and external_navigation internally with sensible defaults. deep_link and tool_trigger cross the SDK boundary — the partner app registers a callback (see Card CTAs on the SDK side).

    Tracking ID Format

    The Tracking ID Format field (in the right sidebar, under Settings) generates a unique identifier per tool invocation. The same ID is shared across every action of that invocation — email subject, body, webhook payload, webhook headers, the AI’s user-facing reply, and the action log row — so one user-visible reference number traces a single transaction end-to-end.

    Set it once on the tool. Reference it anywhere admin-authored strings live via the {{tool.trackingId}} token.

    BehaviorWhat happens
    EmptyRuntime auto-generates TRK-<base36 epoch>-<4 hex> per invocation (~13 chars, time-prefixed, CX-friendly). Use this when you don’t care about the format.
    Custom formatWhatever template string you write is resolved per invocation. Must contain at least one dynamic token ({{system.*}} / {{user.*}}); a static string would produce the same ID for every complaint. The validator rejects format strings without tokens at save time.
    Legacy params.noTools that shipped before this field existed and used parameters[name="no"] with a templated defaultValue keep working — the runtime promotes that value to the tracking ID when the format field is empty. New tools should use the format field directly and skip the no parameter.

    Examples

    FormatExample outputUse case
    (empty)TRK-LM3K8F2A-9C2FDefault — anything tracking-shaped
    SHK-{{system.digits10}}SHK-8984690258Customer-facing complaint number, easy to read aloud
    RES-{{system.id10}}RES-K7vN2pBxR9Reservation reference, alphanumeric
    {{user.userId}}-{{system.digits10}}1825-8984690258Per-user tracking, helpful when one CRM has multiple sources
    TKT-{{system.ymd}}-{{system.id10}}TKT-2026-05-01-K7vN2pBxR9Daily-grouped tickets

    Where it shows up

    • AI replies — write {{tool.trackingId}} inside the tool’s Description (e.g. “Your complaint has been filed under reference {{tool.trackingId}}”) and the AI quotes the same ID in its user-facing message.
    • Email body — auto-rendered as a tracking-number row at the top of the details block; the admin doesn’t need to touch the email config to surface it.
    • Email subject — write {{tool.trackingId}} inside the Subject prefix to put the ID in inbox listings (e.g. [Complaint] {{tool.trackingId}}).
    • Webhook payload — sent as a top-level trackingId field on every webhook delivery, regardless of the action’s other config.
    • Webhook headers — sent as X-Qafka-Tracking-Id automatically; admin headers can also reference {{tool.trackingId}} (e.g. X-CRM-Reference: {{tool.trackingId}}).
    • Action log — stored in the tracking_id column with a B-tree index, so the Action Logs search box returns the row sub-millisecond.

    Uniqueness

    Tracking IDs are generated fresh per invocation — different complaints in the same chat session get different IDs (a session-wide cache earlier collapsed every complaint to one ID; that bug is fixed). Within a single invocation, every reference resolves to the same string by construction (resolved once when the prompt is built, then propagated). The IDs are not DB-unique; collision probability is governed by the random space of the format you choose. For {{system.digits10}} (10⁰¹⁰), birthday-paradox first collision at ~100k complaints, way past practical workloads. If you need stricter guarantees, add a unique index in your own migration.

    Risk & Confirmation

    Form fieldWhat it does
    Risk levellow, medium, or high. Medium and high tools are surfaced separately in the dashboard’s risk reports; high-risk tools are flagged for the AI in the system prompt.
    Requires confirmationWhen on, the AI is instructed to ask the user “Are you sure?” before emitting the tool call.

    Custom Data

    The Custom Data field is a free-form JSON blob that travels with the tool to the SDK. Use it to pass partner-specific configuration (apiBaseUrl, brand strings, feature flags) so the mobile app’s onToolSuggested handler can stay generic across tools.

    Loading Message

    Form fieldWhat it does
    Loading messageShown in the chat (text mode) or as a voice pill (voice mode) while async work is in flight. Single string or an object keyed by locale.

    Enabled

    Toggle a tool off without deleting it. Disabled tools are not sent to the AI for matching.

    Last updated on June 3, 2026
    DocumentsAction Logs

    MIT 2026 QAFKA