i strongly suspect your server or Twilio has issue...
# telephony
a
i strongly suspect your server or Twilio has issues. Only 2/6 calls got through. with this simple code, it should not has bugs.
Copy code
const {
  WorkerOptions,
  cli,
  defineAgent,
  voice,
  llm,
  initializeLogger,
} = require('@livekit/agents');
const openai = require('@livekit/agents-plugin-openai');
const silero = require('@livekit/agents-plugin-silero');
const { RoomServiceClient } = require('livekit-server-sdk');

// Load environment variables
const livekitUrl = process.env.LIVEKIT_URL || '<ws://localhost:7880>';
const livekitApiKey = process.env.LIVEKIT_API_KEY;
const livekitApiSecret = process.env.LIVEKIT_API_SECRET;

// Verify required environment variables
if (!livekitApiKey || !livekitApiSecret) {
  console.error('❌ Missing required environment variables: LIVEKIT_API_KEY, LIVEKIT_API_SECRET');
  process.exit(1);
}

// OpenAI API requires OPENAI_API_KEY
const openaiApiKey = process.env.OPENAI_API_KEY;
if (!openaiApiKey) {
  console.error('❌ Missing OPENAI_API_KEY - required for OpenAI');
  process.exit(1);
}
console.log('✅ OpenAI API key configured');

const roomServiceClient = new RoomServiceClient(
  livekitUrl,
  livekitApiKey,
  livekitApiSecret,
);

// Initialize logger
initializeLogger({
  level: process.env.LIVEKIT_LOG_LEVEL || 'warn',
  pretty: process.env.NODE_ENV === 'development'
});

// Preload VAD model
let cachedVAD = null;
const loadVAD = async () => {
  if (!cachedVAD) {
    cachedVAD = await silero.VAD.load();
    console.log('✅ VAD model preloaded');
  }
  return cachedVAD;
};

// Preload VAD at startup
loadVAD().catch(err => {
  console.error('⚠️ Failed to preload VAD:', err.message);
});

const SYSTEM_MESSAGE = `You are Tike Mrapp, the original host and creator of 'Um, Actually.'
Your mission is to deliver the quintessential 'Um, Actually' experience to people who call in to your show.

You will provide a series of statements about various aspects of 'nerd' culture—video games, movies, comics, fantasy, sci-fi, etc. Each statement will contain exactly one factual inaccuracy.

The caller must identify and correct that inaccuracy, starting their correction with a resounding 'Um, Actually...' to earn a point. If the caller's response does not begin with 'Um, Actually,' or if they provide an incorrect correction, you, Tike Mrapp, receive the point and the caller cannot attempt to correct that statement again.

Emphasize this rule: 'Um, Actually' is not just a suggestion, it's a requirement!
Maintain your signature enthusiastic, slightly chaotic, and pedantic hosting style.
Embrace tangents, celebrate the minutiae, and deliver dramatic pauses before revealing the correct answers.
Remember to use phrases like 'That's a good correction' or 'Oh, that's a deep cut!'

Keep responses SHORT - this is a voice conversation. One or two sentences at a time.

Rules:
- Do not offer the caller a chance to correct their answer.
- Do not offer the caller another round of the game.
- When asked about points, call pointsStatus function.
- When caller makes correct correction, call userPoints function.
- When caller makes incorrect correction or fails to say 'Um, Actually', call systemPoints function.
- When caller says goodbye or tries to end the call, call gameEnd function.
- When anyone accumulates three points, thank them and call gameEnd function.`;

