Skip to content

feat: add fire + list_claimable + claim + claim_next#22

Closed
mikemolinet wants to merge 1 commit intocueapi:mainfrom
mikemolinet:feat/fire-and-claim-methods
Closed

feat: add fire + list_claimable + claim + claim_next#22
mikemolinet wants to merge 1 commit intocueapi:mainfrom
mikemolinet:feat/fire-and-claim-methods

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Brings cueapi-sdk toward parity with the @cueapi/mcp 0.3.0 + 0.4.0 surface. Adds four new methods covering the SEND side (fire) and the RECEIVE side (claimable list, claim, claim-next). The heartbeat signature fix is held for a follow-up commit pending technical review.

What's added

CuesResource:

Method Wraps Notes
fire(cue_id, payload_override=None, merge_strategy=None) POST /v1/cues/{id}/fire Ad-hoc one-shot triggers; using cues as a messaging channel between agents.

ExecutionsResource:

Method Wraps Notes
list_claimable(task=None, agent=None) GET /v1/executions/claimable?task=&agent= Server-side SQL filter (NOT client-side).
claim(execution_id, worker_id=...) POST /v1/executions/{id}/claim Atomic; returns 409 if already claimed.
claim_next(worker_id=..., task=None) POST /v1/executions/claim (no task) OR list+claim chain (with task) Internal fan-out when task is provided.

Notable design choices

  • list_claimable uses server-side query params, not client-side filter. Client-side filter after fetch hits the LIMIT 50 starvation bug fixed in the 2026-04-25 prod incident (see app/routers/executions.py:122-131 docstring in cueapi-core for the prior repro). Same call we made on @cueapi/mcp 0.4.0 and cueapi-cli 0.2.0.
  • claim_next(task=...) fans out via list_claimable + claim by ID because the server's POST /v1/executions/claim endpoint does not accept a task filter today. Tiny race window between list and claim is bounded by the atomic claim returning 409, in which case the caller retries.

Tests

pytest tests/ 42 unit tests pass (was 30; +12 net). New tests follow the existing MagicMock pattern in tests/test_executions_resource.py. The 14 staging-integration errors visible locally are expected (need real CI credentials); CI handles them.

42 passed, 14 errors in 0.26s   # 14 errors all "api_key required" — staging fixture not loaded locally

Version

0.1.3 -> 0.2.0. Minor bump for additive new methods.

Aligned cueapi/__init__.py (had drifted to 0.1.2) with pyproject.toml at the same time.

Pending follow-up (NOT in this PR)

The existing ExecutionsResource.heartbeat(execution_id) method sends an empty body and does NOT include worker_id via the X-Worker-Id request header that the server reads from. worker_id is what the server uses to enforce ownership on heartbeat (returns 403 on mismatch); without it the race-protection check is silently bypassed.

A signature change to add worker_id is held pending technical review of the deprecation cadence:

  • (a) Additive kwarg-only with default-warn-on-omit, ship as 0.2.x patch.
  • (b) Hard signature change requiring worker_id, ship as 0.3.0 with breaking-change note.
  • (c) Some hybrid.

Holding that commit so this PR ships clean and the heartbeat fix gets its own consideration.

Lineage

Brings the Python SDK toward parity with the @cueapi/mcp 0.3.0 + 0.4.0
surface. Adds four new methods covering the SEND side (fire) and the
RECEIVE side (claimable list, claim, claim-next). Heartbeat signature
fix is held for a follow-up commit pending technical review.

CuesResource:
- fire(cue_id, payload_override=None, merge_strategy=None)
  POST /v1/cues/{id}/fire. For ad-hoc one-shot triggers and for using
  cues as a messaging channel between agents (carry message, instruction,
  task, reply_cue_id in payload_override).

ExecutionsResource:
- list_claimable(task=None, agent=None)
  GET /v1/executions/claimable?task=&agent=
  Filters server-side via query params (NOT client-side). Required for
  single-purpose workers; client-side filter after fetch hits the LIMIT
  50 starvation bug fixed in the 2026-04-25 prod incident.

- claim(execution_id, worker_id=...)
  POST /v1/executions/{id}/claim
  Atomic; returns 409 if already claimed.

- claim_next(worker_id=..., task=None)
  POST /v1/executions/claim (no task) OR list+claim chain (with task).
  Server's claim endpoint does not accept a task filter today; with task
  the SDK fans out (list_claimable filtered, pick oldest, claim by ID).
  Tiny race window between list and claim is bounded by the atomic claim
  returning 409, in which case the caller retries.

Version: 0.1.3 -> 0.2.0. Aligned cueapi/__init__.py (had drifted to
0.1.2) with pyproject.toml at the same time.

Tests: 42 unit tests pass (was 30; +12 net). Mirrors the existing
MagicMock pattern in tests/test_executions_resource.py.

Pending follow-up:
- ExecutionsResource.heartbeat(execution_id) currently sends an empty
  body and does not include worker_id via the X-Worker-Id request
  header that the server reads from. Worker-id is what the server uses
  to enforce ownership on heartbeat (returns 403 on mismatch); without
  it the race-protection check is silently bypassed. A signature change
  to add worker_id is held pending technical review of the deprecation
  cadence (additive kwarg-only with default-warn-on-omit vs hard
  signature change in a major bump).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@mikemolinet
Copy link
Copy Markdown
Collaborator Author

Superseded by upstream-branch PR (will be opened next). Fork-PR can't access staging secrets needed by integration tests.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant