Skip to content

feat: add selectable phone call voice stacks - #52

Merged
dimavrem22 merged 33 commits into
mainfrom
feat/phone-call-voice-stacks
Aug 1, 2026
Merged

feat: add selectable phone call voice stacks#52
dimavrem22 merged 33 commits into
mainfrom
feat/phone-call-voice-stacks

Conversation

@dimavrem22

@dimavrem22 dimavrem22 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Executive Summary

  • Adds a three-option Phone call voice stack wizard: Inkbox Voice AI, OpenAI Realtime API, and Inkbox TTS/STT.
  • Routes inbound and outbound calls through the selected stack, inherits saved Voice AI authority by default, and passes the configured voicemail policy explicitly.
  • Adds signed, restart-safe hosted call.ended reconciliation with exact-recipient, exact-once post-call SMS settlement.

Description

  • Pauses before the phone-call section, preserves rerun defaults, validates Realtime access before saving, and returns failed validation to all three choices.
  • Configures Contact-scoped or YOLO Voice AI authority with transient admin credentials; runtime keeps the agent-scoped key and the canonical local mirror is INKBOX_VOICE_AI_AUTHORITY_MODE.
  • Reconciles remote incoming-call routing during setup and gateway startup, and reports local/remote routing and authority drift in doctor.
  • Uses stack-specific outbound call schemas: Voice AI sends mode=hosted_agent with a required bounded reason and no authority override; Realtime and Inkbox TTS/STT send mode=client_websocket with the current media URL.
  • Preserves server-owned Voice AI voice/model/instructions while changing routing or authority.
  • Registers signed identity call.ended delivery without replacing mail, text, iMessage, A2A, or external-event subscriptions.
  • Grounds hosted completion in the authoritative call, transcript, caller number, and open action items. Current-call recipient data overrides generated memory or similarly named contacts.
  • Journals the exact SMS target and tool attempt before provider I/O, correlates the real Claude tool result, permits one correction only for deterministic known-no-send failures, and never blindly retries ambiguous writes.
  • Stores bounded private receipts atomically without SMS bodies, transcripts, contact memory, credentials, provider payloads, or completed replay material.
  • Bumps the plugin from 0.2.7 to 0.2.8 and requires Inkbox SDK >=0.5.9,<1.0.0 everywhere.

Reason

Operators need one explicit setup surface for who owns phone audio and one saved Voice AI authority default for inbound and outbound hosted calls. Hosted calls also need to complete promised work after hangup without allowing model memory, duplicate delivery, restart, or an ambiguous provider outcome to redirect or replay an external write.

Decisions

  • Product copy says Inkbox Voice AI while the compatible API wire mode remains hosted_agent.
  • Claude Code uses its supported Agent SDK session/resume surface, per-contact sessions, narrow Inkbox tool auto-allow rules, and pre/post tool hooks around the real side-effect boundary.
  • Realtime exposes one consult_agent bridge into Claude Code. Hermes' direct realtime contact-tool scenario is not applicable because Claude does not expose that host-specific surface.
  • Product calls retain the configured/default voicemail policy; call-capable CI explicitly sets and verifies disabled.
  • The container is manual local-test support only and is not published or used as a CI/release gate.

Testing

Live-test inventory

  • Updated — test_inbound_call_inkbox_tts_stt: proves a direct inbound client-WebSocket call has two-way audio, uses Inkbox STT/TTS, and persists voicemail_detection=disabled. This closes the prompt/audio-only false positive where the actual call record could retain the product default.
  • Updated — test_outbound_call_realtime: correlates the driver's fresh inbound media leg with the AUT's fresh outbound request, proves two-way audio through OpenAI Realtime, and verifies disabled voicemail detection on the exact AUT-owned record. This closes both the uninspected-policy gap and the wrong-owner false failure where the driver's independent inbound default was asserted instead.
  • New — test_outbound_call_hosted_and_post_call_wakeup: pairs fresh driver and AUT legs, requires hosted mode, non-empty reason, saved effective authority, disabled voicemail detection, current caller transcript plus matching open action before hangup, call-ID-scoped reconciliation, one exact-target sender row with the current speech-safe marker, and a full duplicate grace window. This removes acknowledgement/arbitrary-delay false positives, stale-call and wrong-leg races, recipient-inbox ambiguity, and duplicate-send false negatives.
  • Updated — test_email_request_gets_call: correlates exactly one fresh driver inbound leg with exactly one fresh AUT outbound leg, observes the full duplicate grace window, and verifies disabled voicemail detection on the AUT-owned request. This closes stale-call, wrong-owner, prompt-only, and duplicate-call gaps.
  • Updated — test_sms_request_gets_call: applies the same two-owner correlation, duplicate rejection, and exact AUT policy assertion to the SMS-triggered path. This closes the same stale/wrong-leg race without treating the driver's independent inbound default as the agent's request policy.
  • Updated — test_reports_sender_details: explicitly asks for the full known email and phone while keeping exact contact-card assertions. This closes a live false negative where the model correctly reported the name and phone but referred to the email generically because the prompt only explicitly required the phone.
  • Updated — setup and hosted-proof contracts: rejects an agent-scoped credential entered for YOLO, returns to all three stack choices, and proves the rejected key and remote authority were never persisted. Hosted timeout diagnostics inspect at most ten action items and emit only counts, booleans, and exception class names—never transcript, action, credential, or provider content.
  • Updated — hosted action request contract: repeated cross-host live runs showed that a generic “SMS containing these words” request could reach the caller transcript while the hosted action summarizer omitted or reinterpreted the marker. The driver now requires Voice AI to create the post-call action immediately with the exact SMS body and read back all five words only after the action is saved. A deterministic workflow contract locks that wording; transcript, durable action, exact recipient, exact body, and duplicate gates remain strict.

Validation

  • Full local suite: 438 passed, 23 skipped.
  • Focused call-owner correlation contracts: 10 passed.
  • Focused wizard/doctor/startup/tools/hosted/live-contract suite: 139 passed.
  • Fatal Ruff rules, Python compilation, workflow YAML parsing, wheel contents, and git diff --check: passed.
  • Exact-head unit and contract CI: passed on 23d406fe73960aec9a26f6da2115692735535b29.
  • Exact-head full-stack CI: passed on the same head, including real/mock channels, all four A2A variants, inbound TTS/STT, outbound Realtime, hosted Voice AI, external events, and the aggregate gate.

Related PRs

@dimavrem22
dimavrem22 merged commit 33a3d69 into main Aug 1, 2026
15 checks passed
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.

1 participant