fix(voice-call): avoid duplicate OpenAI initial greetings#86502
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed May 30, 2026, 3:37 AM ET / 07:37 UTC. Summary PR surface: Source +21, Tests +177. Total +198 across 4 files. Reproducibility: yes. The linked report gives a concrete Twilio/OpenAI outbound-call repro, and current main source shows both Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land one canonical fix after maintainers choose the desired first-greeting strategy and redacted live proof demonstrates both the default one-greeting path and the Do we have a high-confidence way to reproduce the issue? Yes. The linked report gives a concrete Twilio/OpenAI outbound-call repro, and current main source shows both Is this the best way to solve the issue? Unclear pending maintainer choice. The patch is a plausible narrow source fix with focused tests, but it should be compared with the sibling implementation and backed by live call proof before merge. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 0f8ea1d3d905. Label changesLabel justifications:
Evidence reviewedPR surface: Source +21, Tests +177. Total +198 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
52b03a3 to
202fe8e
Compare
|
Addressed the OpenAI realtime opt-out review finding in
PR body is updated with the new real behavior proof. Live Twilio/OpenAI call proof is still not available from this cron environment because it has no external telephony/provider credentials. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Applied the OpenAI bridge-creation follow-up in Verification after the fix:
I updated the PR body with the new RED/GREEN and changed-gate proof. Live Twilio/OpenAI call proof still is not available from this cron environment because it has no external telephony/provider credentials. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
Closing stale contributor PR that has been open for over a week without merge progress. I am keeping the branch intact so it can be reopened or reused if maintainers want to continue it. |
Summary
triggerGreeting()for OpenAI realtime outbound calls when OpenAI server VAD auto-response is active.autoRespondToAudio: falseis configured, and now pass that opt-out through to the OpenAI bridge so server VADcreate_responseis disabled for that path.Fixes #85846
Test Plan
node scripts/run-vitest.mjs extensions/voice-call/src/webhook/realtime-handler.test.ts --testNamePattern 'keeps explicit greetings when OpenAI auto response is disabled'failed before the source fix withexpected undefined to be falseforcreateRequest?.autoRespondToAudio.node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts --testNamePattern "preserves explicit realtime auto-response opt-out during config resolution"failed before the provider-resolution fix withexpected undefined to be falseforresolveConfig(...).autoRespondToAudio.node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts --testNamePattern "preserves explicit realtime auto-response opt-out during config resolution"passed after the provider-resolution fix.node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts --testNamePattern "applies provider-configured realtime auto-response opt-out when creating bridges"failed before the bridge-creation fix withturn detection.create_response: expected true to deeply equal false.node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts --testNamePattern "applies provider-configured realtime auto-response opt-out when creating bridges"passed after the bridge-creation fix (1 passed | 50 skipped).node scripts/run-vitest.mjs extensions/voice-call/src/webhook/realtime-handler.test.tsnode scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts extensions/voice-call/src/webhook/realtime-handler.test.tspnpm check:changed --stagedpnpm openclaw voicecall --help(runtime CLI/build smoke; exits becausevoice-callis disabled by default in this checkout).Real behavior proof
Behavior addressed: OpenAI realtime outbound calls with a queued initial greeting no longer create two independent greetings when server VAD auto-response is active; the initial greeting is provided through session instructions and
triggerGreeting()is suppressed for that OpenAI auto-response path. WhenautoRespondToAudio: falseis configured, the voice-call handler keeps the explicittriggerGreeting()path and passesautoRespondToAudio: falseinto the OpenAI bridge so the provider session disables server VADcreate_response.Real environment tested: Local OpenClaw checkout on macOS with the voice-call realtime WebSocket handler exercised through the repository runtime/test harness, the OpenAI realtime provider bridge tests, and OpenClaw CLI runtime smoke from this branch.
Exact steps or command run after this patch:
node scripts/run-vitest.mjs extensions/voice-call/src/webhook/realtime-handler.test.ts --testNamePattern 'keeps explicit greetings when OpenAI auto response is disabled'before the source fix;node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts --testNamePattern "preserves explicit realtime auto-response opt-out during config resolution"before and after the provider-resolution fix;node scripts/run-vitest.mjs extensions/voice-call/src/webhook/realtime-handler.test.ts;node scripts/run-vitest.mjs extensions/openai/realtime-voice-provider.test.ts extensions/voice-call/src/webhook/realtime-handler.test.ts;pnpm check:changed --staged; earlierpnpm openclaw voicecall --help.Evidence after fix: The new provider-resolution RED assertion failed before the fix with
expected undefined to be false, proving OpenAIresolveConfigdropped the configuredautoRespondToAudio: falsebefore the voice-call handler could read it. After the fix, that focused resolver test passed (1 passed | 49 skipped), and the combined OpenAI provider plus voice-call handler run passed (2 files, 71 tests passed). The changed gate reported lanesextensions, extensionTests, then completed typecheck extensions, typecheck extension tests, lint extensions, media helper guard, runtime sidecar loader guard, and runtime import-cycle checks successfully. The earlier CLI runtime smoke built OpenClaw and bundled plugin assets, then exited with the expected message thatopenclaw voicecallis provided by the disabled-by-defaultvoice-callplugin. A follow-up bridge-creation RED assertion failed before this update withturn detection.create_response: expected true to deeply equal false; after the bridge fix, the focused createBridge test passed (1 passed | 50 skipped), and the combined OpenAI provider plus voice-call handler run passed (2 files, 71 tests passed).Observed result after fix: OpenAI's default auto-response path receives the initial greeting in session instructions and the voice-call plugin no longer sends a second explicit greeting request. The disabled-auto-response path now sends exactly one explicit greeting request while carrying
autoRespondToAudio: falseto the OpenAI bridge so OpenAI server VAD does not auto-create a second response. Provider-levelautoRespondToAudio: falsenow also reaches bridge creation when no per-request override is present.What was not tested: A live Twilio/OpenAI phone call was not placed from this environment because external telephony/provider credentials are not available to this cron job; the after-fix proof uses local realtime WebSocket handler/provider bridge execution and CLI/build smoke rather than external telephony credentials.
Risk/Notes