Skip to content

feat: add WorkersResource + UsageResource (parity with /v1/workers + /v1/usage)#26

Merged
govindkavaturi-art merged 1 commit intomainfrom
feat/sdk-workers-and-usage-resources
May 4, 2026
Merged

feat: add WorkersResource + UsageResource (parity with /v1/workers + /v1/usage)#26
govindkavaturi-art merged 1 commit intomainfrom
feat/sdk-workers-and-usage-resources

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Closes 2 entries from cueapi-python #24's endpoints_missing parity manifest plus a bonus DELETE that wasn't listed:

SDK Endpoint
client.workers.list() GET /v1/workers
client.workers.delete(worker_id) DELETE /v1/workers/{id}
client.usage.get() GET /v1/usage

New resource classes

  • cueapi/resources/workers.pyWorkersResource
  • cueapi/resources/usage.pyUsageResource

Both registered on the CueAPI client (client.workers, client.usage) and exported from cueapi.__init__ so callers can from cueapi import WorkersResource, UsageResource if they want to mock them in tests.

Skipped from manifest

POST /v1/worker/heartbeat (worker registration). The hosted endpoint is meant for cueapi-worker (which already wraps it correctly with heartbeat-loop semantics); direct SDK-driven registration would be redundant. Documented in WorkersResource's class docstring so future readers don't wonder why it's missing.

Tests

5 new (12 → 17 unit tests). Mock-based, mirrors the existing ExecutionsResource test pattern:

  • test_list_calls_get_workers — verifies path
  • test_list_passes_no_params — pinned bare-call shape (no params kwarg leakage)
  • test_delete_calls_delete_workers_id — verifies path + 204→None handling
  • test_get_calls_get_usage — verifies path + a representative response shape
  • test_get_returns_server_dict_unchanged — pinned no-transform behavior so a future refactor can't silently start coercing into a typed object

Pre-existing CI flake

The 14 errors on test_cues.py (ValueError: api_key is required) are pre-existing and unrelated to this PR. Captured in the Backlog row added when surveying cueapi-python earlier today (cueapi-python staging-cred test flake, tier-5-maintenance).

No hosted-PR dependency

All 3 endpoints already shipped on prod. Pure SDK catch-up.

Companion PR

#25mark_verified bug fix + replay() (sibling executions-resource changes from the same survey pass).

Test plan

  • python3 -m pytest tests/test_workers_resource.py tests/test_usage_resource.py -q → 5 passed
  • python3 -m pytest tests/test_executions_resource.py -q → 12 passed (unchanged)
  • Manual smoke against staging:
    • client.workers.list() → returns dict with workers + total
    • client.usage.get() → returns plan + cues + executions + rate_limit

Parity Impact

Closes 2 entries from endpoints_missing in cueapi-python #24's parity-manifest.json:

  • GET /v1/workers
  • GET /v1/usage

Plus the bonus DELETE /v1/workers/{id}. After this and #25 merge, remaining endpoints_missing is the messaging primitive (Phase 12.1.5 — large surface, separate PR) plus the deliberately-skipped destructive operations and POST /v1/worker/heartbeat.

🤖 Generated with Claude Code

…/v1/usage)

Closes 2 entries from cueapi-python #24's `endpoints_missing` parity manifest:

- GET /v1/workers           → client.workers.list()
- DELETE /v1/workers/{id}   → client.workers.delete(worker_id)
- GET /v1/usage             → client.usage.get()

(`DELETE /v1/workers/{id}` wasn't in the manifest but is part of the same
hosted surface — added for completeness.)

New resource classes:

- `cueapi/resources/workers.py`: WorkersResource — `.list()` + `.delete()`
- `cueapi/resources/usage.py`:   UsageResource — `.get()`

Both registered on the CueAPI client and exported from cueapi.__init__.

Skipped from manifest: POST /v1/worker/heartbeat (worker registration).
The hosted endpoint is meant for cueapi-worker (which already wraps it
correctly with heartbeat-loop semantics); direct SDK-driven registration
is redundant. Documented in WorkersResource's class docstring.

Tests: 5 new (12 → 17 unit tests). Mock-based, mirrors the existing
ExecutionsResource test pattern.

The 14 pre-existing staging-cred test_cues.py failures (`ValueError:
api_key is required`) are unrelated to this PR — same flake captured in
the Backlog row added when surveying cueapi-python earlier this session.

No hosted-PR dependency. All 3 endpoints already shipped on prod.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Copy link
Copy Markdown
Member

@govindkavaturi-art govindkavaturi-art left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean parity port — WorkersResource + UsageResource just wrap GET endpoints. Approve.

@govindkavaturi-art govindkavaturi-art merged commit 4b37d97 into main May 4, 2026
3 of 4 checks passed
govindkavaturi-art pushed a commit that referenced this pull request May 4, 2026
Wraps the entire `/v1/agents` surface from the messaging primitive
(Phase 12.1.5). Closes the agents portion of the `Messaging primitive`
endpoints_missing entry in cueapi-python #24's parity manifest. The
companion `MessagesResource` (send/get/read/ack lifecycle) ships in a
follow-up PR.

New resource:

- `cueapi/resources/agents.py`: AgentsResource
  - .create(display_name, slug=None, webhook_url=None, metadata=None)
  - .list(status=None, include_deleted=False, limit=50, offset=0)
  - .get(ref, include_deleted=False)
  - .update(ref, display_name=None, webhook_url=None, clear_webhook_url=False,
           status=None, metadata=None)
  - .delete(ref)
  - .webhook_secret_get(ref)
  - .webhook_secret_regenerate(ref)  # sends X-Confirm-Destructive: true
  - .inbox(ref, state=None, limit=50, offset=0)
  - .sent(ref, limit=50, offset=0)

Client extension:

- `client._request` now accepts an optional `headers` kwarg, which
  extends (does not replace) the client's default Authorization +
  Content-Type + User-Agent headers. Used here for the destructive
  X-Confirm-Destructive guard; will also be used by the upcoming
  MessagesResource for X-Cueapi-From-Agent + Idempotency-Key.

Design notes pinned by tests:

- `--include-deleted` mirror: `include_deleted=True` sends `"true"`,
  `False` (default) omits. Same omit-when-default pattern as PR #26's
  `executions list --has-evidence`.

- `clear_webhook_url=True` sends literal JSON `null` (key present,
  value None), NOT field omission. Server uses `model_fields_set` to
  disambiguate "omitted = no change" from "explicit null = clear", so
  the SDK MUST send the key with explicit None. Pinned by
  test_clear_webhook_url_sends_explicit_null.

- `webhook_url` and `clear_webhook_url` mutex enforced with a clear
  ValueError before any HTTP call.

- `webhook_secret_regenerate` sends X-Confirm-Destructive: true in
  the header. The server requires it; the SDK adds it automatically
  so callers don't have to know about the header. Pinned by
  test_regenerate_sends_destructive_header.

Tests: 18 new across 9 test classes (12 → ~30 unit tests; total 46
passing across all unit-test files).

No hosted-PR dependency. All 9 endpoints already shipped on prod.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
govindkavaturi-art pushed a commit that referenced this pull request May 4, 2026
Wraps the entire `/v1/agents` surface from the messaging primitive
(Phase 12.1.5). Closes the agents portion of the `Messaging primitive`
endpoints_missing entry in cueapi-python #24's parity manifest. The
companion `MessagesResource` (send/get/read/ack lifecycle) ships in a
follow-up PR.

New resource:

- `cueapi/resources/agents.py`: AgentsResource
  - .create(display_name, slug=None, webhook_url=None, metadata=None)
  - .list(status=None, include_deleted=False, limit=50, offset=0)
  - .get(ref, include_deleted=False)
  - .update(ref, display_name=None, webhook_url=None, clear_webhook_url=False,
           status=None, metadata=None)
  - .delete(ref)
  - .webhook_secret_get(ref)
  - .webhook_secret_regenerate(ref)  # sends X-Confirm-Destructive: true
  - .inbox(ref, state=None, limit=50, offset=0)
  - .sent(ref, limit=50, offset=0)

Client extension:

- `client._request` now accepts an optional `headers` kwarg, which
  extends (does not replace) the client's default Authorization +
  Content-Type + User-Agent headers. Used here for the destructive
  X-Confirm-Destructive guard; will also be used by the upcoming
  MessagesResource for X-Cueapi-From-Agent + Idempotency-Key.

Design notes pinned by tests:

- `--include-deleted` mirror: `include_deleted=True` sends `"true"`,
  `False` (default) omits. Same omit-when-default pattern as PR #26's
  `executions list --has-evidence`.

- `clear_webhook_url=True` sends literal JSON `null` (key present,
  value None), NOT field omission. Server uses `model_fields_set` to
  disambiguate "omitted = no change" from "explicit null = clear", so
  the SDK MUST send the key with explicit None. Pinned by
  test_clear_webhook_url_sends_explicit_null.

- `webhook_url` and `clear_webhook_url` mutex enforced with a clear
  ValueError before any HTTP call.

- `webhook_secret_regenerate` sends X-Confirm-Destructive: true in
  the header. The server requires it; the SDK adds it automatically
  so callers don't have to know about the header. Pinned by
  test_regenerate_sends_destructive_header.

Tests: 18 new across 9 test classes (12 → ~30 unit tests; total 46
passing across all unit-test files).

No hosted-PR dependency. All 9 endpoints already shipped on prod.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

2 participants