<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Agora.io - Medium]]></title>
        <description><![CDATA[Agora delivers cutting edge APIs for developers. Our blog covers the world of technology. - Medium]]></description>
        <link>https://medium.com/agora-io?source=rss----548c45ba4c8b---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Agora.io - Medium</title>
            <link>https://medium.com/agora-io?source=rss----548c45ba4c8b---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 05 Nov 2026 16:29:47 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/agora-io" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Architecture Tradeoffs in Native Audio, Transcription, and Tool Calling]]></title>
            <link>https://medium.com/agora-io/architecture-tradeoffs-in-native-audio-transcription-and-tool-calling-f6d24b9c3c9b?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/f6d24b9c3c9b</guid>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[voice-assistant]]></category>
            <dc:creator><![CDATA[jingyi]]></dc:creator>
            <pubDate>Thu, 05 Nov 2026 13:26:01 GMT</pubDate>
            <atom:updated>2026-11-05T13:26:01.552Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sWcdwrf9ElHFIykwtGS1vw.png" /></figure><p>In our recent Agora × Google Discord livestream, Thor from Google DeepMind and Hermes from Agora discussed a recurring question in voice AI: when does native audio make sense, and when is a cascaded voice pipeline still the better fit?</p><p>From an AI DJ and live transcription to reasoning, context, tool calling, and multimodal input, the conversation focused on the tradeoffs developers face when choosing how to build a voice AI application.</p><h3>Native audio vs. cascaded pipelines</h3><p>Thor opened with an AI DJ built on Gemini Live.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*BsFb8zx-rStjdMicSUZEFw.png" /></figure><p>Wacth the <a href="https://drive.google.com/file/d/1mlTfSkbJkFkfXjUxUuYvnYJEkS5OaFts/view?usp=sharing">AI DJ demo video</a></p><p>The model held a live conversation, switched between German, Cantonese, and Hindi, and generate music.</p><p>The demo also highlighted a core advantage of native audio: the model works directly with speech instead of first reducing it to text. That lets it work with information such as tone and delivery that may be lost in transcription — including sarcasm.</p><p>A cascaded pipeline works differently: speech is transcribed, sent to an LLM, and then converted back to audio with TTS.</p><p>The tradeoff is control. Native audio keeps more of the interaction inside one model, while a cascaded pipeline lets developers choose and tune STT, the LLM, and TTS separately.</p><h3>What should transcription preserve?</h3><p>Thor then showed a coffee-order demo comparing verbatim and smart transcription.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/1*Yjirq5NP_oZgIdmcK3_pVA.png" /></figure><p>Wacth the <a href="https://drive.google.com/file/d/17gyDMFM2mmrsnvt4YmJ_ch56K2jvsSWP/view?usp=drive_link">Latte-order transcription demo video</a></p><p>As he changed his order mid-sentence, verbatim mode preserved the full sequence, while smart transcription resolved the corrections into the final request.</p><p>Hermes pointed out that this could also mean fewer tokens for the downstream LLM to process. Thor agreed that this could be useful, but noted that the right choice depends on the use case: an ordering system may only need the final intent, while medical or other record-sensitive scenarios may need a one-to-one transcript.</p><p>A community example is Zico’s Agora MatchCast, which combines Agora WebRTC with Gemini Transcribe Live to generate real-time captions for League of Legends commentary.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/834/1*GuVuemZ2to4Ib7v8P_3tYg.png" /></figure><p><a href="https://x.com/zicojzc/status/2092681112426529047">Watch: Live captioning built by Zico</a></p><h3>Reasoning vs. latency</h3><p>Native audio brings another tradeoff: more reasoning can also mean more latency.</p><p>Thor described two approaches in Gemini Live.</p><p>Interleaved reasoning keeps reasoning inside the native audio model and is suited to lower-latency tasks.</p><p>Extended thinking can offload heavier reasoning to a text-based model in the background.</p><p>To demonstrate the difference, Thor asked the model to draw an SVG of a pelican riding a bicycle.</p><p>The native model returned quickly, although the drawing was rough. With extended thinking, the intended behavior was for the background reasoning to keep working across multiple turns while the voice conversation continued.</p><p>The live demo hit a system error, but the idea was simple: heavier reasoning can run in the background without blocking the conversation.</p><h3>Context, tools, and multimodal input</h3><p>During the Q&amp;A, Thor returned to the choice between native audio and a cascaded pipeline.</p><p>For applications with large amounts of context, many tools, or high requirements for tool-calling accuracy, he said a cascaded pipeline may still be the better fit.</p><p>Hermes added that, in Agora’s cascaded architecture, developers can control the LLM endpoint and apply RAG, summarization, or other processing before sending context to the model. Server-side tools and client-side actions can also follow different execution paths.</p><p>The discussion then moved into multimodal input. Thor explained that Gemini Live can accept image frames in addition to audio — for example, frames from a user’s screen — so the model can reason about what is visible in the interface.</p><p>Akshay Nandwana’s Live Lens is a community example: the Android app combines camera input with a live voice conversation, using Gemini Live for visual understanding and Agora for the real-time voice and session layer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j8p8h1eJfcI2FdBWvxTjxg.png" /></figure><p><a href="https://x.com/akshay81844/status/2100288468136116298">Watch: Live Lens, built by Akshay Nandwana (Agora)</a></p><h3>Start with the application</h3><p>The livestream did not produce a single winner between native audio and cascaded pipelines.</p><p>The more useful questions are:</p><ul><li>What information needs to survive the speech layer?</li><li>Do you need a verbatim transcript or the user’s final intent?</li><li>How much context and tool calling does the agent need?</li><li>How much latency can the experience tolerate?</li></ul><p>The architecture should follow those requirements — not the other way around.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f6d24b9c3c9b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/architecture-tradeoffs-in-native-audio-transcription-and-tool-calling-f6d24b9c3c9b">Architecture Tradeoffs in Native Audio, Transcription, and Tool Calling</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Your First Voice Agent in Go with the Agora Agents SDK]]></title>
            <link>https://medium.com/agora-io/build-your-first-voice-agent-in-go-with-the-agora-agents-sdk-9ecfa4c4150d?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/9ecfa4c4150d</guid>
            <category><![CDATA[voice-agent]]></category>
            <category><![CDATA[conversational-ai]]></category>
            <category><![CDATA[go]]></category>
            <dc:creator><![CDATA[June]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 14:26:01 GMT</pubDate>
            <atom:updated>2026-11-04T14:26:01.592Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GpBoRdpPu2Jm1aYkQK_r6g.png" /></figure><p>Create a voice interview partner, then explore how a Go backend starts and stops the conversation.</p><p>In this tutorial, you’ll run a Go voice agent that helps you practice talking about a project. Open the app in your browser, describe something you built, and hear the agent ask a follow-up based on your answer. Your project can use any programming language.</p><p>You’ll use the existing <a href="https://recipes.agora.io/recipes/golang-quickstart">Agora Go Quickstart Recipe</a>, which provides a Gin backend and a Next.js client. The browser handles microphone input and playback; the Go service configures the cloud agent and starts and stops its sessions.</p><h3>Before you start</h3><ul><li>Go 1.23 or later and basic familiarity with Go functions and structs.</li><li>Node.js 20.9 or later and <a href="https://pnpm.io/installation">pnpm</a>. The starter pins pnpm 10.23.0.</li><li>The <a href="https://github.com/AgoraIO/cli#readme">Agora CLI</a>, installed and available as agora.</li><li>An Agora project with an App ID and App Certificate, and RTC, RTM, and Conversational AI managed-provider support enabled. You can manage your project in the <a href="https://console.agora.io/">Agora Console</a>.</li><li>A browser with microphone access. Headphones help keep the agent’s voice out of your microphone.</li></ul><p>The project uses Make and Bash. Follow along on macOS, Linux, or Windows through WSL with those tools available.</p><h3>1. Get start</h3><p>Sign in and create a project from the recipe:</p><pre>agora login<br>agora init my-go-agent --recipe golang-quickstart<br>cd my-go-agent<br>make setup</pre><p>make setup downloads the Go modules, installs the frontend workspace dependencies, and prepares server/.env. The main files you&#39;ll use are:</p><pre>server/<br>  main.go        HTTP routes and environment loading<br>  agent.go       Agent instructions, providers, and sessions<br>client/<br>  next.config.ts Browser API rewrites to the Go backend<br>Makefile         Setup, development, and verification commands</pre><p>Open server/.env and replace the two example credential values with those from your Agora project. Keep the other entries supplied by setup:</p><pre>AGORA_APP_ID=your_agora_app_id<br>AGORA_APP_CERTIFICATE=your_agora_app_certificate</pre><p>Alternatively, populate the environment file through the CLI from the project root, replacing &lt;your-project&gt; with your project&#39;s name or ID:</p><pre>agora project use &lt;your-project&gt;<br>agora quickstart env write .</pre><p>Check that server/.env contains your project&#39;s values. Keep the App Certificate in the Go backend; the browser receives a signed token and does not need the certificate.</p><h3>2. Configure the interview assistant</h3><p>Before starting the app, open server/agent.go. Near the top, replace the existing const block containing adaPrompt and defaultGreeting with:</p><pre>const (<br>    adaPrompt = `You are Ada, a friendly interviewer helping a developer<br>practice discussing a software project in English, regardless of the<br>programming language used.</pre><pre>Ask one question at a time and wait for the answer.<br>After each answer, point out one specific strength or one missing detail,<br>then ask a follow-up based on something the developer just said.<br>Focus on the problem, the developer&#39;s decisions, and what they learned.<br>Keep each turn to two or three short sentences suitable for speech.<br>If an answer is unclear, ask for clarification before evaluating it.<br>Treat this as practice, without assigning a hiring score.<br>`<br>    defaultGreeting = &quot;Hi! Let&#39;s practice talking about a project. What did you build, and what problem did it solve?&quot;<br>)</pre><p>Keep the existing constant names. The starter passes adaPrompt into the agent&#39;s instructions and uses defaultGreeting for its opening message. The greeting gives the learner something specific to answer immediately; The instructions guide subsequent turns.</p><p>This exercise uses English because the supplied speech recognition configuration selects English. The recipe already configures managed Deepgram speech recognition, an OpenAI language model, and MiniMax speech output, so you don’t need to add separate provider API keys for this path.</p><h3>3. Try a short interview</h3><p>From the project root, start both services:</p><pre>make dev</pre><p>This starts Gin on port 8000 and Next.js on port 3000. It also sets AGENT_BACKEND_URL=http://localhost:8000 for the frontend&#39;s API rewrites. Keep the terminal running.</p><p>Open <a href="http://localhost:3000">http://localhost:3000</a>, then:</p><ol><li>Click <strong>Start Conversation</strong> and allow microphone access.</li><li>Listen for the interview greeting you just configured.</li><li>Answer aloud. For example, “I built a small service that collects sensor readings. I used a queue so requests would not have to wait for processing.”</li><li>Listen for one specific strength or missing detail in your answer, followed by a related question. For the example above, the agent might ask how you handled a growing queue. Check that your speech and the agent’s response appear in the transcript.</li><li>Answer the follow-up, then click <strong>End Conversation</strong>.</li></ol><p>The sensor-service answer is a practice example; use your own project if you have one. The agent’s exact response will vary. Check that its feedback refers to your answer and that it asks one question before waiting for you to speak.</p><p>Start another conversation to check that a new interview begins with the greeting. If you edit the Go instructions later, end the active conversation, stop the dev processes with Ctrl+C, run make dev again, and refresh the page. This starter runs go run . without a Go file watcher, so saving a file alone won&#39;t reload the backend.</p><h3>4. How a conversation starts and ends</h3><p>The browser talks to three API paths. Next.js rewrites them to handlers in server/main.go:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FW_YkknDhWRKv-32Mngblg.png" /></figure><p>These requests control the conversation. Agora RTC carries the live audio between the browser and the cloud agent; RTM carries transcript and agent-state updates. Go doesn’t receive an HTTP request for each microphone audio chunk.</p><h3>Starting a session</h3><p>Inside server/agent.go, the service creates an authenticated SDK client using the backend credentials. It then builds an agent with your instructions, greeting, speech providers, and turn-detection settings.</p><p>The next step connects that configuration to a channel and its participants. Here is the existing session-start portion of the start method, shown for explanation; keep the surrounding implementation in place:</p><pre>session := agent.CreateSession(agentkit.CreateSessionOptions{<br>    Channel:         channelName,<br>    AgentUID:        strconv.Itoa(agentUID),<br>    RemoteUIDs:      []string{strconv.Itoa(userUID)},<br>    EnableStringUID: &amp;enableStringUID,<br>    IdleTimeout:     &amp;idleTimeout,<br>    ExpiresIn:       expiresIn,<br>})</pre><pre>ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)<br>defer cancel()</pre><pre>agentID, err := session.Start(ctx)<br>if err != nil {<br>    return nil, fmt.Errorf(&quot;start agent: %w&quot;, err)<br>}</pre><p>Channel names the conversation. AgentUID identifies the agent participant, and RemoteUIDs selects the user it listens to. The agentID returned by Start identifies the running agent session for later lifecycle calls.</p><p>The Go context gives the startup call a 30-second deadline. Conversation duration is controlled separately through settings such as IdleTimeout and ExpiresIn. In the referenced starter, those are 30 seconds of idle time and a one-hour session expiry.</p><h3>Ending a session</h3><p>After startup, the backend retains the session under its agent ID. Clicking <strong>End Conversation</strong> sends { agentId } to the stop endpoint, where Go uses that ID to stop the session. The browser also logs out of RTM and clears its conversation state. You can read the full stop handling in server/agent.go.</p><p>End the conversation through the UI before stopping the local server so the app can send that explicit stop request.</p><h3>Troubleshooting</h3><p>If the app doesn’t start, check your local setup from the project root:</p><pre>make doctor-local</pre><p>doctor-local checks local prerequisites and whether the credential fields are configured. It doesn&#39;t make a live Agora call; a browser conversation is still needed to check microphone input and spoken replies.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hQW-JACToZa2hp0LxOMPpA.png" /></figure><p>If you later change backend routes or frontend API handling, the repository’s <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-go/blob/d98ba88bc26a42c5178339d128ccef54a6498502/docs/ai/L1/01_setup.md">local verification guide</a> covers the Go tests and checks using a fake backend. Those checks help find local wiring errors; they don’t test a real voice conversation.</p><h3>Make the next practice round more specific</h3><p>Once the interview works, change one instruction to focus on error handling. Ask Ada to follow up on what happens when part of the system fails. Restart the backend, begin a new conversation, and give the same sensor-service answer.</p><p>Listen for a question tied to that answer, such as what happens if processing fails after a reading enters the queue. If Ada moves to an unrelated interview question, revise the instruction and try again. This gives you a concrete check: does each follow-up build on what you just said?</p><p><em>Implementation reference: this tutorial follows the </em><a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-go/tree/d98ba88bc26a42c5178339d128ccef54a6498502"><em>Go quickstart at revision d98ba88</em></a><em>. The CLI may fetch a newer version; compare its files with that snapshot if paths or defaults differ.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9ecfa4c4150d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/build-your-first-voice-agent-in-go-with-the-agora-agents-sdk-9ecfa4c4150d">Build Your First Voice Agent in Go with the Agora Agents SDK</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Your First Voice Agent in TypeScript with the Agora Agents SDK]]></title>
            <link>https://medium.com/agora-io/build-your-first-voice-agent-in-typescript-with-the-agora-agents-sdk-e585d1a481cf?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/e585d1a481cf</guid>
            <category><![CDATA[voice-agent]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[conversational-ai]]></category>
            <dc:creator><![CDATA[June]]></dc:creator>
            <pubDate>Tue, 03 Nov 2026 13:26:01 GMT</pubDate>
            <atom:updated>2026-11-03T13:26:01.532Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KrgAIQFmUA6CZSgEOrzmgw.png" /></figure><p>You have 45 minutes before a meeting, with a pull request to review and two emails waiting. What would you do first? We can build a voice assistant to help you talk through your priorities and plan how to use that time.</p><p>The <a href="https://recipes.agora.io/recipes/nextjs-quickstart">NextJS Quickstart Recipe</a> gives you a working Next.js app with a voice assistant named Ada, which answers developers’ questions about Agora. You’ll first try that demo, then turn Ada into a planning assistant by changing its instructions and greeting. Finally, you’ll update the page text so users know to share their tasks and available time. You’ll be able to hear Ada’s suggestions and follow the exchange in a live transcript.</p><p>The app’s React components and server API routes live in one TypeScript project. Agora runs the voice agent in the cloud, while the app provides the conversation interface. Basic TypeScript, React, and terminal knowledge are enough to follow along.</p><h3>Before you start</h3><p>You’ll need:</p><ul><li><a href="https://nodejs.org/en/download">Node.js 22 or later</a> and <a href="https://pnpm.io/installation">pnpm</a>.</li><li>The <a href="https://github.com/AgoraIO/cli#readme">Agora CLI</a>, available as agora in your terminal.</li><li>An Agora project with an App ID and App Certificate, with RTC, RTM, and Conversational AI managed-provider support enabled. Use the <a href="https://console.agora.io/">Agora Console</a> to manage the project.</li><li>A browser with microphone access. Headphones help prevent the agent’s voice from feeding back into the microphone.</li></ul><p>This tutorial uses English and Agora-managed providers, so you don’t need separate provider API keys.</p><h3>1. Get started</h3><p>Sign in, create an app from the recipe, and install its dependencies:</p><pre>agora login<br>agora init my-ts-agent --recipe nextjs-quickstart<br>cd my-ts-agent<br>pnpm install</pre><p>The initialization flow binds an Agora project and prepares its environment configuration. Open .env.local in the project root and check these two entries against your project. If the file wasn&#39;t created, copy env.local.example to .env.local and fill them in:</p><pre>NEXT_PUBLIC_AGORA_APP_ID=your_agora_app_id<br>NEXT_AGORA_APP_CERTIFICATE=your_agora_app_certificate</pre><p>Keep the certificate’s variable name exactly as shown. NEXT_PUBLIC_AGORA_APP_ID is available to the browser; NEXT_AGORA_APP_CERTIFICATE stays in server code and must not receive the NEXT_PUBLIC_ prefix.</p><p>From the project root, check the local setup and start Next.js:</p><pre>pnpm run doctor<br>pnpm run dev</pre><p>doctor checks the Node version, package-manager context, and presence of the environment fields. It doesn&#39;t verify that the credentials can start a real agent. Keep the dev terminal running and open <a href="http://localhost:3000">http://localhost:3000</a>.</p><p>First, check the original demo’s audio and transcript. Click <strong>Start Conversation</strong>, allow microphone access, and listen for Ada’s greeting. Ask a short question in English, such as “How can you help me?” Check that you hear a reply and that both speakers appear in the <strong>Transcript</strong> panel. Then click <strong>End Conversation</strong>. Resolve any startup or audio problems using the troubleshooting section before making the edits below.</p><h3>2. Turn Ada into a planning assistant</h3><p>Now give Ada a specific job: learn the user’s tasks and available time, then help them choose an order. The prompt sets these conversational rules, and the greeting invites the user to share their tasks.</p><p>Open app/api/invite-agent/route.ts, where the server uses the Agora Agents SDK to configure and start the cloud agent. Replace the existing ADA_PROMPT and GREETING definitions near the top with:</p><pre>const ADA_PROMPT = `You are Ada, a practical planning partner.<br>Help the user plan their next work session. Speak in English.</pre><pre>Learn what tasks they need to do and how much time they have.<br>If an important detail is missing, ask one focused question and wait.<br>Once you have enough information, suggest at most three actions in order<br>and give a brief reason for the first priority.<br>If the tasks do not fit the time available, ask what can wait.<br>Keep each turn to two or three short sentences suitable for speech.<br>Do not claim to save tasks, set reminders, or update a calendar.`;</pre><pre>const GREETING = `Hi! Tell me what you would like to get done in your next work session.`;</pre><p>Keep the constant names: the existing Agent configuration reads ADA_PROMPT as its instructions and GREETING as the opening message. These edits guide the conversation; the starter has no task-saving or calendar integration. Leave the provider and session settings in place.</p><h3>3. Introduce the planner on the page</h3><p>Ada now has planning instructions, but the page still introduces a general Agora voice demo. Update the start screen so someone opening the app knows to tell Ada their tasks and available time.</p><p>In components/QuickstartPreCallCard.tsx, replace the existing &lt;h1&gt; and the first &lt;p&gt; immediately below it with:</p><pre>&lt;h1 className=&quot;text-[28px] font-medium leading-[1.2] text-white&quot;&gt;<br>  Plan your next work session<br>&lt;/h1&gt;<br>&lt;p className=&quot;mt-[14px] text-sm font-medium leading-6 text-muted-foreground&quot;&gt;<br>  Tell Ada your tasks and available time, then talk through a short plan.<br>&lt;/p&gt;</pre><p>These elements sit above the existing start button. Keep that button, its loading state, and its onClick handler so the page still starts a conversation in the same way.</p><p>Give the live transcript a matching title. Open components/QuickstartTranscriptPanel.tsx and replace the existing &lt;h2&gt; containing Transcript and its Live voice turns subtitle with:</p><pre>&lt;h2 className=&quot;text-sm font-semibold text-foreground&quot;&gt;<br>  Planning conversation<br>&lt;/h2&gt;<br>&lt;p className=&quot;text-xs text-muted-foreground&quot;&gt;<br>  Your tasks and Ada&amp;apos;s suggestions<br>&lt;/p&gt;</pre><p>The labels now describe this exercise. The messages will still use <strong>You</strong> and <strong>Agent</strong> to identify speakers. Changing these React labels changes what the user sees; the server-side prompt changes how Ada responds.</p><h3>4. Try your planning assistant</h3><p>Save all three files. With the previous conversation ended, stop the dev server with Ctrl+C and start it again from the project root:</p><pre>pnpm run dev</pre><p>Refresh the browser and check that the start card says <strong>Plan your next work session</strong>. A fresh conversation is important: editing a prompt doesn’t change an agent session that is already running.</p><ol><li>Click <strong>Start Conversation</strong> and listen for the new planning greeting.</li><li>Say, “I have 45 minutes to review a pull request, reply to two emails, and prepare for a meeting. The meeting starts right after this work session.”</li><li>Check the <strong>Planning conversation</strong> panel. Your tasks and time should appear under <strong>You</strong>. Listen to Ada’s reply and follow its text under <strong>Agent</strong>.</li><li>If Ada asks for a missing detail, answer it. For example, you could say that meeting preparation needs 20 minutes. Check whether the suggested order accounts for the meeting and the time remaining. The exact wording and order may vary.</li><li>Click the microphone button to mute. After any reply already underway finishes, speak a short test sentence and check that it doesn’t become a new transcript turn. Unmute, speak again, and check that new speech appears.</li></ol><p>The microphone selector beside the mute button lets you choose another input device if needed. The agent visualizer provides another cue as the conversation moves between listening, thinking, and speaking; it doesn’t replace checking the actual audio and text.</p><p>Before clicking <strong>End Conversation</strong>, copy any suggestion you want to keep. The transcript is held in the current React conversation view; This starter doesn’t save it as a task list. Ending the conversation unmounts that view, so starting again begins with a fresh transcript and greeting.</p><h3>5. How conversation works</h3><ul><li><strong>Server:</strong> The app/api/ routes keep the App Certificate private, issue connection tokens, and start the agent with your instructions.</li><li><strong>Audio:</strong> Agora RTC carries your voice and the cloud agent’s spoken replies.</li><li><strong>Transcript:</strong> Agora RTM delivers transcript updates, which ConversationComponent.tsx stores in React state for display.</li></ul><p>For more on how transcript updates become visible messages, see the repository’s <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-nextjs/blob/24374411cdd809701e2a39466f4f97d52e23f173/docs/ai/L1/L2/transcript_pipeline.md">transcript guide</a>.</p><h3>Troubleshoot setup and conversation issues</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bRQR-eX0MLWf4HzsjLu05Q.png" /></figure><p>To regenerate .env.local, run the following from the project root. Replace &lt;your-project&gt; with your project&#39;s name or ID, then restart the dev server after running the commands:</p><pre>agora project use &lt;your-project&gt;<br>agora quickstart env write .</pre><p>Before sharing your changes, run pnpm run verify from the project root. It checks local configuration, lint, TypeScript types, mocked API contracts, and the production build. It doesn&#39;t exercise a real microphone or prove that generated suggestions follow the prompt; the browser exercise checks those behaviors.</p><h3>Try the same tasks in less time</h3><p>Start a new conversation with the same tasks, but say you have only 15 minutes. Check whether Ada asks what can wait or narrows the plan to fit. Check your time constraint in the transcript as well as listening to the reply. If the transcript shows the wrong number, correct it aloud before judging the planning advice.</p><p>If the suggestions still ignore the shorter session, refine the prompt’s time constraint and repeat the same example. Keep the screen’s invitation and the assistant’s behavior aligned as you change the task.</p><p><em>Source reference: the </em><a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-nextjs/blob/main/docs/ai/RECIPE.md"><em>Recipe document</em></a> is the source behind the recipe page. Code paths and defaults here follow <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-nextjs/tree/24374411cdd809701e2a39466f4f97d52e23f173"><em>quickstart revision 2437441</em></a><em>; the CLI may fetch a newer version, so compare that snapshot if your files differ.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e585d1a481cf" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/build-your-first-voice-agent-in-typescript-with-the-agora-agents-sdk-e585d1a481cf">Build Your First Voice Agent in TypeScript with the Agora Agents SDK</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Agora Dev Digest #4]]></title>
            <link>https://medium.com/agora-io/agora-dev-digest-4-ccc4c758e1b2?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/ccc4c758e1b2</guid>
            <category><![CDATA[voice-assistant]]></category>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[conversational-ai]]></category>
            <dc:creator><![CDATA[jingyi]]></dc:creator>
            <pubDate>Mon, 02 Nov 2026 12:21:58 GMT</pubDate>
            <atom:updated>2026-11-02T12:21:57.198Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ps6kHmVsiYc7PXMTIT4J9A.png" /></figure><p>Voice AI is taking on more everyday tasks, with developers building apps for group decisions, character conversations, and hands-free computer control. In the fourth Agora Dev Digest, we explore these demos, catch up on October’s Tech Talks, and share a recipe for keeping agents responsive while they work.</p><h3>Demo Spotlight</h3><h4>Agora Decision Rooms: talk together, decide together</h4><p>@<a href="https://x.com/shiiivam12/status/2107111591745634434">Shivam Mahendru</a> built Agora Decision Rooms for group voice conversations with Kabir, an AI facilitator. The demo takes a familiar problem, deciding where to go, and gives everyone a chance to discuss it and vote.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H562AofD83eCoc-Xp5vE2g.png" /></figure><p><a href="https://github.com/shhhivam12/agora-decision-rooms">GitHub</a></p><h4>KIN: create AI characters you can talk to</h4><p><a href="https://x.com/buildsbyshubham/status/2108215722770116744">@Shubham’s</a> KIN lets users describe a character by voice, define their personality and backstory, and start a real-time voice conversation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*F7q1epjoCgCnk3Cl.png" /></figure><p>Built with Flutter, Agora, and Google Gemini, KIN extracts and saves details from conversations, such as user preferences, important events, and promises, to use as context in future conversations.</p><p><a href="https://github.com/shubhamranswal/kin">GitHub</a></p><h3>Agora for Developers</h3><h4>Control your Mac by voice with Jev + Agora</h4><p><a href="https://x.com/akshay81844/status/2104593877831450843">@Akshay</a> built a demo using TypeSafe’s Jev and Agora to control his Mac by voice. It shows voice commands for playing a video, opening folders, navigating the web, and closing tabs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*V75YCkZwaWC-8WCqOK8ZWA.png" /></figure><p><a href="https://x.com/akshay81844/status/2104593877831450843">Watch the demo</a> · <a href="https://github.com/anandwana001/macbrow-agora">GitHub</a></p><h3>Tech Talks</h3><p><strong>Getting Started with Agora Conversational AI: </strong>An introduction to Agora’s developer ecosystem, covering the CLI, Skills for AI coding assistants, MCP, Next.js Quickstart, and Voice AI Recipes.</p><p><a href="https://x.com/AgoraIO/status/2105682557543260211">Watch the replay</a></p><p><strong>Inside Agora Conversational AI: What Powers a Real-Time AI Agent? </strong>A look beyond STT → LLM → TTS, covering turn detection, interruptions, agent states, and how tools, memory, and multimodal inputs fit into a voice AI application.</p><p><a href="https://x.com/AgoraIO/status/2108218408429121895">Watch the replay</a></p><p><strong>Beyond Voice Chatbots: Build AI Agents That Take Action:</strong> Explore how agents connect to APIs and services through tool calling, use RAG and memory, and support multimodal inputs, with Agora adding real-time voice interactions.</p><p><a href="https://x.com/AgoraIO/status/2110755896397807700">Watch the replay</a></p><p><strong>Voice AI for Bharat: The Diwali Edition:</strong> Explore the challenges of building voice AI for India, from Hindi, English, and Hinglish to Indian accents, language switching, and moving from demo to production.</p><p><a href="https://x.com/AgoraIO/status/2113291933682675746">Watch the replay</a></p><h3>Build This Today</h3><h4>Delegated Reasoning: keep talking while your agent works</h4><p>Agora’s Delegated Reasoning recipe separates the conversation from the work behind an answer. GPT Live handles speaking and listening, while a second model reasons through the request and calls tools.</p><p>The example is a trip planner. Ask for somewhere sunny to visit, and the agent checks forecasts for several cities before recommending one. You can keep talking while the lookup runs. Once you choose a destination, it saves the trip; changing your mind updates the same record.</p><p>The recipe includes setup instructions and an MCP tool server for checking forecasts and saving trips. It requires access to Agora’s GPT Live preview and the OpenAI models used in the example.</p><p><a href="https://recipes.agora.io/recipes/agent-delegation">Explore the recipe</a></p><h3>Share Your Project</h3><p>Building something with Agora? We’d love to see it! Share your project and tag <a href="https://x.com/AgoraIO"><strong>@AgoraIO</strong></a><strong> on X</strong>. We’ll be spotlighting community builds from time to time, and yours could be featured in a future edition!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ccc4c758e1b2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/agora-dev-digest-4-ccc4c758e1b2">Agora Dev Digest #4</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Run a Real-Time Voice Translator with Agora Conversational AI]]></title>
            <link>https://medium.com/agora-io/how-to-run-a-real-time-voice-translator-with-agora-conversational-ai-cc3ab3d61b3a?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/cc3ab3d61b3a</guid>
            <category><![CDATA[conversational-ai]]></category>
            <category><![CDATA[realtime]]></category>
            <category><![CDATA[agora]]></category>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[voice-translator]]></category>
            <dc:creator><![CDATA[June]]></dc:creator>
            <pubDate>Fri, 30 Oct 2026 22:26:01 GMT</pubDate>
            <atom:updated>2026-10-30T22:26:01.700Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*meuCOeXCh3eHOTdM-1F9Cg.png" /></figure><p>Imagine speaking a sentence in Spanish and hearing it back in English. That’s what this tutorial gets running: a browser-based voice translator built on Agora’s Real-time Translator project, where Deepgram turns your speech into text, a managed OpenAI stage translates it, and MiniMax speaks the translation back into the same channel.</p><p>By the end, you’ll have the whole thing running locally on your own machine, holding a full speech-to-speech conversation. One caveat up front: end-to-end latency is second-scale.</p><p><a href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-translator">This walkthrough covers the recipe’s own commands, the environment variables that control the language pair, the audio path from microphone to translated speech, and the limitations to resolve before shipping.</a></p><h3>What You Will Get</h3><p>By the end of this tutorial, you will have:</p><ul><li>A browser-based translator that accepts speech and plays back the translation.</li><li>A working Spanish-to-English configuration to try first.</li><li>A starting point you can customize with a different source language, target language, and voice.</li></ul><p>The project uses Agora-managed OpenAI for translation, so the default setup does not require your own OpenAI API key.</p><h3>Architecture at a Glance</h3><p>The project combines a web interface, a small backend, and Agora’s cloud-based voice pipeline:</p><pre>Browser / Next.js (:3000)<br>    │<br>    ├─ controls ──▶ FastAPI (:8000)<br>    │                 │<br>    │                 └─ starts/stops agent<br>    │<br>    └─ audio ⇄ Agora Conversational AI<br>                       │<br>                 Deepgram STT<br>                       │<br>                 OpenAI translation<br>                       │<br>                 MiniMax TTS</pre><p>The project has a browser app and a small backend running locally. Together, they start and control a translation session in Agora’s cloud, where speech is recognized, translated, and spoken back to the browser.</p><p>On the credentials side, the pipeline is zero-key by default: OpenAI is Agora-managed, so no OPENAI_API_KEY is required unless your account specifically needs you to bring your own.</p><p>ServicePathPortResponsibilityWeb clientweb/3000RTC/RTM lifecycle, UI, calls /api/* onlyAgent backendserver/8000Token minting, agent session lifecycleAPI docsserver/8000Interactive reference at /docs</p><h3>Get started</h3><h4>1. Prepare the tools</h4><p>Before you begin, install:</p><ul><li><a href="https://www.python.org/downloads/">Python 3.10 or newer</a>.</li><li><a href="https://bun.sh/">Bun</a>, which runs the project’s setup and development commands.</li><li><a href="https://github.com/AgoraIO/cli">Agora CLI</a>, which scaffolds the project and can write its Agora credentials.</li></ul><h4>2. Create the project</h4><p>Open a terminal and initialize the project:</p><pre>agora init my-realtime-translator --recipe realtime-translator<br>cd my-realtime-translator</pre><p>Run the remaining terminal commands from this project directory.</p><p>Install the project dependencies:</p><pre>bun run setup</pre><p>This installs the web dependencies, prepares the Python environment, and creates server/.env.local from the sample configuration if that file does not already exist.</p><h4>3. Connect your Agora project</h4><p>Log in, select your project, and write its credentials:</p><pre>agora login<br>agora project use &lt;your-project&gt;<br>agora project env write server/.env.local</pre><p>Replace &lt;your-project&gt; with the Agora project you want to use.</p><p>Alternatively, open server/.env.local and replace the existing credential values manually:</p><pre>AGORA_APP_ID=your_agora_app_id<br>AGORA_APP_CERTIFICATE=your_agora_app_certificate</pre><p>These are entries in the existing file, not a replacement for its entire contents. Keep the App Certificate in the backend configuration.</p><h4>4. Check the language settings</h4><p>For your first run, use the project’s default Spanish-to-English pair. In server/.env.local, make sure these entries have the following values, keeping the other settings in place:</p><pre>SOURCE_LANG=es<br>TARGET_LANG=English<br>TTS_VOICE=English_captivating_female1</pre><p>The project already supplies its model and other defaults. You can leave those settings as they are for this walkthrough.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lnqbNuwB2onm_MzIIKdH-w.png" /></figure><p>The table above is the quickest way to sanity-check a misconfiguration before you start reading logs.</p><h4>5. Start the application</h4><p>From the project directory, run:</p><pre>bun run dev</pre><p>This starts the web app on port 3000 and the backend on port 8000. Keep the terminal running and open <a href="http://localhost:3000/">http://localhost:3000</a>. You should see the translator interface with the <strong>Start Conversation</strong> button.</p><h3>6.Try your first translation</h3><p>With the interface open, run through one round trip:</p><ol><li>Click <strong>Start Conversation</strong>.</li><li>Allow microphone access when your browser asks.</li><li>Say a short Spanish sentence, such as “Hola, ¿cómo estás?”</li><li>Pause and listen for an English translation, such as “Hello, how are you?”</li></ol><p>The wording may vary. Check that the response preserves the meaning of your sentence and is spoken in English. The transcript panel also lets you inspect the recognized speech and the agent’s response.</p><p>Try a question next, such as “¿Dónde está la estación de tren?” The agent should translate the question into English rather than answer it with directions. This is a useful way to check that your demo behaves as a translator.</p><p>Click <strong>End Conversation</strong> when you finish testing.</p><h3>Customize the Translation Direction</h3><p>Once the default translation works, you can return to server/.env.local and try a different translation direction. The default is Spanish → English. These three settings control the language pair and the voice:</p><ul><li>SOURCE_LANG sets the language you speak. Use a code supported by Deepgram’s nova-3 model, such as es for Spanish. See the <a href="https://developers.deepgram.com/docs/models-languages-overview">Models &amp; Languages Overview</a> for the available codes.</li><li>TARGET_LANG sets the language the text should be translated into, such as English.</li><li>TTS_VOICE sets the voice that reads the translation aloud. Choose a MiniMax voice that matches TARGET_LANG; the <a href="https://docs.agora.io/en/ai/models/tts/minimax">Agora MiniMax TTS guide</a> explains the voice_id setting and links to the <a href="https://platform.minimax.io/docs/faq/system-voice-id">System Voice ID List</a>.</li></ul><p>After saving your changes, end any active conversation, stop the development process with Ctrl+C, and run bun run devagain. Then start a new conversation in the browser. This reloads the configuration and creates an agent session with your new settings.</p><h3>Next Steps</h3><p>Try the translator with the names, numbers, and questions your users are likely to ask. Check both the recognized input and spoken output before adapting the demo for a real application.</p><p>For deployment, check out the <a href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-translator">guide in the repository</a>, it explains how to host the web app and backend and configure the connection between them. The sample backend exposes token and session controls without user authentication; add access controls before offering those endpoints to real users.</p><h3>Frequently Asked Questions</h3><ol><li><strong>How much does it cost to run a real-time voice translator?</strong><br>Conversational AI Engine audio tasks cost USD 0.10 per minute. The first 300 minutes are free each month. See the <a href="https://docs.agora.io/en/ai/reference/pricing">Conversational AI pricing</a> page for current rates.</li><li><strong>Why does the agent start but not translate anything?<br></strong>Check SOURCE_LANG. It must be a supported Deepgram language code, such as es or es-419, rather than a language name such as Spanish. Then verify that TARGET_LANG and TTS_VOICE match your intended translation direction and restart the session.</li><li><strong>Where should the App Certificate live?<br></strong>Keep it in the backend environment, such as server/.env.local. Do not expose it in the browser or commit it to source control.</li><li><strong>How do I add live captions?<br></strong>Enable the RTM data channel for the agent and handle transcript updates in the client. Follow Agora’s <a href="https://docs.agora.io/en/ai/build/transcripts">live transcript guide</a> for the required configuration.</li><li><strong>How do I deploy the backend so the web app can reach it?</strong><br>Deploy the FastAPI backend at a reachable URL, then set AGENT_BACKEND_URL in the web app’s environment. The <a href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-translator">deployment guide</a> covers the remaining setup.</li></ol><h3>References</h3><ul><li><a href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-translator">Real-time Translator project repository</a>.</li><li><a href="https://github.com/AgoraIO-Conversational-AI/recipe-agent-translator/blob/c7f12dcea7745feee19ea68774528a5f8325bf86/ARCHITECTURE.md">Architecture and component responsibilities</a>.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cc3ab3d61b3a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/how-to-run-a-real-time-voice-translator-with-agora-conversational-ai-cc3ab3d61b3a">How to Run a Real-Time Voice Translator with Agora Conversational AI</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build Your First Voice Agent in Python with the Agora Agents SDK]]></title>
            <link>https://medium.com/agora-io/build-your-first-voice-agent-in-python-with-the-agora-agents-sdk-d717502d2fc1?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/d717502d2fc1</guid>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[ai-development]]></category>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[agorasdk]]></category>
            <dc:creator><![CDATA[June]]></dc:creator>
            <pubDate>Wed, 28 Oct 2026 22:26:01 GMT</pubDate>
            <atom:updated>2026-10-28T22:26:01.810Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o0DkQ8BVvE3vgWutOzgRlQ.png" /></figure><p><em>Run a conversation with Ada, turn her into a Python tutor, and follow the path from your microphone to her spoken reply.</em></p><p>Open a browser, ask Ada a question, and hear her answer while the transcript appears on screen. Then change her instructions and start a new conversation: the same assistant now helps you learn Python.</p><p>This tutorial uses Agora’s <a href="https://recipes.agora.io/recipes/python-quickstart">Python Quickstart Recipe</a>, which includes a web client and a Python backend built with FastAPI and the Agora Agents SDK. You’ll run the existing project, customize it, and then examine how the conversation works. Basic Python and terminal knowledge are enough.</p><p>The code examples follow <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-python/tree/bd1af724bed885c39a5a57235b37ec3bb3fd6396">quickstart revision bd1af724</a>. The CLI may fetch a newer version; compare its files with that snapshot if names or behavior differ.</p><h3>Before you start</h3><p>You’ll need:</p><ul><li><a href="https://www.python.org/downloads/">Python 3.10 or later</a>, available as python3 in your terminal.</li><li><a href="https://bun.sh/docs/installation">Bun</a> and the <a href="https://github.com/AgoraIO/cli#installation">Agora CLI</a>.</li><li>An <a href="https://console.agora.io/">Agora project</a> with an App ID and App Certificate, with RTC, RTM, and Conversational AI enabled. RTC carries audio; RTM carries messaging updates such as transcripts.</li><li>A browser with access to your microphone and speakers. Headphones can help prevent speaker audio from feeding back into the microphone.</li></ul><p>The setup scripts use Bash, so use a Bash-capable environment such as macOS, Linux, or WSL on Windows.</p><h3>1. Create and configure the project</h3><p>Log in, create a project from the recipe, and enter its directory:</p><pre>agora login<br>agora init my-python-agent --recipe python-quickstart<br>cd my-python-agent</pre><p>The project has two main directories: server/ contains the Python backend, and web/ contains the browser client. Install their dependencies:</p><pre>bun run setup</pre><p>Before starting the app, open server/.env. Set these two entries to your project&#39;s values, leaving the other settings in place:</p><pre>AGORA_APP_ID=your_agora_app_id<br>AGORA_APP_CERTIFICATE=your_agora_app_certificate</pre><p>If you prefer to populate the file through the CLI, select your project and write its environment configuration from the project root. Replace &lt;your-project&gt; with your project&#39;s name or ID:</p><pre>agora project use &lt;your-project&gt;<br>agora quickstart env write .</pre><p>Check that server/.env now contains your credentials rather than the example values. Keep the App Certificate in the backend. The browser receives a token from the server and does not need the certificate.</p><h3>2. Have your first conversation</h3><p>From the project root, start the Python backend and web client:</p><pre>bun run dev</pre><p>Keep the terminal running. Open <a href="http://localhost:3000">http://localhost:3000</a>, click <strong>Start Conversation</strong>, and allow microphone access. Ada should introduce herself:</p><blockquote><em>Hi there! I’m Ada, your virtual assistant from Agora. How can I help?</em></blockquote><p>Ask a short question in English, such as “What is a voice agent?” Listen for the answer and check that your question and Ada’s reply appear in the transcript panel.</p><p>These are two useful checks. Hearing the greeting confirms playback. Receiving a spoken answer to your question exercises the full loop: microphone input, speech recognition, response generation, and speech output.</p><p>Click <strong>End Conversation</strong> before moving on. If the conversation does not work, use the troubleshooting section below before editing the agent.</p><h3>3. Turn Ada into a Python tutor</h3><p>Open server/src/agent.py. Find the existing ADA_PROMPT and DEFAULT_GREETING definitions near the top and replace them with:</p><pre>ADA_PROMPT = &quot;&quot;&quot;You are Ada, a patient Python tutor.<br>Explain beginner Python concepts using short, spoken answers.<br>Use one concrete example when it helps, and ask a follow-up question<br>when the learner&#39;s request is unclear.<br>&quot;&quot;&quot;</pre><pre>DEFAULT_GREETING = (<br>    &quot;Hi! I&#39;m Ada, your Python tutor. What would you like to learn?&quot;<br></pre><p>Keep those variable names: the existing agent wrapper reads them. The prompt guides the model’s replies; the greeting supplies the first message in a new session. Leave the rest of the file unchanged for this exercise.</p><p>Save the file. With the conversation ended, press <strong>Ctrl+C</strong> in the terminal to stop the dev processes, then restart them from the project root:</p><pre>bun run dev</pre><p>Refresh the browser page and start a new conversation. You should hear the Python tutor greeting. Ask “What is a Python list?” and listen for a short explanation with an example. The exact wording of the generated answer will vary.</p><p>The restart matters: the backend in the referenced version does not automatically reload your Python changes. Starting a fresh browser conversation also ensures you’re listening to a new agent session.</p><h3>4. Follow a question from microphone to reply</h3><p>You changed Ada’s role without changing how audio reaches her. To see why, separate the application into three parts:</p><ul><li><strong>The browser</strong> captures microphone audio, plays Ada’s replies, and displays transcripts.</li><li><strong>The Python backend</strong> uses the Agora Agents SDK to configure, start, and stop agent sessions.</li><li><strong>The Agora cloud agent</strong> processes the conversation and sends spoken replies back to the browser.</li></ul><p>The browser and cloud agent exchange audio through Agora RTC, or Real-Time Communication. Inside the agent, each turn passes through three stages:</p><ol><li><strong>Speech-to-text (STT)</strong> turns your speech into text.</li><li><strong>A large language model (LLM)</strong> generates reply text using the conversation and the instructions you supplied.</li><li><strong>Text-to-speech (TTS)</strong> turns that reply into audio, which returns through RTC for playback.</li></ol><p>The referenced recipe configures Deepgram nova-3 for English speech recognition, OpenAI gpt-4o-mini for replies, and MiniMax speech_2_6_turbo for speech output. Those are this recipe&#39;s defaults, not requirements for every voice agent.</p><p>The transcript takes a separate path: Agora RTM, or Real-Time Messaging, carries text and agent-state updates to the browser. This distinction is useful when debugging: working audio with an empty transcript points you toward the messaging path.</p><p>Python controls the session lifecycle rather than receiving every audio chunk through an HTTP request. The backend supplies connection details through /get_config, starts the agent through /startAgent, and stops it through /stopAgent. The web client reaches these routes under /api/ through its development proxy.</p><h3>How the Python configuration connects</h3><p>Look again at server/src/agent.py. The wrapper creates an authenticated AsyncAgora client from your App ID and App Certificate. Inside Agent.start(), it passes that client and your instructions to AgoraAgent:</p><pre>agora_agent = AgoraAgent(<br>    client=self.client,<br>    instructions=ADA_PROMPT,<br>    greeting=self.greeting,<br>    # Other settings are omitted from this excerpt.<br>)</pre><p>This is an explanatory excerpt, not a replacement for the full block. The wrapper sets self.greeting from DEFAULT_GREETING, which connects your edit to the session&#39;s opening message.</p><p>The speech and language providers are then attached to the agent:</p><pre>agora_agent = (<br>    agora_agent<br>    .with_stt(stt)<br>    .with_llm(llm)<br>    .with_tts(tts)<br>)</pre><p>Finally, create_async_session(...) associates the agent with the conversation&#39;s channel and user. Calling await session.start() returns an agent ID that the backend retains for stopping the session later.</p><p>The full configuration also includes voice activity detection (VAD), which detects speech activity and helps determine pauses and interruptions. Keep those defaults while learning the basic flow; prompt changes and turn-timing changes are easier to evaluate separately.</p><h3>Troubleshooting</h3><p>If the conversation does not start, run this from the project root:</p><pre>agora project doctor --deep</pre><p>Follow the reported remediation. A passing diagnostic checks project readiness; the browser conversation remains the check for the complete audio loop.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J1QGpuvIU8GDItyoMaE37A.png" /></figure><h3>Give Ada a focused next task</h3><p>Try narrowing the tutor to one topic, such as Python lists, and ask the same few questions after each prompt change. Listen for whether the answers stay short, use examples, and ask for clarification when needed. Change one instruction at a time so you can judge what it did.</p><p>Voice can carry a guided explanation while the transcript provides something to revisit. For exact code that a learner needs to copy or compare, keep a readable on-screen version rather than relying on speech alone.</p><p>The <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-python">quickstart repository</a> contains the full implementation. With the first conversation and role change working, you have a concrete place to explore the next layer: the prompt, a speech provider, or the timing of each turn.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d717502d2fc1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/build-your-first-voice-agent-in-python-with-the-agora-agents-sdk-d717502d2fc1">Build Your First Voice Agent in Python with the Agora Agents SDK</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build a Talking Tongue Twister Game with Agora and NVIDIA Nemotron]]></title>
            <link>https://medium.com/agora-io/build-a-talking-tongue-twister-game-with-agora-and-nvidia-nemotron-3ccfb69ee923?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/3ccfb69ee923</guid>
            <category><![CDATA[nvidia]]></category>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[hugging-face]]></category>
            <category><![CDATA[nemotron]]></category>
            <dc:creator><![CDATA[Akshay Nandwana]]></dc:creator>
            <pubDate>Wed, 28 Oct 2026 21:26:43 GMT</pubDate>
            <atom:updated>2026-10-28T21:26:42.374Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Ten challenges. One cheeky AI host. How long before your tongue gives up?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xk45UXIsaszl6auMNRXYlA.png" /></figure><p>Try saying this out loud:</p><p><strong>कच्चा पापड़, पक्का पापड़।</strong></p><p>Now say it faster.</p><p>For English speakers, try:</p><p><strong>Red lorry, yellow lorry.</strong></p><p>These sentences look harmless on a screen. Put someone on a microphone, add a playful AI host, and suddenly you have a game.</p><p>That’s what we’re building: <strong>Zubaan Race</strong>, a Hindi and English tongue twister challenge powered by <strong>Agora Conversational AI</strong> and <strong>NVIDIA Nemotron 3.5 Transcribe</strong>.</p><p>The host introduces each challenge, listens to your voice commands, and talks through your results. NVIDIA transcribes each recorded attempt. Our application compares that transcript with the challenge and calculates the score.</p><p>You can run the web app on your laptop and use a free Hugging Face GPU demo for NVIDIA inference. You won’t need to download the model or configure a GPU server for this tutorial.</p><p><strong>Source code:</strong> <a href="https://github.com/AgoraIO-Community/agora-nemotron-transcribe">AgoraIO-Community/agora-nemotron-transcribe</a></p><h3>What we’re building</h3><p>Zubaan Race is a solo browser game with ten challenges in each language.</p><p>Choose <strong>हिंदी</strong> or <strong>English</strong> at the top right, start the game, and meet <strong>Chulbul</strong>, your AI host.</p><p>Here’s the game loop:</p><ol><li>Chulbul introduces a tongue twister.</li><li>You say the phrase.</li><li>A short pause ends your recording automatically.</li><li>NVIDIA transcribes what it heard.</li><li>The game calculates word match and a speed bonus.</li><li>Chulbul explains the result.</li><li>Say “try again” or “next” to continue.</li></ol><p>After the final round, ask the host which words matched, which ones differed, and what to practice. You can also review individual rounds, replay your best recordings, and download a score card.</p><p>The interface stays within the screen. Results use previous and next controls rather than a scrolling report.</p><p>The first Start action and microphone permission require a click. After that, voice commands control the main game flow, with buttons available as fallbacks.</p><h3>How Agora and NVIDIA work together</h3><p>A talking game needs two kinds of speech handling.</p><p>The host needs a live conversation loop: hear a command, respond naturally, and speak to the player. Scoring needs a completed recording that we can inspect and compare with a known phrase.</p><p>Each part has a specific responsibility:</p><ul><li><strong>Agora RTC</strong> carries the player’s microphone audio and the host’s spoken responses.</li><li><strong>Agora Conversational AI</strong> runs the host’s speech recognition, language model, and speech generation.</li><li><strong>Agora RTM and Client Toolkit</strong> carry host context, captions, and conversation events.</li><li><strong>NVIDIA Nemotron 3.5 Transcribe</strong> transcribes completed player attempts.</li><li><strong>The game’s scoring engine</strong> calculates word differences, match percentage, and points.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q-XE9dK1ULZdCf1jigeqJg.png" /></figure><p>NVIDIA describes Nemotron 3.5 Transcribe as an instruction-following model for recorded speech. Its promptable transcription is useful here: we want repetitions and mistakes preserved rather than rewritten into a cleaner sentence. <a href="https://huggingface.co/blog/nvidia/nemotron-transcribe-granary">NVIDIA’s introduction</a></p><p><strong>Nemotron is not the host’s live streaming recognizer in this application.</strong> It evaluates completed attempts separately.</p><p>The host’s live recognition handles conversation and commands. Only the NVIDIA transcript supplies the words used for scoring.</p><h3>Before you start</h3><p>You’ll need:</p><ul><li>Node.js 22 or newer.</li><li>pnpm.</li><li>An Agora account and project with an App Certificate, RTC, RTM, and Conversational AI available.</li><li>Access to the managed providers used by the host.</li><li>A free Hugging Face account and access token for your account’s GPU allowance.</li><li>A browser with microphone access.</li></ul><p>The host configuration uses Agora-managed Deepgram Nova-3, OpenAI GPT-4o-mini, and MiniMax TTS. Availability and usage charges depend on your Agora project.</p><p>The <strong>free part of this setup is the limited Hugging Face inference route</strong>. It does not make every service in the application unlimited or free.</p><p>Use headphones so the host’s voice is less likely to enter your microphone.</p><h3>Step 1: Install Agora Skills and the CLI</h3><p>The <a href="https://github.com/AgoraIO/cli">Agora CLI</a> handles account login, project discovery, configuration, and diagnostics.</p><p>For macOS or Linux:</p><pre>curl -fsSL https://dl.agora.io/cli/install.sh | sh</pre><p>Open a new terminal if necessary, then check the installation:</p><pre>agora version<br>agora doctor --json</pre><p>Use a current CLI release. This workflow requires version 0.2.1 or newer.</p><p>For Windows, use the installer documented in the <a href="https://github.com/AgoraIO/cli">CLI repository</a>.</p><p>If you’re working with an AI coding assistant, install <a href="https://github.com/AgoraIO/skills">Agora Skills</a> too:</p><pre>npx skills add github:AgoraIO/skills</pre><p>Skills give the assistant Agora-specific implementation guidance and references. They don’t replace account configuration or runtime testing.</p><p>The CLI also exposes its built-in workflow catalog:</p><pre>agora skills list --json</pre><p>Then sign in and find your project:</p><pre>agora login<br>agora project list</pre><p>Use your project ID or exact project name in the following steps.</p><h3>Step 2: Clone the game and configure Agora</h3><p>Clone the repository:</p><pre>git clone https://github.com/AgoraIO-Community/agora-nemotron-transcribe.git<br>cd agora-nemotron-transcribe</pre><p>Install dependencies and create the local configuration file:</p><pre>pnpm install --frozen-lockfile<br>cp env.local.example .env.local</pre><p>Bind the existing checkout to your Agora project:</p><pre>agora quickstart env write . \<br>  --template nextjs \<br>  --scenario voice-agent \<br>  --project YOUR_PROJECT</pre><p>Replace YOUR_PROJECT with your project ID or exact name.</p><p>The template-aware writer populates the names this Next.js application expects:</p><pre>NEXT_PUBLIC_AGORA_APP_ID=your_app_id<br>NEXT_AGORA_APP_CERTIFICATE=your_app_certificate</pre><p>The App ID is used by the browser. The App Certificate stays on the server.</p><p>Select the project and check Conversational AI readiness:</p><pre>agora project use YOUR_PROJECT<br>agora project doctor --feature convoai --json</pre><p>Resolve any reported project or feature requirements before continuing. A successful diagnostic checks configuration; an actual spoken conversation confirms the runtime connection.</p><p>This game was adapted from the <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-nextjs">Agora Next.js agent quickstart</a>. It preserves the quickstart’s RTC/RTM lifecycle and token patterns.</p><p>Use quickstart env write for this existing checkout. Running agora init creates a separate starter rather than installing the game’s custom UI and scoring logic.</p><h3>Step 3: Connect free NVIDIA inference</h3><p>The default provider uses the public <a href="https://huggingface.co/spaces/hugging-apps/nemotron-3-5-transcribe">Nemotron 3.5 Transcribe Hugging Face Space</a>.</p><p>It runs the exact model used in this tutorial:</p><pre>nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B</pre><p>Open .env.local and set:</p><pre>NEMOTRON_PROVIDER=hf-space<br>HF_TOKEN=hf_your_token_here</pre><p>You do not need NEMOTRON_BASE_URL for this provider.</p><p>To create your token:</p><ol><li>Sign in to Hugging Face.</li><li>Open <a href="https://huggingface.co/settings/tokens">Settings → Access Tokens</a>.</li><li>Create a <strong>Read</strong> token named zubaan-race.</li><li>Copy it into HF_TOKEN in .env.local.</li></ol><p>Read access is sufficient for this inference workflow; write access is unnecessary. Keep the token server-side and out of Git. <a href="https://huggingface.co/docs/hub/security-tokens">Hugging Face token documentation</a></p><h3>Understand the free quota</h3><p>At the time of writing:</p><ul><li>Anonymous users receive <strong>2 minutes of GPU time daily</strong>.</li><li>Free accounts receive <strong>5 minutes of GPU time daily</strong>.</li><li>This Space uses xlarge GPU allocation, which consumes quota at <strong>twice the standard rate</strong>.</li><li>GPU time is different from recording duration.</li><li>Players using the same backend token share its allowance.</li><li>Anonymous backend requests share the server’s anonymous allowance.</li></ul><p>Check the <a href="https://huggingface.co/docs/hub/spaces-zerogpu">current ZeroGPU limits</a> before relying on these numbers.</p><p>This is suitable for experimentation, but a ten-round run with retries may hit the quota.</p><p>The application never switches to a paid inference provider automatically. If the free GPU is unavailable or its quota is exhausted, the attempt remains unscored.</p><h3>Step 4: Check the connection and launch</h3><p>Check local prerequisites:</p><pre>pnpm run doctor</pre><p>Optionally, run one inference connectivity test:</p><pre>pnpm run smoke:inference</pre><p>This sends the bundled, attributed English sample to your selected provider. It uses GPU quota, so there’s no need to repeat it after a successful result.</p><p>A successful response includes a transcript beginning with:</p><pre>The birch canoe slid on the smooth planks.</pre><p>Now start the web app:</p><pre>pnpm dev</pre><p>Open the Local URL printed in your terminal.</p><p>Choose a language, accept audio processing, and start the game. In English, tell Chulbul:</p><blockquote><em>Start.</em></blockquote><p>In Hindi:</p><blockquote><em>शुरू करो।</em></blockquote><p>Choose <strong>Peek at the challenges</strong> if you want to inspect the phrases without starting the host or using inference.</p><p>Restart the server whenever you change .env.local.</p><h3>Step 5: Configure the conversational host</h3><p>The host is configured in app/api/invite-agent/route.ts.</p><p>Its provider chain uses the selected language:</p><pre>.withStt(new DeepgramSTT({<br>  model: &quot;nova-3&quot;,<br>  language,<br>}))<br>.withLlm(new OpenAI({<br>  model: &quot;gpt-4o-mini&quot;,<br>  greetingMessage: greeting,<br>  failureMessage,<br>  maxHistory: 30,<br>  params: {<br>    max_tokens: 300,<br>    temperature: 0.6,<br>  },<br>}))<br>.withTts(new MiniMaxTTS({<br>  model: &quot;speech_2_6_turbo&quot;,<br>  voiceId:<br>    language === &quot;en&quot;<br>      ? process.env.AGORA_HOST_VOICE_EN || &quot;English_Aussie_Bloke&quot;<br>      : process.env.AGORA_HOST_VOICE_HI ||<br>        process.env.AGORA_HOST_VOICE ||<br>        &quot;hindi_female_1_v2&quot;,<br>}))</pre><p>This is an excerpt from the existing server route. Its surrounding code validates requests, starts the agent session, and returns a signed capability used for cleanup.</p><p>The host’s personality is playful, but its responsibilities are narrow:</p><ul><li>Read the supplied challenge.</li><li>Wait for the player.</li><li>Explain results supplied by the application.</li><li>Answer questions about those results.</li></ul><p>The host does not invent a score or grade an attempt from its live recognition.</p><p>The application sends three main context messages:</p><ul><li><strong>GAME_LEVEL</strong> supplies the current phrase and instructions to read it once.</li><li><strong>GAME_RESULT</strong> supplies the measured transcript, match percentage, score, and word differences.</li><li><strong>GAME_SUMMARY</strong> supplies the completed run’s results.</li></ul><p>These are application-defined messages sent through the toolkit, not built-in Agora game events.</p><h3>Step 6: Coordinate the host and the recording</h3><p>The application waits until the host finishes introducing a challenge before recording the player’s attempt.</p><p>The browser watches the microphone’s audio level to identify speech. About 1.15 seconds of silence after speech ends the attempt automatically, with a maximum attempt window of 27 seconds.</p><p>The implementation lives in:</p><ul><li>lib/attempt-capture.ts</li><li>lib/capture.ts</li><li>public/pcm-recorder.js</li></ul><p>The recording becomes mono, 16 kHz PCM WAV audio.</p><p>Speaking duration is measured locally from detected speech onset to the last detected speech. Pauses within the utterance count; upload and GPU processing time do not.</p><p>A player should not lose speed points because a GPU request waited in a queue.</p><p>The scored recording comes from the player’s local microphone track rather than the combined conversation. Headphones still matter because a microphone can physically pick up the host’s voice from speakers.</p><h3>Step 7: Ask NVIDIA to preserve the attempt</h3><p>The transcription instruction in lib/game.ts is deliberately specific:</p><pre>export const transcriptionInstruction = (language: GameLanguage) =&gt;<br>  `Transcribe the ${<br>    language === &quot;en&quot;<br>      ? &quot;English speech in English&quot;<br>      : &quot;Hindi speech in Devanagari&quot;<br>  } exactly as spoken. Preserve repetitions, false starts, omissions and incorrect words. Do not correct tongue twisters or infer missing words. Output only the transcript.`;</pre><p><strong>The expected tongue twister is never included in the NVIDIA request.</strong></p><p>Supplying the answer as a hint could encourage the recognizer to reconstruct the intended phrase and hide the differences the game is trying to show.</p><p>The browser sends the recording to:</p><pre>POST /api/evaluate?level=0&amp;language=en&amp;seconds=4.200<br>Content-Type: audio/wav</pre><p>The route validates:</p><ul><li>The selected language.</li><li>The level number.</li><li>The WAV format and upload size.</li><li>The recording length.</li><li>The supplied speaking duration against the clip’s duration.</li></ul><p>It then calls the selected transcription provider:</p><pre>const result = await transcribe(<br>  bytes,<br>  duration,<br>  &quot;verbatim&quot;,<br>  &quot;&quot;,<br>  true,<br>  request.signal,<br>  fetch,<br>  transcriptionInstruction(language),<br>);</pre><p>For the free Space, lib/hf-space.ts:</p><ol><li>Uploads the recording through the Gradio upload API.</li><li>Queues a /transcribe request with the neutral instruction.</li><li>Reads the server-sent event stream.</li><li>Waits for the final completed response.</li><li>Removes processing statistics from the returned text.</li><li>Rejects incomplete, empty, or output-limited responses.</li></ol><p>Partial text is never scored.</p><p>The free Space returns transcript text without word timestamps. The game uses its locally measured speaking duration and transcript comparison. The self-hosted provider has a separate optional alignment path.</p><h3>Step 8: Calculate the score</h3><p>The scoring engine lives in lib/game.ts.</p><p>It normalizes Unicode, ignores punctuation and invisible joiners, and compares words using Levenshtein alignment. Hindi vowel marks, repeated words, and word order remain significant.</p><p>The comparison identifies:</p><ul><li>Matching words.</li><li>Substitutions.</li><li>Missing words.</li><li>Extra words.</li></ul><p>For example:</p><pre>Expected: कच्चा पापड़ पक्का पापड़<br>Heard:    कच्चा पापड़ पापड़</pre><p>One of four expected words is missing:</p><pre>Word match = 75%<br>Accuracy points = 75 × 8 = 600<br>Speed bonus = 0</pre><p>The formulas are:</p><pre>word match =<br>  max(0, round(100 × (1 − word edit distance / expected word count)))<br>accuracy points =<br>  word match × 8</pre><p>A speed bonus unlocks only at 90% word match or higher:</p><pre>speed bonus =<br>  round(200 × min(1, target seconds / speaking seconds))</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ky7U3Cv4Y7XMsGGCMJwUuQ.png" /></figure><p>Each round offers up to 1,000 points, for a maximum run score of 10,000. Retrying keeps the highest-scoring attempt for that level.</p><p>The server calculates these values. It does not accept a score generated by the model.</p><p><strong>Word match is not a pronunciation assessment.</strong> Speech recognition can mishear a correct attempt or infer an intended word. The visible transcript and recorded replay let players inspect the result themselves.</p><h3>Step 9: Turn the score into a conversation</h3><p>After scoring, the application sends the host the actual result:</p><pre>{<br>  level: currentLevel + 1,<br>  expected: TWISTERS[currentLevel].text,<br>  heard: result.transcript,<br>  wordMatch: result.match,<br>  points: result.score,<br>  seconds: result.speakingSeconds,<br>  differences: result.differences.filter(<br>    word =&gt; word.kind !== &quot;match&quot;<br>  )<br>}</pre><p>The expected phrase can be shared with the host at this stage because transcription has already completed.</p><p>The host can explain that a word was missing or that the transcript contained a different word. Its instructions prohibit diagnosing tongue placement, accent quality, or pronunciation disorders.</p><p>At the end, GAME_SUMMARY supplies the best recorded result for each completed round.</p><p>The player can then ask:</p><blockquote><em>Which words should I practice?</em></blockquote><p>The host has concrete results to refer to rather than a score it guessed.</p><h3>Step 10: Support Hindi and English</h3><p>The language switch changes:</p><ul><li>The challenge catalog.</li><li>Interface copy.</li><li>Host greeting and instructions.</li><li>Live recognition language.</li><li>Host voice.</li><li>NVIDIA transcription instruction.</li><li>Expected words used for scoring.</li><li>Result labels and score-card headline.</li></ul><p>English mode has its own ten phrases, including Peter Piper and the woodchuck challenge. It is not a translation of the Hindi phrases.</p><p>The switch is disabled during an active session. Exit the game before changing languages so recordings and results from different catalogs cannot mix.</p><h3>Test the implementation</h3><p>Run the repository checks:</p><pre>pnpm run verify</pre><p>The current suite contains 26 tests covering:</p><ul><li>Hindi text normalization and English challenge targets.</li><li>Word alignment and deterministic scoring.</li><li>Speed bonuses and best-attempt selection.</li><li>Request validation and token behavior.</li><li>Recording finalization.</li><li>Chunked transcription responses.</li><li>Quota errors and cancellation.</li><li>Rejection of incomplete output.</li><li>Isolation of expected phrases from inference prompts.</li></ul><p>The integration was also checked against real NVIDIA inference through the free Space:</p><ul><li>A bundled 15-second speech sample completed through the adapter in <strong>12.4 seconds</strong>.</li><li>A four-second sample completed through /api/evaluate in approximately <strong>9.7 seconds</strong>.</li><li>The free-provider readiness endpoint returned ready.</li></ul><p>These are individual connectivity measurements, not latency guarantees or Hindi accuracy benchmarks.</p><p>Before sharing your own deployment, test the complete microphone experience: host speech, voice commands, all ten rounds, retries, replay, final spoken review, and session cleanup.</p><h3>Troubleshooting</h3><h3>“NVIDIA server is not reachable”</h3><p>Set the free provider explicitly:</p><pre>NEMOTRON_PROVIDER=hf-space</pre><p>Restart the application. The vllm provider expects your own GPU server.</p><h3>“Free GPU quota is exhausted”</h3><p>Check that HF_TOKEN is configured and restart the server after adding it.</p><p>A token uses your account’s allowance; it does not remove daily limits. Wait for the quota to reset if the account allowance is also exhausted.</p><p>Avoid repeating connectivity tests unnecessarily.</p><h3>The host cannot join</h3><p>Check:</p><ul><li>Agora project readiness.</li><li>RTM availability.</li><li>App ID and App Certificate.</li><li>Access to the configured managed providers.</li></ul><h3>No speech is detected</h3><p>Check:</p><ul><li>Browser microphone permission.</li><li>The selected input device.</li><li>Microphone distance and input level.</li></ul><h3>The host misses “next” or “repeat”</h3><p>Use the visible fallback control and try again in a quieter environment.</p><h3>The transcript looks unexpectedly correct</h3><p>Listen to the replay. ASR can reconstruct intended speech even without an answer hint.</p><h3>GPU processing takes a long time</h3><p>The free provider may be queued. Processing time does not affect the speed score.</p><p>The readiness endpoint checks whether the provider’s API is reachable. It cannot reserve GPU time or guarantee sufficient remaining quota.</p><h3>Taking it beyond a local demo</h3><p>For limited experimentation, the free Space keeps setup small: a laptop, an Agora project, and a Hugging Face token.</p><p>For a public deployment:</p><ul><li>Add application access controls.</li><li>Limit request frequency and concurrent inference.</li><li>Account for all visitors sharing a backend token’s quota.</li><li>Review recording handling with your inference provider.</li><li>Configure host and inference usage limits.</li></ul><p>The repository also includes an optional self-hosted NeMo/vLLM route:</p><pre>NEMOTRON_PROVIDER=vllm<br>NEMOTRON_BASE_URL=http://127.0.0.1:8000/v1<br>NEMOTRON_MODEL=nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B</pre><p>Its setup scripts target NVIDIA’s documented BF16 H100 80 GB configuration. Check the current <a href="https://huggingface.co/nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B">model card</a> for supported hardware and serving instructions.</p><p>Granary v2 and NVIDIA’s adaptation recipes offer another direction if you later want to investigate domain-specific transcription. They are not required to run this game. <a href="https://huggingface.co/blog/nvidia/nemotron-transcribe-granary">NVIDIA’s model and dataset introduction</a></p><p>For now, start with the first phrase.</p><p><strong>कच्चा पापड़, पक्का पापड़।</strong></p><p>Your microphone is ready. Is your tongue?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3ccfb69ee923" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/build-a-talking-tongue-twister-game-with-agora-and-nvidia-nemotron-3ccfb69ee923">Build a Talking Tongue Twister Game with Agora and NVIDIA Nemotron</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Conversational AI App in Flutter with Agora]]></title>
            <link>https://medium.com/agora-io/building-a-conversational-ai-app-in-flutter-with-agora-99af67e17c83?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/99af67e17c83</guid>
            <category><![CDATA[voice-ai]]></category>
            <category><![CDATA[conversational-ai]]></category>
            <category><![CDATA[flutter]]></category>
            <category><![CDATA[flutter-app-development]]></category>
            <dc:creator><![CDATA[Akshay Nandwana]]></dc:creator>
            <pubDate>Mon, 26 Oct 2026 18:21:39 GMT</pubDate>
            <atom:updated>2026-10-26T18:21:37.978Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Build a voice agent for web, mobile, and desktop with a Flutter interface you can extend.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DqWaNXwVU-vrMSlkacMzfA.png" /></figure><p>A useful voice interface needs to do several things at once: capture speech, deliver the agent’s response, show what was said, and keep the user informed while the conversation connects or ends. Those details shape the experience as much as the model behind it.</p><p>The <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter">Agora Conversational AI Flutter Quickstart</a> brings those pieces together in an app you can run and explore. It pairs a Flutter client with a small Node.js backend and Agora’s Conversational AI Engine.</p><p>In this tutorial, we’ll start a conversation in Chrome, trace it through the code, and customize the agent for a different use case. Then we’ll explore the web, Android, iOS, and macOS targets. The repository shares its Flutter UI and session controller across these platforms, with platform-specific services underneath.</p><p><a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter#demo">Watch the conversation demo.</a></p><h3>What you’ll build</h3><p>The sample starts a voice conversation with Ada, an assistant configured to help developers with Agora. You can speak into your microphone, hear the agent’s replies, read the transcript, mute yourself, and end the session.</p><p>The interface also exposes the channel, user IDs, agent ID, and connection state. Those details make it easier to understand what is happening while you develop your own experience.</p><p>You can adapt this foundation into a language practice partner, an onboarding assistant, a product guide, or another voice experience with your own prompt and interface.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jTx0YNYwEy4Q1gmZqWXF2w.png" /></figure><p><em>One Flutter interface, several places to talk. The platform section below explains what each target currently supports.</em></p><h3>How the pieces fit together</h3><p>The app has three main parts:</p><ul><li><strong>Flutter client:</strong> Renders the interface, requests microphone access, joins audio, and displays conversation updates.</li><li><strong>Node.js backend:</strong> Generates tokens and starts or stops agent sessions using server-side credentials.</li><li><strong>Agora services:</strong> Carry RTC audio, run the configured conversational AI pipeline, and deliver RTM events.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B_ohpI913aGAg0hQ6faibg.png" /></figure><p>RTC carries the live audio. RTM carries messages such as transcript and agent-state updates. The backend keeps the Agora App Certificate out of the Flutter application.</p><p>That separation gives you clear places to work: change the interface in Flutter, adjust the agent configuration on the server, and keep credentials on the server throughout.</p><h3>1. Get the quickstart</h3><p>You’ll need Flutter, its bundled Dart SDK, Node.js 22 or newer, npm, Chrome, and an Agora project with Conversational AI and RTM enabled. You’ll also need the project’s App ID and App Certificate from the <a href="https://console.agora.io">Agora Console</a>.</p><p>This walkthrough uses the dependency-upgrade snapshot at commit d859829, which requires Flutter 3.47.7 and Dart 3.13.5 or newer. Checking out that revision keeps the code aligned with the examples here:</p><pre>git clone https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter.git<br>cd agent-quickstart-flutter<br>git checkout d859829<br>flutter --version<br>node --version</pre><p>To make your own changes on this snapshot, create a branch:</p><pre>git switch -c my-voice-agent</pre><h3>2. Configure the backend</h3><p>Create a file named .env.local in the repository root, beside pubspec.yaml:</p><pre>NEXT_PUBLIC_AGORA_APP_ID=your_agora_app_id<br>NEXT_AGORA_APP_CERTIFICATE=your_agora_app_certificate<br>NEXT_PUBLIC_AGENT_UID=123456<br>NEXT_AGENT_GREETING=&quot;Hi! I&#39;m Ada. What would you like to build today?&quot;</pre><p>The backend reads this file and exposes the public client configuration through /api/client-config. The NEXT_ prefixes are the environment-variable names used by this sample; the companion server is a Node.js application.</p><p>The App ID identifies your project. The App Certificate is a secret used by the backend for authentication and token generation. Keep the certificate in this server-side file and out of Dart code, browser JavaScript, and --dart-define values. The repository ignores .env.local in Git.</p><p>The sample configures its speech recognition, language model, and speech synthesis through Agora-managed inference, so its base configuration does not require separate provider API keys. Your Agora project must have access to the configured services.</p><p>Start the backend from the repository root:</p><pre>cd backend<br>npm ci<br>npm run dev</pre><p>It listens on port 3001 by default. In another terminal, check that it is running:</p><pre>curl http://localhost:3001/health</pre><p>The response should be:</p><pre>{&quot;ok&quot;:true}</pre><p>That confirms the server is reachable. The first conversation will exercise the Agora credentials and agent configuration.</p><h3>3. Start the Flutter app</h3><p>In a second terminal, navigate to the repository root and run:</p><pre>flutter pub get<br>flutter run -d chrome</pre><p>Click <strong>Start Conversation</strong> and allow microphone access when Chrome asks. Once the agent joins, speak a short question such as “What can I build with Agora?”</p><p>Look for the agent’s audio, transcript updates, and connection information. Try <strong>Mute mic</strong>, unmute, and then choose <strong>End Conversation</strong>.</p><p>You now have a concrete flow to modify: start a session, exchange speech, observe its state, and clean it up.</p><h3>4. Follow a conversation through the code</h3><p>The main session logic lives in <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter/blob/d85982910a49a3a59413b26060bb5c4e79fc7e8a/lib/services/conversation_session_controller.dart">ConversationSessionController</a>. It extends ChangeNotifier, allowing the interface to rebuild as session state changes.</p><p>When you start a conversation, the controller requests microphone access, obtains a token, and asks the backend to invite the agent. This excerpt shows the token-to-agent handoff:</p><pre>final tokenData = await _backendApi.generateToken();<br>final agentResponse = await _backendApi.inviteAgent(<br>  ClientStartRequest(<br>    requesterId: tokenData.uid,<br>    channelName: tokenData.channel,<br>  ),<br>);</pre><p>The backend routes provide a small API surface:</p><ul><li><strong>GET /api/client-config:</strong> Returns the public App ID, agent UID, and greeting.</li><li><strong>GET /api/generate-agora-token:</strong> Returns a token, client UID, and channel name.</li><li><strong>POST /api/invite-agent:</strong> Starts the agent for the requested channel and returns its agent ID.</li><li><strong>POST /api/stop-conversation:</strong> Stops the agent identified by that agent ID.</li></ul><p>The controller then initializes RTM with the returned client identity and subscribes to the conversation channel. It initializes RTC and joins that same channel for audio.</p><p>The <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter/blob/d85982910a49a3a59413b26060bb5c4e79fc7e8a/lib/services/rtc_session_service.dart">RTC service</a> joins with these media options:</p><pre>options: const ChannelMediaOptions(<br>  clientRoleType: ClientRoleType.clientRoleBroadcaster,<br>  publishMicrophoneTrack: true,<br>  autoSubscribeAudio: true,<br>  autoSubscribeVideo: false,<br>),</pre><p>This publishes microphone audio and subscribes to incoming audio. The sample does not subscribe to video.</p><p>Keep the identities consistent when extending the app: the token’s client UID is also the RTM login identity, and the agent, RTC client, and RTM subscription use the same conversation channel.</p><p>The client joining RTC and the agent joining RTC are separate events. A successful client connection is useful progress; the remote-user join event tells you that the agent’s audio participant has arrived.</p><p>Here is the successful session path, from the first click to cleanup:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YZGTBONK03H-TaNb0u6eTg.png" /></figure><p>The channel ties the audio and events together. The agent ID identifies the server-side session to stop; the client UID identifies the person joining it.</p><h3>5. Understand the agent configuration</h3><p>The backend configures the agent in <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter/blob/d85982910a49a3a59413b26060bb5c4e79fc7e8a/backend/src/agent.js">backend/src/agent.js</a>.</p><p>At this snapshot, the pipeline uses Deepgram nova-3 for speech recognition, OpenAI gpt-4o-mini for language responses, and MiniMax speech_2_6_turbo for speech synthesis. These are the sample’s configured choices; they are not requirements for every app you build.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sEinTmugHAt9dxkqVSP0jw.png" /></figure><p><em>A voice turn takes a trip through the pipeline. RTM separately brings transcript and state updates back to the interface.</em></p><p>The agent configuration contains its instructions, greeting, turn-detection settings, and RTM options. The following excerpt enables the RTM data channel and requests metrics and error messages:</p><pre>advancedFeatures: { enable_rtm: true, enable_tools: true },<br>parameters: {<br>  data_channel: &#39;rtm&#39;,<br>  enable_error_message: true,<br>  enable_metrics: true,<br>},</pre><p>The server creates a session for the client’s channel and starts it:</p><pre>const session = agent.createSession({<br>  channel: channel_name,<br>  agentUid: process.env.NEXT_PUBLIC_AGENT_UID ?? String(DEFAULT_AGENT_UID),<br>  remoteUids: [requester_id],<br>  idleTimeout: 30,<br>  expiresIn: ExpiresIn.hours(1),<br>  debug: false,<br>});<br>const agentId = await session.start();</pre><p>Flutter stores the returned agent ID so it can ask the backend to stop that specific session later.</p><h3>6. Make the agent your own</h3><p>Start with a focused change to the agent’s purpose. For example, replace the ADA_PROMPT text in backend/src/agent.js with instructions for a language practice partner:</p><pre>const ADA_PROMPT = `You are a patient English conversation partner.<br>Help the learner practice everyday situations.<br>Keep each response to one or two short sentences.<br>Ask one question at a time.<br>When correcting a mistake, offer one natural alternative and continue the conversation.`;</pre><p>Update the greeting in .env.local to match:</p><pre>NEXT_AGENT_GREETING=&quot;Let&#39;s practice ordering at a café. What would you like to order?&quot;</pre><p>Restart the backend and start a fresh conversation. The existing RTC, RTM, and session flow can support the new persona without changes to the transport code.</p><p>Next, adapt the Flutter interface in lib/main.dart. You might add a scenario selector, a lesson objective, or a completion screen. Transcript formatting lives under lib/utils/, while the session controller owns lifecycle state.</p><p>If you add scenarios that affect the server prompt, send an allowed scenario identifier to the backend and map it to server-owned instructions. That gives your app a controlled configuration surface as it grows.</p><p>The scenario selector is an extension you can add; the current sample starts with Ada’s configured persona. A possible extension would look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Pw9k2Ih_3WVTX7E_UYJwXw.png" /></figure><h3>7. Take the same app to web, mobile, and desktop</h3><p>Flutter lets this sample share its interface and session logic across targets. The RTC and RTM implementations still depend on the platform, so the current quickstart has the following scope:</p><ul><li><strong>Web / Chrome:</strong> Run flutter run -d chrome for browser RTC audio and RTM transcripts/state through the JavaScript bridge.</li><li><strong>Android:</strong> Run flutter run -d &lt;android-device-id&gt; for native RTC audio and RTM transcripts/state.</li><li><strong>iOS:</strong> Run flutter run -d &lt;ios-device-id&gt; for native RTC audio and RTM transcripts/state. Requires Xcode, CocoaPods, and device setup.</li><li><strong>macOS:</strong> Run flutter run -d macos for RTC audio and microphone capture. RTM is stubbed, so live transcripts and RTM agent-state updates are unavailable.</li></ul><p>This repository includes host projects for these targets. Windows and Linux would require additional host setup, compatible SDKs, and validation; this article does not treat them as supported quickstart targets.</p><h3>Web: share a browser experience</h3><p>Keep the Node.js companion running and launch Chrome:</p><pre>flutter run -d chrome</pre><p>The browser target defaults to http://localhost:3001. To generate the web assets for hosting, run:</p><pre>flutter build web</pre><p>The output goes into build/web. A hosted version also needs a reachable backend, <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#privacy_and_security">HTTPS for microphone access</a>, and the public backend URL supplied when building:</p><pre>flutter build web \<br>  --dart-define=BACKEND_BASE_URL=https://your-backend.example.com</pre><p>The backend address is embedded in that build. Supply the real address before deploying the web assets, and add the backend access controls described at the end of this tutorial.</p><h3>Android: emulator or physical device</h3><p>For an Android emulator, keep the backend running and use:</p><pre>flutter devices<br>flutter run -d &lt;android-device-id&gt;</pre><p>The app defaults to http://10.0.2.2:3001 on Android, which lets an emulator reach the host computer. The updated project builds against Android SDK 37 and requires API 24 or newer at runtime. For a physical Android phone, use the LAN override below.</p><h3>iOS: simulator or physical device</h3><p>On a Mac with the required Xcode components installed, select an iOS simulator or connected device from flutter devices:</p><pre>flutter run -d &lt;ios-device-id&gt;</pre><p>The iOS default is http://127.0.0.1:3001, suitable for a simulator reaching the backend on the same Mac. The iOS project requires iOS 15 or newer, Xcode with the appropriate platform components, and CocoaPods for the RTM plugin. Physical-device builds also need signing configured and a reachable backend URL.</p><h3>Physical phones: use a reachable backend</h3><p>For a physical Android or iOS device, point Flutter at a backend address the device can reach. For example, with the phone and computer on the same network:</p><pre>flutter run -d &lt;device-id&gt; \<br>  --dart-define=BACKEND_BASE_URL=http://192.168.1.10:3001</pre><p>Replace the example address with your computer’s LAN IP. Allow local-network access if prompted and make sure the computer’s firewall allows the backend connection. Use HTTPS for a deployed backend.</p><h3>macOS: explore a desktop voice interface</h3><p>With the backend running on the same Mac:</p><pre>flutter run -d macos</pre><p>The app defaults to http://127.0.0.1:3001. You can explore RTC audio and microphone capture in a native desktop window. The current macOS RTM service is a stub, so transcript and RTM agent-state events do not reach the UI. Adding a compatible macOS event transport is one way to extend this quickstart.</p><p>Choose a target for the experience you want to explore: Chrome offers the tutorial’s initial browser path, Android and iOS take the conversation onto phones, and macOS provides a starting point for a desktop voice interface.</p><h3>Where to look when something goes wrong</h3><p>If the app cannot load configuration, check the backend’s /health endpoint and the client’s backend URL. On a physical phone, localhost points to the phone itself.</p><p>If a conversation fails to start, check the backend terminal, the App ID and certificate, and whether your Agora project has access to Conversational AI and RTM. If you already use the Agora CLI, agora project doctor --deep provides additional project diagnostics.</p><p>If audio works but transcripts do not appear, inspect the RTM connection and channel identity. On web, <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter/blob/d85982910a49a3a59413b26060bb5c4e79fc7e8a/web/index.html">web/index.html</a> loads the browser SDKs, and web/rtm_bridge.js connects the RTM JavaScript SDK to Flutter.</p><p>When you change SDK versions, keep the Flutter RTC package and its documented Iris browser script compatible. The snapshot above pins a matching combination.</p><h3>Build on top of the quickstart</h3><p>Once your first conversation works, choose one useful behavior to add: a different agent persona, a guided practice session, a product-specific interface, or a conversation history view.</p><p>The session controller already provides places to work with microphone controls, token renewal, transcript updates, and ending a conversation. When <strong>End Conversation</strong> succeeds, it stops the backend agent, leaves RTM and RTC, disposes the services, and resets the client state.</p><p>For a deployed product, extend the companion backend with user authentication and session ownership checks before exposing its agent-control routes publicly. Its current routes are designed for a local quickstart. Add recovery for partial startup and cleanup failures as you develop the complete session experience.</p><p><a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-flutter">Clone the Flutter quickstart</a>, run the sample conversation, and give Ada a new purpose. A working voice session is a useful starting point for discovering what your own app should do next.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99af67e17c83" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/building-a-conversational-ai-app-in-flutter-with-agora-99af67e17c83">Building a Conversational AI App in Flutter with Agora</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Agora Skill Now Supports RTC: From Prompt to Video Call]]></title>
            <link>https://medium.com/agora-io/agora-skill-now-supports-rtc-from-prompt-to-video-call-4f729e3c8e75?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/4f729e3c8e75</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[vibe-coding]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[webrtc]]></category>
            <dc:creator><![CDATA[June]]></dc:creator>
            <pubDate>Fri, 09 Oct 2026 15:08:53 GMT</pubDate>
            <atom:updated>2026-10-09T15:08:52.518Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="agroa skill now supports RTC" src="https://cdn-images-1.medium.com/max/1024/1*4Vv7eHGGKuoaAIo2Phfkyw.jpeg" /></figure><p>Agora Skill now supports setting up a one-to-one voice and video calling demo for the web, extending its guided setup workflow from Voice Agent to RTC. Once Agora Skill and the Agora CLI are installed, you can ask your AI coding assistant to set up and run the demo.</p><p>The Skill gives your assistant the instructions to follow, while the Agora CLI handles project setup and credentials. Together, they help your assistant get the demo running with less manual work from you.</p><h3>How it works</h3><p>The CLI now includes a one-to-one calling scenario. Following the Skill’s instructions, your assistant uses the CLI to guide you through signing in and choosing an Agora project, or creating one if needed. It then retrieves the App ID and project credentials, prepares the demo, and runs it.</p><p>Once the demo is running, turn on your camera for a video call, or leave it off for an audio-only conversation. You have a Web calling demo and its source code to explore and extend. The interface follows the same design as the Voice Agent Quickstart, giving both scenarios a consistent look and feel.</p><h3>A faster path from prompt to prototype</h3><p><strong>Less manual setup.</strong> The CLI retrieves the credentials the demo needs, so you don’t have to copy values from the console and pass them back to your assistant. Your main setup interactions are signing in once and choosing a project.</p><p><strong>A more predictable workflow.</strong> Your assistant starts with a complete calling example and a defined setup sequence. That reduces the implementation decisions it needs to make before you can try the demo, while the Skill and CLI connect project preparation with running the sample.</p><p><strong>Up and running sooner.</strong> In early trials, our engineering team reported completing setup in under 10 minutes. Actual time will vary with your development environment, network, and coding assistant.</p><h3>Get started</h3><p>Run the demo locally and try a one-to-one video call between two browser windows.</p><h3>Prerequisites</h3><ul><li>An AI coding tool that supports Skills, such as Codex or Claude Code</li><li>Node.js 22 and npm or pnpm installed locally</li></ul><h3>1. Install Agora Skill and the CLI</h3><p>In your terminal, install Agora Skill for your coding assistant:</p><pre>npx skills add github:AgoraIO/skills</pre><p>Then install the Agora CLI. On macOS or Linux:</p><pre>curl -fsSL https://dl.agora.io/cli/install.sh | sh</pre><p>On Windows, use PowerShell 7+:</p><pre>irm https://dl.agora.io/cli/install.ps1 | iex</pre><p>Make sure Agora Skill is loaded in your coding tool. Tool-specific setup instructions are in the Agora Skill repository listed below.</p><p><em>Agora Skill installed in Codex.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZHKo3g1bivs183PwOzseUw.png" /></figure><h3>2. Run the demo with a prompt</h3><p>With Agora Skill loaded, send this request to your coding assistant:</p><pre>I&#39;d like to create an Agora video call demo, could you help me?</pre><p><em>Ask your coding assistant to create an Agora video call demo.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*qOdS9uIyNNzgxp_-0F1eNA.png" /></figure><p>Follow the sign-in prompts, then select an Agora project or create one. If the project has no primary App Certificate, enable one in Agora Console or choose another project.</p><p>When your assistant returns the local URL, open it in your browser. You should see the Quickstart home page with a <strong>Create Channel</strong> action.</p><p><em>The assistant returns the local URL for the running RTC demo.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/590/1*BmLy99ZFCcGIuCJXX9-yVQ.png" /></figure><h3>3. Make your first call</h3><p>Select <strong>Create Channel</strong>, enter your display name, and copy the invite link. Select <strong>Join Call</strong> and allow camera and microphone access when prompted.</p><p><em>Enter your name, copy the invite link, and join the call.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/964/1*M60SifzOzI3VXQsDn1MvUQ.png" /></figure><p>Open the invite link in a second browser window on the same computer. Enter a different display name and join the channel. Keep both microphones and cameras on, and check that each window shows the other participant’s video and receives their audio. Use headphones to avoid feedback.</p><p>You now have a local copy of the Quickstart to explore and extend. See the RTC Quickstart repository below for configuration and deployment instructions.</p><p>We plan to add more scenarios and extend support to additional platforms and programming languages.</p><p>We’re also refreshing the Voice Agent and RTC experiences in the <a href="https://console.agora.io">Agora Console</a>. You can try both scenarios more easily and copy sample code to continue building.</p><h3>GitHub resources</h3><ul><li><a href="https://github.com/AgoraIO/skills">Agora Skill — installation and tool setup</a></li><li><a href="https://github.com/AgoraIO/cli">Agora CLI — installation and troubleshooting</a></li><li><a href="https://github.com/AgoraIO-Community/agora-rtc-quickstart-nextjs">RTC Quickstart — source code, npm setup, and deployment</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4f729e3c8e75" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/agora-skill-now-supports-rtc-from-prompt-to-video-call-4f729e3c8e75">Agora Skill Now Supports RTC: From Prompt to Video Call</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Jev VAD: Turn Detection That Understands What You Say]]></title>
            <link>https://medium.com/agora-io/jev-vad-turn-detection-that-understands-what-you-say-9cfab27b0f1a?source=rss----548c45ba4c8b---4</link>
            <guid isPermaLink="false">https://medium.com/p/9cfab27b0f1a</guid>
            <category><![CDATA[jevs]]></category>
            <category><![CDATA[typesafe-ai]]></category>
            <category><![CDATA[conversational-ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Jay Albo]]></dc:creator>
            <pubDate>Thu, 01 Oct 2026 14:27:15 GMT</pubDate>
            <atom:updated>2026-10-01T14:27:14.283Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CLHvUXxlXM3CumRNmmcfLA.png" /></figure><p><em>Splitting turn-taking in an Agora Conversational AI agent between a fast acoustic gate and TypeSafe’s Jev, starting from a quickstart recipe.</em></p><p>Voice agents are very good at noticing silence. They’re much worse at knowing what the silence means.</p><p>Say “So what I want to know is…” and pause while you look for the next word. In a silence-driven turn detector, that pause can be enough to close the turn and send an unfinished thought to the agent. In a basic VAD-driven setup the language model may never see the problem: the turn was already closed because the audio pipeline interpreted the pause as end of speech.</p><p>Silence doesn’t tell you whether someone has finished their turn. A speaker may be searching for a word. An “uh-huh” during the agent’s response may only be a backchannel, and speech picked up by the microphone might not be directed at the agent at all. Audio activity can tell you that something happened; it gives you very little information about the speaker’s intent.</p><h3>What I built</h3><p>Instead of asking one detector to solve the entire problem, I split turn-taking into two jobs. Audio still detects that someone has started speaking. Once text begins arriving from speech recognition, Jev decides whether the speaker has actually yielded the floor.</p><p>The project is called Jev VAD, although Jev itself isn’t doing voice activity detection. The VAD-like part is a lightweight acoustic gate in the browser; Jev handles the semantic decisions that conventional VAD can’t make. It runs on Agora’s Conversational AI Engine, and it’s open source.</p><p>Jev is TypeSafe’s System One model. Instead of generating text, it takes application state and focused questions and returns typed probabilistic decisions. That makes it useful here because I don’t need another model to write anything. I need a few numbers the application can branch on.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FB3Y6CnUkC2c%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DB3Y6CnUkC2c&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FB3Y6CnUkC2c%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/dc71e03e33ce4f9a56bd8b29f1a9b9db/href">https://medium.com/media/dc71e03e33ce4f9a56bd8b29f1a9b9db/href</a></iframe><h3>Architecture at a glance</h3><pre>mic<br> ↓<br>acoustic gate (browser)<br> ↓<br>manualSOS<br> ↓<br>Agora ASR → streaming transcript → /judgeTurn → Jev<br>                                                 ↓<br>                         turn_complete · holding_floor ·<br>                         addressed_to_agent · taking_floor<br>                                                 ↓<br>                         browser: manualEOS, interrupt(), or keep listening</pre><p>The short version of the design is <em>open fast, decide late</em>.</p><p>Speech onset and end-of-turn detection have very different latency requirements. For onset, I care more about speed than intelligence, because waiting too long risks clipping the first word. The browser watches microphone energy against a moving noise floor and opens the turn after roughly 110 ms of sustained activity. It also drops obvious impulsive bursts, like a single click or thump, before they open anything.</p><p>Some non-speech sounds can still get through the gate and open a turn. That is intentionally cheap: if speech recognition produces no text, the controller never closes the turn or sends anything to the agent.</p><p>End of turn is where Jev comes in. As the streaming transcript evolves, the browser sends it to Jev, which returns four scores in one call:</p><ul><li>turn_complete: has the speaker actually handed over the floor? &quot;So what I want to know is…&quot; hasn&#39;t.</li><li>holding_floor: are they explicitly asking for more time, as in &quot;hold on, let me type something&quot;?</li><li>addressed_to_agent: is the latest speech intended for the assistant? &quot;Hey, can you hold my coffee?&quot; usually isn&#39;t.</li><li>taking_floor: while the agent is talking, is this a real interruption or just a backchannel like &quot;right&quot;?</li></ul><p>In my test sessions the Jev call usually came back in roughly 300 ms. That is too slow to sit in front of speech onset, but perfectly usable once speech recognition is already streaming words, which is why the two jobs are split the way they are.</p><p>The client still measures silence, but it no longer treats a fixed silence duration as the decision. Instead, silence gradually relaxes the score Jev needs to reach before the client closes the turn.</p><h3>Start from the recipe with the Agora CLI</h3><p>Jev VAD is available in the <a href="https://recipes.agora.io/recipes/jev-vad">Agora recipes catalog</a>. Once the CLI is authenticated, agora init creates a local copy and binds it to one of your Agora projects.</p><p><strong>1. Install the CLI and log in.</strong></p><pre>curl -fsSL https://dl.agora.io/cli/install.sh | sh<br>agora login</pre><p><strong>2. Find the recipe.</strong></p><pre>agora recipes list --type ai<br>agora recipes show jev-vad</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/0*UvNlZr1KU3BUAHFW.png" /></figure><p><strong>3. Create your copy.</strong></p><pre>agora init my-jev-vad --recipe jev-vad</pre><p>It can create or reuse an Agora project, clone the recipe, and write the project credentials into the local environment file (server/.env). Then it prints the next steps.</p><p><strong>4. Add your TypeSafe key and start it.</strong></p><pre>cd my-jev-vad<br>echo &#39;TYPESAFE_API_KEY=&lt;your-key&gt;&#39; &gt;&gt; server/.env<br>bun run setup<br>bun run dev</pre><p>Open http://localhost:3000, click <strong>Start Conversation</strong>, and start talking. Jev&#39;s scores move in the side panel as you speak.</p><h3>Already have a ConvoAI app?</h3><p>The recipe also has a smaller drop-in path for an existing Conversational AI app. It keeps the two decisions that matter most for turn-taking, completion and interruption, and leaves out the demo’s side-talk handling, patient mode, telemetry and tuning UI.</p><p>There’s also a copyable coding-agent prompt at the top of the <a href="https://github.com/AgoraIO-Community/convoai-jev-vad/blob/main/recipe/README.md">recipe guide</a>, so the same instructions can be applied to an existing project instead of starting from the demo. The rest of this post describes the full demo.</p><h3>What changed from the Agora quickstart</h3><p>I started from the Agora <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-python">Python quickstart</a> rather than building the agent stack from scratch. It already provides the Next.js client, the FastAPI backend, the transcription flow and the agent lifecycle. Jev VAD changes the parts responsible for deciding when a user turn opens, closes, or interrupts the agent.</p><h3>1. Switch Agora’s turn detection to manual (agent config)</h3><p>In the backend’s agent configuration, start of speech and end of speech are set to manual, and automatic interruption is disabled:</p><pre>turn_detection={<br>    &quot;mode&quot;: &quot;default&quot;,<br>    &quot;config&quot;: {<br>        &quot;start_of_speech&quot;: {&quot;mode&quot;: &quot;manual&quot;},<br>        &quot;end_of_speech&quot;:   {&quot;mode&quot;: &quot;manual&quot;},<br>    },<br>},<br>interruption={&quot;enable&quot;: False, &quot;disabled_config&quot;: {&quot;strategy&quot;: &quot;append&quot;}},</pre><p>Agora still handles the realtime session, transcription, agent execution and speech output. What it no longer owns in this demo is turn control: the browser explicitly sends manualSOS, manualEOS and interrupt() through the Agora client toolkit.</p><p>With interruption disabled, strategy: &quot;append&quot; keeps speech captured while the agent is talking instead of throwing it away before the client has decided what it means.</p><h3>2. Add one judgment route (API routes)</h3><p>/judgeTurn receives the current transcript along with enough conversational state to interpret it: recent turns, the agent&#39;s last message and current state, mic silence, and some information about how the partial transcript has changed. Jev evaluates all four questions against that state in one call. The browser reaches it through the same /api/* path as the rest of the app, so the TypeSafe key stays on the server.</p><p>Normal transcript changes are debounced by about 150 ms before calling /judgeTurn. During a potential interruption the controller evaluates partials immediately, which is why a real &quot;wait, wait&quot; can stop the agent quickly.</p><p>The Jev questions define what the model judges; thresholds and timing determine how aggressively the client acts on those judgments.</p><h3>3. The browser state machine (conversation UI)</h3><p>The browser owns the state machine. Jev returns probabilities; it never calls Agora directly. Stripped down, the branches look like this:</p><pre>complete + addressed + quiet   → manualEOS<br>side-talk or backchannel       → keep listening<br>taking_floor                   → interrupt()</pre><p>The completion threshold starts at 0.72 and relaxes toward 0.55 as mic silence approaches three seconds. A separate quiet-confirmation timer prevents a high semantic score from ending the turn while the user is still audibly speaking, and five seconds remains the hard fallback. When Jev says the user is holding the floor, the threshold doesn’t relax and the fallback stretches to twelve seconds.</p><p>In practice a user turn produces several judgments rather than one, usually three to six. The partial transcript changes as the user speaks, and the client may ask again during silence before closing the turn.</p><p>I also added a panel that shows the four scores live, and a <strong>Tune</strong> drawer for changing thresholds and timers mid-call without restarting anything. Most of my tuning happened there, watching the numbers move while I talked.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/366/0*jHONAMWExDx3mJn_.png" /></figure><h3>What happened in actual calls</h3><p>These are scores from my test sessions, not fixed outputs you should expect from Jev.</p><p>The test I cared about most was a long pause in the middle of an unfinished sentence. I said “So what I want to know is…”, stayed silent for three seconds, and finished with “…did you jump in?” During the pause turn_complete sat around 0.05, so the turn stayed open even as the threshold relaxed. The agent answered about a second after the question.</p><p>I also wanted to see what happened when I explicitly asked for time. “Hold on, let me type something” scored 0.8 to 0.9 on holding_floor, so the agent stayed quiet while I typed and then answered the question I asked afterwards.</p><p>For backchannels, I asked the agent to walk me through how a call works and reacted the way I normally would while it talked. “Right.” scored 0.03 on taking_floor and &quot;Okay.&quot; scored 0.04; both were held and the agent kept going. &quot;Wait, wait. Let me stop you there.&quot; scored 0.97, and the agent stopped within about a second.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/420/0*lvEn4PDOUvdS_gjL.png" /></figure><p>Side-talk was the last case. I turned away and said “Hey, can you hold my coffee, please?”, which scored 0.09 on addressed_to_agent, so nothing was sent to the agent. &quot;Sorry, that wasn&#39;t for you.&quot; scored 0.79, and the agent replied that it had noticed.</p><h3>Wrapping up</h3><p>The useful part of this experiment wasn’t replacing VAD with another model. I still use audio to open the turn. What changed was treating end of turn as a judgment about the conversation rather than a timer attached to silence.</p><p>If you want to experiment with the same approach, the full demo and the smaller drop-in recipe are both available below.</p><ul><li><strong>The recipe:</strong> <a href="https://recipes.agora.io/recipes/jev-vad">recipes.agora.io/recipes/jev-vad</a>, or agora init my-jev-vad --recipe jev-vad</li><li><strong>The demo source:</strong> <a href="https://github.com/AgoraIO-Community/convoai-jev-vad">convoai-jev-vad</a></li><li><strong>The Agora CLI:</strong> <a href="https://github.com/AgoraIO/cli">AgoraIO/cli</a></li><li><strong>The base recipe:</strong> <a href="https://github.com/AgoraIO-Conversational-AI/agent-quickstart-python">agent-quickstart-python</a></li><li><strong>Agora Conversational AI:</strong> <a href="https://docs.agora.io/">docs.agora.io</a></li><li><strong>TypeSafe Jev:</strong> <a href="https://typesafe.ai/">typesafe.ai</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9cfab27b0f1a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/agora-io/jev-vad-turn-detection-that-understands-what-you-say-9cfab27b0f1a">Jev VAD: Turn Detection That Understands What You Say</a> was originally published in <a href="https://medium.com/agora-io">Agora.io</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>