Skip to content

Fix ElevenLabs end_call detection giving up before the transcript is ready - #235

Merged
gabegma merged 2 commits into
mainfrom
fix/elevenlabs-end-call-detection
Oct 14, 2026
Merged

gabegma merged 2 commits into
mainfrom
fix/elevenlabs-end-call-detection

Conversation

@gabegma

@gabegma gabegma commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

conversation_valid_end scores a conversation valid only if the ElevenLabs caller hung up with end_call. _check_end_call_via_api finds that out after the call by fetching the conversation from the ElevenLabs API, but it gave up after 5 polls (~34 s). ElevenLabs is often still processing at that point and returns an empty transcript, so a conversation that ended properly was scored invalid and rerun.

Measured on a medical_hr run with gpt-realtime-2.1-mini (18 trials):

  • 24 attempts were rejected with "conversation ended for unknown reasons", about 1.3 reruns per trial.
  • 12 of those conversations were re-queried a few minutes later. 10 were done with end_call in the transcript; the other 2 had hit ElevenLabs's maximum duration and were rightly invalid.
  • In 8 of the saved API responses, metadata.termination_reason already read "end_call tool was called." while the transcript was still empty.

Besides wasting conversations, the reruns bias the kept sample toward conversations ElevenLabs processes quickly.

Fix

  • Accept metadata.termination_reason containing end_call. It is set before the transcript is populated.
  • Conclude "no end_call" only once the status is done. A populated transcript alone no longer ends polling.
  • Poll on a time budget of 5 min (END_CALL_CHECK_BUDGET_SECONDS) instead of 5 attempts, same backoff capped at 10 s. 2 min still missed about 1 in 20 conversations.
  • If ElevenLabs never finishes processing within the budget, the end reason becomes end_call_unverified instead of session_ended, visible in result.json and user_simulator_events.jsonl. A specific reason such as inactivity_timeout is kept.

After the fix, 13 of 13 conversations in a fresh run of the same setup ended with reason=goodbye and none were rerun.

Tests

New tests: termination_reason counts before the transcript arrives; polling continues past a minute until done; a partial transcript while processing is not read as "no end_call"; the end-reason mapping for end_call_unverified. The two tests pinning the old attempt count and delays are updated. pytest tests/unit/user_simulator passes.

Comment thread src/eva/user_simulator/elevenlabs.py Outdated
max_attempts = 5
# ~2 minutes in total. At 5 attempts (~34s) most medical_hr conversations were still
# in-progress, so valid endings were scored invalid and rerun.
max_attempts = 14

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how did we select this? should it be even higher just to be safe? i think the issue last time was i didn't check how high this needed to be

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

14 attempts (~2 min) was a round number, not a measurement, and it wasn't enough: on a later run, 2 of ~40 conversations were still in-progress after 2 min, and both turned out to be done with end_call when re-queried a few minutes later.

Replaced the attempt count with a time budget, END_CALL_CHECK_BUDGET_SECONDS = 300 (same backoff, capped at 10s). The API only reports the current status, not when it changed, so I can't measure the lag distribution directly; 5 min is a safety margin rather than a fitted value. The cost is that a slow conversation holds its worker a bit longer before it's released. Anything that still slips through is now labelled (see the other thread), so if 5 min turns out too short we'll see it.

Comment thread src/eva/user_simulator/elevenlabs.py Outdated
@gabegma
gabegma added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 1c5d70d Oct 14, 2026
2 checks passed
@gabegma
gabegma deleted the fix/elevenlabs-end-call-detection branch October 14, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants