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
| Grup | type | Ce face |
|---|---|---|
| Custom | api_request | Apelează un endpoint HTTP al tău. URL cu template, parametri de cale, auth, retry, extragere din răspuns. |
function | Trimite 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_provider | O formă custom, specifică unui furnizor. | |
client_side | Executat în browserul vizitatorului, de Web SDK. | |
| Control de apel | transfer_call | Transferă către un număr, un URI SIP, o extensie sau o coadă. |
handoff | Predă conversația altui asistent din squad. | |
end_call | Încheie apelul. | |
sms | Trimite un SMS. | |
dtmf | Trimite cifre DTMF. | |
voicemail | Lasă un mesaj vocal. | |
sip_request | Trimite un request SIP în dialog. | |
| Knowledge | query, knowledge_base | Regăsește dintr-un knowledge base. |
| MCP | mcp | Un tool dintr-un server MCP. Creat prin discovery, nu de mână. |
| Sandbox | bash, computer, text_editor | Rulează într-un container de unică folosință, niciodată în procesul gateway. |
| Integrări | google_calendar_create_event, google_calendar_availability, google_sheets_append_row, slack_send_message, gohighlevel_availability, gohighlevel_event_create, gohighlevel_contact_create, gohighlevel_contact_get | Conectori 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.
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:
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:
{"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
| Cheie | Valori |
|---|---|
url | Obligatoriu. Cu template {{variabilă}} și {parametruDeCale}. |
method | GET · POST · PUT · PATCH · DELETE. Implicit POST. |
headers | Obiect sau listă de perechi nume/valoare. Host nu poate fi suprascris. |
query | Obiect sau listă de perechi nume/valoare. |
path_parameters | [{ "name": "…" }], potrivite cu {name} din URL. |
body_format | json · form · multipart · raw · none. Implicit json. |
body | Nepermis pe GET sau DELETE. Validat ca JSON dacă nu conține {{. |
parameters | Legături de argumente — vezi mai jos. |
auth | { "type": …, "credential_id": … }. |
response_extraction | [{ "path": "order.status" }]. |
retry | max_attempts 0–5, backoff fixed·linear·exponential, excluded_status_codes. |
timeout_seconds | 1–120. |
follow_redirects | boolean. Redirect-urile sunt reverificate de garda SSRF. |
async | Nu poate fi combinat cu response_extraction. |
Legături de argumente
config.parameters spune de unde vine fiecare argument:
"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ă:
| Strat | Implicit | Plafon |
|---|---|---|
config.timeout_seconds — request-ul HTTP în sine | 20 | 120 |
timeout_seconds pe tool — bugetul de execuție | 20 | 120 la scriere, 600 în contract |
timeout_seconds de server MCP | 20 în baza de date, 30 în contract | 120 |
| Tool MCP la legare | cel 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.
"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.
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:
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}/validateParametri și răspunsuri complete: referința tools.