This page shows you how to build a server that starts and stops a voice AI agent using the Agora Conversational AI SDKs. The SDKs wrap the Conversational AI REST API with typed vendor configuration, automatic token generation, and a session lifecycle API.
Before you begin, make sure you have:
_1npm install agora-agent-server-sdk
The package name on npm is agora-agent-server-sdk. Imports use agora-agent-sdk.
_1pip install agora-agent-sdk
_1go get github.com/AgoraIO-Conversational-AI/agent-server-sdk-go
Store credentials in a .env file. Never commit this file or expose its contents client-side; your App Certificate must stay on the server.
Sync with Console to see your credentials
AGORA_APP_ID=<your_agora_app_id>
AGORA_APP_CERT=<your_agora_app_cert>
# ASR,LLM and TTS vendor keys
DEEPGRAM_API_KEY=<your_deepgram_key>
OPENAI_API_KEY=<your_openai_key>
ELEVENLABS_API_KEY=<your_elevenlabs_key>
ELEVENLABS_VOICE_ID=<your_voice_id>
The following steps set up a client, configure an agent, and manage session lifecycle.
AgoraClient holds your credentials and handles authentication. Pass your App ID and App Certificate to use app-credentials mode. The SDK auto-generates a temporary token scoped to each channel before every request.
_7import { AgoraClient, Area } from 'agora-agent-sdk';
_7const client = new AgoraClient({
_7 area: Area.US, // Sets the regional API endpoint
_7 appId: process.env.AGORA_APP_ID!,
_7 appCertificate: process.env.AGORA_APP_CERT!,
Use the region closest to your users: Area.US, Area.EU, Area.AP, or Area.CN.
The Python SDK supports both synchronous and asynchronous usage.
See Sync vs. Async to choose the right approach for your application.
Agora (sync) and AsyncAgora (async) hold your credentials and handle authentication. Pass your App ID and App Certificate to use app-credentials mode. The SDK auto-generates a temporary token scoped to each channel before every request.
-
Sync
_8from agora_agent import Agora, Area
_8 app_id=os.environ['AGORA_APP_ID'],
_8 app_certificate=os.environ['AGORA_APP_CERT'],
-
Async
_8from agora_agent import AsyncAgora, Area
_8 app_id=os.environ['AGORA_APP_ID'],
_8 app_certificate=os.environ['AGORA_APP_CERT'],
Use the region closest to your users: Area.US, Area.EU, Area.AP, or Area.CN.
In Go, the client handles authentication for REST API calls, while your App ID and App Certificate are passed separately when creating a session. The session uses them to auto-generate a temporary token for the Agora channel.
_10 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/client"
_10 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/option"
_10c := client.NewClient(
_10 option.WithArea(option.AreaUS),
Use the region closest to your users: option.AreaUS, option.AreaEU, option.AreaAP, or option.AreaCN.
Agent is a reusable configuration object. Define it once at startup and call createSession() on it for each user conversation.
_23import { Agent, OpenAI, ElevenLabsTTS, DeepgramSTT } from 'agora-agent-sdk';
_23const agent = new Agent({
_23 name: 'support-assistant',
_23 instructions: 'You are a helpful voice assistant. Keep responses concise.', // LLM system prompt
_23 greeting: 'Hello! How can I help you today?', // the first thing the agent says
_23 .withLlm(new OpenAI({
_23 apiKey: process.env.OPENAI_API_KEY!,
_23 model: 'gpt-4o-mini',
_23 .withTts(new ElevenLabsTTS({
_23 key: process.env.ELEVENLABS_API_KEY!,
_23 modelId: 'eleven_flash_v2_5',
_23 voiceId: process.env.ELEVENLABS_VOICE_ID!,
_23 .withStt(new DeepgramSTT({
_23 apiKey: process.env.DEEPGRAM_API_KEY!,
Vendor classes are imported from agora_agent.agentkit.vendors. Builder methods use snake_case.
_14from agora_agent.agentkit import Agent
_14from agora_agent.agentkit.vendors import OpenAI, ElevenLabsTTS, DeepgramSTT
_14 name='support-assistant',
_14 instructions='You are a helpful voice assistant.', # LLM system prompt
_14 greeting='Hello! How can I help you today?', # first words spoken on session start
_14 .with_llm(OpenAI(api_key=os.environ['OPENAI_API_KEY'], model='gpt-4o-mini'))
_14 .with_tts(ElevenLabsTTS(key=os.environ['ELEVENLABS_API_KEY'], model_id='eleven_flash_v2_5', voice_id=os.environ['ELEVENLABS_VOICE_ID']))
_14 .with_stt(DeepgramSTT(api_key=os.environ['DEEPGRAM_API_KEY'], language='en-US'))
Go uses functional options to configure the agent. Vendor classes are imported from agentkit/vendors and constructed with options structs.
_26 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/agentkit"
_26 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/agentkit/vendors"
_26agent := agentkit.NewAgent(
_26 agentkit.WithName("support-assistant"),
_26 agentkit.WithInstructions("You are a helpful voice assistant. Keep responses concise."), // LLM system prompt
_26 agentkit.WithGreeting("Hello! How can I help you today?"), // the first thing the agent says
_26 agentkit.WithMaxHistory(10),
_26 vendors.NewOpenAI(vendors.OpenAIOptions{
_26 APIKey: os.Getenv("OPENAI_API_KEY"),
_26 Model: "gpt-4o-mini",
_26 vendors.NewElevenLabsTTS(vendors.ElevenLabsTTSOptions{
_26 Key: os.Getenv("ELEVENLABS_API_KEY"),
_26 ModelID: "eleven_flash_v2_5",
_26 VoiceID: os.Getenv("ELEVENLABS_VOICE_ID"),
_26 vendors.NewDeepgramSTT(vendors.DeepgramSTTOptions{
_26 APIKey: os.Getenv("DEEPGRAM_API_KEY"),
For the full list of Agent options and vendor classes, see the SDK reference.
Bind the agent to a specific RTC channel, register event listeners, then start the session.
Register listeners before starting the session. Otherwise you may miss the started event.
_24import { ExpiresIn } from 'agora-agent-sdk';
_24const session = agent.createSession(client, {
_24 channel: 'your-channel-name',
_24 expiresIn: ExpiresIn.hours(1),
_24// Register before start()
_24session.on('started', ({ agentId }) => {
_24 console.log('Agent is live:', agentId);
_24session.on('stopped', ({ agentId }) => {
_24 console.log('Agent has left:', agentId);
_24session.on('error', (err) => {
_24 console.error('Session error:', err);
_24const agentId = await session.start();
start() transitions the session through idle → starting → running states and returns the agentId. The agentId is the same value as the agent_id returned by the REST API.
You can check the session state at any time with session.status.
Event handlers receive a dict payload. Register them before calling start().
-
Sync
_17from agora_agent.agentkit import expires_in_hours
_17session = agent.create_session(
_17 channel='your-channel-name',
_17 expires_in=expires_in_hours(1),
_17# Register before start()
_17session.on('started', lambda data: print('Agent is live:', data['agent_id']))
_17session.on('stopped', lambda data: print('Agent has left:', data['agent_id']))
_17session.on('error', lambda err: print('Session error:', err))
_17agent_id = session.start()
-
Async
_1agent_id = await session.start()
start() transitions the session through idle → starting → running states and returns the agentId. The agentId is the same value as the agent_id returned by the REST API.
You can check the session state at any time with session.status.
_38 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/agentkit"
_38session := agentkit.NewAgentSession(agentkit.AgentSessionOptions{
_38 AppID: os.Getenv("AGORA_APP_ID"),
_38 AppCertificate: os.Getenv("AGORA_APP_CERT"),
_38 Channel: "your-channel-name",
_38 RemoteUIDs: []string{"100"},
_38// Register before Start()
_38session.On("started", func(data interface{}) {
_38 info := data.(map[string]string)
_38 fmt.Println("Agent is live:", info["agent_id"])
_38session.On("stopped", func(data interface{}) {
_38 fmt.Println("Agent has left")
_38session.On("error", func(data interface{}) {
_38 log.Println("Session error:", data)
_38ctx := context.Background()
_38agentId, err := session.Start(ctx)
_38 log.Fatalf("Failed to start session: %v", err)
Start() transitions the session through idle → starting → running states and returns the agent ID. The agent ID is the same value as the agent_id returned by the REST API.
You can check the current session state at any time with session.Status().
Once a session is in the running state, you can instruct the agent or update its configuration mid-session.
_13// Make the agent speak a specific message
_13await session.say('One moment while I look that up for you.');
_13// Interrupt the agent mid-speech
_13await session.interrupt();
_13// Update agent configuration without restarting the session.
_13// Accepts a partial properties object in REST API format.
_13await session.update({
_13 system_messages: [{ role: 'system', content: 'You are now in concise mode.' }],
-
Sync
_13# Make the agent speak a specific message
_13session.say('One moment while I look that up for you.')
_13# Interrupt the agent mid-speech
_13# Update agent configuration without restarting the session.
_13# Accepts a partial properties object in REST API format.
_13 'system_messages': [{'role': 'system', 'content': 'You are now in concise mode.'}],
-
Async
_7await session.say('One moment while I look that up for you.')
_7await session.interrupt()
_7 'system_messages': [{'role': 'system', 'content': 'You are now in concise mode.'}],
_24// Make the agent speak a specific message
_24err := session.Say(ctx, "One moment while I look that up for you.", nil, nil)
_24 log.Printf("Say failed: %v", err)
_24// Interrupt the agent mid-speech
_24err = session.Interrupt(ctx)
_24 log.Printf("Interrupt failed: %v", err)
_24// Update agent configuration without restarting the session.
_24// Accepts a partial UpdateAgentsRequestProperties struct in REST API format.
_24err = session.Update(ctx, &Agora.UpdateAgentsRequestProperties{
_24 Llm: &Agora.UpdateAgentsRequestPropertiesLlm{
_24 SystemMessages: []map[string]any{
_24 {"role": "system", "content": "You are now in concise mode."},
_24 log.Printf("Update failed: %v", err)
Call the session stop method when the user ends the conversation. This transitions the session through running → stopping → stopped states and removes the agent from the channel.
_4err := session.Stop(ctx)
_4 log.Fatalf("Failed to stop session: %v", err)
The following is a minimal server your client app can call to manage agent sessions.
Express server example
_97import 'dotenv/config';
_97import express from 'express';
_97} from 'agora-agent-sdk';
_97const app = express();
_97app.use(express.json());
_97// Initialized once at startup; shared across all requests
_97const client = new AgoraClient({
_97 appId: process.env.AGORA_APP_ID!,
_97 appCertificate: process.env.AGORA_APP_CERT!,
_97const agent = new Agent({
_97 name: 'support-assistant',
_97 instructions: 'You are a helpful voice assistant. Keep responses concise.',
_97 greeting: 'Hello! How can I help you today?',
_97 .withLlm(new OpenAI({ apiKey: process.env.OPENAI_API_KEY!, model: 'gpt-4o-mini' }))
_97 .withTts(new ElevenLabsTTS({
_97 key: process.env.ELEVENLABS_API_KEY!,
_97 modelId: 'eleven_flash_v2_5',
_97 voiceId: process.env.ELEVENLABS_VOICE_ID!,
_97 .withStt(new DeepgramSTT({ apiKey: process.env.DEEPGRAM_API_KEY!, model: 'nova-2', language: 'en-US' }));
_97// Maps agentId → session object.
_97// In production, use a database or Redis so any server process can stop any session.
_97const sessions = new Map<string, ReturnType<typeof agent.createSession>>();
_97// POST /sessions/start
_97// Called by your client app after the user joins the Agora channel.
_97// Body: { channel: string, userId: string }
_97// Returns: { agentId: string }
_97app.post('/sessions/start', async (req, res) => {
_97 const { channel, userId } = req.body;
_97 const session = agent.createSession(client, {
_97 remoteUids: [userId],
_97 expiresIn: ExpiresIn.hours(1),
_97 session.on('error', (err) => console.error(`Session error [${channel}]:`, err));
_97 const agentId = await session.start();
_97 sessions.set(agentId, session);
_97 res.json({ agentId });
_97 if (err instanceof AgoraError) {
_97 res.status(err.statusCode).json({ error: err.message });
_97 res.status(500).json({ error: 'Failed to start agent' });
_97// POST /sessions/stop
_97// Called by your client app when the user ends the conversation.
_97// Body: { agentId: string }
_97app.post('/sessions/stop', async (req, res) => {
_97 const { agentId } = req.body;
_97 const session = sessions.get(agentId);
_97 return res.status(404).json({ error: 'Session not found' });
_97 await session.stop();
_97 sessions.delete(agentId);
_97 res.json({ status: 'stopped' });
_97 if (err instanceof AgoraError) {
_97 res.status(err.statusCode).json({ error: err.message });
_97 res.status(500).json({ error: 'Failed to stop agent' });
_97app.listen(3000, () => console.log('Server listening on port 3000'));
Python example
-
Sync
_36from agora_agent import Agora, Area
_36from agora_agent.agentkit import Agent
_36from agora_agent.agentkit.vendors import OpenAI, ElevenLabsTTS, DeepgramSTT
_36 app_id=os.environ['AGORA_APP_ID'],
_36 app_certificate=os.environ['AGORA_APP_CERT'],
_36 name='support-assistant',
_36 instructions='You are a helpful voice assistant.', # LLM system prompt
_36 greeting='Hello! How can I help you today?', # first words spoken on session start
_36 .with_llm(OpenAI(api_key=os.environ['OPENAI_API_KEY'], model='gpt-4o-mini'))
_36 .with_tts(ElevenLabsTTS(
_36 key=os.environ['ELEVENLABS_API_KEY'],
_36 model_id='eleven_flash_v2_5',
_36 voice_id=os.environ['ELEVENLABS_VOICE_ID'],
_36 .with_stt(DeepgramSTT(api_key=os.environ['DEEPGRAM_API_KEY'], language='en-US'))
_36session = agent.create_session(
_36 channel='support-room-123',
_36agent_id = session.start()
_36session.say('Hello! How can I help you today?')
-
Async
_40from agora_agent import AsyncAgora, Area
_40from agora_agent.agentkit import Agent
_40from agora_agent.agentkit.vendors import OpenAI, ElevenLabsTTS, DeepgramSTT
_40 app_id=os.environ['AGORA_APP_ID'],
_40 app_certificate=os.environ['AGORA_APP_CERT'],
_40 name='support-assistant',
_40 instructions='You are a helpful voice assistant.', # LLM system prompt
_40 greeting='Hello! How can I help you today?', # first words spoken on session start
_40 .with_llm(OpenAI(api_key=os.environ['OPENAI_API_KEY'], model='gpt-4o-mini'))
_40 .with_tts(ElevenLabsTTS(
_40 key=os.environ['ELEVENLABS_API_KEY'],
_40 model_id='eleven_flash_v2_5',
_40 voice_id=os.environ['ELEVENLABS_VOICE_ID'],
_40 .with_stt(DeepgramSTT(api_key=os.environ['DEEPGRAM_API_KEY'], language='en-US'))
_40 session = agent.create_session(
_40 channel='support-room-123',
_40 agent_id = await session.start()
_40 await session.say('Hello! How can I help you today?')
Go example
_82 // uncomment for typed structs and pointer helpers
_82 // Agora "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go"
_82 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/agentkit"
_82 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/agentkit/vendors"
_82 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/client"
_82 "github.com/AgoraIO-Conversational-AI/agent-server-sdk-go/option"
_82 // Initialized once at startup; shared across all requests
_82 c := client.NewClient(
_82 option.WithArea(option.AreaUS),
_82 agent := agentkit.NewAgent(
_82 agentkit.WithName("support-assistant"),
_82 agentkit.WithInstructions("You are a helpful voice assistant. Keep responses concise."), // LLM system prompt
_82 agentkit.WithGreeting("Hello! How can I help you today?"), // first words spoken on session start
_82 agentkit.WithMaxHistory(10),
_82 vendors.NewOpenAI(vendors.OpenAIOptions{
_82 APIKey: os.Getenv("OPENAI_API_KEY"),
_82 Model: "gpt-4o-mini",
_82 vendors.NewElevenLabsTTS(vendors.ElevenLabsTTSOptions{
_82 Key: os.Getenv("ELEVENLABS_API_KEY"),
_82 ModelID: "eleven_flash_v2_5",
_82 VoiceID: os.Getenv("ELEVENLABS_VOICE_ID"),
_82 vendors.NewDeepgramSTT(vendors.DeepgramSTTOptions{
_82 APIKey: os.Getenv("DEEPGRAM_API_KEY"),
_82 session := agentkit.NewAgentSession(agentkit.AgentSessionOptions{
_82 AppID: os.Getenv("AGORA_APP_ID"),
_82 AppCertificate: os.Getenv("AGORA_APP_CERT"),
_82 Channel: "support-room-123",
_82 RemoteUIDs: []string{"100"},
_82 session.On("started", func(data interface{}) {
_82 info := data.(map[string]string)
_82 fmt.Println("Agent is live:", info["agent_id"])
_82 session.On("stopped", func(data interface{}) {
_82 fmt.Println("Agent has left")
_82 session.On("error", func(data interface{}) {
_82 log.Println("Session error:", data)
_82 ctx := context.Background()
_82 agentId, err := session.Start(ctx)
_82 log.Fatalf("Failed to start session: %v", err)
_82 fmt.Println("Agent running with ID:", agentId)
_82 err = session.Say(ctx, "Hello! How can I help you today?", nil, nil)
_82 log.Printf("Say failed: %v", err)
_82 err = session.Stop(ctx)
_82 log.Fatalf("Failed to stop session: %v", err)