← All Posts Technical

Enabling Agentforce with Sarvam for Indian Languages in Voice Channel

A real-time outbound voice channel for any Agentforce agent - Hindi, Marathi, Gujarati, Kannada, Tamil, Telugu (and 5 more) - at sub-4-second turn latency. Built as a proof of concept by a Salesforce AI solution engineer with Claude Code as the coding partner. This post is for engineers, SEs, partners and customers who want to know how, and for anyone who needs to know whether it’s worth doing.


TL;DR

If you’re a Salesforce customer running Agentforce in chat today, you already have a brain - topics, actions, workflow, guardrails, the agent your team has been tuning for months. What you don’t have is a way to put that brain on an outbound phone call to someone whose first language is Marathi or Tamil.

Native Agentforce Voice exists and is the right answer for inbound, English+Hindi first scenarios. For outbound calls in regional Indian languages, on top of an existing Agentforce agent, with the customer’s existing telephony - there’s a gap. This proof of concept fills it.

The stack: a thin Node.js bridge connects a telephony provider (Twilio in this PoC, swappable with Exotel, Ozonetel, Plivo, Tata Tele) to Sarvam AI for Indian-language speech, with Salesforce Agentforce Agent API as the reasoning brain. One Week, ~1,500 lines of bridge code, 11 languages supported. Works on top of any existing Agentforce agent without changing it.

What this isn’t: a productized SKU. A replacement for native Agentforce Voice. A reason to skip the platform.

The rest of this post is how it works and why each piece matters.


What The User Experiences

The phone rings. The DSR picks up. A natural Indian voice asks, in Hindi:

“आप किस भाषा में बात करना चाहेंगे?” (Which language would you like to speak?)

The DSR says “मराठी”. A confirmation clip plays in Marathi. The agent then greets the DSR by name in Marathi, briefs them on today’s three shops, takes an order verbally, logs a complaint as a Case, answers a Gold Tier policy question, and says goodbye. Total call: ~80 seconds.

The Salesforce side records: 1 CallSession__c with the full transcript, 2 records (one order, one service request), all linked to the right RetailShop__c records. Downstream Flows fire. Queue routing kicks in. SLA timers start. The Agentforce agent - the actual reasoning brain - only ever speaks Hindi. The bridge handles translation in and out so the user experiences a native Marathi conversation.

A live observability dashboard captures everything in real time during the call - every utterance, every translation hop with millisecond latency, every TTS render, every echo-suppressed false positive. 6.7s average turn latency across 17 turns, including the slower Marathi turns where translation and a longer agent reply combined.


The Architecture

┌───────────────────────────────────────────────────────────────┐
│  Trigger UI (React or Salesforce Lightning)                   │
└────────────────────────┬──────────────────────────────────────┘
                         │ POST /calls/start

┌───────────────────────────────────────────────────────────────┐
│  Node.js Bridge (~1,500 LOC)                                  │
│  • Telephony WebSocket (Twilio Media Streams)                 │
│  • SOQL context pre-fetch from Salesforce                     │
│  • Sarvam STT WebSocket (saaras:v3)                           │
│  • Sarvam Translate REST (~300ms p50)                         │
│  • Sarvam TTS REST (bulbul:v2, native 8kHz)                   │
│  • Agentforce Agent API HTTPS + SSE streaming                 │
└──┬─────────────────────────────────────────────────────────┬──┘
   │ μ-law 8kHz                                              │ HTTPS
   ▼                                                          ▼
┌──────────┐    audio in    ┌──────────────────┐  text  ┌──────────────┐
│ Twilio   │ ─────────────► │  Sarvam STT      │ ─────► │  Salesforce  │
│ Exotel   │                │  Sarvam Translate│        │  Agentforce  │
│ Ozonetel │ ◄───────────── │  Sarvam TTS      │ ◄───── │  Agent API   │
│ Plivo    │   audio out    └──────────────────┘  reply │  Atlas__     │
│ Tata Tele│                                            │  VoiceAgent  │
└──────────┘                                            └──────┬───────┘
                                                               │ Apex

                                                 ┌──────────────────────┐
                                                 │  Salesforce CRM      │
                                                 │  • DSR · Shop        │
                                                 │  • Scheme · Case     │
                                                 │  • CallSession__c    │
                                                 │  + Flows + queues    │
                                                 │  + validation rules  │
                                                 └──────────────────────┘

