Skip to content

calls.waitForResult returns before the result arrives, while goals.waitForResult waits for it #17

Description

@cnpierrepapi

calls.waitForResult returns as soon as the status is terminal, without checking whether the result came with it.

while (Date.now() <= deadline) {
    const call = await this.get(callId);
    if (call.status === "completed" || call.status === "failed" || call.status === "canceled") {
        return call;
    }
    await sleep(intervalMs);
}

goals.waitForResult, in the same package, does the opposite. It ignores the status and waits for the thing the caller asked for:

if (run.result !== null || run.error !== null) {
    return run;
}

The goals one is right, and the calls one would also be right if terminal always meant finished. It does not always. Across five calls that each sent a result_schema, four had structured_result populated the moment the status went terminal. The fifth came back null, and reading the same call about forty seconds later, the result was there. Filed that separately as CALLE-AI/calle-docs#40.

So waitForResult sometimes returns a call with no result on a call that has one.

Reproduction

No network needed, since the client takes a fetch. This replays what the API did, with the timing compressed:

import { CalleClient } from "@call-e/calle";

let reads = 0;
const stub = async () => {
  reads += 1;
  const structured_result = reads === 1 ? null : { open_saturday: "yes" };
  return new Response(JSON.stringify({
    id: "call_x", object: "call_task", status: "completed", task: "t",
    recipients: [], structured_result, summary: null, task_completed: true,
    completion_confidence: { score: 0.9, label: "high" }, evidence: [],
    metadata: {}, failure_code: null, failure_message: null,
    created_at: "2026-09-04T20:00:00Z", completed_at: "2026-09-04T20:01:00Z",
  }), { status: 200, headers: { "Content-Type": "application/json" } });
};

const client = new CalleClient({ apiKey: "x", fetch: stub });
const call = await client.calls.waitForResult("call_x", { intervalMs: 1 });
console.log(reads, call.status, call.structuredResult);
1 completed null

One read, terminal, no result. createAndWait inherits it, and that is the method the quickstart reaches for.

Four times out of five is the annoying frequency. A day of testing looks clean and then it drops one in production, and the report says the API returned nothing, on a call id that has a result on it by the time anybody looks.

Suggested fix

Do what the goals loop already does. When the caller sent a resultSchema and the status is terminal with structuredResult still null, keep polling for a bounded settle window before giving up on it.

Only when a schema was sent, otherwise a call that never asked for a result waits out the window for something that was never coming.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions