Skip to content

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

Merged
mikemolinet merged 1 commit into
mainfrom
feat/sdk-additive-model-classes
May 11, 2026
Merged

feat: add Execution / Worker / Agent / Message Pydantic models (additive)#31
mikemolinet merged 1 commit into
mainfrom
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

govindkavaturi-art pushed a commit that referenced this pull request May 6, 2026
#32)

* ci(test): spin up cueapi-core locally instead of hitting staging with ARGUS_STAGING_KEY

The `test` job's `pytest tests/` runs the SDK's CRUD tests against a real
CueAPI server. Previously that server was remote staging, authenticated by
`secrets.ARGUS_STAGING_KEY`. Argus was retired 2026-05-02 (cueapi PR #539)
and that key/user is no longer valid — every PR's `test` job has been
red for ~3 days with `AuthenticationError: Invalid API key`, blocking
PRs #30 and #31 (and any future SDK PRs).

This switches the job to the same self-contained pattern that's already
proven by the passing `sdk-integration` job: clone cueapi-core, install,
migrate, boot uvicorn locally, register a fresh test user via
POST /v1/auth/register (gated by ALLOW_REGISTER=true), capture the key,
plumb it through the existing `CUEAPI_STAGING_URL` / `CUEAPI_STAGING_API_KEY`
env vars (no SDK code change needed — `tests/conftest.py` already reads
them from env).

Workflow-only diff. No SDK behavior change.

Note: `notify-merge` still references `secrets.ARGUS_CUEAPI_KEY` for the
post-merge prod telemetry cue. That key is also stale, but the step runs
after auto-merge so it doesn't gate the PR — leaving for a follow-up that
needs a new prod key minted by an operator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(test): replace alembic with Base.metadata.create_all (matches cueapi-core conftest)

First push failed because OSS migration set ends at 023 while the User
model declares an `api_key_encrypted` column with no migration backing it.
That's a parity drift in cueapi-core (private migration 019 in the hosted
repo includes the column; the OSS port renamed/replaced it with the
alert-webhook bits but kept the column on the model). `alembic upgrade
head` produced a schema missing that column → register endpoint 500'd
on the User SELECT.

Switch the CI bootstrap to model-driven schema init via
`Base.metadata.create_all`, which is the exact pattern cueapi-core's own
`tests/conftest.py` uses (and which is robust to model/migration drift
because the model is the source of truth for tests).

Imports the same model list as conftest so all tables register before
create_all runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@govindkavaturi-art govindkavaturi-art enabled auto-merge (squash) May 7, 2026 00:59
…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)
@mikemolinet mikemolinet force-pushed the feat/sdk-additive-model-classes branch from 7414093 to f74ca30 Compare May 11, 2026 23:49
@mikemolinet mikemolinet merged commit bda862b into main May 11, 2026
4 checks passed
@mikemolinet mikemolinet deleted the feat/sdk-additive-model-classes branch May 11, 2026 23:52
mikemolinet added a commit that referenced this pull request May 12, 2026
…dy coverage, bump audit to 2026-05-12 (#43)

Manifest was dated 2026-05-07 and missing the PR-1b event-emit endpoint
coverage (4 endpoints) plus the body-verify Phase 2 + inline_body
extensions that shipped 2026-05-09 → 2026-05-12. Brings the manifest
back in sync with SDK head.

Endpoints added to `endpoints_covered`:
- POST /v1/agents/{ref}/subscriptions (subscriptions_create, PR #38;
  inline_body kwarg in PR #42 / cueapi #791 Item 1)
- GET /v1/agents/{ref}/subscriptions (subscriptions_list, PR #38)
- DELETE /v1/agents/{ref}/subscriptions/{sub_id} (subscriptions_delete,
  PR #38)
- GET /v1/agents/{ref}/events (events_pull, PR #38)

Updates to existing entries:
- POST /v1/messages — added auto_verify body-verify Phase 2 (PR #39 +
  #40, cueapi/cueapi #795 + #798 parity)
- POST /v1/cues/{id}/fire — note that #33 shipped (was "in-flight")
- GET /v1/agents/roster — note that #35 shipped (was "in-flight")
- GET /v1/agents/{ref}/presence — note that #35 shipped (was "in-flight")

Replaced `in_flight_ports_2026_05_07` section with
`ports_shipped_2026_05_08_to_2026_05_12` (now-resolved entries) plus a
near-empty `ports_in_flight_2026_05_12` placeholder for future ports.

Backlog row: cmp1vukmc.

Out of scope:
- `model_drift` section walk-through (Cue/Execution/Worker missing
  fields) — PR #31 just landed the Execution + Worker + Agent +
  Message additive models; a fuller `model_drift` refresh deserves a
  separate audit pass against the now-shipped models to figure out
  what's still drifting.
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