Three things matter about this architecture:

  1. The bridge is content-agnostic. It contains zero domain logic about the use case. It doesn’t know what a DSR is, doesn’t know about kirana shops, doesn’t know about schemes. It just orchestrates audio I/O and the Agentforce session lifecycle. The same bridge can voice-enable any Agentforce agent.

  2. All business logic lives in Salesforce. Topics, Apex actions, validation rules, Flows, queue routing, sharing rules, permission sets - all enforced natively. The voice channel inherits everything that already runs there.

  3. Telephony is swappable. The Twilio interface is a standard WebSocket media stream protocol. Exotel, Ozonetel, Plivo, Tata Tele all expose equivalent interfaces. For most Indian customers, the deal-killer with native Agentforce Voice is “we’d have to switch our telephony provider.” This bridge meets them where they are.


Why Salesforce as the Brain

For an enterprise running Salesforce, putting the reasoning brain on Agentforce is the structurally correct choice - not a vendor preference. Six concrete reasons:

WhatWhy it matters
Data model already thereDSR, RetailShop, Scheme, CheckIn, CallSession - same records the rest of the org sees
Business logic already thereApex, Flows, validation rules, before-insert triggers - fire automatically when the agent inserts a Case
Permissions already thereFLS, sharing rules, role hierarchy, profile access - agent runs as Einstein Agent User with a permission set
Workflows already thereQueue routing, SLA timers, escalation paths - voice-originated Cases inherit the full lifecycle
Chat agent already existsTopics, guardrails, Apex actions - already tuned for chat. Voice adds a channel, not a parallel agent
Improvements compoundTune the brain once, benefit everywhere - chat, voice, WhatsApp, kiosk

This is the Headless 360 vision Salesforce articulated at TDX 2026 - Agentforce as a reasoning brain that any experience layer can call. This PoC is one application of that vision, focused on outbound voice in Indian languages.

The alternative - calling a raw LLM API and writing your own prompts - means rebuilding the data model, the business logic, the permissions, the workflows, the audit trail. For most enterprise scenarios, that’s a year of engineering to recreate what’s already on the platform. The commercial implication is direct: building voice on top of Agentforce drives Agentforce API + Data Cloud consumption and makes the whole platform stickier. Building it on raw LLMs commoditizes everything.


Why Bother With The Engineering Depth?

The next half of this post gets into the architectural decisions that made this work - planner choice, audio sample rates, latency budgets, translation glossaries. If you’re a business reader, here’s why these matter to you:

Voice AI fails commercially when it sounds robotic, when it pauses too long, when it mishears the user, when it says “Gold Tier” wrong in Tamil. The engineering decisions below are the difference between a demo that wins a customer over and a demo that gets polite nods. Each one was a real iteration. Each one is reusable for any voice channel built on the same pattern.


The Latency Budget

Voice AI lives or dies on latency. A 6-second pause feels broken. A 2-second pause feels alive. We set a hard target of <1.5s end-of-speech to start-of-reply audio for the Phase 0.5 latency spike, knowing the floor would be set by Agentforce reply time. Measured per-turn breakdown in the final build:

ComponentLatencyNotes
STT batch + transcript300–500ms200ms audio batch + ~150ms inference
Translate (regional only)300msOne per direction; 600ms round-trip
Agentforce reasoning (no Apex)2.0–2.5sAtlas__VoiceAgent planner
Agentforce reasoning (with Apex DML)4–6sCase insert + dependent SOQL
Sarvam TTS synthesis0.8–1.2sbulbul:v2 REST, full reply, 8kHz native
Network + Twilio buffering200–400msμ-law media stream RTT

