Run the Example
Two example projects show a full working setup - the repository ships a minimal bridge embedding (examples/basic-bridge), and the Node sibling repository ships ready-to-run agents (examples/agents, Python agents that work with either bridge). This page walks through both so you understand every moving part.
What a working setup needs
Section titled “What a working setup needs”A LiveKit call has three processes, two of them yours:
- Your agent worker - registers with your LiveKit project under an
agent_nameand waits for dispatch. - This bridge - creates a room per Teams call, dispatches the agent into it, relays audio.
- StandIn (hosted) - joins the Teams call and dials the bridge.
1. Run the example voice agent
Section titled “1. Run the example voice agent”The example agents are plain LiveKit agents (OpenAI STT/LLM/TTS + Silero VAD) - nothing Teams-specific:
git clone https://github.com/komaa-com/livekit-msteams-bridgecd livekit-msteams-bridge/examples/agentscp .env.example .env # LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, OPENAI_API_KEYuv syncuv run voice_agent.py download-filesuv run voice_agent.py dev(Plain pip works too: pip install -r requirements.txt && python voice_agent.py dev.)
The worker registers as standin-voice-agent and waits - it will not join anything until the bridge creates a room and dispatches it.
2. Run the bridge example
Section titled “2. Run the bridge example”pip install livekit-msteams-bridgegit clone https://github.com/komaa-com/livekit-msteams-bridge-pycd livekit-msteams-bridge-py/examples/basic-bridgecp .env.example .env # same LiveKit project + LIVEKIT_AGENT_NAME=standin-voice-agent + WORKER_SHARED_SECRETpython main.pyIt prints the WebSocket URL to give StandIn:
Point your StandIn identity's agent WebSocket URL at ws://<this-host>:8080/voice/msteams/streamThe main.py is the recommended embedding shape in ~25 lines: load_dotenv(), load_config() (fails loud on any misconfiguration), await start_server(cfg), and a graceful await server.close() on Ctrl-C / SIGTERM that ends live calls with a spoken-protocol session.end rather than a hard drop.
3. Connect StandIn and call
Section titled “3. Connect StandIn and call”- Expose port 8080 with a tunnel (
tailscale funnel --bg --https=8080 8080,cloudflared tunnel --url http://localhost:8080, orngrok http 8080). - In your StandIn dashboard, set the identity’s Agent voice URL to the
wss://.../voice/msteams/streamform and make sure the shared secret equalsWORKER_SHARED_SECRET. - Call your Teams bot (or join the sandbox meeting). The bridge creates the room, dispatches
standin-voice-agent, and the agent answers.
4. Swap in the avatar agent
Section titled “4. Swap in the avatar agent”avatar_agent.py is the same pipeline plus a lip-synced bitHuman avatar. Two extra variables in the agent’s .env (BITHUMAN_API_SECRET, BITHUMAN_MODEL_PATH), then:
uv run avatar_agent.py devand restart the bridge with LIVEKIT_AGENT_NAME=standin-avatar-agent. The caller hears the avatar’s audio; the avatar’s video stays in the room (the Teams tile is rendered by StandIn’s own animated avatar - see Agents and Dispatch).
What the example agents demonstrate
Section titled “What the example agents demonstrate”Each example shows the three integration points your own agent can use:
agent_nameinWorkerOptions- the dispatch contract withLIVEKIT_AGENT_NAME.ctx.job.metadata- per-call caller context (caller_name,tenant_id,call_direction,user_idwhen known) for greetings and personalization.teams.context/teams.goodbyedata topics - call context and the governor’s goodbye handler (interrupt the current turn, speak the line).
Details and copy-paste handlers: Agents and Dispatch.
From example to your own service
Section titled “From example to your own service”- Keep your own agent worker exactly as it is for WebRTC users - just give it an
agent_name. - Embed the bridge (
await start_server(load_config())) or run the stock CLI. - Set the governor variables (
MAX_CALL_MINUTES,GOODBYE_TEXT) before production. - For tests, inject a fake room with the
connect_roomargument - see Library API.