Skip to content

Asistenți ​

Un asistent e un pachet versionat de comportament: un prompt, un transcriber, un model, o voce, tools-urile pe care le poate apela și planurile care decid când vorbește, când se oprește și ce înregistrează. E unitatea pe care o rulează un apel.

Fă câte unul per treabă, nu per client. Diferențele de la un apelant la altul stau în variabile, nu într-un al doilea asistent.

Draft, versiune, apel ​

Când editezi un asistent modifici draft-ul lui. publish îngheață draft-ul într-un rând de versiune imutabil și îndreaptă asistentul spre el. Un apel fixează versiunea cu care a pornit, deci o republicare în timpul apelului nu poate ajunge la o sesiune vie.

GET /assistants/{id} raportează has_unpublished_changes, pe care îl citește badge-ul din dashboard. version e 0 până la prima publicare.

POST /api/v1/assistants/{id}/publish            → 201 assistant_version
POST /api/v1/assistants/{id}/unpublish
GET  /api/v1/assistants/{id}/versions
GET  /api/v1/assistants/{id}/versions/{version}
POST /api/v1/assistants/{id}/versions/{version}/restore

O versiune publicată poartă un config_hash, tool_refs și knowledge_base_refs — așa îți dai seama dacă două apeluri chiar au rulat aceeași configurație.

Creare și editare ​

API-ul de asistenți e snake_case. Un PATCH schimbă doar câmpurile pe care le numește.

bash
curl -X PATCH "$CALLAGENT_API_URL/assistants/$ASSISTANT_ID" \
  -H "Authorization: Bearer $CALLAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": { "provider": "openai", "model": "gpt-4o-mini", "temperature": 0.4 },
    "silence_timeout_seconds": 20
  }'

PUT și PATCH ajung la același handler. În documentul OpenAPI e doar PUT; PATCH funcționează și nu e documentat acolo.

Câmpurile de nivel superior ​

CâmpObservații
nameObligatoriu, ≤255.
description≤255.
modepipeline (implicit) sau realtime. Vezi avertismentul de la Speech to speech.
language≤16, de ex. ro, en. Plus additional_languages[].
first_message≤5000.
first_message_modeassistant_speaks_first · assistant_speaks_first_with_model_generated_message · assistant_waits_for_user.
system_prompt≤100000.
template_strictnesslenient · warn (implicit) · strict — ce se întâmplă când un template numește o variabilă pe care nu o dă nimeni.
silence_timeout_seconds1–600, implicit 30.
max_duration_secondsde la 10 până la plafonul platformei, implicit 1800.
transcriber{ provider, model, language, … }.
model{ provider, model, temperature, … }.
voice{ provider, voice_id, … }.
speech_to_speech_modelSe salvează și e ignorat — vezi mai jos.
end_call_phrases[], idle_messages[], background_messages[], pronunciations[], custom_keywords[]
server{ url, … } — serverul de rezervă pentru tools-uri function și pentru hook-uri. server.url trebuie să fie un URL valid.
hooks[]14 puncte de declanșare.
fallbacks{ model: [], transcriber: [], voice: [] }, maximum două fiecare, indexul 0 primul.
variables[], variable_values{}Vezi Variabile.
knowledge_only, knowledge_only_plan
metadata{}Cheile tale, transmise neatinse.
tools[], tool_ids[], knowledge_base_ids[], structured_output_ids[]Atașamente; fiecare id e verificat față de organizația ta.

Blocurile de plan ​

Treisprezece blocuri de plan sunt acceptate ca obiecte libere, și fiecare e plat, în snake_case. Un bloc camelCase imbricat, din @callagent/contracts, se salvează curat și nu ajunge niciodată la gateway.

BlocChei
start_speaking_planwait_seconds, smart_endpointing_provider, completion_threshold, smart_endpointing_ms, on_punctuation_seconds, on_no_punctuation_seconds, on_number_seconds, custom_rules[]
stop_speaking_planenabled, num_words, voice_seconds, backoff_seconds, acknowledgement_phrases[], interruption_phrases[]
artifact_planrecording_enabled, recording_format, stereo_recording, video_enabled, transcript_enabled, messages_enabled, events_enabled, logs_enabled, debug_json_enabled, retention_days, pii_redaction, post_call_transcription.{enabled,provider,model,language}
analysis_plansummary_enabled, summary_prompt, sentiment_enabled, topics_enabled, success_evaluation_enabled, success_evaluation_prompt, success_evaluation_rubric, model, timeout_seconds
message_planidle_timeout_seconds, idle_max_count, idle_message_reset_count_on_user_speech
keypad_input_planenabled, delimiters[], timeout_seconds, max_digits, mute_assistant_while_typing
voicemail_detection_planenabled, strategy, beep_max_await_seconds, message
recording_consent_planrequired, mode, prompt, audio_url, on_refusal, regions[]
observability_planprovider, endpoint, project, sample_rate, include_prompts, include_transcripts, tags, metadata
compliance_planhipaa, pci, zero_data_retention
transfer_plandestinations[]
knowledge_only_planaction, message, min_passages, min_score
background_speech_denoisingenabled, mode, aggressiveness

Plus background_sound ({ type, volume } sau { type: "custom", url, volume }; tipurile sunt off, office, call-center, cafe, street, nature) și voice_formatting (enabled, min_characters, max_wait_ms, expand_numbers, expand_currency, expand_dates, expand_abbreviations, read_emails_naturally, strip_markdown).

Unele dintre astea fac mai puțin decât par

Câmpuri pe care nu le citește nimic la runtime, verificate prin căutare în sursa gateway-ului:

  • analysis_plan configurează un pipeline care nu rulează niciodată. Rezumatul, sentimentul, subiectele și evaluarea de succes nu se produc pe un apel viu.
  • compliance_plan ajunge în snapshot-ul gateway-ului și nu e citit niciodată.
  • observability_plan aplică tag-uri și sampling; nu se trimit span-uri.
  • model.num_fast_turns e convertit pe fir, iar gateway-ul nu îl citește niciodată. fast_model nici măcar nu e convertit — există doar în contract. Primele tururi nu sunt trimise către un model mai ieftin.
  • model.emotion_recognition e convertit și niciodată citit.
  • voice_formatting devine chunkPlan din contract, pe care gateway-ul nu îl citește niciodată. Normalizarea textului înainte de sinteză nu e configurabilă azi.
  • pronunciations devine pronunciationDictionary, pe care gateway-ul nu îl citește niciodată.
  • artifact_plan.storage_path_template e ignorat; recorderul își scrie calea hardcodat.

Ce este citit: max_tool_iterations, context_window_messages, background_sound, keypad_input_plan, voicemail_detection_plan, message_plan, end_call_phrases, idle_messages, background_messages, fallbacks, knowledge_base_ids, variable_values și cele două planuri de vorbire.

Vezi Ce nu este construit.

Vorbire la intrare, gândire, vorbire la ieșire ​

json
{
  "transcriber": {
    "provider": "deepgram",
    "model": "nova-3",
    "language": "ro",
    "smart_format": true,
    "numerals": true,
    "diarization": false,
    "profanity_filter": false,
    "auto_language_detection": false
  },
  "model": {
    "provider": "openai",
    "model": "gpt-4o-mini",
    "temperature": 0.4,
    "max_tokens": 400,
    "tool_choice": "auto",
    "max_tool_iterations": 5,
    "context_window_messages": 60,
    "timeout_seconds": 30
  },
  "voice": {
    "provider": "elevenlabs",
    "voice_id": "rachel",
    "speed": 1.0
  }
}

Valori implicite care merită știute: temperature 0.4, max_tokens 400, max_tool_iterations 5, context_window_messages 60, timeout_seconds 30 pe model, speed 1.0 pe voce.

API-ul ciuntește blocurile astea, iar una dintre victime strică orice apel

POST și PATCH /assistants folosesc $request->validated() din Laravel, care întoarce doar cheile care au avut o regulă de validare. În interiorul lui transcriber, model, voice și server, clasa de request declară reguli pentru exact cinci sub-chei:

transcriber.provider · model.provider · model.model · voice.provider · server.url

Orice altă sub-cheie din cele patru blocuri e aruncată în tăcere. Trimisă, acceptată cu 201, și dispărută:

bash
# trimis
"voice": { "provider": "elevenlabs", "voice_id": "rachel", "speed": 1.1 }
"model": { "provider": "openai", "model": "gpt-4o-mini", "temperature": 0.9 }
# salvat
"voice": { "provider": "elevenlabs" }
"model": { "provider": "openai", "model": "gpt-4o-mini" }

