Tipuri de evenimente
Evenimentele tipizate pe care le emite un apel și ce poartă fiecare. Acesta este vocabularul intern de apel, folosit în două locuri: stream-ul de evenimente al apelului (GET /calls/{call}/events) și subiectele NATS pe care și le schimbă cele două plane. Definit ca CallEventType în @callagent/contracts și oglindit în App\Enums\CallEventType, cu un test care citește sursa PHP și eșuează la divergență.
Astea nu sunt nume de evenimente de webhook
Webhook-urile de ieșire folosesc un vocabular separat, versionat deliberat, de 28 de nume, iar cele două se suprapun destul cât să te încurce:
| Aici (evenimente de apel) | Acolo (webhooks) |
|---|---|
call.created | call.started |
call.connected | call.answered |
tool.started | tool.called |
user.speech.started | speech.started |
Abonează un endpoint de webhook la un nume din pagina asta și este respins ca necunoscut.
Fiecare eveniment are același envelope; doar data diferă, și doar el este descris mai jos.
Ciclu de viață
| Eveniment | data |
|---|---|
call.created | direction, from, to, phoneNumberId, assistantId, squadId, campaignId, telephonyProvider, idempotencyKey |
call.ringing | ringingAt, destination |
call.connected | answeredAt, setupMs, sipCallId |
call.ended | endedReason, durationMs, billableSeconds, endedBy (customer · assistant · operator · system · provider) |
call.failed | endedReason, error |
call.state.changed | from, to, reason |
transport.connected | transport, remoteAddress, connectMs, codec, sampleRate |
transport.disconnected | code, reason |
Vorbire în stt
| Eveniment | data |
|---|---|
user.speech.started | energyDb, duringAssistantSpeech |
user.speech.ended | speechMs, silenceMs |
transcript.partial | text, isFinal: false, confidence, speaker, language, words[] |
transcript.final | ca mai sus, cu isFinal: true |
endpoint.detected | strategy (provider · vad_timeout · punctuation · semantic · hybrid), silenceMs, minSpeechMs, maxWaitMs, confidence, transcript |
words[] poartă startMs, endMs, confidence și speaker pentru fiecare cuvânt, atunci când transcriber-ul le furnizează.
Model llm
| Eveniment | data |
|---|---|
llm.started | provider, model, temperature, maxTokens, messageCount |
llm.first_token | ca mai sus, plus ttftMs |
llm.completed | plus tokens (prompt, completion, total, cachedPrompt, reasoning), durationMs, finishReason, toolCallCount, fallbackIndex |
llm.failed | error (code, message, statusCode, retryable) |
llm.aborted | abortReason: barge_in · timeout · handoff · call_ended · operator |
finishReason este stop, length, tool_calls, content_filter, aborted sau error.
Sinteză tts
| Eveniment | data |
|---|---|
tts.started | voice (provider, voiceId, model), text, chunkIndex |
tts.first_audio | plus ttfaMs |
tts.completed | plus characters, durationMs, audioMs, fallbackIndex |
tts.failed | error |
tts.aborted | abortReason |
Redare playback
| Eveniment | data |
|---|---|
assistant.speech.started | text, messageId |
assistant.speech.interrupted | spokenText, remainingText, spokenMs, detectionMs, stopAudioMs |
assistant.speech.completed | text, audioMs, messageId |
spokenText față de remainingText este perechea care contează: transcrierea păstrează doar ce a auzit efectiv apelantul.
Speech to speech
s2s.started · s2s.first_audio (ttfaMs) · s2s.completed (durationMs, inputAudioMs, outputAudioMs, tokens) · s2s.failed.
Tool-uri tool
| Eveniment | data |
|---|---|
tool.started | toolId, toolCallId, name, toolType, args |
tool.completed | plus result, durationMs, async |
tool.failed | plus error |
tool.rejected | plus rejectionReason, rejectionMessage |
rejectionReason este unul dintre cele unsprezece de pe codurile de eroare.
MCP
mcp.started · mcp.completed · mcp.failed, fiecare purtând serverId, serverName, transport (streamable_http · sse · stdio), toolName, args, iar la finalizare result și durationMs.
Cunoștințe
| Eveniment | data |
|---|---|
knowledge.queried | knowledgeBaseId, query, provider, matchCount, topScore, durationMs, documentIds |
knowledge.insufficient | knowledgeBaseId, query, threshold, topScore, safetyMode |
knowledge.insufficient este semnalul de răspuns onest: căutarea a venit înapoi sub prag, iar asistentul a spus asta în loc să inventeze un răspuns. Vezi modul knowledge-only.
Rutare
| Eveniment | data |
|---|---|
handoff.started | fromAssistantId, toAssistantId, squadId, trigger (tool · intent · variable · dynamic · explicit · silent), contextMode, reason |
handoff.completed | toAssistantId, durationMs, messagesCarried |
transfer.started | mode (blind · warm · queue · sip_uri · assistant · dynamic), destination, destinationType |
transfer.completed | plus legId, durationMs |
transfer.failed | plus error |
Contact centre
operator.queued · operator.ringing · operator.connected · operator.rejected · operator.missed · operator.wrap_up · queue.abandoned · queue.overflowed.
Toate poartă operatorId, operatorName, queueId, queueName, extension, waitMs, ringMs, position și reason acolo unde se aplică. operator.wrap_up adaugă dispositionId, disposition, notes și wrapUpMs; queue.abandoned adaugă abandonedAfterMs; queue.overflowed adaugă overflowTo și overflowType (queue · ring_group · voicemail · assistant · number).
DTMF, SIP și voicemail
| Eveniment | data |
|---|---|
dtmf.received | digits, method (rfc2833 · rfc4733 · sip_info · inband · provider), buffer |
dtmf.sent | digits, method, interDigitMs |
sip.request.sent | method (INFO · MESSAGE · NOTIFY · REFER · OPTIONS · UPDATE), destination, headers, body |
sip.response.received | statusCode, reason, method, headers |
voicemail.detected | detector (provider_amd · classifier · beep · tool), confidence, beepDetected, policy (hangup · leave_message · continue · custom), detectionMs |
Artefacte
| Eveniment | data |
|---|---|
recording.consent_announced | mode, spokenText, audioUrl, region |
recording.consent_recorded | plus acknowledged |
recording.started | recordingId, channels (mono · stereo · dual), track (mixed · caller · assistant · operator), format |
recording.paused | plus reason |
recording.resumed | ca la recording.started |
recording.ready | plus url, storagePath, bytes, durationMs |
analysis.completed | summary, sentiment, success, successReason, topics, structuredOutputs, scorecardIds, durationMs |
analysis.completed
Tipul de eveniment și payload-ul lui sunt definite, iar control plane-ul stochează rezultatele dacă ajung. Pipeline-ul de analiză post-apel care le-ar produce nu este în prezent pornit de control plane — vezi Stadiul implementării și Analytics și costuri.
Sănătatea providerilor
| Eveniment | data |
|---|---|
provider.fallback | component, from, to, reason (timeout · error · rate_limit · auth · circuit_open · health_check), attempt |
provider.error | component, provider, model, error, circuitOpened |
component este model, transcriber, voice, speech_to_speech, telephony, iar pentru provider.error și storage și observability.
Cum le categorisești
Prefixul de dinaintea primului punct este categoria, și așa un consumator se poate abona larg fără să enumere 60 de nume:
const category = (type: string) => type.split('.')[0];
// 'endpoint.detected' → 'endpoint'
const isError = (type: string) =>
type.includes('failed') || type.includes('error') || type === 'tool.rejected';Ambele funcții ajutătoare se livrează ca eventCategory() și isErrorEvent() în @callagent/contracts.