<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sakshyam Bhattarai</title>
    <description>The latest articles on DEV Community by Sakshyam Bhattarai (@sakshyambhttr).</description>
    <link>https://dev.to/sakshyambhttr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4078158%2Fbe83f1b0-172a-4263-9f9c-8446097d0e0f.jpg</url>
      <title>DEV Community: Sakshyam Bhattarai</title>
      <link>https://dev.to/sakshyambhttr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sakshyambhttr"/>
    <language>en</language>
    <item>
      <title>Building BolBuddy: From a Voice Agent to an Indian English Learning Companion in 10 Days</title>
      <dc:creator>Sakshyam Bhattarai</dc:creator>
      <pubDate>Fri, 14 Aug 2026 20:33:06 +0000</pubDate>
      <link>https://dev.to/sakshyambhttr/building-bolbuddy-from-a-voice-agent-to-an-indian-english-learning-companion-in-10-days-1b7m</link>
      <guid>https://dev.to/sakshyambhttr/building-bolbuddy-from-a-voice-agent-to-an-indian-english-learning-companion-in-10-days-1b7m</guid>
      <description>&lt;h2&gt;
  
  
  1. The Real-World Problem: The Indian Spoken English Paradox
&lt;/h2&gt;

&lt;p&gt;Across India, many students and early-career job seekers experience a specific linguistic barrier: &lt;strong&gt;they can read, write, and comprehend English grammar from textbooks, but struggle with conversational speaking.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In India's multilingual landscape, English operates as a key language for higher education and employment opportunities. However, the classroom environment often creates an asymmetry between passive comprehension and active spoken production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mv17prw5xmz4jvehe0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3mv17prw5xmz4jvehe0r.png" alt="Passive Active" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Context and Evidence
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Focus on Rote Literacy over Spoken Practice:&lt;/strong&gt; Field research from the &lt;em&gt;Annual Status of Education Report (ASER)&lt;/em&gt; conducted by the Pratham Education Foundation indicates that foundational English instruction across government and affordable private schools has historically emphasized reading short passages and writing answers rather than oral communication. English is frequently taught as an academic exam subject rather than as a communicative tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Foreign Language Speaking Anxiety (FLSA):&lt;/strong&gt; Academic studies by Horwitz et al and Indian curriculum analysis by NCERT highlight &lt;em&gt;communication apprehension&lt;/em&gt; and &lt;em&gt;fear of negative evaluation&lt;/em&gt; as major hurdles for learners transitioning from regional-medium education to English-speaking academic or workplace settings. When learners worry about peer judgment or grammatical errors, they avoid speaking, which slows down fluency development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Why Voice Matters:&lt;/strong&gt; Text-based chat applications allow users to hesitate, edit, delete, and avoid real-time formulation. Spoken fluency, however, requires spontaneous vocabulary retrieval, phonological articulation, and conversational rhythm. A voice interface provides a low-pressure practice environment where learners can make mistakes without fear of judgment.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  2. Responsible Product Positioning: Companion, Not Teacher Replacement
&lt;/h2&gt;

&lt;p&gt;A conversational AI agent in education must have clear boundaries. BolBuddy was engineered with the following positioning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Core Positioning:&lt;/strong&gt; BolBuddy is &lt;strong&gt;NOT&lt;/strong&gt; a certified teacher, an examiner, or a high-stakes evaluator. It is a 24/7 &lt;strong&gt;speaking practice companion&lt;/strong&gt; designed to help learners build confidence through supportive, conversational practice.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────┐     ┌───────────────────────────────┐
│     WHAT BOLBUDDY IS          │     │     WHAT BOLBUDDY IS NOT      │
├───────────────────────────────┤     ├───────────────────────────────┤
│ • A low-pressure practice tool│     │ • A replacement for teachers  │
│ • Natural Hinglish bridge     │     │ • A certified grading system  │
│ • Repetitive spoken exercises │     │ • An infallible tutor         │
│ • Verbal consent for memory   │     │ • An automated PII collector  │
│ • Human escalation on distress│     │ • A guaranteed outcome system │
└───────────────────────────────┘     └───────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Safety and Responsible AI Safeguards
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explicit Verbal Consent:&lt;/strong&gt; BolBuddy does not store learner names, goals, or recurring challenges without asking for verbal agreement first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Erasure ("Forget Me"):&lt;/strong&gt; If a learner asks to delete their data, the system requests confirmation and deletes their record from the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PII Redaction:&lt;/strong&gt; Before support escalation payloads are dispatched to external webhooks, phone numbers and email addresses are scrubbed using regular expression filters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Specialist Routing:&lt;/strong&gt; Rather than relying on a single prompt to handle every subject, the architecture delegates specialized tasks (such as mock interviews) to dedicated specialist agents with domain-specific instructions and distinct voices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. What Was Built: The 10-Day Evolution
&lt;/h2&gt;

&lt;p&gt;The project progressed through a modular voice architecture over the course of the 10-day challenge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────────────────────────────┐
│                                 BOLBUDDY BUILD ROADMAP                                  │
├───────────────────────┬─────────────────────────────────────────────────────────────────┤
│ Days 1–3: Core Engine │ Real-Time WebRTC Audio Loop, Multilingual Persona, Voice Orb UX │
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Days 4–5: Memory/Tools│ Contextual Memory (SQLite), Structured Spoken Exercises/Scoring │
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Day 6: Telephony      │ Scheduled Practice Calls (SIP / State Machine Integration)      │
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Day 7: Human Safety   │ Human Escalation Protocol (Discord Webhook &amp;amp; Reference ID)      │
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Day 8: Observability  │ Call Analytics Tracking &amp;amp; Real-Time Metrics Dashboard           │
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Day 9: Specialization │ Multi-Agent Handoff (BolBuddy → InterviewBuddy) with Murf Voices│
├───────────────────────┼─────────────────────────────────────────────────────────────────┤
│ Day 10: System Audit  │ Codebase Audit, Verified Telemetry &amp;amp; Practical Developer Guide  │
└───────────────────────┴─────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Technical Architecture
&lt;/h2&gt;

&lt;p&gt;BolBuddy runs as a full-stack system connecting a Next.js 15 frontend to a Python 3.12 LiveKit Agents backend over WebRTC and WebSockets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyq7c3r9b9yuoefopbsig.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyq7c3r9b9yuoefopbsig.jpg" alt="Full-stack real-time voice pipeline connecting the browser client to LiveKit WebRTC, Deepgram Nova-3 STT, Gemini/Groq LLM core, SQLite persistence, and Murf Falcon Indian TTS." width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  End-to-End Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffib06wwqfelr0w35db64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffib06wwqfelr0w35db64.png" alt="End to End Pipeline" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Transport:&lt;/strong&gt; LiveKit Cloud manages bidirectional WebRTC audio tracks with adaptive jitter buffers and low-latency packet recovery.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speech Recognition (STT):&lt;/strong&gt; &lt;strong&gt;Deepgram Nova-3&lt;/strong&gt; (&lt;code&gt;en-IN&lt;/code&gt; / multilingual) transcribes audio, handling Indian English accents and code-mixed Hinglish phrases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Core &amp;amp; LLM Orchestration:&lt;/strong&gt; Configured with multi-provider fallback (&lt;strong&gt;OpenRouter / NVIDIA NIM / Groq / Google Gemini&lt;/strong&gt;). For development and test automation, Groq (&lt;code&gt;llama-3.1-8b-instant&lt;/code&gt;) with multi-key rotation and Gemini provide fast token generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speech Synthesis (TTS):&lt;/strong&gt; &lt;strong&gt;Murf Falcon&lt;/strong&gt; streams synthesized speech frames over WebSockets.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BolBuddy (Main Agent):&lt;/strong&gt; Configured with Murf Falcon voice &lt;strong&gt;"Anisha"&lt;/strong&gt; (conversational Indian English female voice).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;InterviewBuddy (Specialist Agent):&lt;/strong&gt; Configured with Murf Falcon voice &lt;strong&gt;"Samar"&lt;/strong&gt; (professional Indian English male voice).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Layer &amp;amp; Observability:&lt;/strong&gt; Local SQLite database (&lt;code&gt;bolbuddy_memory.db&lt;/code&gt;) tracks 5 tables: &lt;code&gt;user_memory&lt;/code&gt;, &lt;code&gt;scheduled_calls&lt;/code&gt;, &lt;code&gt;daily_schedules&lt;/code&gt;, &lt;code&gt;escalations&lt;/code&gt;, and &lt;code&gt;call_analytics&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  5. Visual Evidence from the Build
&lt;/h2&gt;

