Skip to content

feat: add MessagesResource (messaging primitive lifecycle)#28

Merged
govindkavaturi-art merged 1 commit into
mainfrom
feat/sdk-messages-resource
May 4, 2026
Merged

feat: add MessagesResource (messaging primitive lifecycle)#28
govindkavaturi-art merged 1 commit into
mainfrom
feat/sdk-messages-resource

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Wraps the /v1/messages surface (Phase 12.1.5). Closes the messages portion of the Messaging primitive endpoints_missing entry in cueapi-python #24's parity manifest. Pairs with PR #27 (AgentsResource) to close the entire messaging-primitive entry.

Surface

client.messages exposes:

Method Endpoint Notes
.send(from_agent, to, body, ...) POST /v1/messages sender via X-Cueapi-From-Agent header; idempotency via Idempotency-Key header
.get(msg_id) GET /v1/messages/{id}
.mark_read(msg_id) POST /v1/messages/{id}/read idempotent on already-read
.ack(msg_id) POST /v1/messages/{id}/ack terminal

Design notes pinned by tests

  • from_agent goes via X-Cueapi-From-Agent HEADER, not in body. Matches the server's contract — MessageCreate schema is extra=\"forbid\", so a refactor putting from in the body would 400 at integration time. The test pins this so the failure is loud at unit-test time instead.

  • expects_reply=False (default) NOT sent in body. Server default is False; sending expects_reply: false is no-op + adds noise. Pinned: test_omits_expects_reply_when_default.

  • idempotency_key >255 chars raises ValueError client-side BEFORE any HTTP call. Matches server's hard limit; pinned that no HTTP request is made when the validation fails.

  • idempotency_key=None omits the Idempotency-Key header entirely — no \"Idempotency-Key\": None leakage. Pinned.

Client extension

This branch contains the same _request(headers=...) extension as PR #27 (since both PRs need it independently). Minor merge conflict on client.py will auto-resolve when one lands first — both PRs add the kwarg in the same way.

Tests

9 new (12 → 21 in this resource family; 38 total across all unit-test files).

Server-side signals not yet exposed

Two server-side signals exist but aren't yet surfaced richly through the SDK return type:

  • Dedup-hit on Idempotency-Key: server returns 200 (not 201) when same key + same body found within 24h. SDK's _handle_response returns the data dict on both 200 and 201 — callers can't easily tell which they got.
  • Priority downgrade: server signals via X-CueAPI-Priority-Downgraded: true response header when receiver-pair limits downgrade priority>3 to 3.

Both could be surfaced via a richer return type (e.g. a MessageResponse dataclass with status code + headers exposed) in a follow-up. Documented but not implemented in this PR — keeping scope tight on endpoint coverage.

No hosted-PR dependency

All 4 endpoints already shipped on prod via Phase 12.1 messaging primitive.

Companion PRs from this session

  • #25mark_verified bug fix + replay()
  • #26WorkersResource + UsageResource
  • #27AgentsResource

🤖 Generated with 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.

MessagesResource port for the messaging-primitive lifecycle. Approve.

Wraps the `/v1/messages` surface (Phase 12.1.5). Closes the messages
portion of the `Messaging primitive` `endpoints_missing` entry in
cueapi-python #24's parity manifest.

New resource:

- `cueapi/resources/messages.py`: MessagesResource
  - .send(from_agent, to, body, subject=, reply_to=, priority=,
          expects_reply=, reply_to_agent=, metadata=, idempotency_key=)
  - .get(msg_id)
  - .mark_read(msg_id)   # idempotent on already-read
  - .ack(msg_id)         # terminal

Client extension:

- Same `_request(headers=...)` extension as PR #27 (AgentsResource).
  Independent commit on this branch since the two resources can land
  in either order; minor merge conflict on client.py is auto-resolvable
  (both PRs add the same kwarg in the same way).

Design notes pinned by tests:

- `from_agent` goes via `X-Cueapi-From-Agent` HEADER, NOT in body.
  The server's MessageCreate schema is extra="forbid" — putting `from`
  in the body would 400, but we want this caught at unit-test time.
  Pinned by test_minimal_body_and_from_header.

- `expects_reply=False` (default) NOT sent in body. Server default
  is False; sending `expects_reply: false` is no-op + adds noise.
  Pinned by test_omits_expects_reply_when_default.

- `idempotency_key` >255 chars raises ValueError client-side BEFORE
  any HTTP call. Matches server's hard limit. Pinned that no HTTP
  request is made when the validation fails.

- `idempotency_key=None` omits the header entirely (no `Idempotency-Key:
  None` leakage). Pinned.

Tests: 9 new (12 → 21 in this resource family; 38 total across all
unit-test files).

Server-side dedup-hit (200 response) and priority-downgrade signals
(`X-CueAPI-Priority-Downgraded` header) are surfaced through the
underlying httpx response — the SDK's `_handle_response` returns the
data dict on 2xx, so callers see status_code 200 vs 201 only via the
underlying client. A future enhancement could expose these signals
explicitly via a richer return type; documented for follow-up.

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

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@govindkavaturi-art govindkavaturi-art force-pushed the feat/sdk-messages-resource branch from e7899b6 to f968e54 Compare May 4, 2026 18:13
@govindkavaturi-art govindkavaturi-art merged commit ff28c30 into main May 4, 2026
1 of 2 checks passed
mikemolinet added a commit that referenced this pull request May 9, 2026
…t recent ports (#36)

Manifest was 3 days stale; many endpoints listed as missing have
been ported since the last audit.

Moved from endpoints_missing → endpoints_covered (with PR refs):

  - POST /v1/cues/{id}/fire (PR #23; in-flight kwargs in #33)
  - POST /v1/executions/{id}/replay (PR #25)
  - GET /v1/executions/claimable (PR #23)
  - POST /v1/executions/{id}/claim (PR #23)
  - POST /v1/executions/claim (PR #23)
  - GET /v1/workers + DELETE /v1/workers/{id} (PR #26)
  - GET /v1/usage (PR #26)
  - POST /v1/agents + GET/PATCH/DELETE /v1/agents/{ref}
    + GET /v1/agents/{ref}/webhook-secret
    + GET /v1/agents/{ref}/inbox + /sent (PR #27)
  - POST /v1/messages + GET/read/ack (PR #28)

Added in-flight refs (open PRs):

  - GET /v1/agents/roster (in-flight PR #35; cueapi #630 parity)
  - GET /v1/agents/{ref}/presence (in-flight PR #35; cueapi #662 parity)
  - send_at + exit_criteria + idempotency_key kwargs on fire (PR #33)
  - send_at kwarg on messages.send (PR #34)

New endpoints_missing items (post-audit):

  - POST /v1/agents/{ref}/webhook-secret/regenerate (destructive; tracked)
  - DELETE /v1/messages bulk (cueapi #650; bounded by cueapi-cli upstream)
  - POST /v1/executions/{id}/live-claim (cueapi #664; handler-runtime, not SDK)

New "in_flight_ports_2026_05_07" section listing all 4 currently-open
SDK PRs with PR-overlap notes (PR #30/#33 lane-flagged with cueapi-main).

Bumped sdk_version_at_audit 0.1.3 → 0.2.x.

This refresh closes the Backlog row "Refresh cueapi-python parity-manifest.json"
filed earlier today (Self-flag 2026-05-07).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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