A typical Hindi turn that doesn’t trigger an Apex action: ~3.3s end-to-end. Marathi turn with translation but no Apex: ~3.9s. A turn that logs an order (Apex DML inside): ~6s. Five engineering decisions got this from the 8s+ first version down to current numbers.

Business takeaway: a 3.3s Hindi turn feels like a fast human responding. A 6s Marathi turn with Apex feels like calling a call center. Both are usable; the gap between them is exactly where engineering effort pays off.


Five Engineering Decisions That Made The Difference

1. The Right Agentforce Planner

Agentforce supports multiple planner types under the hood. The org default is Atlas__ConcurrentMultiAgentOrchestration - designed for complex multi-agent flows with parallel topic evaluation. Great for branching chat. Wrong for real-time voice.

Atlas__VoiceAgent is the planner specifically tuned for voice: shorter reasoning steps, faster first-token latency, designed for interrupt-driven conversations. Switching planners dropped average turn latency from 3.7s to 2.2s - a 40% improvement.

There’s a gotcha. Every sf agent publish resets PlannerType back to the org default. The fix is a Tooling API patch right after publish:

sf api request rest \
  "/services/data/v66.0/tooling/sobjects/GenAiPlannerDefinition/<v_ID>" \
  --method PATCH \
  --body '{"PlannerType":"Atlas__VoiceAgent"}'

In production CI/CD this should be wrapped into the deploy pipeline as a post-publish step.

Business takeaway: a 1.5-second improvement per turn is the difference between a phone call that feels alive and one where the user starts wondering if the line dropped. On a 6-turn call that’s nearly 10 seconds of saved silence.

2. SOQL Context Pre-Fetch

The Agentforce Agent API rejects mutable variable seeding at session creation time. You cannot do startSession({variables: {dsrId: "..."}}) - it throws InternalVariableMutationAttemptException. The session starts variable-bare, and any context the agent needs has to come from an Apex action mid-conversation. Each Apex round-trip costs 4-5 seconds.

The workaround: pre-fetch all required context via SOQL before the Agentforce session starts, then inject it as the first user message of the session. The agent reads it like a briefing note and treats every subsequent turn as having that context already in scope.

const contextMsg = `DSR context:
name="${dsr.name}", region="${dsr.region}", dsrId="${dsrId}"

Today's shops (use exact IDs when logging orders):
${shopsWithIds.map(s => `  - "${s.name}" (type: ${s.type}, id: ${s.id})`).join("\n")}

Active schemes for ${dsr.region}:
${schemes.map(s => `  - ${s.shopType}: "${s.name}" - ${s.pitch}`).join("\n")}

Policy facts: <tier benefits embedded here>`;

This priming message fires silently in the background while the user listens to the greeting - so its 2-3 second cost is hidden. By the time the user asks their first real question, the agent already has full context. Scheme queries no longer trigger an Apex round-trip mid-conversation. Saves 4-5 seconds per scheme turn.

Business takeaway: this pattern is reusable for any Agentforce session - user profile, current case, account history. Once an enterprise has it, every voice use case starts faster, and chat agents add a voice channel in days instead of quarters.

3. Native 8kHz Audio From The Speech Vendor

Telephony is μ-law 8kHz. The first version of the bridge asked Sarvam TTS for 22050Hz output and downsampled to 8kHz client-side with an anti-aliasing filter. The audio sounded muffled - like talking through a pillow. We assumed it was the phone line. It wasn’t.

Sarvam has a separate 8kHz-trained pipeline. Setting speech_sample_rate=8000 in the request gives crisp, native 8kHz output. Client-side resampling against a model trained for 22kHz is always going to lose information.

body: JSON.stringify({
  inputs: [text],
  target_language_code: "hi-IN",
  speaker: "abhilash",
  model: "bulbul:v2",
  speech_sample_rate: 8000,    // native 8kHz - no resampling
  pace: 1.1,                   // slightly faster - natural for telephony
  temperature: 0.4,            // low variance, IVR-style consistency
}),

