Skip to content

[voice-call] get_status returns found:false for completed calls once evicted from in-memory manager — no fallback to persisted call store #96586

Description

@NiTeCoMM-code

Filed against @openclaw/[email protected] (also present in 2026.6.5).

Summary

The voice_call tool's get_status action (and the legacy mode: "status" path) only checks the in-memory call manager via rt.manager.getCall(callId) || rt.manager.getCallByProviderCallId(callId). There is no fallback to the persisted call store when the in-memory record has been evicted.

This causes get_status to report { found: false } for calls that completed successfully and have a full transcript persisted to disk — the agent has no way to retrieve the conversation that happened.

Root cause

In dist/index.js:

case "get_status": {
    const callId = normalizeOptionalString(rawParams.callId) ?? "";
    const call = rt.manager.getCall(callId) || rt.manager.getCallByProviderCallId(callId);
    return json(call ? { found: true, call } : { found: false });
}

rt.manager.getCall() is an in-memory lookup. Once a call exits the manager's active map (cleanup after completion, gateway restart, or simply enough time passing), this returns undefined regardless of whether a persisted record exists.

Meanwhile, the full call record — including a complete turn-by-turn transcript — is independently persisted under plugin_state_entries (plugin_id=voice-call) as base64-encoded, chunked JSON blobs keyed like event:<seq6>:<sequence>:<uuid>:chunk:NNNN. This data is confirmed present and complete (verified manually via direct SQLite query) for calls where get_status reports found: false.

Repro

  1. Initiate an outbound call via voice_call (initiate_call).
  2. Let the call complete naturally.
  3. Wait — even a few minutes is enough, and a gateway restart in between guarantees it — then call get_status with the same callId.
  4. Observe: { found: false }, despite the call having completed normally and a full transcript existing in the plugin's persisted SQLite state.

Impact

Any agent workflow that says "call me and report back what I said" silently fails at the reporting step. The agent has no way to know the call succeeded or to retrieve what was said — it can only report that the call status is unknown, which reads to the end user as if voice memory/transcription doesn't work at all, when in fact the data is sitting right there in the plugin's own store.

Suggested fix

get_status (and mode: "status") should fall back to querying the persisted call store (the same one transcripts are written to) when the in-memory manager lookup misses, before returning found: false. Alternatively, expose a dedicated get_transcript action that reads directly from the persisted store by callId, independent of in-memory manager state, since transcripts are clearly intended to survive past the live call lifecycle (they're written incrementally during the call as discrete event chunks).

Happy to provide the decoded persisted record structure if useful for reproducing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.no-staleExclude from stale automation

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions