<?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: Krishna Soni</title>
    <description>The latest articles on DEV Community by Krishna Soni (@krishna_soni_82f9708a82f8).</description>
    <link>https://dev.to/krishna_soni_82f9708a82f8</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%2F4078832%2F195b7887-ff89-41c7-b05e-ba39d0423b5f.jpg</url>
      <title>DEV Community: Krishna Soni</title>
      <link>https://dev.to/krishna_soni_82f9708a82f8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/krishna_soni_82f9708a82f8"/>
    <language>en</language>
    <item>
      <title>Building MoneyMitra: A Financial Guidance Multilingual Voice AI Agent in 10 Days</title>
      <dc:creator>Krishna Soni</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:58:14 +0000</pubDate>
      <link>https://dev.to/krishna_soni_82f9708a82f8/building-moneymitra-a-financial-guidance-multilingual-voice-ai-agent-in-10-days-5gbc</link>
      <guid>https://dev.to/krishna_soni_82f9708a82f8/building-moneymitra-a-financial-guidance-multilingual-voice-ai-agent-in-10-days-5gbc</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Why I Built This&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;India has government financial schemes for almost everyone — loans for small shopkeepers, income support for&lt;br&gt;
farmers, pensions for the unorganized sector — but knowing which scheme you qualify for, and what documents&lt;br&gt;
you need, is its own small ordeal. It usually means a form, a queue, or a relative who “knows someone at the bank.”&lt;/p&gt;

&lt;p&gt;That gap is what **MoneyMitra **is for. It's a voice agent you can call or open in a browser and just talk to, in Hindi,&lt;br&gt;
English, or the Hindi-English mix most of us actually speak. Tell it your age, your occupation, your rough income&lt;br&gt;
— it tells you whether you qualify for something like PM Mudra Loan or PM Kisan, and exactly what documents to&lt;br&gt;
bring. No forms. No app to download. Just a conversation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I built MoneyMitra over 10 Days of Voice Agents&lt;/strong&gt; — &lt;strong&gt;VoiceForBharat&lt;/strong&gt; Edition, one capability a day, using &lt;strong&gt;Murf Falcon&lt;/strong&gt; for **speech **throughout. This post is the story of what got built, what quietly broke along the way, and what I'd&lt;br&gt;
tell someone starting the same challenge today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I chose the Financial Services track&lt;/strong&gt; because the problem — scheme discovery being harder than it should be — is one I've watched happen to people around me.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;What MoneyMitra Actually Does&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By the end of ten days, MoneyMitra could:&lt;/p&gt;

&lt;p&gt;• Hold a natural, code-mixed Hindi-English conversation in a real Indian voice (Murf Falcon)&lt;br&gt;
• Refuse to do things it shouldn't — never ask for an OTP, PIN, or account number; never promise a scheme&lt;br&gt;
approval&lt;br&gt;
• Recognize returning callers and pick up where the last conversation left off&lt;br&gt;
• Look up real eligibility rules and document checklists for five government schemes&lt;br&gt;
• Make outbound calls to remind eligible users about deadlines, with a proper compliance opening&lt;br&gt;
• Recognize when it's out of its depth (a fraud report, a decision it can't make) and hand the caller to a&lt;br&gt;
human, with consent&lt;br&gt;
• Track every call's outcome on a dashboard, so I could actually see whether the agent was working or just&lt;br&gt;
sounding like it was&lt;br&gt;
• Hand off scheme-specific questions to a second, specialist agent — Samer — with his own voice and a&lt;br&gt;
narrower, sharper job&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%2Fsr4jh3o0u6uyxfh8gktf.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%2Fsr4jh3o0u6uyxfh8gktf.png" alt=" " width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;🏗️  How the System Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The stack is the standard voice-agent shape, wired together with LiveKit:&lt;/p&gt;

&lt;p&gt;• STT — Deepgram, in multilingual mode, so it can pick up Hindi and English in the same sentence&lt;br&gt;
• LLM — Google Gemini, doing the reasoning and deciding which tool to call&lt;br&gt;
• TTS — Murf Falcon, giving each agent its Indian voice&lt;br&gt;
• Real-time transport — LiveKit, handling browser WebRTC and SIP for outbound calls&lt;br&gt;
• SQLite — for caller memory, escalation tickets, and call analytics&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%2Frq2f1rxito3eoozqn9gl.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%2Frq2f1rxito3eoozqn9gl.png" alt=" " width="461" height="587"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;🚀 Complete Day-by-Day Journey&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 1: Real-Time Audio Pipeline &amp;amp; Murf Falcon TTS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Configured LiveKit Agents SDK with browser WebRTC and SIP audio streaming.&lt;/p&gt;

&lt;p&gt;Wired Deepgram Nova-3 &lt;strong&gt;(model="nova-3", language="multi")&lt;/strong&gt; for multilingual speech recognition, and Murf Falcon TTS &lt;strong&gt;(hi-IN-anisha — female Indian Hindi-English voice)&lt;/strong&gt; for speech synthesis.&lt;/p&gt;

&lt;p&gt;Implemented Silero VAD prewarming via prewarm() so the agent starts listening with low latency instead of a cold-start delay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt; -&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofaivoiceagents-voiceforbharat-10daysofaivoiceagents-activity-7491196681603063809-Wtnk?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-1 video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 2: System Persona, Tone &amp;amp; Safety Guardrails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Defined the MoneyMitra identity — a clear, professional, empathetic Hindi-English (Hinglish) financial-guidance voice.&lt;/p&gt;

&lt;p&gt;Set hard safety guardrails: never ask for an &lt;strong&gt;OTP&lt;/strong&gt;, &lt;strong&gt;PIN&lt;/strong&gt;, or &lt;strong&gt;account number&lt;/strong&gt;; never promise scheme approval.&lt;/p&gt;

&lt;p&gt;Verified the agent could hold a code-mixed conversation and stay in character across multiple turns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt; -&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-voiceforbharat-activity-7491547200070623232-ByhV?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-2 video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 3: Financial-Advisor Frontend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built a custom UI &lt;strong&gt;(financial-avatar.tsx, agent-state-header.tsx, mic-permission-modal.tsx)&lt;/strong&gt; themed in trust-building emerald green and navy.&lt;/p&gt;

&lt;p&gt;Implemented all five agent states clearly: Ready, Connecting, Listening, Speaking, and Call Ended.&lt;/p&gt;

&lt;p&gt;Added a mic-permission-denied modal with browser-specific unblock instructions (Chrome, Safari, Edge, Firefox).&lt;br&gt;
&lt;strong&gt;Demo Video&lt;/strong&gt;-&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-voiceforbharat-activity-7491899659792293888-39kF?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-3&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%2F8k7256w57avwbpo6hh3p.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%2F8k7256w57avwbpo6hh3p.png" alt=" " width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 4: SQLite Persistent Memory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built caller memory storage &lt;strong&gt;(db.py)&lt;/strong&gt; with &lt;strong&gt;lookup_caller&lt;/strong&gt; and save_caller_info function tools.&lt;/p&gt;

&lt;p&gt;Consent rule: MoneyMitra only writes caller data to storage after explicit user_consent=True — declining means nothing is saved.&lt;/p&gt;

&lt;p&gt;Returning callers are greeted by name and the conversation continues from their last recorded topic.&lt;br&gt;
&lt;strong&gt;Demo video&lt;/strong&gt; - &lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-voiceforbharat-activity-7492231884886843393-jGiQ?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-4 video&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%2Fs7xeefz3qbvls7hvvrvs.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%2Fs7xeefz3qbvls7hvvrvs.png" alt=" " width="798" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 5: Government Scheme Eligibility Engine&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built** check_scheme_eligibility *&lt;em&gt;**(scheme_data.py)&lt;/em&gt;*, evaluating real eligibility and document checklists based on age, annual income, occupation, category, and requested loan amount for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PM Mudra Loan (Pradhan Mantri Mudra Yojana)&lt;br&gt;
PM Kisan Samman Nidhi&lt;br&gt;
PM SVANidhi&lt;br&gt;
Stand-Up India&lt;br&gt;
Atal Pension Yojana (APY)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added graceful failure handling — a timed-out or failed lookup produces a spoken explanation, not silence or an invented answer, and every response states the policy date the data is current as of.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Demo video *&lt;/em&gt;- &lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-10daysofvoiceagents-activity-7492574959756591104-65qt?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-5 video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 6: Outbound SIP Calling &amp;amp; Compliance Opening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrated outbound telephony over SIP **(via Linphone, in place of Twilio) **for reminder-style calls.&lt;/p&gt;

&lt;p&gt;Mandatory 2-sentence compliance opening: every outbound call states who's calling, why, and gives an immediate opt-out — &lt;strong&gt;"Agar aap aage se aisi reminder calls nahi chahte, toh aap abhi 'stop' bolein ya bol skate ki 'call mat karo'"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt; -&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-10daysofvoiceagents-activity-7492953844746776577-houP?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-6 video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 7: Human Escalation &amp;amp; Fraud Protocol&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built &lt;strong&gt;create_escalation&lt;/strong&gt; — creates a support ticket for fraud reports or decisions beyond the agent's authority, only after explicit caller consent.&lt;/p&gt;

&lt;p&gt;Generates secure ticket codes in the format &lt;strong&gt;ECW_XXXXXXXX&lt;/strong&gt;, with urgency ratings (HIGH for fraud), while excluding passwords, OTPs, PINs, and account numbers from the stored summary.&lt;/p&gt;

&lt;p&gt;Added &lt;strong&gt;opt_out_caller&lt;/strong&gt;, triggered by phrases like "&lt;strong&gt;stop&lt;/strong&gt;," "&lt;strong&gt;opt out&lt;/strong&gt;," or "&lt;strong&gt;don't call me&lt;/strong&gt;," recorded for future outbound-call suppression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt;-&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-10daysofvoiceagents-activity-7493317478270283777-wCPs?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-7 video&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%2Fgi4h6hnzmcbt7rxvktc3.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%2Fgi4h6hnzmcbt7rxvktc3.png" alt=" " width="799" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 8: Call Analytics Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Added a &lt;strong&gt;call_analytics&lt;/strong&gt; table and a dashboard tracking real-time Total Calls, Successful Calls, and Failed Calls.&lt;/p&gt;

&lt;p&gt;Defined success meaningfully — a completed eligibility check or created escalation, not just "&lt;strong&gt;the call didn't crash&lt;/strong&gt;."&lt;/p&gt;

&lt;p&gt;Real bug caught and fixed: calls were showing SUCCESS even when hung up on mid-sentence, because outcome tracking relied on crash/no-crash rather than actual goal completion. Fixed with an &lt;strong&gt;objective_achieved&lt;/strong&gt; flag that only flips true inside tools representing a real outcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt; -&lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-voiceforbharat-10daysofvoiceagents-activity-7493663006602625024-f-ff?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-8 video&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%2Flynkufkzvmplirmrhhil.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%2Flynkufkzvmplirmrhhil.png" alt=" " width="799" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔹 Day 9: Multi-Agent Handoff — "Samer"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Built a separate specialist agent,** SchemeSpecialist *&lt;em&gt;**(scheme_specialist.py)&lt;/em&gt;*, named Samer, scoped narrowly to scheme eligibility, benefits, and documents.&lt;/p&gt;

&lt;p&gt;Added &lt;strong&gt;transfer_to_scheme_specialist&lt;/strong&gt; — announces the handoff out loud and transfers the live conversation without asking the caller to repeat themselves.&lt;/p&gt;

&lt;p&gt;Dynamic voice swap: session TTS switches from MoneyMitra's hi-IN-anisha to Samer's distinct voice, so the handoff is audible, not just stated.&lt;br&gt;
Used a shared shared_state dictionary across both agents so Day 8's objective_achieved tracking stays correct regardless of which agent completes the task.&lt;/p&gt;

