Quickstart

End-to-end examples for both session flows, including a 3-primitive stream-mode loop.

Two end-to-end examples: stream mode (deterministic, scripted) and full agent mode (LLM-driven).

Stream mode — the 3-primitive loop

joinRoomonUserTranscriptassistantSpeak. That’s the whole loop for a scripted deterministic voice experience.

import { joinRoom } from '@juspay/breeze-buddy-client-sdk';

// 1. Your backend provisions a Daily room (with execution_mode: DAILY_STREAM)
//    and hands you { roomUrl, token }. Join it:
const session = await joinRoom({ roomUrl, token });

// 2. Listen to what the user says:
session.on('transcript', (entry) => {
  if (entry.role === 'user' && entry.isComplete) {
    console.log('user said:', entry.text);
    // Decide what the assistant should say next…
  }
});

// 3. Make the assistant speak — deterministically, bypasses the LLM:
await session.assistantSpeak('Hello! How can I help you today?');

// Later
await session.close();

Why stream mode?

In 'stream' execution mode (wire DAILY_STREAM), the backend pipeline is STT → TTS with no LLM in the middle. session.assistantSpeak(text) sends text directly to TTS — useful for compliance disclosures, IVR prompts, agent handoff, and any case where the assistant must say exactly what you tell it to, unchanged.

Full agent mode — LLM-driven conversation

Let the SDK handle lead creation + WebRTC connect, and let the backend’s LLM drive the conversation.

import { BuddyClient } from '@juspay/breeze-buddy-client-sdk';

const client = new BuddyClient({
  auth: { token: 'your-jwt-token' },
  resellerId: 'my-reseller',
  merchantId: 'my-merchant'
});

const session = await client.startSession({
  templateId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
  payload: { customer_name: 'John', phone: '555-0100' },
  executionMode: 'production', // 'production' | 'test' | 'stream'
  on: {
    connected:    () => showCallUI(),
    transcript:   (entry) => renderBubble(entry),
    disconnected: () => showEndedScreen(),
    error:        (msg) => showError(msg)
  }
});

With await using (ES2024)

Modern engines support await using for automatic resource cleanup:

{
  await using session = await joinRoom({ roomUrl, token });
  session.on('transcript', (e) => {
    if (e.role === 'user') console.log(e.text);
  });
  await session.assistantSpeak('Hello.');
  // session.close() runs automatically when the block exits
}

Minimal React shell

import { useEffect, useRef, useState } from 'react';
import { joinRoom, type Session } from '@juspay/breeze-buddy-client-sdk';

function VoiceCall({ roomUrl, token }: { roomUrl: string; token: string }) {
  const sessionRef = useRef<Session | null>(null);
  const [transcripts, setTranscripts] = useState<string[]>([]);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      const session = await joinRoom({ roomUrl, token });
      if (cancelled) return void session.close();

      sessionRef.current = session;
      session.on('transcript', (entry) => {
        if (entry.role === 'user' && entry.isComplete) {
          setTranscripts((prev) => [...prev, entry.text]);
        }
      });
    })();

    return () => {
      cancelled = true;
      sessionRef.current?.close();
    };
  }, [roomUrl, token]);

  return (
    <div>
      <button onClick={() => sessionRef.current?.assistantSpeak('Please hold.')}>
        Say hold
      </button>
      {transcripts.map((t, i) => <div key={i}>{t}</div>)}
    </div>
  );
}
Was this helpful?