Deci voice_id, speed, stability, temperature, max_tokens, tool_choice, num_fast_turns, context_window_messages, transcriber.model, transcriber.language, smart_format și restul nu pot fi setate deloc prin API.

Ar fi doar enervant dacă s-ar opri aici. Nu se oprește: voice.voice_id e unul dintre cele cinci câmpuri fără de care configurația de apel a gateway-ului nu poate fi construită. Fără el, convertorul nu întoarce nimic, apelul nu are configurație, iar apelantul aude o linie moartă. validate le verifică pe celelalte patru și pe ăsta nu, deci asistentul se validează și se publică fără reproș.

Un asistent al cărui bloc de voce a fost scris ultima dată prin API-ul REST nu poate porni un apel. CLI-ul trimite către același endpoint și moștenește problema.

Blocurile de plan nu sunt afectate — nu au sub-reguli, deci start_speaking_plan, artifact_plan, metadata, variable_values și background_sound trec întregi. Iar dashboard-ul scrie direct în model, nu prin clasa asta de request, deci un asistent configurat acolo e complet.

Setează vocea din dashboard până se repară asta.

Cuvintele-cheie de transcriber nu sunt transcriber.keywords. Vin din custom_keywords, de la nivelul de sus al asistentului, care acceptă șiruri simple sau obiecte { "term": …, "boost": … }. E cea mai valoroasă setare de transcriber pentru numele de brand și de produs pe care transcriber-ul le-ar auzi altfel greșit.

num_fast_turns și fast_model ar trebui să trimită primele tururi ale unui apel către un model mai mic, pe teoria că „Bună, cu ce te pot ajuta?" nu are nevoie de cel scump. Niciunul nu e citit de gateway. Fiecare tur folosește model.model.

Transcriber-ul trebuie să fie unul pentru care gateway-ul are un adaptor live. validate impune asta la publicare, pentru că un transcriber pe care gateway-ul nu îl poate numi invalidează toată configurația apelului, nu doar câmpul acela, iar apelantul aude o linie moartă.

Încrederea în furnizori

Sunt declarați nouăsprezece furnizori de voce; doi sunt marcați ca revizuiți față de documentația vendorului, și niciunul nu a fost rulat pe un vendor live în CI. Vezi Furnizori și Ce nu este construit.

Fallback-uri ​

json
{ "fallbacks": { "voice": [ { "provider": "azure", "voice_id": "ro-RO-AlinaNeural" } ] } }

Ordonate, maximum două fiecare, indexul 0 se încearcă primul. Vezi Furnizori.

Speech to speech ​

speech_to_speech_model acceptă un furnizor și un model, le salvează, le versionează și le publică.

E ignorat la runtime

Sesiunea live de apel nu citește niciodată câmpul. Un asistent configurat pentru speech-to-speech rulează pipeline-ul obișnuit transcriere → model → sinteză. Setarea mode: "realtime" nu schimbă asta; schimbă doar ce câmpuri cere validate.

Variabile ​

Două jumătăți. variables[] le declară; variable_values{} dă valorile implicite.

json
{
  "variables": [
    { "name": "company_name", "source": "static", "default_value": "Example SRL", "required": true },
    { "name": "plan_tier",    "source": "call" }
  ],
  "variable_values": { "company_name": "Example SRL" },
  "system_prompt": "Ești agent de suport pentru {{company_name}}. Apelantul e pe planul {{plan_tier}}."
}

name trebuie să se potrivească cu ^[A-Za-z_][A-Za-z0-9_]*$. source e una dintre static, call, contact, webhook, tool, handoff, environment.

Sintaxa și ce e disponibil ​

Sintaxa e {{cale.cu.puncte}}. Nu e Liquid; nu există filtre, nu există condiționale, nu există bucle. O cale nerezolvată se randează ca șir gol.

Substituția rulează pe system prompt, pe primul mesaj, pe mesajele de fundal, pe mesajele de inactivitate, pe anunțul de consimțământ la înregistrare și pe mesajul de căsuță vocală.

Variabilele interne disponibile la runtime:

CaleValoare
{{call.id}}ULID-ul apelului.
{{call.from}}Numărul apelantului.
{{customer.name}}, {{customer.number}}, {{customer.email}}, {{customer.language}}, {{customer.id}}, {{customer.external_id}}, {{customer.attributes.*}}Contextul clientului, când a fost dat unul.

Precedență: variable_values de pe asistent, apoi variables trimise per apel către POST /calls, care câștigă.

Nu există {{now}} sau {{date}} la runtime. Resolverul de preview din dashboard expune un namespace env cu now, date, time, timezone, region și environment, și e o listă curată de valori permise, nu mediul procesului — dar resolverul acela randează preview-uri, nu apeluri vii.

POST /assistants/{id}/render-prompt randează prompt-ul pe un context pe care îl dai tu și întoarce missing, ceea ce e cel mai rapid mod de a găsi o greșeală de tipar într-o cale.

Hooks ​

hooks[] ar trebui să declanșeze o acțiune într-un punct numit. Paisprezece triggere:

call.start · call.end · call.ending · speech.update · transcript.final · tool.calls · tool.completed · customer.speech.timeout · customer.speech.interrupted · assistant.speech.interrupted · phone.call.control · silence.timeout · handoff · transfer.failed

Fiecare hook are filters opționale (oneOf, regex, equals) și cel puțin o acțiune: say, tool, transfer, handoff, endCall, setVariable, webhook.

Se declanșează doar hook-urile handoff

Hook-urile sunt convertite pe fir și trimise gateway-ului. Sursa gateway-ului nu conține nicio referință la ele. Control plane-ul rulează hook-uri pentru exact un eveniment — handoff, prin runnerul lui. Celelalte treisprezece triggere sunt salvate, publicate, transmise și ignorate.

Folosește un webhook sau un tool pentru orice plănuiai să faci cu restul.

Un hook cu o acțiune nerecunoscută e aruncat la conversie, nu respins. Supraviețuiesc doar say, transfer, tool și end_call; handoff, setVariable și webhook nu ajung deloc pe fir.

Inspectare ​

GET  /api/v1/assistants/{id}/validate       verificări de publicare, fără publicare
GET  /api/v1/assistants/{id}/preview        snapshot-ul rezolvat
POST /api/v1/assistants/{id}/render-prompt  randează template-urile pe un context

validate verifică structura și disponibilitatea adaptoarelor. Nu verifică dacă există sau funcționează o credențială, și nici dacă tools-urile atașate se rezolvă. Vezi Pornire rapidă, pasul 4 pentru lista exactă.

preview întoarce snapshot-ul rezolvat în forma snake_case a API-ului. Nu e formatul de pe fir al gateway-ului — acela e o a doua conversie, care în plus aruncă tools-urile pe care nu le poate mapa.

Ca fișier ​

yaml
name: Support Line
firstMessageMode: assistant-speaks-first
firstMessage: Bună, ai sunat la suport. Cu ce te pot ajuta?
systemPrompt: |
  Ești agent de suport pentru {{company_name}}.
  Fii scurt. Pune o singură întrebare pe rând.
transcriber: { provider: deepgram, model: nova-3, language: ro }
model:       { provider: openai, model: gpt-4o-mini, temperature: 0.4 }
voice:       { provider: elevenlabs, voiceId: rachel }
tools:
  - lookupOrder
knowledgeBases:
  - Manual de produs

CLI-ul vorbește vocabularul contractelor — camelCase, valori de enum cu cratimă — și convertește singur în ortografia API-ului. tools și knowledgeBases numesc resurse, iar CLI-ul le rezolvă. Vezi Config as code.

API ​

GET/POST         /api/v1/assistants
GET/PATCH/DELETE /api/v1/assistants/{id}
POST             /api/v1/assistants/{id}/duplicate
POST             /api/v1/assistants/{id}/publish
POST             /api/v1/assistants/{id}/unpublish
GET              /api/v1/assistants/{id}/versions
GET              /api/v1/assistants/{id}/versions/{version}
POST             /api/v1/assistants/{id}/versions/{version}/restore
GET              /api/v1/assistants/{id}/preview
POST             /api/v1/assistants/{id}/render-prompt
GET              /api/v1/assistants/{id}/validate

Parametri, body-uri și răspunsuri complete: referința asistenților.

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