Tool Catalog
A deployed assistant can do more than generate text. Divinci’s tool surface spans three independent subsystems, each with its own config and its own gate, and all three are off by default:
| Subsystem | What it does | Configured via | Gate |
|---|---|---|---|
| RP1 tool-loop | In-chat tools the model calls during a send (search, fetch, RAG, media, CRM, drafts) | Release.toolRouting + server env | Double-gated (env + release) |
| MCP tools | The platform’s full surface exposed to external MCP/agent clients | Release.mcpConfig | mcpConfig.enabled |
| Site Control | Navigate / submit forms on the embedded customer site | Release.siteControl | siteControl.enabled (THE WALL) |
RP1 tool-loop (in-chat tools)
Section titled “RP1 tool-loop (in-chat tools)”What it is. When a chat turn is routed, the send path hands the message to a
tool-calling model that loops call-model → execute-tool → feed-result until the
model answers tool-free or a safety net trips. Use it when you want an in-chat
assistant that actually does things — searches the web, fetches a URL, retrieves
from RAG, generates media, or drafts an email/event/contact.
The 11 tools
Section titled “The 11 tools”| Tool | Category | Side effect | In default set? |
|---|---|---|---|
webSearch | read-only | none | ✅ |
fetchUrl | read-only | none (SSRF-guarded) | ✅ |
ragSearch | read-only | none | ✅ |
composeEmail | draft | none — emits a deep-link draft | ✅ |
draftCalendarEvent | draft | none — emits a deep-link draft | ✅ |
draftCrmContact | draft | none — emits a deep-link draft | ✅ |
generateImage | media | provider spend | ❌ opt-in |
generateVideo | media | provider spend | ❌ opt-in |
generateDiagram | media | provider spend | ❌ opt-in |
crmCreateContact | mutation | creates/upserts a contact | ❌ opt-in |
crmLookup | read-only | — (no implementation) | ❌ |
The three draft tools are read-only: they return a structured deep-link the client turns into an “open in Gmail / Calendar / CRM” button — no server-side write happens.
Enabling it (double gate)
Section titled “Enabling it (double gate)”Routing requires both a server env gate and per-release config. Either one alone does nothing.
# 1. Server env gate on the public-api service:TOOL_ROUTING_ENABLED=true # (or 1)# 2. Per-release config (read-only default tool set):curl -X PATCH https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"toolRouting":{"enabled":true}}'To opt media + CRM-create tools in (and accept their un-escrowed spend), set a
custom threshold, or pin the model, list them explicitly in enabledTools:
curl -X PATCH https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"toolRouting":{ "enabled":true, "threshold":0.5, "modelId":"@cf/moonshotai/kimi-k2.7-code", "enabledTools":[ "webSearch","fetchUrl","ragSearch", "generateImage","generateDiagram","crmCreateContact", "composeEmail","draftCalendarEvent","draftCrmContact" ] }}'SDK equivalent:
await client.releases.updateInWorkspace(workspaceId, releaseId, { toolRouting: { enabled: true, enabledTools: ["webSearch", "ragSearch"] },} as any); // set via the API body; not a typed CLI flag yettoolRouting fields and defaults
Section titled “toolRouting fields and defaults”| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | false | Per-release gate (coerced to boolean by the API) |
threshold | 0–1 | 0.6 | Tool-intent signal must cross this to route |
regexWeight | 0–1 | 0.6 | Weight of the cheap regex prior in the signal |
modelId | string | @cf/moonshotai/kimi-k2.7-code | Tool-calling model |
enabledTools | string[] | the read-only DEFAULT_ROUTED_TOOLS set | Omit/empty = read-only set; list to add media/CRM |
DEFAULT_ROUTED_TOOLS = webSearch, fetchUrl, ragSearch, composeEmail,
draftCalendarEvent, draftCrmContact — i.e. read-only / no un-escrowed
spend. Media generators and crmCreateContact are excluded unless you add them.
Tool-loop safety nets
Section titled “Tool-loop safety nets”The orchestrator enforces hard bounds you cannot relax via release config:
| Bound | Default |
|---|---|
| Max iterations | 8 |
| Max wall-clock | 90 000 ms |
| Repetition limit | 3 identical calls |
| Token budget | off (undefined) |
| Confirmation for mutations | always required |
| Per-tool-result size | bounded to 8000 chars |
ragSearch topK | default 6, clamped to ≤ 20 |
Gotchas
Section titled “Gotchas”- Double gate.
TOOL_ROUTING_ENABLED=trueandtoolRouting.enabled=trueare both required. One without the other = no routing. - Default set is read-only only. Media +
crmCreateContactare opt-in because their provider cost currently bypasses chat escrow — enabling them means that spend is uncounted. crmLookuphas no implementation. Even if advertised it always returns “CRM lookup is not available.” Only create/upsert exists.crmCreateContactneeds an email. If the model didn’t supply one, the call short-circuits with a message rather than upserting an empty key.- Mutations always confirm.
crmCreateContactrequires runtime confirmation regardless of config —requireConfirmationForMutationscannot be disabled. fetchUrlis SSRF-guarded. Private / loopback / link-local / metadata targets are rejected.- Routing reads a cheap signal, not a fresh classifier. The send-time signal is
the client-carried
toolLikelihoodor the regex prior — there is no per-turn 70B classifier call (removed for cost). A weak prompt won’t route even with a low threshold.
MCP tools
Section titled “MCP tools”What it is. The MCP server (workers/mcp-server) exposes ~60+ named tools
across ~25 categories — chat, RAG, config, fine-tune, QA, analytics, terms, trust,
and more — to external MCP/agent clients. Use mcpConfig when you want to expose
some of that surface to an MCP client rather than to the in-chat model.
Enabling it
Section titled “Enabling it”curl -X PATCH https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"mcpConfig":{ "enabled":true, "exposedTools":["send_message","search_knowledge","get_transcript"], "allowAnonymousMcp":true, "maxSpendPerTokenCents":500, "mcpRateLimit":{"requestsPerMinute":30,"requestsPerDay":2000} }}'mcpConfig fields and defaults
Section titled “mcpConfig fields and defaults”| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | false | The MCP gate |
exposedTools | string[] | empty = all release tools | Unknown names are rejected by the API |
allowedScopes | string[] | — | Restricts callable scopes |
mcpRateLimit.requestsPerMinute | number | 60 | Per-minute cap |
mcpRateLimit.requestsPerDay | number | 10000 | Per-day cap |
allowAnonymousMcp | boolean | false | Requires a positive maxSpendPerTokenCents |
maxSpendPerTokenCents | cents | 1000 ($10) | Per-token spend cap |
Gotchas
Section titled “Gotchas”- Unknown
exposedToolsare rejected. Listing a tool name the server doesn’t know fails validation (it would otherwise expose nothing). - Anonymous access needs a spend cap.
allowAnonymousMcp: truerequires a positivemaxSpendPerTokenCents.
Site Control (navigation / action tools)
Section titled “Site Control (navigation / action tools)”What it is. The crawler builds a SiteManifest of the embedded customer site;
Site Control turns that map into executable tools — a navigate_site action plus
per-form submit actions. Use it when you want the assistant to move around the
embedded site (and, opt-in, fill and submit forms with runtime confirmation).
Enabling it
Section titled “Enabling it”# Navigation only (THE WALL opt-in):curl -X PATCH https://api.stage.divinci.app/white-label/$WL/release/$RELEASE \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"siteControl":{"enabled":true,"allowedCategories":["navigation"]}}'
# Add form submission (each submit action is confirmation-gated, always):# -d '{"siteControl":{"enabled":true,"allowedCategories":["navigation","mutation"]}}'siteControl fields and defaults
Section titled “siteControl fields and defaults”| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | false | THE WALL gate |
allowedCategories | "navigation" | "query" | "mutation" | "utility"[] | ["navigation"] | Which action categories are derived |
allowList | string[] | — | Strictly validated |
blockList | string[] | — | Strictly validated |
Manifest-derived limits: navigation route enum capped at 60, max 20 form actions, action name length 48.
Gotchas
Section titled “Gotchas”- Form submissions always confirm. Site Control
mutation/ submit actions carryrequiresConfirmation: true, which config cannot disable. - Sensitive fields are stripped. Password / hidden inputs and any name matching
pass/pwd/card/cvv/ssn/secret/token/otp/pin/account-number/routingnever become fillable params. - Cross-origin hrefs are dropped from navigation actions.
Inspecting derived actions
Section titled “Inspecting derived actions”import { deriveReleaseSiteActions } from "@divinci-ai/models";import { selectToolDefinitions, DEFAULT_ROUTED_TOOLS } from "@divinci-ai/server-resources";
// Tool-loop: which tools a release advertises to the modelconst toolDefs = selectToolDefinitions( release.toolRouting?.enabledTools?.length ? release.toolRouting.enabledTools : [...DEFAULT_ROUTED_TOOLS],);
// Site Control: derived actions ([] unless siteControl.enabled)const siteActions = deriveReleaseSiteActions(release);