AWS Builder Center
How I built a Strands bidi voice agent that checks the docs while you talk

How I built a Strands bidi voice agent that checks the docs while you talk

I built a Strands voice agent that reads the docs over MCP mid-call, with a tool that returns at once so Nova Sonic speaks while the lookup runs.

Last updated: 6 October 2026
Strands Bidi Agents went GA yesterday . They're a real, useful feature for legitimate business cases, but I wanted to make a diva version and have an excuse to use a prop (I love whimsy, I love a prop), so I built Strands Hotline. You call Diva, a BidiAgent on Amazon Nova 2.5 Sonic, and ask a question about Strands. While you're still on the line, a second Strands agent looks it up in the official docs through the Strands Agents MCP server, and every page it reads shows up on screen next to the conversation.
Here's part of the call from the demo video :
Me: yes, diva. receipts and everything. when did it become generally available?Diva: Hunting for the date, boots.Diva: She entered her general availability era on October fifth, twenty twenty six. This release brought direct support for Amazon Nova Sonic, Open AI Realtime, and Google Gemini Live, plus echo cancellation and automatic session restarts to keep the conversation from flopping.

What is a Strands bidi agent?

A Strands bidi agent keeps one connection to a voice model open in both directions, so you can talk while it's talking. BidiAgent streams your microphone audio in and the model's voice out at the same time, and you can cut in mid-sentence to change the question. (Bidi is short for bidirectional, and it's pronounced "bye-dye". I had to put that in the system prompt so the voice model would say it right.)
The GA announcement  lists support for Amazon Nova Sonic, OpenAI and Gemini voice models. The agent also restarts the provider connection in the background before the provider's session limit, so a call can outlast Nova 2.5 Sonic's 8-minute cap. Echo suppression on the mic input keeps it from hearing itself through open speakers and interrupting itself.
A regular Strands Agent takes turns (one request, one reply, even when the reply streams), while a BidiAgent holds the line open the way a phone call needs. According to the announcement, the two share tools, hooks and system prompts, so the @tool functions and MCP clients you use with a regular Agent work on a voice agent too.

How does Strands Hotline work?

Strands Hotline uses two agents: a voice agent that holds the conversation, and a docs agent that does the reading.
  1. Diva is a BidiAgent on amazon.nova-2-5-sonic with an "Internet Diva" persona prompt and one tool, ask_strands_docs.
  2. That tool starts a regular Strands Agent on Claude Haiku 4.5. Its only tools are search_docs and fetch_doc, from the Strands Agents MCP server.
  3. The docs agent reads the right page and hands back an answer of three sentences or fewer, which Diva says in character.
You talk to Diva through a small web page on my laptop. It streams the mic to a local server over a WebSocket and shows both sides of the call: the transcript on the left, and every MCP call in a terminal window on the right.
The terminal during that call:
1
2
3
4
5
6
7
8
9
10
$ uvx strands-agents-mcp-server
tools: search_docs, fetch_doc
> ask_strands_docs("what are bi directional agents?")
fetch_doc("/docs/user-guide/sdk/bidi/")
read sdk/bidi
< answer handed to Diva
> ask_strands_docs("when did BidiAgent become generally available?")
fetch_doc("/blog/bidi-agents-now-ga/")
read blog/bidi-agents-now-ga
< answer handed to Diva
The work is split this way because the voice model needs to reply fast and sound like a person, while the docs agent needs to read a whole page and get the package names right. The announcement uses the same split in its own example, a voice agent with a research agent as a tool, and you can choose the two models separately. The terminal also doubles as the receipt: when Diva says the install command has four extras, you can see it came from the quickstart page.

How do I connect a voice agent to the Strands docs MCP server?

Run the Strands Agents MCP server with uvx and give its tools to the docs agent. It's the same server you can add to Kiro or any other MCP client.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from mcp import StdioServerParameters, stdio_client
from mcp.client.stdio import get_default_environment
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient

docs = MCPClient(lambda: stdio_client(StdioServerParameters(
command="uvx",
args=["strands-agents-mcp-server==0.3.0"], # pin the version you've checked
# Only the basics (PATH, HOME...), not your AWS credentials. The docs server
# doesn't need them. PREFETCH_ALL indexes page text so searches match inside pages.
env={**get_default_environment(), "STRANDS_MCP_PREFETCH_ALL": "1"},
)))

with docs: # keep the client open for the whole call
researcher = Agent(
model=BedrockModel(model_id="us.anthropic.claude-haiku-4-5-20251001-v1:0"),
tools=docs.list_tools_sync(),
system_prompt="Answer questions about Strands using search_docs and fetch_doc only.",
callback_handler=None, # don't print the docs agent's reply to the terminal
)
# build the BidiAgent and run the call in here, while the MCP client is open
My first version had the docs agent search, read the results and then fetch a page, so a simple question took 5 to 8 seconds. Now its prompt includes a map of the bidi pages (quickstart, agent, models, tools, I/O, events and so on). For a bidi question it fetches the right page first, and simple lookups now take about 4 seconds.

Why does my voice agent go quiet during a tool call?

In my tests, Nova Sonic called the docs tool within half a second of the question, then said nothing until the tool returned. Anything it planned to say first, like "checking the docs", came out together with the answer after 5 to 8 seconds of silence.
The fix was to make the tool return immediately and send the answer into the conversation when it's ready. BidiAgent.send() takes text, so a background task can pass the answer to the voice model whenever the docs agent finishes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import asyncio

from strands import tool

@tool
async def ask_strands_docs(question: str) -> str:
"""Start a docs lookup. The answer arrives a few seconds later
as a message starting with [docs answer]."""


async def lookup() -> None:
answer = str(await researcher.invoke_async(question))
await agent.send(f"[docs answer] {answer}") # agent is the BidiAgent

asyncio.create_task(lookup()) # keep a reference to this task in real code
return "Lookup started. Tell the caller you're checking, then wait."
With that change, Diva's "checking" line starts about 0.7 seconds after the question and the answer starts at about 4 seconds. The checking line is generated live, so it's different every call. In the demo it was "Hunting for the date, boots" and "Pulling up the starter pack, diva."
The answer arrives as a new message, so the voice model has to be told what it is. My system prompt says a message starting with [docs answer] comes from the lookup, not the caller, and to say it only if it still fits where the conversation has got to.
A long lookup still leaves a gap after the checking line (one migration question read three pages and took 12 seconds). I tried pre-recorded hold lines in Diva's voice to cover gaps like that, then took them out again, because I want everything you hear on the call to come from the agent.

How do I build my own Strands voice agent?

Start with the bidi quickstart . Install PortAudio first (brew install portaudio on macOS, sudo apt-get install portaudio19-dev on Debian or Ubuntu), then install the SDK with the voice extras:
1
pip install "strands-agents[bidi,bidi-io,bidi-pyaudio,bidi-aec]"
That's the command Diva read out in the demo. The quickstart agent talks through your laptop's mic and speakers in a terminal, and Hotline swaps that for a web page that shows the docs lookups next to the transcript.
Every call runs Nova 2.5 Sonic and Claude Haiku 4.5 on your own AWS account at Amazon Bedrock pricing , and I haven't measured what a single call costs.
Strands Hotline only runs locally on my laptop for now, but I'm manifesting it becoming a real part of the Strands website. If you'd like my wish to be a reality, please leave a comment and say so, because I'm collecting the comments as "business evidence".
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article