Skip to content

Dataset-less model runs: create_model_run + add_predictions - #476

Open
luke-e-schaefer wants to merge 2 commits into
masterfrom
lukeschaefer/create-model-run-add-predictions
Open

Dataset-less model runs: create_model_run + add_predictions#476
luke-e-schaefer wants to merge 2 commits into
masterfrom
lukeschaefer/create-model-run-add-predictions

Conversation

@luke-e-schaefer

@luke-e-schaefer luke-e-schaefer commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a create-run-then-add-predictions API that does not require threading a dataset. You create a run with no founding dataset, then upload predictions that each name their own target — by dataset_item_id (preferred) or dataset_id + reference_id. The server groups by dataset and widens the run's dataset set.

This is the SDK half. Backend counterpart (required): scaleapi lukeschaefer/dataset-less-model-run-predictions. Live calls 404 until that deploys; the tests here are mock-based and pass regardless.

API

run = model.create_run_without_dataset(name="my-run")   # no dataset
run.add_predictions([
    BoxPrediction(..., dataset_item_id="di_abc"),        # preferred
    BoxPrediction(..., dataset_id="ds_1", reference_id="img_2"),  # fallback
])

Changes

  • Model.create_run_without_dataset(name, metadata=None, reference_id=None)POST model/{id}/modelRun/create, returns a ModelRun with no datasets (unreadable until first upload, by design).
  • ModelRun.add_predictions(...)POST modelRun/{id}/uploadPredictions.
  • Predictions now emit item_id (sourced from the existing read-only dataset_item_id field) and/or dataset_id in to_payload() when set.
  • PredictionUploader: a bare model_run_id (no dataset_id, no explicit route) now routes to modelRun/{id}/uploadPredictions. All other routing branches are unchanged; the previously-raising "model_run_id without dataset_id" case is now valid (one existing test in test_multi_dataset_model_runs.py updated accordingly).
  • Version 0.20.2 → 0.21.0; CHANGELOG entry.

Not covered / follow-ups

  • Async upload raises NotImplementedError — the presigned-URL path is dataset-scoped and has no founding dataset here. Matches the backend, which 400s on ?async=1. Needs a model-run-scoped signed-URL route to support async.
  • Segmentations go through the per-dataset route (backend 400s them here).

Tests

tests/test_dataset_less_model_runs.py (new) + updated test_multi_dataset_model_runs.py: 24 passed (mock/spy, no live API).

🤖 Generated with Claude Code

Greptile Summary

The PR adds dataset-less model-run creation and model-run-scoped prediction uploads, allowing each prediction to identify its target dataset item.

  • Adds Model.create_run_without_dataset and ModelRun.add_predictions.
  • Extends prediction payloads with optional item_id and dataset_id target fields.
  • Routes uploads with only a model-run ID through the new model-run-scoped endpoint.
  • Explicitly rejects unsupported asynchronous dataset-less uploads and guards legacy asynchronous prediction against a missing dataset.
  • Adds mock-based coverage and updates the package version and changelog.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
nucleus/model.py Adds dataset-less model-run creation and constructs a client-bound ModelRun from the returned run ID.
nucleus/model_run.py Adds synchronous dataset-less prediction upload and prevents asynchronous legacy prediction from using an absent dataset ID.
nucleus/annotation_uploader.py Adds model-run-scoped route selection when no dataset ID is supplied while preserving existing dataset-scoped branches.
nucleus/prediction.py Adds optional dataset targeting fields to prediction constructors, serializers, and response hydration.
tests/test_dataset_less_model_runs.py Covers model-run creation, route selection, target serialization, upload options, and unsupported asynchronous behavior.

Sequence Diagram

sequenceDiagram
    participant U as SDK caller
    participant M as Model
    participant R as ModelRun
    participant P as PredictionUploader
    participant A as Nucleus API
    U->>M: create_run_without_dataset(name)
    M->>A: "POST model/{model_id}/modelRun/create"
    A-->>M: model_run_id
    M-->>U: "ModelRun(dataset_id=None)"
    U->>R: add_predictions(predictions)
    R->>P: Upload using model_run_id
    P->>A: "POST modelRun/{run_id}/uploadPredictions"
    Note over P,A: Each payload identifies its target via item_id or dataset_id + reference_id
    A-->>U: Aggregate upload result
Loading

Reviews (2): Last reviewed commit: "fix(model-runs): guard async predict() a..." | Re-trigger Greptile

Context used (3)

Add a create-run-then-add-predictions flow that does not require threading
a dataset. A run can be created with no founding dataset; predictions then
carry their own target (dataset_item_id, or dataset_id + reference_id) and
the server groups by dataset and widens the run's dataset set.

- Model.create_run_without_dataset(name, metadata=None, reference_id=None)
  -> POST model/{id}/modelRun/create, returns a ModelRun with no datasets.
- ModelRun.add_predictions(...) -> POST modelRun/{id}/uploadPredictions.
- Predictions emit item_id (from dataset_item_id) and/or dataset_id when set.
- PredictionUploader: bare model_run_id routes to the dataset-less endpoint.

Requires the matching scaleapi backend routes; async upload is not yet
supported on this path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@luke-e-schaefer luke-e-schaefer self-assigned this Aug 20, 2026
@luke-e-schaefer
luke-e-schaefer marked this pull request as ready for review August 20, 2026 00:04
Making dataset_id Optional[str] for dataset-less runs broke mypy on the
deprecated predict() async path, which passes self.dataset_id straight to
serialize_and_write_to_presigned_url (expects str). Async predict is inherently
per-dataset, so raise a clear ValueError when dataset_id is None (dataset-less
runs must use add_predictions) — this both fixes the type error and prevents a
confusing runtime failure.

Fixes the build_test MyPy failure.

Co-Authored-By: Claude Opus 4.8 <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.

1 participant