&lt;p&gt;Here is how the system looks and behaves across core interaction touchpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Landing &amp;amp; Practice Goals
&lt;/h3&gt;

&lt;p&gt;The main interface allows learners to choose practice focus areas (Interview, College Viva, Everyday English, Presentation) and configure daily practice schedules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftn19nb7114l13dz80kg6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftn19nb7114l13dz80kg6.png" alt="BolBuddy welcome view featuring practice goal selection and daily scheduled outbound call preferences." width="800" height="735"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  B. Active Voice Conversation &amp;amp; State Feedback
&lt;/h3&gt;

&lt;p&gt;During an active session, the animated Voice Orb visualizer renders real-time state feedback (listening, thinking, speaking) alongside an active agent and voice indicator badge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzl0hlzrtuopaamq9yjnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzl0hlzrtuopaamq9yjnp.png" alt="Active session view displaying real-time audio connection state, Murf Falcon Anisha voice badge, and speaking indicator." width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  C. Human Support Escalation Drawer &amp;amp; Discord Alerts
&lt;/h3&gt;

&lt;p&gt;When a learner requests human assistance or expresses distress, BolBuddy opens a support ticket (&lt;code&gt;ESC-XXXX&lt;/code&gt;), displays it in the Human Help drawer, and dispatches a sanitized alert to academic counselors via Discord Webhooks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxo3jjhr6nus209w0l0jy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxo3jjhr6nus209w0l0jy.png" alt="The Human Help Requests drawer displaying tracked escalation tickets with status badges and counselor workflow actions." width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7siuci0qnp14pnclyk19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7siuci0qnp14pnclyk19.png" alt="Automated counselor alert delivered to Discord with sanitized learner data and reference ID ESC-1352" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  D. Production Call Analytics Dashboard
&lt;/h3&gt;

&lt;p&gt;The built-in analytics dashboard reads directly from the SQLite &lt;code&gt;call_analytics&lt;/code&gt; table, presenting real session counts, success rates, failure breakdowns, and duration logs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0bl22af5l4ic9kizmfdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0bl22af5l4ic9kizmfdd.png" alt="Real-time call analytics dashboard tracking 48 logged calls, 89.6% completion rate, and recent session history." width="649" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Verified Code Highlights
&lt;/h2&gt;

&lt;p&gt;Here are key implementation patterns from the repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 1: Murf Falcon TTS Factory with &lt;code&gt;NOT_GIVEN&lt;/code&gt; Sentinel
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Location: &lt;a href="//backend/src/agent.py"&gt;&lt;code&gt;backend/src/agent.py&lt;/code&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To give different agents distinct voices without duplicating the voice pipeline, a dynamic TTS factory is used. Passing &lt;code&gt;NOT_GIVEN&lt;/code&gt; ensures &lt;code&gt;Assistant&lt;/code&gt; inherits session TTS cleanly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_murf_tts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Anisha&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Conversation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;min_sentence_len&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;text_pacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;murf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Factory helper to instantiate Murf Falcon TTS with consistent streaming parameters.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;murf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TTS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SentenceTokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="n"&gt;min_sentence_len&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;min_sentence_len&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;text_pacing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text_pacing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;chat_ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatContext&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;tts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TTS&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Anisha&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SYSTEM_PROMPT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;chat_ctx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;chat_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tts&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tts&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;NOT_GIVEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Example 2: Context-Preserving Specialist Handoff
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Location: &lt;a href="//backend/src/agent.py"&gt;&lt;code&gt;backend/src/agent.py&lt;/code&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When handing off from BolBuddy to InterviewBuddy, the learner's prior conversation context is copied, while system prompts are stripped to avoid instruction bleeding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@function_tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transfer_to_interview_buddy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
  &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Transfer the learner to InterviewBuddy for job interview preparation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
  &lt;span class="n"&gt;copied_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exclude_instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_ctx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat_ctx&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;interview_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InterviewBuddy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;chat_ctx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;copied_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Samar&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;interview_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connecting you with InterviewBuddy now for focused interview practice.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Example 3: Multi-Key Groq Manager for Rate-Limit Resilience
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Location: &lt;a href="//backend/src/groq_key_manager.py"&gt;&lt;code&gt;backend/src/groq_key_manager.py&lt;/code&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To mitigate API rate limits during automated testing and high-turn sessions, a round-robin key manager rotates across configured backup keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GroqKeyManager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_load_keys_from_env&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed_keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_active_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No Groq API keys configured.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mark_key_failed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;failed_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed_keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failed_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current_index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Example 4: PII Redaction for Support Escalations
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Location: &lt;a href="//backend/src/escalation_tools.py"&gt;&lt;code&gt;backend/src/escalation_tools.py&lt;/code&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When support escalation is triggered, phone numbers and email addresses are redacted before the payload is dispatched to external webhooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scrub_pii&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Redact phone numbers, emails, and sensitive identifiers.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\+?\d[\d\s-]{8,14}\d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[REDACTED_PHONE]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[REDACTED_EMAIL]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Performance &amp;amp; Development Telemetry
&lt;/h2&gt;

&lt;p&gt;The following metrics were extracted directly from the project's development database (&lt;code&gt;backend/data/bolbuddy_memory.db&lt;/code&gt;) and automated test logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────────────────────────┐
│                      DEVELOPMENT &amp;amp; TEST TELEMETRY                           │
├───────────────────────────────────┬─────────────────────────────────────────┤
│ Total Recorded Calls in DB        │ 48 Browser Sessions (Dev/Test Activity) │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Successful Calls                  │ 43 (89.58% of recorded dev sessions)    │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Incomplete / Failed Calls         │ 5 (10.42% — Reason: incomplete_exercise)│
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Completed Activities Logged       │ 27 Spoken Practice Exercises            │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Escalation Tickets Logged         │ 16 Total (12 OPEN, 4 RESOLVED in dev)   │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Stored Memory Records             │ 34 Records in user_memory               │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Scheduled Call Logs               │ 24 Records in scheduled_calls           │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Measured LLM Time-To-First-Token  │ 330ms – 440ms (Groq / Gemini)           │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Observed End-to-End Turnaround    │ ~500ms – 750ms in browser testing       │
├───────────────────────────────────┼─────────────────────────────────────────┤
│ Automated Unit &amp;amp; Integration Tests│ 77 Passing Tests                        │
└───────────────────────────────────┴─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Data Context Note:&lt;/strong&gt; These database records represent development sessions, manual browser interactions, and automated test runs accumulated during the challenge. They reflect internal development activity rather than external consumer deployment.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  8. Hard Technical Challenges &amp;amp; Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Here are the primary technical issues encountered during development and how they were resolved.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The LiveKit &lt;code&gt;NOT_GIVEN&lt;/code&gt; Sentinel Issue
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Subclassing &lt;code&gt;Agent&lt;/code&gt; with &lt;code&gt;tts=None&lt;/code&gt; in &lt;code&gt;Assistant&lt;/code&gt; caused LiveKit to raise &lt;code&gt;RuntimeError: 'tts_node' called but no TTS node is available&lt;/code&gt; during speech output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; In LiveKit Agents SDK, &lt;code&gt;Agent&lt;/code&gt; uses &lt;code&gt;NOT_GIVEN&lt;/code&gt; as the default sentinel to inherit the session-level TTS. Passing &lt;code&gt;None&lt;/code&gt; explicitly disabled the TTS node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Updated constructors to pass &lt;code&gt;tts if tts is not None else NOT_GIVEN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Inspect framework-level sentinel objects (&lt;code&gt;NOT_GIVEN&lt;/code&gt;) when subclassing agent classes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Next.js 15 React Server Component (RSC) Boundary Crash
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Adding a custom &lt;code&gt;useActiveAgent&lt;/code&gt; hook resulted in &lt;code&gt;Error: Could not find the module ... in the React Client Manifest&lt;/code&gt; and &lt;code&gt;TypeError: __webpack_modules__[moduleId] is not a function&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; The hook file omitted the &lt;code&gt;'use client';&lt;/code&gt; directive. In Next.js 15 App Router, hooks utilizing &lt;code&gt;useState&lt;/code&gt; or &lt;code&gt;useEffect&lt;/code&gt; must explicitly declare client boundaries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Added &lt;code&gt;'use client';&lt;/code&gt; at the top of &lt;code&gt;frontend/hooks/useActiveAgent.ts&lt;/code&gt; and rebuilt with &lt;code&gt;pnpm build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Every custom hook that uses React lifecycle state in Next.js App Router must include the &lt;code&gt;'use client';&lt;/code&gt; directive.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Latency in Multi-Turn Specialist Handoffs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; Transferring from BolBuddy to InterviewBuddy previously took multiple conversational turns (&lt;em&gt;Ask permission&lt;/em&gt; $\rightarrow$ &lt;em&gt;User confirmation&lt;/em&gt; $\rightarrow$ &lt;em&gt;Transfer&lt;/em&gt;), making the transition feel delayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; Prompt instructions required confirmation for all mentions of interviews, even when the user explicitly asked for immediate practice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Updated prompt rules so that when a user explicitly requests interview practice (&lt;em&gt;"I have an interview next week and want to practice"&lt;/em&gt;), BolBuddy triggers &lt;code&gt;transfer_to_interview_buddy&lt;/code&gt; in the same turn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lesson:&lt;/strong&gt; Reserve multi-step verbal confirmation for destructive operations (e.g. data deletion); routing to specialized skills should happen promptly upon explicit intent.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Architectural Design Decisions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Decision 1: Single Unified Voice Pipeline vs Multi-Session Orchestration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Options Considered:&lt;/strong&gt; Creating a separate WebRTC room/session for InterviewBuddy vs swapping agent state within the existing session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choice:&lt;/strong&gt; Swapped agent instances within the active &lt;code&gt;AgentSession&lt;/code&gt; using LiveKit's native &lt;code&gt;AgentHandoffEvent&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tradeoff:&lt;/strong&gt; Avoids WebRTC reconnection delay and audio track disruption, keeping the transition within ~400ms without page reloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Decision 2: Local SQLite vs Cloud Vector Database for Memory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Options Considered:&lt;/strong&gt; Pinecone / cloud vector database vs local SQLite table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choice:&lt;/strong&gt; Local SQLite database (&lt;code&gt;bolbuddy_memory.db&lt;/code&gt;) with async memory prefetching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tradeoff:&lt;/strong&gt; Local key-value and summary lookups complete in &amp;lt;5ms without external network latency or infrastructure dependencies.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  10. Practical Step-by-Step Build Guide
&lt;/h2&gt;

