Browserul
Același asistent care răspunde la un număr de telefon poate răspunde și pe o pagină web. Browserul primește o cheie publică, o schimbă pe un token de scurtă durată și deschide o sesiune de media cu gateway-ul — audio-ul și barge-in-ul funcționează exact ca la telefon, pentru că e același pipeline în spatele aceleiași abstracții de transport.
Două căi de intrare
Widget-ul — fără build, un singur tag de script. Vezi Widget.
<script src="/widget.js"
data-public-key="ca_pk_…"
data-assistant-id="01JQ…"
data-mode="voice"></script>SDK-ul — când vrei conversația în interfața ta. Vezi Web SDK.
import { CallAgent } from '@callagent/web-sdk';
const client = new CallAgent({ publicKey: 'ca_pk_…', apiUrl: 'https://api.example.com' });
const call = await client.start({ assistantId: '01JQ…' });
call.on('transcript', (event) => console.log(event.speaker, event.text, event.final));
call.on('state', ({ state }) => render(state));SDK-ul vine cu zero dependențe la runtime — widget-ul se pune pe paginile de marketing ale altora, iar o bibliotecă de validare ar fi o bună parte din bugetul de octeți. Stările de apel și rolurile de mesaj pe care le împarte cu control plane-ul sunt verificate față de @callagent/contracts printr-un test, deci o divergență pică build-ul, în loc să fie acceptată în tăcere la runtime.
Chei și token-uri
Un browser nu ține niciodată o cheie privată. SDK-ul o refuză din prima:
new CallAgent({ publicKey: 'sk_…' });
// CallAgentError: private_key_rejectedSchimbul e POST /api/v1/client-tokens, autentificat cu cheia publică și verificat față de origin-urile permise ale cheii — o cheie validă prezentată de pe un site pe care nu îl numește e refuzată. JWT-ul întors e legat de o organizație, un asistent, o sesiune și o expirare, iar SDK-ul îl reîmprospătează cu 60 de secunde înainte să moară, în loc să aștepte un 401.
Dacă preferi să generezi token-uri pe backend-ul tău, dă-i { token } în loc de { publicKey } și SDK-ul nu apelează niciodată schimbul. Detalii complete pe Autentificare.
Tools client-side
Un tool client_side se execută în browserul vizitatorului, ceea ce permite asistentului să acționeze pe pagina în care e încorporat — să citească coșul, să precompleteze un formular, să deruleze la o secțiune.
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, iar un tool neînregistrat e raportat, nu aruncat în tăcere. Vezi Tools.
Stare
Protocolul de sesiune e livrat parțial
Formatul de pe fir e un WebSocket care duce cadre PCM16 brute ca mesaje binare, plus un mic canal de control JSON, iar SDK-ul vorbește exact ce implementează deja transportul WebRTC al gateway-ului, nu un al doilea format inventat.
Implementate azi în gateway: start, dtmf, mark, stop, offer/answer/ice la intrare; format, clear, mark, stop la ieșire; PCM binar în ambele sensuri. Audio-ul și barge-in-ul funcționează.
Rămân de livrat evenimentele de conversație — ready, state, transcript, message, speech, tool_call, error, ended la ieșire, și mute, text, tool_result, auth la intrare. Evenimentele necunoscute sunt ignorate de ambele părți, prin design, deci SDK-ul rulează pe gateway-ul actual pentru audio și aprinde restul pe măsură ce apare.
Separat, POST /api/v1/client/calls nu e publicat de control plane. Schimbul de token e viu; pornirea unui apel din browser prin API nu e. Până atunci, dezvoltă pe gateway-ul mock livrat cu SDK-ul: pnpm --filter @callagent/web-sdk demo.
Urmărit pe Stadiul implementării.
Mai departe
- Referința Web SDK — toată suprafața de client.
- Widget — opțiunea fără build și atributele ei.
- Autentificare — chei, token-uri și origin-uri.