const agent = defineAgent({
  name: 'um-actually-agent',
  entry: async (ctx) => {
    
    try {
      await ctx.connect();
      console.log('✅ Connected to room:', ctx.room?.name);
      
      const vad = await loadVAD();

      // Create voice agent with OpenAI
      const phoneAgent = new (class extends voice.Agent {
        constructor() {
          super({ instructions: SYSTEM_MESSAGE });
        }
      })();

      // Use OpenAI for STT, LLM, TTS
      // Use recoverable STT wrapper to prevent cleanup errors from killing the session
      const stt = new openai.STT({ model: 'whisper-1' });
      const llmInstance = new openai.LLM({ model: 'gpt-4o' });
      const tts = new openai.TTS({ voice: 'alloy' });

      console.log('🔧 Creating AgentSession...');
      const session = new voice.AgentSession({
        stt: stt,
        llm: llmInstance,
        tts,
        vad,
        max_tool_steps: 3
      });

      session.on('error', (error) => {
        // Filter out expected cleanup errors (these occur during normal shutdown)
        const errorMessage = error.error?.message || error.message || '';
        const errorStack = error.error?.stack || error.stack || '';
        const isCleanupError = 
          errorMessage.includes('Stream is closed') ||
          errorMessage.includes('VADStream.endInput') ||
          errorStack.includes('VADStream.endInput') ||
          errorStack.includes('StreamAdapterWrapper') ||
          (error.type === 'stt_error' && errorMessage.includes('closed'));
        
        if (isCleanupError) {
          // Silently ignore cleanup errors - these are expected during call termination
          return;
        }
        
        console.error('❌ Session error:', error);
      });

      console.log('🚀 Starting session...');
      await session.start({ agent: phoneAgent, room: ctx.room });
      console.log('✅ Session started successfully');

      // Send initial greeting
      const greeting = "Welcome to Um, Actually! I'm your host, Tike Mrapp. Here's how this works: I'll give you a statement about pop culture, and it will contain one inaccuracy. Your job is to find it and correct me, but you MUST start your correction with 'Um, Actually.' Ready for your first statement?";
      console.log('📢 Sending greeting...');
      session.say(greeting, { addToChatCtx: true, allowInterruptions: true });
      console.log('✅ Greeting sent');

      // Wait for call to end
      await new Promise((resolve) => {
        let resolved = false;
        
        const cleanup = () => {
          if (resolved) return;
          resolved = true;
          console.log('🔌 Call ended, cleaning up');
          resolve();
        };

        if (ctx.room) {
          ctx.room.once('disconnected', (reason) => {
            console.log(`🔌 Room disconnected. Reason: ${reason || 'unknown'}`);
            cleanup();
          });

          const checkInterval = setInterval(() => {
            if (!ctx.room || !ctx.room.isConnected) {
              console.log('🔌 Room no longer connected');
              clearInterval(checkInterval);
              cleanup();
            }
          }, 5000);

          setTimeout(() => {
            console.log('⏰ Call timeout (20m)');
            clearInterval(checkInterval);
            cleanup();
          }, 20 * 60 * 1000);
        } else {
          cleanup();
        }
      });

    } catch (error) {
      console.error('❌ Error in agent entry:', error);
      console.error('   Stack:', error.stack);
    }
  },
});

module.exports = agent;

console.log('🚀 Starting Um Actually agent...');

if (require.main === module) {
  process.argv = [process.argv[0], process.argv[1], 'start'];
  cli.runApp(new WorkerOptions({ agent: __filename }));
}
my code is based on this official demo: https://github.com/livekit-examples/livekit-sip-agent-example/blob/main/src/agent.ts It was table few days ago and now failure rate is high.
r
What do you see in the PCAP?
What is a call ID that failed?
a
twilio call id: CA520d650ff5b5531c5c36a8a9a4e6f1ca PCAP says twilio dialed but sip provider didn't respond within 30 seconds. i throw the log to chatGPT, it says; "Twilio successfully reaches LiveKit, authenticates, and LiveKit keeps the call in “Ringing” forever. LiveKit never sends a
200 OK
to answer the call, so Twilio eventually gives up and cancels."
r
Sounds like something is not configured properly on your trunk
a
Am i rate limited? I also noticed one call took about 28 seconds to respond. and the call will automatically end after 34 seconds.
checking my trunk. any clue on what is going wrong?
r
I guess one easy check it to make sure the agent name in your code matches your agent name in your dispatch rule
a
from livekit, i see error on failed calls "invalid credentials were provided"
r
then check your credentials
a
but why some of my calls get through? wired. i just ran it multiple times and some of my calls get answered.
r
Are you using a unique room name each time?
a
yes. call_<desnation number>_randomNumer
r
The call ID above the agent did not answer. For that you need to check your agent logs to see what happened
a
trying. i didn't set agent name in the dispatch rule.
r
I thought when I looked at the code you shared above that you had an agent name.
If your dispatch agent name does not match your codes agent name it won't work.
a
this code doesn't specify agent name: https://github.com/livekit/agents-js/blob/main/examples/src/basic_agent.ts I put a name which is listed on livekit dashboard or dispatch rule: const agent = defineAgent({ name: 'um-actually-agent',
i will remove that and try again.
r
Those two should help
a
same after remove it. i think it is timeout issues. because some of them indeed take 25 seconds to respond. if there are dispatch errors, all calls should fail, right?
r
Depends on what you are doing
You don't see anything in your agent logs?
a
only this: {"level":40,"time":1766602011566,"pid":9874,"hostname":"franklinyaos-MacBook-Pro.local","msg":"job is unresponsive"}
from terminal
just noticed the last call ended after 34 seonds and then i see "inital greeting" arrive. that confirms my idea of timeout out. It took too long for the agent to response.
r
Why is your agent taking so long to respond?
Do you have agent insight enabled?
Maybe that will give you a hint
Oh, never mind you are using JS
Maybe give Python agent a try and see if that works for you
a
will python more likely have less issues? It seems JS is less favored and might be not stress tested
r
Python is better
a
why do u say this?
r
Python has a lot more work done on it than JS agent
a
i rebooted my laptop and it seems 10/10 succeeded. Maybe that is the reason. CPU or memory overloaded.
i found sometimes, it has no issues. now all my calls get through. So it might be because your server load is too high? @refined-appointment-81829
r
Doubtful that is is a LiveKit server load issue.
a
any debugging tips? when my call can't get through, i can't see logs for my application.
r
Why can't you see your logs?