openclaw - 💡(How to fix) Fix voice-call: realtime.tools[] entries advertised to model but no handler bind path

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

plugins.entries.voice-call.config.realtime.tools[] entries are passed through to the realtime model (advertised as callable functions), but the plugin has no path to bind a runtime handler for them. When the model invokes one, the realtime handler logs tool=<name> status=error hasHandler=false error="Tool \"<name>\" not available" and the call falls back to whatever timer-based hangup is configured.

Concretely: voicemail-delivery flows that ask the model to invoke end_call after speaking the message can't terminate cleanly — they rely on outbound.notifyHangupDelaySec or the line stays open until maxDurationSeconds.

Error Message

plugins.entries.voice-call.config.realtime.tools[] entries are passed through to the realtime model (advertised as callable functions), but the plugin has no path to bind a runtime handler for them. When the model invokes one, the realtime handler logs tool=<name> status=error hasHandler=false error="Tool \"<name>\" not available" and the call falls back to whatever timer-based hangup is configured.

  • realtime-handler-B_aqJXZj.js:954,1027,1045 — at dispatch time, lookup is this.toolHandlers.get(name); if missing → { error: 'Tool "${name}" not available' }.

Root Cause

plugins.entries.voice-call.config.realtime.tools[] entries are passed through to the realtime model (advertised as callable functions), but the plugin has no path to bind a runtime handler for them. When the model invokes one, the realtime handler logs tool=<name> status=error hasHandler=false error="Tool \"<name>\" not available" and the call falls back to whatever timer-based hangup is configured.

Concretely: voicemail-delivery flows that ask the model to invoke end_call after speaking the message can't terminate cleanly — they rely on outbound.notifyHangupDelaySec or the line stays open until maxDurationSeconds.

Fix Action

Fix / Workaround

  • runtime-entry-CQfEI6TJ.js:3171config.realtime.tools[] flows into resolveRealtimeVoiceAgentConsultTools(...) which advertises every entry to the realtime model.
  • runtime-entry-CQfEI6TJ.js:3173 — only REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME (= "openclaw_agent_consult", defined at dist-session-runtime-BVWzUxTU.534e1716.cjs:336) is registered against the realtime handler.
  • realtime-handler-B_aqJXZj.js:954,1027,1045 — at dispatch time, lookup is this.toolHandlers.get(name); if missing → { error: 'Tool "${name}" not available' }.

end_call exists as an outer MCP voice_call action at index.js:1249-1255 (dispatches to rt.manager.endCall(callId)) but is unreachable from the realtime model's tool surface.

Code Example

"realtime": {
  "tools": [
    {
      "type": "function",
      "name": "end_call",
      "description": "Hang up the current voice call.",
      "parameters": {"type": "object", "properties": {}, "required": []}
    }
  ]
}

---

{"name": "end_call", "action": "end_call"}
RAW_BUFFERClick to expand / collapse

Summary

plugins.entries.voice-call.config.realtime.tools[] entries are passed through to the realtime model (advertised as callable functions), but the plugin has no path to bind a runtime handler for them. When the model invokes one, the realtime handler logs tool=<name> status=error hasHandler=false error="Tool \"<name>\" not available" and the call falls back to whatever timer-based hangup is configured.

Concretely: voicemail-delivery flows that ask the model to invoke end_call after speaking the message can't terminate cleanly — they rely on outbound.notifyHangupDelaySec or the line stays open until maxDurationSeconds.

Repro

In ~/.openclaw/openclaw.json:

"realtime": {
  "tools": [
    {
      "type": "function",
      "name": "end_call",
      "description": "Hang up the current voice call.",
      "parameters": {"type": "object", "properties": {}, "required": []}
    }
  ]
}

Fire an outbound call where the prompt instructs the model to call end_call after speaking. Logs show (paths from ~/.openclaw/npm/node_modules/@openclaw/voice-call/dist/):

  • runtime-entry-CQfEI6TJ.js:3171config.realtime.tools[] flows into resolveRealtimeVoiceAgentConsultTools(...) which advertises every entry to the realtime model.
  • runtime-entry-CQfEI6TJ.js:3173 — only REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME (= "openclaw_agent_consult", defined at dist-session-runtime-BVWzUxTU.534e1716.cjs:336) is registered against the realtime handler.
  • realtime-handler-B_aqJXZj.js:954,1027,1045 — at dispatch time, lookup is this.toolHandlers.get(name); if missing → { error: 'Tool "${name}" not available' }.

end_call exists as an outer MCP voice_call action at index.js:1249-1255 (dispatches to rt.manager.endCall(callId)) but is unreachable from the realtime model's tool surface.

Expected

Either:

  • (a) end_call becomes a built-in realtime tool the model can call directly (mirroring the voice_call.end_call MCP action), or
  • (b) Config exposes a way to bind realtime.tools[] entries to plugin actions, e.g.:
    {"name": "end_call", "action": "end_call"}

Suggested fix

Auto-register a built-in end_call realtime tool when realtime.toolPolicy !== "none", with handler = manager.endCall(callId). ~5 lines in runtime-entry-CQfEI6TJ.js.

Severity

Medium-high. Blocks notify/voicemail flows that need clean programmatic hangup. Affects 2026.5.10-beta.5; pre-bump state likely same shape.

Environment

  • OpenClaw 2026.5.10-beta.5
  • Plugin version per ~/.openclaw/npm/node_modules/@openclaw/voice-call/package.json
  • macOS 14+

Related

Companion to a separate issue covering AMD support + dynamic mode switch on machine-detected (filed simultaneously). Together these are the substrate needed for "outbound conversation mode that gracefully degrades to VM-delivery on machine pickup."

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix voice-call: realtime.tools[] entries advertised to model but no handler bind path