Skip to content

Commit d57279c

Browse files
committed
2 parents 63268d0 + b01b6a9 commit d57279c

7 files changed

Lines changed: 39 additions & 6 deletions

File tree

backend/api/routers/tasks.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ async def init_task_upload(
250250
org_id=auth.org_id,
251251
content_hash=payload.content_hash,
252252
message=payload.message,
253+
force_new_version=payload.force_new_version,
253254
)
254255

255256

oddish/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "oddish"
77
version = "0.1.12"
88
description = "Run Harbor tasks in the cloud with scheduling, monitoring, and persistent state"
99
readme = "README.md"
10-
requires-python = ">=3.14"
10+
requires-python = ">=3.13,<3.14"
1111
license = { file = "LICENSE" }
1212
authors = [
1313
{ name = "Rishi Desai", email = "rishi@abundant.ai" },

oddish/src/oddish/cli/api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ def upload_task(
379379
message: str | None = None,
380380
user: str | None = None,
381381
priority: str | None = None,
382+
force_new_version: bool = False,
382383
) -> dict:
383384
"""Upload a task directory to the API.
384385
@@ -404,6 +405,8 @@ def upload_task(
404405
}
405406
if message:
406407
init_body["message"] = message
408+
if force_new_version:
409+
init_body["force_new_version"] = True
407410

408411
try:
409412
with httpx.Client(timeout=600.0, headers=get_auth_headers()) as client:
@@ -481,6 +484,7 @@ def upload_tasks_with_progress(
481484
quiet: bool = False,
482485
json_output: bool = False,
483486
progress_label: str = "Uploading",
487+
force_new_version: bool = False,
484488
) -> list[dict]:
485489
"""Upload a batch of task directories with a shared progress bar.
486490
@@ -501,6 +505,7 @@ def _upload_one(task_path: Path) -> dict:
501505
message=message,
502506
user=user,
503507
priority=priority,
508+
force_new_version=force_new_version,
504509
)
505510

506511
show_progress = not quiet and not json_output

oddish/src/oddish/cli/run.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,17 @@ def run(
258258
help="Force rebuild the environment Docker image",
259259
),
260260
] = None,
261+
force_new_version: Annotated[
262+
bool,
263+
typer.Option(
264+
"--force-new-version",
265+
help=(
266+
"Allocate a new task version even when the local content is "
267+
"unchanged from the latest existing version. Useful when "
268+
"appending trials with a different run_analysis setting."
269+
),
270+
),
271+
] = False,
261272
agent_env: Annotated[
262273
Optional[list[str]],
263274
typer.Option(
@@ -531,6 +542,7 @@ def submit_task(
531542
quiet=quiet,
532543
json_output=json_output,
533544
progress_label="Uploading",
545+
force_new_version=force_new_version,
534546
)
535547
for task_path, result in zip(task_paths, upload_results):
536548
is_existing = bool(result.get("existing_task", False))

oddish/src/oddish/core/endpoints.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,11 +1644,16 @@ async def create_task_sweep_core(
16441644
task = await get_task_for_org_core(
16451645
session, task_id=submission.task_id, org_id=org_id
16461646
)
1647+
# Allow flipping task.run_analysis from False to True on append.
1648+
# ``run_analysis`` runs at trial-completion time, so updating the
1649+
# task-level flag does not retroactively analyze pre-existing
1650+
# trials, but new trials submitted with ``--run-analysis`` will be
1651+
# analyzed as the caller requested. This matches the documented
1652+
# purpose of ``--force-new-version`` (see ``TaskUploadInitRequest``)
1653+
# and lets a task that was first registered without analysis later
1654+
# opt in without manual intervention.
16471655
if submission.run_analysis and not task.run_analysis:
1648-
raise HTTPException(
1649-
status_code=400,
1650-
detail="Cannot enable run_analysis when appending to a task that was created without it",
1651-
)
1656+
task.run_analysis = True
16521657

16531658
new_experiment_id: str | None = None
16541659
experiment: ExperimentModel | None = None

oddish/src/oddish/core/tasks.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ async def initialize_task_upload(
7373
org_id: str | None = None,
7474
content_hash: str,
7575
message: str | None = None,
76+
force_new_version: bool = False,
7677
) -> TaskUploadInitResponse:
7778
"""Prepare a task upload and return direct-upload details when supported."""
7879
normalized_name = _normalize_task_name(task_name)
@@ -86,7 +87,8 @@ async def initialize_task_upload(
8687
)
8788

8889
if (
89-
latest is not None
90+
not force_new_version
91+
and latest is not None
9092
and latest.content_hash
9193
and latest.content_hash == content_hash
9294
):

oddish/src/oddish/schemas.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,14 @@ class TaskUploadInitRequest(BaseModel):
314314
message: str | None = Field(
315315
None, description="Optional description of what changed in this version"
316316
)
317+
force_new_version: bool = Field(
318+
False,
319+
description=(
320+
"Allocate a new task version even when the content hash matches the "
321+
"latest existing version. Used when callers need a fresh version "
322+
"stamp (e.g. to flip run_analysis on)."
323+
),
324+
)
317325

318326

319327
class TaskUploadCompleteRequest(BaseModel):

0 commit comments

Comments
 (0)