Skip to content

feat: add Execution / Worker / Agent / Message Pydantic models (additive)#31

Open
mikemolinet wants to merge 1 commit intomainfrom
feat/sdk-additive-model-classes
Open

feat: add Execution / Worker / Agent / Message Pydantic models (additive)#31
mikemolinet wants to merge 1 commit intomainfrom
feat/sdk-additive-model-classes

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Closes the remaining model_drift items in cueapi-python #24's parity manifest. Adds 4 new model files + 11 new exported classes covering response shapes that resource methods currently return as raw dicts.

Additive only — resource methods still return raw dict. No breaking change. Callers opt into typed accessors via Model.model_validate(dict). Promoting resource methods to return typed objects directly is a separate breaking-change PR (would warrant a major version bump).

New models

File Classes Coverage
cueapi/models/execution.py Execution, ExecutionList, OutcomeDetail All 13 fields the manifest flagged as missing on Execution: payload (PR #589), outcome, outcome_state, triggered_by, evidence_*, claimed_by_*, chain_*, last_heartbeat_at
cueapi/models/worker.py Worker, WorkerList heartbeat_status (online / stale / dead), seconds_since_heartbeat, handlers
cueapi/models/agent.py Agent, AgentList Phase 12.1.5 identity surface; webhook_secret field captures one-time-on-create / one-time-on-regenerate contract
cueapi/models/message.py Message, MessageList, FromAgentRef, StateTransitionResponse Phase 12.1.5 message lifecycle; Message.from_agent aliases server's from field

Design notes

  • extra="allow" on every new model so the server can grow response shapes without breaking SDK callers. Same pattern as AlertConfig / VerificationConfig from feat: expand Cue model with 8 missing fields (drift fix-up) #29.

  • Message.from_agent aliases server's from field via Field(alias="from"). from is a reserved keyword in Python so the SDK exposes it as from_agent while still parsing the server's from on the wire. populate_by_name=True lets callers use either name on construction.

  • All 11 new classes exported from cueapi.__init__ for ergonomic access:

    from cueapi import Agent, Execution, Message, Worker
    
    ex = Execution.model_validate(client.executions.get("exec_x"))
    print(ex.outcome.success, ex.outcome_state)  # typed access

Tests

17 new (93 → 110 total unit tests). Coverage:

  • Minimal vs full responses parse cleanly
  • Forward-compat: unknown fields land in model_extra instead of raising (pinned by test_forward_compat_extra_field)
  • fromfrom_agent alias roundtrip
  • webhook_secret one-time-view shape on Agent
  • All new classes are exported from top-level + are BaseModel subclasses

No hosted-PR dependency

All response shapes already shipped on prod. Pure SDK catch-up.

Companion PRs from this session

  • #25mark_verified bug fix + replay()
  • #26WorkersResource + UsageResource
  • #27AgentsResource
  • #28MessagesResource
  • #29 — Cue model 8-field expansion
  • #30fire(send_at=...) (#618 port)

After this lands, the entire model_drift section of cueapi-python #24's manifest is closed.

🤖 Generated with Claude Code

…ive)

Closes the remaining `model_drift` items in cueapi-python #24's parity
manifest. Adds 4 new model files + 7 new exported classes covering the
response shapes that resource methods currently return as raw dicts.

**Additive only** — resource methods still return raw `dict` (no breaking
change to return types). Callers opt into typed accessors via
`Model.model_validate(dict)`. Promoting resource methods to return typed
objects is a separate breaking-change PR and would warrant a major version
bump.

New files:

- `cueapi/models/execution.py` — `Execution` + `ExecutionList` +
  `OutcomeDetail` (typed outcome inline). Covers all 13 fields the
  manifest flagged as missing on Execution: `payload` (PR #589),
  `outcome`, `outcome_state`, `triggered_by`, evidence_*, claimed_by_*,
  chain_*, last_heartbeat_at.

- `cueapi/models/worker.py` — `Worker` + `WorkerList`. Captures
  `heartbeat_status` (online / stale / dead),
  `seconds_since_heartbeat`, `handlers` list.

- `cueapi/models/agent.py` — `Agent` + `AgentList` (Phase 12.1.5
  messaging primitive identity surface). Mirrors server's
  `AgentResponse`. `webhook_secret` field captures the one-time-on-create
  / one-time-on-regenerate contract.

- `cueapi/models/message.py` — `Message` + `MessageList` +
  `FromAgentRef` (inline sender reference) + `StateTransitionResponse`
  (read / ack response shape).

Notable design choices:

- All new models use `extra="allow"` so server can grow response shapes
  without breaking SDK callers. Same pattern already in use on
  `AlertConfig` + `VerificationConfig` from #29.

- `Message.from_agent` aliases the server's `from` field via
  `Field(alias="from")` — `from` is a reserved keyword in Python so
  the SDK exposes it as `from_agent` while still parsing server's `from`
  on the wire. `populate_by_name=True` lets callers use either name on
  construction.

- All 11 new classes exported from `cueapi.__init__` for ergonomic
  access (`from cueapi import Agent, Message, ...`).

Tests: 17 new (93 → 110 total). Coverage:
- Minimal vs full responses parse cleanly
- Forward-compat: unknown fields land in `model_extra` instead of
  raising
- `from` → `from_agent` alias roundtrip
- `webhook_secret` one-time-view shape on Agent
- All new classes are exported from top-level + are BaseModel subclasses

🤖 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant