Skip to content

calls.wait_for_result differs from goals.wait_for_result twice, and goals is right both times #30

Description

@cnpierrepapi

calls.py and goals.py disagree in two places, and goals.py is the one that is right both times.

Waiting

# calls.pyifcall.get("status") in {"completed", "failed", "canceled"}:
returncall
# goals.pyifrun.get("result") isnotNoneorrun.get("error") isnotNone:

The goals version waits for what the caller asked for. The calls version waits for the status and assumes the result came with it.

It does not always. Across five calls that each sent a result schema, four had structured_result populated the moment the status went terminal, and the fifth came back None with the result appearing on a read about forty seconds later. Filed against the docs as CALLE-AI/calle-docs#40, because three places promise otherwise, including the CallStatus description in the spec:

terminal states are published only after the post-call outcome is available

So this is inherited rather than invented here. Worth knowing it is not the only place: the TypeScript SDK makes the identical split (CALLE-AI/server-sdk-typescript#17) and so does the n8n node (CALLE-AI/n8n-nodes-calle#3). Four codebases, same shape, same sentence behind all of them.

Polling arguments

goals.wait_for_result validates:

def_validate_polling_seconds(value: float, name: str) ->None:
ifnotmath.isfinite(value) orvalue<=0:
raiseValueError(f"{name} must be a finite positive number.")

calls.wait_for_result does not, and the value goes straight to time.sleep:

interval_seconds goals calls
-5 ValueError, names the parameter ValueError: sleep length must be non-negative
nan ValueError, names the parameter ValueError: Invalid value NaN
0 ValueError, names the parameter accepted

Zero is the one worth fixing. On the calls path it means a loop with no sleep in it, reading GET /v1/calls/{id} as fast as the network allows, for up to the full ten minute default timeout. Nobody passes zero on purpose, but it is an easy thing to arrive at from a config value or a division, and the failure mode is hammering your API rather than an error.

The other two raise, but the message comes from time.sleep and does not say which argument was wrong.

Suggested fix

Reuse _validate_polling_seconds in calls.wait_for_result. It already exists and already says the right thing.

For the waiting difference, mirror the goals loop: when the caller passed a result_schema and the status is terminal with structured_result still None, keep polling for a bounded settle window. Only when a schema was passed, otherwise a call that never asked for a result waits out the window for nothing.

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