&lt;p&gt;To set up and run the BolBuddy repository locally:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.10+&lt;/strong&gt; with &lt;code&gt;uv&lt;/code&gt; package manager&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js 18+&lt;/strong&gt; with &lt;code&gt;pnpm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LiveKit Cloud Project&lt;/strong&gt; (URL, API Key, API Secret from &lt;a href="https://cloud.livekit.io" rel="noopener noreferrer"&gt;cloud.livekit.io&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Murf AI API Key&lt;/strong&gt; (&lt;a href="https://murf.ai/api" rel="noopener noreferrer"&gt;murf.ai/api&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deepgram API Key&lt;/strong&gt; (&lt;a href="https://console.deepgram.com" rel="noopener noreferrer"&gt;console.deepgram.com&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Gemini API Key&lt;/strong&gt; or &lt;strong&gt;Groq API Key&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 1: Clone and Configure Environment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/sakshyambhttr-cyber/10_days_voice_agent.git
&lt;span class="nb"&gt;cd &lt;/span&gt;10_days_voice_agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Backend Configuration (&lt;code&gt;backend/.env.local&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret

MURF_API_KEY=your_murf_api_key
DEEPGRAM_API_KEY=your_deepgram_api_key
GOOGLE_API_KEY=your_gemini_api_key
GROQ_API_KEY=your_groq_api_key

DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/your_webhook_url
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Frontend Configuration (&lt;code&gt;frontend/.env.local&lt;/code&gt;):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Security Note:&lt;/strong&gt; Never commit &lt;code&gt;.env.local&lt;/code&gt; files, webhook URLs, or private database files to version control.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Step 2: Start the System
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Using the Startup Scripts:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Windows:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\start_app.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;macOS / Linux:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./start_app.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Manual Startup:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Terminal 1: Backend&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;backend
uv &lt;span class="nb"&gt;sync
&lt;/span&gt;uv run python src/agent.py dev

&lt;span class="c"&gt;# Terminal 2: Frontend&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:3000&lt;/code&gt; in a browser and click &lt;strong&gt;🎙 Talk to BolBuddy&lt;/strong&gt; to start a voice session.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Run the Test Suite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Backend unit &amp;amp; integration tests&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;backend
uv run pytest tests/test_analytics.py tests/test_escalation.py tests/test_memory_db.py tests/test_handoff.py &lt;span class="nt"&gt;-k&lt;/span&gt; test_specialist_murf_voice_configuration &lt;span class="nt"&gt;-v&lt;/span&gt;

&lt;span class="c"&gt;# Frontend lint &amp;amp; build check&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../frontend
pnpm lint
pnpm build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11. Practical Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: Audio Playback Fails on Initial Page Load
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; Modern browsers block autoplay audio until a user interaction event occurs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; The frontend uses an explicit Start Audio button (&lt;code&gt;StartAudioButton&lt;/code&gt;) to ensure an audio context is initialized before streaming starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Issue 2: Discord Webhook Times Out
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cause:&lt;/strong&gt; Network egress latency or invalid webhook URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; &lt;code&gt;escalation_tools.py&lt;/code&gt; wraps webhook requests in a non-blocking background task with a 5-second timeout, ensuring the voice dialogue continues even if the webhook call fails.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  12. Planned Improvements
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Phoneme-Level Pronunciation Feedback:&lt;/strong&gt; Integrating visual waveform feedback in the UI to display specific syllable stress differences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Additional Regional Dialect Support:&lt;/strong&gt; Expanding Indian English regional voice options (e.g. Tamil English, Bengali English) through Murf's regional voice catalog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Telephony Carrier Integration:&lt;/strong&gt; Completing live PSTN carrier trunking via Twilio or Telnyx SIP endpoints for automated outbound daily phone practice calls.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  13. References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pratham Education Foundation (2023).&lt;/strong&gt; &lt;em&gt;Annual Status of Education Report (Rural) 2023: Beyond Basics.&lt;/em&gt; New Delhi: ASER Centre. Available at: &lt;a href="https://www.asercentre.org" rel="noopener noreferrer"&gt;https://www.asercentre.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Horwitz, E. K., Horwitz, M. B., &amp;amp; Cope, J. (1986).&lt;/strong&gt; Foreign language classroom anxiety. &lt;em&gt;The Modern Language Journal&lt;/em&gt;, 70(2), 125-132.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;National Council of Educational Research and Training (NCERT) (2020).&lt;/strong&gt; &lt;em&gt;Position Paper on the Teaching of English.&lt;/em&gt; National Curriculum Framework, Ministry of Education, Government of India.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LiveKit Agents Framework Documentation (2026).&lt;/strong&gt; &lt;em&gt;Real-Time Multimodal Voice Agent Framework.&lt;/em&gt; &lt;a href="https://docs.livekit.io/agents" rel="noopener noreferrer"&gt;https://docs.livekit.io/agents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Murf AI Falcon Streaming API (2026).&lt;/strong&gt; &lt;em&gt;Ultra Low-Latency Text-to-Speech Engine for Conversational AI.&lt;/em&gt; &lt;a href="https://murf.ai/api/docs" rel="noopener noreferrer"&gt;https://murf.ai/api/docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>voiceai</category>
    </item>
  </channel>
</rss>
