Skip to content

Tools ​

Un tool e o funcție pe care modelul o poate apela în timpul conversației: caută o comandă, transferă apelul, trimite cifre într-un IVR, interoghează un knowledge base. Dă-i unui asistent un tool când are nevoie de un fapt pe care nu îl poate ști sau de o acțiune pe care nu o poate face vorbind.

Un tool e o resursă versionată de sine stătătoare, publicată ca un asistent și atașată unuia sau mai multor asistenți.

Cele 25 de tipuri ​

GruptypeCe face
Customapi_requestApelează un endpoint HTTP al tău. URL cu template, parametri de cale, auth, retry, extragere din răspuns.
functionTrimite contextul apelului către un URL de server și așteaptă. Cade pe server-ul de la nivelul asistentului dacă tool-ul nu are unul.
custom_providerO formă custom, specifică unui furnizor.
client_sideExecutat în browserul vizitatorului, de Web SDK.
Control de apeltransfer_callTransferă către un număr, un URI SIP, o extensie sau o coadă.
handoffPredă conversația altui asistent din squad.
end_callÎncheie apelul.
smsTrimite un SMS.
dtmfTrimite cifre DTMF.
voicemailLasă un mesaj vocal.
sip_requestTrimite un request SIP în dialog.
Knowledgequery, knowledge_baseRegăsește dintr-un knowledge base.
MCPmcpUn tool dintr-un server MCP. Creat prin discovery, nu de mână.
Sandboxbash, computer, text_editorRulează într-un container de unică folosință, niciodată în procesul gateway.
Integrărigoogle_calendar_create_event, google_calendar_availability, google_sheets_append_row, slack_send_message, gohighlevel_availability, gohighlevel_event_create, gohighlevel_contact_create, gohighlevel_contact_getConectori nativi.

Cinci dintre astea nu ajung niciodată într-un apel

bash, computer, text_editor, client_side și custom_provider sunt acceptate de API și salvate, iar convertorul care construiește lista de tools a gateway-ului nu are nicio mapare pentru niciunul dintre ele. Un tool de unul dintre tipurile alea e aruncat în tăcere din fiecare apel. Modelul nu îl vede niciodată.

Tools-urile client_side funcționează prin calea proprie de registerTool a Web SDK-ului, care e un mecanism diferit. Vezi Ce nu este construit.

Contractul gateway-ului are 27 de membri: cele 25 de aici plus markDoNotCall și scheduleCallback, injectate de gateway pe apelurile de campanie și care nu pot fi create prin API.

Cum declari un tool HTTP ​

API-ul de tools e snake_case, iar tot ce ține de transport stă sub config.

bash
curl -X POST "$CALLAGENT_API_URL/tools" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Caută comanda",
    "key": "lookup_order",
    "description": "Caută o comandă după numărul ei.",
    "type": "api_request",
    "parameters_schema": {
      "type": "object",
      "properties": {
        "orderNumber": { "type": "string", "description": "Numărul comenzii." }
      },
      "required": ["orderNumber"]
    },
    "config": {
      "url": "https://api.example.com/orders/{orderNumber}",
      "method": "GET",
      "path_parameters": [{ "name": "orderNumber" }],
      "parameters": [{ "name": "orderNumber", "source": "model" }],
      "timeout_seconds": 10,
      "response_extraction": [{ "path": "order.status" }],
      "retry": { "max_attempts": 2, "backoff": "exponential", "excluded_status_codes": [400, 404] }
    },
    "messages": [
      { "type": "request_start", "content": "O clipă, verific." },
      { "type": "request_failed", "content": "Nu am reușit să ajung la sistemul de comenzi." }
    ],
    "risk_level": "read",
    "timeout_seconds": 20
  }'

Câmpuri de nivel superior: name (obligatoriu), key (^[a-zA-Z_][a-zA-Z0-9_]*$ — ăsta e numele pe care îl vede modelul), description (obligatoriu, ≤2000), type (obligatoriu), parameters_schema, config, messages, rejection_plan, server, metadata, is_async, timeout_seconds (1–120), requires_confirmation, risk_level.

Apoi publică-l, la fel ca pe un asistent:

bash
curl -X POST "$CALLAGENT_API_URL/tools/$TOOL_ID/publish" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY"

Patru lucruri care îți vor da 422 ​

Astea sunt greșelile care merită știute înainte să le faci.

1. config.url e obligatoriu. Un tool api_request, function sau custom_provider fără URL e respins la scriere. config.method nu e obligatoriu — e implicit POST, în tăcere. Setează-l explicit.

2. Hostul din URL trebuie să se rezolve, acum. Fiecare URL trece prin garda SSRF când creezi tool-ul, iar garda rezolvă hostname-ul:

json
{"error":{"type":"validation_error","errors":{
  "config":["Request URL rejected: The hostname \"api.example.com\" could not be resolved."]}}}

Un URL care nu se rezolvă, sau care se rezolvă la o adresă privată sau link-local, e refuzat. Verificarea rulează din nou în gateway înainte de fiecare request și la fiecare hop de redirect. Un URL care conține {{ e sărit la scriere, pentru că nu poate fi rezolvat până nu rulează apelul.

3. Placeholder-ele de cale sunt cu o singură acoladă și trebuie declarate.{orderNumber} în URL cere o intrare corespunzătoare în config.path_parameters, iar un parametru de cale declarat care nu apare în URL e tot o eroare. Dacă scrii {{orderNumber}} primești The URL uses {orderNumber} but no path parameter of that name is defined, pentru că acoladele interioare se potrivesc oricum.

4. response_extraction e o listă de reguli cu un path. Nu un obiect {mode, json_path}. Calea e o cale cu puncte și paranteze drepte ([A-Za-z0-9_.\[\]*$] și atât), intenționat nu un limbaj de expresii JSONPath — un motor de expresii peste date necontrolate e o suprafață de atac de care nu are nimeni nevoie aici.

response_extraction contează mai mult decât pare. Dacă îi dai modelului un body JSON de 2 MB, distrugi timpul până la primul token. Extrage exact câmpul de care ai nevoie.

config complet ​

CheieValori
urlObligatoriu. Cu template {{variabilă}} și {parametruDeCale}.
methodGET · POST · PUT · PATCH · DELETE. Implicit POST.
headersObiect sau listă de perechi nume/valoare. Host nu poate fi suprascris.
queryObiect sau listă de perechi nume/valoare.
path_parameters[{ "name": "…" }], potrivite cu {name} din URL.
body_formatjson · form · multipart · raw · none. Implicit json.
bodyNepermis pe GET sau DELETE. Validat ca JSON dacă nu conține {{.
parametersLegături de argumente — vezi mai jos.
auth{ "type": …, "credential_id": … }.
response_extraction[{ "path": "order.status" }].
retrymax_attempts 0–5, backoff fixed·linear·exponential, excluded_status_codes.
timeout_seconds1–120.
follow_redirectsboolean. Redirect-urile sunt reverificate de garda SSRF.
asyncNu poate fi combinat cu response_extraction.

Legături de argumente ​

config.parameters spune de unde vine fiecare argument:

json
"parameters": [
  { "name": "orderNumber", "source": "model" },
  { "name": "tenant",      "source": "static",   "value": "acme" },
  { "name": "callId",      "source": "variable", "variable": "call.id" },
  { "name": "apiKey",      "source": "secret",   "credential_id": "01JQ…" }
]

Patru surse: model (îl completează LLM-ul), static (are nevoie de value), variable (are nevoie de o cale variable cu puncte), secret (trebuie să refere o credențială salvată). Un parametru secret cu value inline e respins — ăla nu e un argument criptat, e un secret în clar într-o coloană JSON.

Auth ​

bearer, basic, api_key și oauth2 cer toate credential_id sau oauth_connection_id. Secretele nu se țin niciodată în body-ul tool-ului. api_key are nevoie și de numele header-ului în care se trimite cheia.

Timeout-uri ​

Patru straturi, și dacă știi care mușcă îți economisești o după-amiază:

StratImplicitPlafon
config.timeout_seconds — request-ul HTTP în sine20120
timeout_seconds pe tool — bugetul de execuție20120 la scriere, 600 în contract
timeout_seconds de server MCP20 în baza de date, 30 în contract120
Tool MCP la legarecel mai strâns dintre intrarea de tool și server

Impunerea e în gateway, ca semnal de abort combinat cu semnalul propriu al sesiunii de apel — deci barge-in-ul anulează și un tool aflat în zbor. Un timeout întoarce un rezultat structurat pentru acel singur apel de tool. Nu doboară niciodată apelul.

O valoare de tool în afara intervalului e aruncată, nu limitată

Dacă timeout-ul de execuție salvat e în afara intervalului 1–600, convertorul îl omite și se aplică valoarea implicită a gateway-ului, de 20 de secunde. Tăcere, nu eroare.

Mesaje rostite ​

Apelantul aude tăcere cât rulează un tool, dacă nu o umpli tu.

json
"messages": [
  { "type": "request_start",    "content": "O clipă, verific." },
  { "type": "request_delayed",  "content": "Durează mai mult decât de obicei.", "timing_milliseconds": 4000 },
  { "type": "request_complete", "content": "Gata." },
  { "type": "request_failed",   "content": "Nu am reușit să ajung la sistemul acela." }
]

Doar patru tipuri. Ambele ortografii sunt acceptate la intrare (request_start și request-start), iar message e acceptat ca alias pentru content. Orice altceva e aruncat, nu respins — verifică ce ți-a venit înapoi. timing_milliseconds are înțeles doar pentru request_delayed. blocking e implicit false.

Tools asincrone ​

is_async: true (sau config.async: true) trimite request-ul și se întoarce imediat cu „Request accepted and running in the background." Erorile ajung în log și nu ajung niciodată la model.

Asta funcționează doar pentru api_request. Niciun alt tip nu se ramifică pe el.

Niveluri de risc și confirmare ​

Cinci niveluri, crescător: read, write, destructive, financial, privileged.

Fiecare tip are o valoare implicită: query, knowledge_base și conectorii doar-citire sunt read; transfer_call și end_call sunt destructive; bash, computer și text_editor sunt privileged; tot restul e write.

requires_confirmation face asistentul să întrebe înainte să execute. Pentru tools-urile MCP politica e per server — vezi MCP.

Respingere ​

rejection_plan decide ce se întâmplă când un apel de tool e refuzat — de politică, de nivelul de risc, sau pentru că apelantul a refuzat o confirmare. Asistentul spune linia configurată, iar modelul e informat că apelul a fost respins, ca să poată ocoli, în loc să se repete.

O respingere nu e niciodată o excepție. Un tool care aruncă întoarce un rezultat de eroare către model; turul continuă.

Tools de tip function ​

Un tool function trimite contextul apelului către un URL de server. server e opțional pe tool: dacă nu are unul, se ocupă server.url de la nivelul asistentului.

Dacă nu e setat niciunul, tool-ul se creează și se atașează oricum, iar fiecare apel către el se întoarce ca not_found, cu „this function tool has no server URL configured". Legal de construit, inutil la runtime. Setează unul.

Tools client-side ​

Un tool client_side rulează în browserul vizitatorului, deci asistentul poate acționa pe pagina în care e încorporat — să citească coșul, să deruleze la o secțiune, să precompleteze un formular.

ts
client.registerTool('getCartTotal', async () => ({ total: 42.5, currency: 'EUR' }));

// sau un singur handler pentru mai multe tools; întoarce undefined ca să refuzi
client.on('client-tool', async ({ name, arguments: args }) => {
  if (name !== 'scrollTo') return undefined;
  document.querySelector(String(args.selector))?.scrollIntoView();
  return { scrolled: true };
});

Un handler care aruncă trimite eroarea înapoi la model, în loc să blocheze turul. Un tool neînregistrat e raportat, nu aruncat în tăcere.

Observă distincția: asta e calea de înregistrare a Web SDK-ului, care funcționează. Un rând Tool salvat, de tip client_side, e altceva și e aruncat din snapshot-ul gateway-ului.

Cum atașezi un tool unui asistent ​

Nu există un endpoint /assistants/{id}/tools. Atașează prin body-ul asistentului:

bash
curl -X PATCH "$CALLAGENT_API_URL/assistants/$ASSISTANT_ID" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tools": [
      { "tool_id": "01JQ…", "pin_mode": "latest", "enabled": true },
      { "tool_id": "01JQ…", "pin_mode": "pinned", "tool_version_id": "01JQ…", "alias": "orders" }
    ]
  }'

pin_mode e latest (se rezolvă la publicare) sau pinned (înghețat pe o versiune). alias redenumește tool-ul doar pentru asistentul ăsta. tool_ids e prescurtarea pentru atașare după id, cu valorile implicite.

GET /assistants/{id}/preview arată lista rezolvată, cu exposed_name — numele pe care îl va vedea efectiv modelul.

API ​

GET/POST         /api/v1/tools
GET/PATCH/DELETE /api/v1/tools/{id}
POST             /api/v1/tools/{id}/duplicate
POST             /api/v1/tools/{id}/publish
GET              /api/v1/tools/{id}/versions
GET              /api/v1/tools/{id}/versions/{version}
POST             /api/v1/tools/{id}/versions/{version}/restore
GET              /api/v1/tools/{id}/validate

Parametri și răspunsuri complete: referința tools.

Scrisă după cod. Ce nu este încă implementat este marcat ca atare, niciodată descris ca funcțional.