&lt;p&gt;Three real bugs caught and fixed: a constructor-ordering issue that left the specialist silent after handoff, a missing tts= parameter that meant the voice wasn't actually swapping, and a stray generate_reply() call left in the introduction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo video&lt;/strong&gt; - &lt;a href="https://www.linkedin.com/posts/krishna-soni-15075b341_10daysofvoiceagents-10daysofvoiceagents-murffalcon-activity-7494098476297977858-nc23?utm_source=share&amp;amp;utm_medium=member_desktop&amp;amp;rcm=ACoAAFW4BAwBMEUKetg7s7UrB9CntoVgv6mSovE" rel="noopener noreferrer"&gt;Day-9 video&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%2Fm37zjekrxa8pytixu4oq.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%2Fm37zjekrxa8pytixu4oq.png" alt=" " width="800" height="677"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;🐛 Real-World Challenges &amp;amp; Silent Bugs Solved&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🐞 Bug #1: Every call showed up as "successful" — even the ones I hung up on&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; Building the analytics dashboard, I wired up a try/finally block to record the call outcome when the room disconnected. My first instinct was: If nothing crashed, it's a success. I tested it by calling MoneyMitra, saying nothing useful, and hanging up mid-sentence. The dashboard still logged SUCCESS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Root Cause:&lt;/strong&gt; A failed call doesn't mean something broke on the server—it means the call never reached its goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; Shifted from checking "Did an exception happen?" to "Did the agent actually accomplish something?" Added an objective_achieved state flag that only flips to True inside tools that represent real outcomes (e.g., a completed eligibility check or a created escalation ticket). Cutting the call mid-question now correctly shows up as FAILED.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🐞 Bug #2: The specialist agent went completely silent after handoff&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; MoneyMitra would say "Connecting you to our specialist..." and then dead air. No introduction, no reply, and no error traceback pointing to the cause.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Root Cause:&lt;/strong&gt; In the specialist's &lt;strong&gt;init&lt;/strong&gt;, I was setting self.shared_state = shared_state before calling super().&lt;strong&gt;init&lt;/strong&gt;(...). LiveKit's Agent base class performs internal setup inside its constructor. Assigning attributes before that setup ran put the object into a broken state quietly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; Reordered the operations in the specialist's constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Before — silently broken
def __init__(self, shared_state):
    self.shared_state = shared_state
    super().__init__(instructions=PROMPT)

# After — fixed
def __init__(self, shared_state):
    super().__init__(instructions=PROMPT)
    self.shared_state = shared_state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;🐞 Bug #3: The specialist sounded exactly like the main agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Symptom:&lt;/strong&gt; Once Samer was actually speaking, he sounded identical to MoneyMitra—same voice, same tone. The entire point of a handoff is that it's audibly obvious something changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Root Cause:&lt;/strong&gt; I had added a distinct voice ID to the design plan, but omitted the tts= parameter in SchemeSpecialist.Agent.&lt;strong&gt;init&lt;/strong&gt;(). The sub-agent was silently inheriting the session's default main voice (hi-IN-anisha).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; Explicitly passed the specialist TTS instance in the constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;super().__init__(
    tts=murf.TTS(voice="hi-IN-samer", style="Conversational"),
    # ... other tools &amp;amp; configs
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;🗄️ Database Schemas (SQLite)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Located at backend/data/caller_memory.db:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Caller Profile Storage
CREATE TABLE caller_profiles (
    user_id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    language_preference TEXT,
    facts TEXT, -- JSON string (Sanitized)
    last_topic TEXT,
    last_interaction TEXT
);

-- Human Escalation Support Tickets
CREATE TABLE human_escalations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    ticket_code TEXT UNIQUE,
    user_id TEXT NOT NULL,
    caller_name TEXT NOT NULL,
    reason_category TEXT NOT NULL,
    what_happened TEXT NOT NULL,
    what_agent_checked TEXT,
    urgency TEXT,
    language TEXT,
    preferred_followup TEXT,
    status TEXT DEFAULT 'OPEN',
    created_at TEXT
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;⚡ How to Run MoneyMitra Locally&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Clone the Repository&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;git clone https://github.com/krishnaasoni/MoneyMitra-Voice-Agent.git
cd MoneyMitra-Voice-Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Create a .env file for your API keys and configuration.&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;# backend/.env.local
LIVEKIT_URL=
LIVEKIT_API_KEY=
LIVEKIT_API_SECRET=
MURF_API_KEY=
DEEPGRAM_API_KEY=
GOOGLE_API_KEY=

cd backend
uv sync
uv run dotenv -f .env.local run -- python src/agent.py start
cd frontend
pnpm install
pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Never commit your .env file to GitHub.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add it to .gitignore:&lt;/p&gt;