A separate gotcha: Sarvam’s audio_format=mulaw parameter returns PCM16 wrapped in a WAV envelope with the format field claiming μ-law. Twilio rejected it outright. The fix was to strip the WAV header and run a standard ITU-T G.711 μ-law encoder - about 10 lines of bit math. For STT (Sarvam saaras:v3 requires 16kHz), the 8kHz incoming audio is upsampled with linear interpolation between adjacent samples, not sample duplication. Sample duplication produces a staircase waveform that confuses speech recognition models.

Business takeaway: audio quality is what makes voice AI feel like a person versus an IVR. Customers will tell you within 30 seconds of a demo whether your voice sounds robotic - there’s no recovering from that first impression.

4. Buffer The Full Reply Before TTS

Agentforce streams its reply word-by-word over Server-Sent Events. The temptation is to start TTS on the first chunk for “streaming-like” responsiveness. The result sounds like a robot - every word with its own intonation, no flow, jarring pauses between syllables.

Sarvam TTS is REST-only for stable usage; their WebSocket TTS still has rough edges (returned 422 Input parameters has to be a valid dictionary on every message format we tried). The right pattern is to accumulate all SSE chunks until the agent emits EndOfTurn, then make one TTS call with the full reply text:

let fullReply = "";
await agentforce.sendMessage(sessionId, userText, (chunk) => {
  fullReply += chunk;  // accumulate, don't speak yet
});
// Single synthesis call for the entire reply
await tts.speak(fullReply, sessionLanguage);

The synthesis takes ~1 second for a typical 2-sentence reply. The result sounds like a person talking, not a glitchy mashup. Wall-clock latency goes up by ~1s vs streaming-per-chunk; perceived quality goes up dramatically more.

Business takeaway: end users are tolerant of a one-second delay before a reply starts. They are not tolerant of a reply that sounds like it’s been chopped into pieces and stitched back together. Fluency wins over speed in voice.

5. Perceived-Latency Engineering

Even with all the above optimizations, 2.2 seconds of silence between question and answer feels long. The fix isn’t to reduce wall-clock latency further - it’s to fill the silence so the perceived latency drops.

Three layers of audio play in sequence during agent reasoning:

  1. Spoken filler clip (~600ms, language-specific, pre-baked offline): “एक सेकंड…” / “एक क्षण…” / “बघतो…”. Fires the moment STT final arrives.
  2. Looping marimba tune (procedurally generated, ~5s loop, gentle pentatonic): plays while Agentforce is still thinking past the filler clip.
  3. Hard cutoff: the moment Agentforce returns text, sendClear() is called on Twilio (which flushes its outbound buffer), and the real reply starts instantly. No awkward overlap.
private startTuneLoop(): void {
  const tune = readFileSync("assets/filler-tune.ulaw");
  const tuneDurationMs = tune.length / 8;
  this.state.tuneAborted = false;

  // Safety cap: never loop more than 15s
  const safetyStop = setTimeout(() => this.stopTune(), 15000);

  const loop = () => {
    if (this.state.tuneAborted) { clearTimeout(safetyStop); return; }
    this.sendAudio(tune);
    setTimeout(loop, tuneDurationMs);
  };
  loop();
}

The user hears activity, never silence. Wall-clock latency is unchanged; perceived latency drops dramatically.

Business takeaway: the user experience floor for voice AI is “doesn’t feel broken.” Filler audio is what gets us there. It’s also the cheapest engineering improvement on this list - pre-baked clips and a tune file, no API costs, no models, no inference. Disproportionate impact for the effort.


Multilingual: One Brain, Eleven Languages

Agentforce is tuned for Hindi (or whatever language your existing agent was trained on). The user might speak Marathi, Tamil, or Kannada. The bridge handles bidirectional translation so the agent stays monolingual:

