OPEN SOURCE · APACHE-2.0 · TYPESCRIPT
An AI haggles on the phone and books the room. "Confirmed" only gets its check when the other party says so.
Below is the real call in which GPT-4o mini negotiated with a hotel that lists at ¥23,500, redrawn at 3× from the saved events. It is not a recording.


confirmed = yes (callee) lands at the top of the evidence. Nothing the agent says can fill that row.Play
Watch two agents haggle. Then answer the phone yourself.
Six scenarios ship with the simulator: a restaurant that is full at 7 pm (in English too: oathra play restaurant-reservation-en), an "impossible" hotel with a secret floor price, a bulk purchase, a serial number read-back, and a trap where every slot is full and the only correct answer is "I could not book it." Pit models against each other and share the card.
$ npx oathra battle impossible-hotel \
--agent scripted --agent openai --agent gemini \
--png card.png --json run.json
Impossible Hotel
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
scripted ████████████████████ 6540
openai:gpt-4o-mini ███████████████████▋ 6444
gemini:gemini-flash-latest ███████████████████▌ 6410
SUCCESS TIME COST SCORE
scripted ✓ 69s $0.00 95.4
openai:gpt-4o-mini ✓ 95s $0.00 89.5
gemini:gemini-flash-latest ✓ 79s $0.00 90.1
False completions: 0
The run behind the video. All three closed under ¥20,000 (¥19,900 / ¥19,900 / ¥20,000) — and every "win" is anchored to the hotel saying "your reservation is confirmed."
This run first produced one false completion: a hotel line that merely restated the price was being counted as a "yes". The evidence engine was fixed and the same three calls re-run to zero. That is what the battle command is for. Points reflect price and time; cards export as SVG/PNG and the run as JSON.
The three agents calling at once (63 s, sound on; Japanese audio, English captions). The windows are the Arena replaying the recorded calls.
Call
Same runtime, real phone. Bring your own carrier. Bring your own model.
Twilio keeps its direct media-streams fast path. Plivo and any SIP trunk go through a SIP gateway (LiveKit by default, Cloud or self-hosted). The voice engine is a separate choice: GPT-Live was the most natural on our test calls, so it is the default; a Deepgram + LLM + TTS pipeline is there when you want control or lower cost.
$ npx oathra setup phone Choose voice engine ❯ GPT-Live Recommended · best conversation quality OpenAI Realtime speech-to-speech Pipeline Deepgram + any brain + OpenAI TTS How would you like to make calls? ❯ Twilio direct media streams · verified Plivo SIP via gateway Custom SIP Setting up Twilio ✓ Verify credentials account · Full ✓ Find a voice-capable number +1 947 ··· ✓ Check outbound permission for Japan ✓ Media Streams configured per call ✓ Twilio is ready. $ npx oathra phone doctor --to +81… Carrier ✓ authenticated · active · caller ID · Japan enabled Media · requires a live call — oathra phone test Voice Engine ✓ GPT-Live (gpt-live-1) Latency Oathra → api.twilio.com 244 ms Cost JP mobile · twilio · $0.185/min READY ✓
- Guided, not one-click-liesProviders that need a human step (caller-ID verification, geo permissions, regulatory bundles) return a
user_actionwith a link; Oathra polls until it is done. Everything the API allows is automated. - Test without paying for minutes
oathra phone testhas three levels — Local ¥0 (engine loopback with synthesized audio), Gateway ¥0, PSTN paid. You stop burning a carrier minute on every bug. - Doctor tells you which layer brokeCarrier · SIP gateway · media · voice engine · latency · cost, with a fix line for each failed check.
Prove
「予約できました」 is not evidence.
Oathra returns a VerifiedResult. Each field is anchored to an utterance from the other party (and to audio on real calls). Ten thousand mutated callees produce zero false completions — reproducible with one command.
{
"field": "time",
"value": "19:30",
"source": "callee",
"transcript": "19時はいっぱいですが、19時半でしたら空いております。",
"span": "19時半",
"explicit": true,
"verified": true,
"note": "accepted with value restated by caller",
"audio": { "startMs": 14210, "endMs": 18960 }
}
Success = Connected
∧ date.verified ∧ time.verified
∧ partySize.verified ∧ confirmed.verified
∧ constraintsSatisfied
$ npx oathra eval --adversarial 10000
never-confirm · wrong-restate · negate-then-offer
silent-hangup · caller-echo-trap
False Completion: 0 / 10000 adversarial runs 6.2s
- Refusals never become offers. 「19時はいっぱいですが」 produces no claim for 19:00.
- Corrections supersede. 「13日、いや14日」 keeps the 14th, with a supersedes edge.
- Hedges do not confirm. 「たぶん大丈夫」 is neither agreement nor confirmation.
- Only the callee can confirm. The agent saying it booked is recorded and ignored.
- Confirmations go stale. Change the price after 「承りました」 and it must be re-confirmed.
- Walking away is not accepting. 「わかりました、他を探します」 verifies nothing.
Mix and match
Carriers on one side, voice engines on the other.
| Carrier | |
|---|---|
| Twilio direct | verified on real calls |
| Plivo sip | via gateway · PSTN unverified |
| Custom SIP sip | any trunk |
| Telnyx · Wavix · Sinch · didlogic | v0.2 |
| Yours | oathra provider create phone <id> |
| Voice engine | |
|---|---|
| GPT-Live recommended | full-duplex · $0.05/min |
| OpenAI Realtime | speech-to-speech |
| Pipeline | Deepgram + any brain + TTS |
| Brains | OpenAI · Gemini · Ollama · scripted |
| Local | experimental |
OATHRA
│
Call Runtime ── Evidence Engine ── VerifiedResult
│
┌──────────┴──────────┐
Phone Layer Voice Layer
│ │
Twilio Direct · SIP Gateway GPT-Live · Realtime · Pipeline · Local
│
LiveKit Cloud / self-host → Plivo · Custom SIP · (Telnyx …)
What is verified and what is not (the v0.1 release-candidate status) lives in the README. Every number on this page was measured by us and can be reproduced with the commands shown.