Skip to content

feat(extract): async cancel lifecycle + canonical types across MCP/SDK#290

Merged
us merged 6 commits into
mainfrom
feat/extract-cancel
Jul 15, 2026
Merged

feat(extract): async cancel lifecycle + canonical types across MCP/SDK#290
us merged 6 commits into
mainfrom
feat/extract-cancel

Conversation

@us

@us us commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Adds the async cancel lifecycle to /v1/extract and makes the extract types
canonical across the HTTP, MCP and SDK surfaces.

What changes

  • DELETE /v1/extract/{id} and Cancelling/Cancelled states on the extract
    job state machine. The worker claims one URL at a time and shares the job
    write-lock with DELETE, so a cancel and the final write race on exactly one
    lock and terminal state is never rewritten.
  • A finished job is never relabelled as cancelled: a DELETE that lands in the
    narrow window after the last URL is persisted but before finalize runs now
    settles the job by its per-URL outcomes instead of reporting cancelled over
    results that are all completed with real data.
  • crw_cancel_extract MCP tool; crw_extract/crw_check_extract_status keep the
    success envelope every other MCP tool returns (removing it silently broke
    clients that read it). The MCP/OpenAPI parity check ignores that one envelope
    field while still enforcing the data contract.
  • start_extract/get_extract/cancel_extract on the Python and TypeScript
    SDKs, with an extract() waiter that treats cancelled as terminal (raising
    with any partial results) and issues a best-effort cancel on timeout.
  • The Python SDK search unit test now mocks the transport the client actually
    uses (_http_request), fixing the scheduled Examples Test that had gone red.

Verification

crw-server test suite green (lib + integration), clippy clean, Python SDK
38/38, TypeScript SDK builds and tests, OpenAPI drift check passes (served
/openapi.json byte-equal to the committed spec), lockfile unchanged from main.

Refs the Agent A readiness work (async extract lifecycle + canonical types).

us added 6 commits July 15, 2026 16:25
A DELETE that landed in the narrow window after the worker persisted the last
URL but before finalize ran marked the whole job cancelled unconditionally,
even though every per-URL result was completed with real data — a response that
contradicted itself. Only report cancelled when at least one in-flight URL was
actually stopped; otherwise settle the job by its outcomes, as the naturally
finished job it is. Lockfile re-synced to the workspace version.
The canonical cancellation work dropped `success` from crw_extract,
crw_check_extract_status and crw_cancel_extract to mirror the native /v1 HTTP
shape, but every other MCP tool returns `success` and clients already read it,
so removing it silently broke those consumers. Re-add `success` on the MCP
surface only (injected from the shared HTTP type, false only when every URL
failed) and relax the MCP/OpenAPI parity check to ignore that one envelope
field while still enforcing the data-field contract.
@us us merged commit 0bff321 into main Jul 15, 2026
13 of 14 checks passed
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