DSR speaks Marathi
  → Sarvam STT (mr-IN, saaras:v3) → "100 unit book kara"
  → Sarvam Translate (mr → hi, ~300ms) → "100 यूनिट बुक करो"
  → Agentforce Agent API (Hindi)        → "100 यूनिट? पुष्टि करें।"
  → Sarvam Translate (hi → mr, ~300ms) → "100 युनिट? पुष्टी करा."
  → Sarvam TTS (mr-IN, abhilash)        → Marathi audio
  → DSR hears Marathi

Hindi is the zero-overhead path - no translation calls. For other Indian languages, ~600ms of round-trip translation is added per turn but hidden under the spoken filler clip, so perceived latency is unchanged.

The user picks the language during the call, not in the trigger UI. The agent asks at the start, the user replies in any language, and a keyword matcher (covering native script, Devanagari, and English transliteration) detects the choice. saaras:v3’s auto-detect is used as a fallback. The STT WebSocket then reconnects mid-call to the chosen language; a small ring buffer holds incoming audio frames during the ~200ms reconnect gap so nothing is lost.

One technical decision worth flagging: proper nouns get corrupted by translation if you don’t protect them. Tested case - “Gold Tier में 100 रुपए पर 1.5 अंक मिलते हैं” → Kannada. Sarvam returned: “ಚಿನ್ನದ ದರ್ಜೆ: 100 ರೂಪಾಯಿಗಳಿಗೆ 100 ಅಂಕಗಳು” - the “1.5” became “100.” Brand names, scheme names, tier names, decimal numbers all at risk. The fix is placeholder substitution: swap protected terms with tokens before translation, restore them after. Fifteen UCPL-specific terms protected. “Gold Tier” stays intact across all five demo languages.

Business takeaway: this is what makes regional language voice viable for enterprise use. Without glossary protection, the agent says “100 points” instead of “1.5 points,” and the customer hears “Sherma Karna” instead of “Sharma Kirana.” That’s the level of detail that determines whether an Indian-language voice product is shippable.


Echo Suppression and Barge-In

Two real-world voice problems that have nothing to do with AI but everything to do with whether the experience feels human:

Echo suppression. When TTS audio plays through the phone, the DSR’s microphone picks up the agent’s own voice. STT then transcribes the agent’s voice as if the DSR said it - creating an infinite loop where the agent talks to itself. Fix: track a muteUntil timestamp. While TTS is playing plus an 800ms cooldown, discard all STT finals.

Barge-in with grace period. If the DSR starts talking while the agent is speaking, you want to stop the agent immediately. But if the DSR coughs or makes a brief noise, you don’t want to abort. Fix: 300ms grace period. If speech starts within the first 300ms of TTS, wait 400ms more. If the speech ends quickly (cough), cancel the abort. If it continues (real interrupt), abort TTS, send 60ms of silence to avoid a click/pop, and start listening.

Both are unglamorous. Both make the difference between “feels human” and “feels broken.”


What This Took To Build

About One Week from blank repo to a working multilingual demo. ~1,500 lines of Node.js bridge code. Salesforce-side: 5 custom objects, 6 Apex invocable actions, 1 agent with 8 topics, 1 permission set.

The build wasn’t linear. It went through phased iterations - Phase 0 to Phase 6 - each one cracking a different problem. Phase 0.5 was a deliberate latency spike: place one outbound call, loop audio through Sarvam STT and TTS with a fake Agentforce, measure end-of-speech to first-audio-out. The gate was <1.5s. We hit 651ms / 834ms / 902ms p50. That early measurement gave us the confidence to commit to the full build.

Most of the engineering effort wasn’t in the AI integration - that part is well-trodden once you understand Agentforce’s session lifecycle. The time went into:

  • Audio pipeline tuning - sample rates, codec encoding, upsampling for STT, eliminating client-side resampling
  • Latency optimization - pre-fetching context, planner choice, pre-built greetings, perceived-latency engineering
  • Multilingual handling - in-call language switching, glossary protection, mid-call WebSocket reconnect, hidden translation
  • Interruption handling - barge-in with grace period, echo suppression, clean cutoffs with silence padding
  • Salesforce integration patterns - the priming context message workaround, post-publish planner configuration via Tooling API