&lt;p&gt;Then install the dependencies and start the LiveKit agent according to the project's setup instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Run Startup Script&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;#powershell
.\start_app.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Bash
chmod +x start_app.sh
./start_app.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Open Web Apps&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Voice Agent UI:&lt;/strong&gt; &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human Escalations Portal:&lt;/strong&gt; &lt;a href="http://localhost:3000/escalations" rel="noopener noreferrer"&gt;http://localhost:3000/escalations&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analytics Dashboard:&lt;/strong&gt; &lt;a href="http://localhost:3000/analytics" rel="noopener noreferrer"&gt;http://localhost:3000/analytics&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🔮 What I'd Improve Next&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;*&lt;em&gt;MoneyMitra still has a lot of room to grow.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Some things I'd like to work on next are:&lt;/p&gt;

&lt;p&gt;1.More Indian languages beyond Hindi-English&lt;br&gt;
2.More specialist agents (beyond Samer)&lt;br&gt;
3.Better multilingual conversation handling&lt;br&gt;
4.Improved personalization for returning callers&lt;br&gt;
More advanced call analytics (failure-type breakdown, success rate, trends over time)&lt;br&gt;
5.Wider government-scheme coverage&lt;br&gt;
6.Better accessibility for low-literacy and low-bandwidth users&lt;br&gt;
7.Smarter follow-up workflows (like automatic callbacks after an escalation is resolved)&lt;br&gt;
8.A richer human-support dashboard&lt;br&gt;
9.More robust real-world integrations (payment status checks, live scheme-portal data instead of a local dataset)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;📚 What I Learned&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The biggest lesson I learned from this challenge is that building a voice agent isn't really about making an AI talk.&lt;br&gt;
The interesting engineering begins after that.&lt;br&gt;
You have to think about:&lt;/p&gt;

&lt;p&gt;What should the agent know?&lt;br&gt;
What should it remember?&lt;br&gt;
When should it use a tool?&lt;br&gt;
When should it stop?&lt;br&gt;
When should a human take over?&lt;br&gt;
When should another agent take over?&lt;br&gt;
How should context move between agents?&lt;br&gt;
How do we measure success?&lt;br&gt;
How do we protect user information?&lt;/p&gt;

&lt;p&gt;These questions completely changed how I think about voice AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Repository &amp;amp; Resources
&lt;/h2&gt;

&lt;p&gt;GitHub Repository: &lt;a href="https://github.com/krishnaasoni/murf-livekit-starter" rel="noopener noreferrer"&gt;git-hub link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Murf Falcon Documentation:&lt;a href="https://murf.ai/api/docs/text-to-speech-models/falcon-2" rel="noopener noreferrer"&gt; Falcon 2 TTS Docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LiveKit Agents Quickstart:&lt;a href="https://docs.livekit.io/agents/start/voice-ai/" rel="noopener noreferrer"&gt; LiveKit Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;❤️ What 10 Days Taught Me&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I started the challenge, I thought the hardest part would be getting an AI agent to speak.&lt;/p&gt;

&lt;p&gt;By Day 10, I realized:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice is only the beginning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The real challenge is building an agent that knows how to behave.&lt;/p&gt;

&lt;p&gt;An agent that can say:&lt;/p&gt;

&lt;p&gt;"I can help with that."&lt;/p&gt;

&lt;p&gt;But also knows when to say:&lt;/p&gt;

&lt;p&gt;"Let me connect you with Krishna, our specialist."&lt;/p&gt;

&lt;p&gt;And sometimes:&lt;/p&gt;

&lt;p&gt;"This needs human assistance."&lt;/p&gt;

&lt;p&gt;That's what I wanted FINORA AI to become.&lt;/p&gt;

&lt;p&gt;Not just an AI that talks.&lt;/p&gt;

&lt;p&gt;An AI that knows what to do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🌟 Acknowledgments&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A big thank you to &lt;a class="mentioned-user" href="https://dev.to/murf"&gt;@murf&lt;/a&gt; AI for hosting the 10 Days of Voice Agents — #VoiceForBharat Edition challenge!&lt;/p&gt;

&lt;h1&gt;
  
  
  VoiceForBharat #10DaysOfVoiceAgents #MurfAI #VoiceAI #GenerativeAI #AI #FinTech
&lt;/h1&gt;

&lt;p&gt;@MURFAI&lt;/p&gt;

&lt;p&gt;If you enjoyed reading this engineering breakdown, please give it a 💖 or 🦄 on DEV.to!&lt;/p&gt;

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