None of these are unsolvable problems. Each one needed a deliberate engineering decision. Composing them into a single voice experience that feels natural took real iteration. As a Salesforce solution engineer using Claude Code as a coding partner, I could move fast on architecture while Claude handled the implementation. That pairing is what made this buildable in weeks rather than quarters.


Where This Fits - And Where It Doesn’t

This pattern fits a specific shape of opportunity. Some examples of what that looks like in real industries:

  • BFSI rural collections. A bank with thousands of agricultural loan accounts in Maharashtra needs to make pre-EMI reminder calls in Marathi. Native AF Voice today doesn’t speak Marathi yet. The customer already runs an Agentforce collections agent in chat. This pattern reuses the agent, adds Marathi voice as a channel, keeps their existing telephony.

  • Pharma detailing. A pharmaceutical company runs an Agentforce agent that briefs medical reps on new molecule launches. They want to extend it to outbound morning briefings to reps in Tier-2 cities - in Tamil, Telugu, Kannada - with a voice that sounds like a colleague, not an IVR.

  • Government scheme outreach. A state-level program wants to call beneficiaries in their preferred language to confirm eligibility, walk through documents, and answer policy questions. The data already lives in Salesforce. The agent is already tuned. What’s missing is the voice channel in the right language with the right tone.

  • Healthcare appointment confirmations. A hospital chain wants AI-driven outbound calls in Gujarati and Hindi to confirm appointments, answer pre-procedure questions, and capture rescheduling. Native AF Voice is English-first; the patient population isn’t.

Where it doesn’t fit:

  • Inbound, English-first scenarios - native Agentforce Voice is the right answer.
  • Use cases where time-to-market matters more than language coverage - wait for the platform.
  • Customers who want a click-to-deploy SKU - this is a co-build / accelerator pattern, not a packaged product.

Commercial Considerations

A few things to factor into customer conversations upfront:

  • The customer pays for telephony (Twilio or alternative) and Sarvam usage separately from their Salesforce flex credit (Agentforce API + Data Cloud consumption).
  • TRAI and DLT compliance for outbound calls in India is a responsibility that needs to be evaluated well - DLT registration, consent, call-time windows, opt-outs, outbound employee calling. Outbound voice in India has real regulatory teeth; flag this early.
  • For the latest go-forward guidance on positioning, supported scenarios, and the productization roadmap, loop in your Salesforce account team.

What This Unlocks

For decades, building voice AI for India meant bespoke IVRs, vendor lock-in, and integrations that broke every six months. The customer who matters - the field officer, the retailer, the dealer, the patient, the rural beneficiary - picks up phones, speaks in regional languages, and expects to be understood. Most enterprise software pretended that customer didn’t exist.

The technology has caught up. Indian-language voice AI now sounds native, not synthesized. Telephony is commodity infrastructure. And Agentforce, sitting on top of the Salesforce platform, gives enterprises a brain that already knows their data, their permissions, their workflows, their customers.

What this stitch shows is that the gap between “Agentforce in chat” and “Agentforce on an outbound phone call in Marathi” is bridgeable in weeks, not quarters. For Indian enterprises that already run on Salesforce - and most do - this opens a customer reach that was previously out of bounds. Outbound. Multilingual. On their existing telephony. Without rebuilding any of the data, logic, or permissions that make their business actually work.

Pick up the phone. Your agent is ready to talk!


Built on Salesforce Agentforce, Twilio for telephony (swappable with Indian providers like Exotel, Ozonetel, Plivo, Tata Tele), and Sarvam AI for Indian language speech and translation. The brain stays on Salesforce.

Built by a Salesforce AI solution engineer using Claude Code as a coding partner. UCPL is a fictitious reference application invented for this proof of concept.

If you’d like to see this in action or discuss what it could look like for your org, I’d love to hear from you.