A run says whether the dashboard, the CLI or a script asked for it
`POST /runs/flows/{name}` hardcoded `cause: "api"`, so every row in the
history claimed the same origin. The body now carries an optional `cause`,
closed to the values the column knows — the dashboard sends nothing and stays
"api", `fluksio run` says "cli", and the SDK client says "sdk".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Gf7WaExcJ9bs3kfJXB3nK
This commit is contained in:
@@ -6,7 +6,7 @@ or to listen on the flow socket, which carries its start and finish.
|
||||
"""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
from typing import Any, Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
@@ -35,6 +35,12 @@ def elapsed_ms(since: datetime) -> float:
|
||||
return round((datetime.now(UTC) - start).total_seconds() * 1000, 2)
|
||||
|
||||
|
||||
#: Where a caller may say a run came from. "sweep" is not here because the
|
||||
#: sweep route writes it itself, and neither is a value a client made up: the
|
||||
#: column is only worth a table row if it means the same thing every time.
|
||||
RunCause = Literal["api", "cli", "sdk"]
|
||||
|
||||
|
||||
class RunCreate(BaseModel):
|
||||
params: dict[str, Any] = Field(default_factory=dict)
|
||||
seed: int | None = None
|
||||
@@ -42,6 +48,8 @@ class RunCreate(BaseModel):
|
||||
draft: bool = False
|
||||
#: Execute every node, whatever an earlier run already worked out.
|
||||
no_cache: bool = False
|
||||
#: Who is asking. The dashboard leaves it, and is the "api" default.
|
||||
cause: RunCause = "api"
|
||||
|
||||
|
||||
class SweepEntry(BaseModel):
|
||||
@@ -172,7 +180,7 @@ async def create_run(
|
||||
name,
|
||||
params=body.params,
|
||||
seed=body.seed,
|
||||
cause="api",
|
||||
cause=body.cause,
|
||||
actor=user.email,
|
||||
draft=body.draft,
|
||||
no_cache=body.no_cache,
|
||||
|
||||
@@ -340,7 +340,7 @@ class Run(SQLModel, table=True):
|
||||
group_id: str | None = Field(default=None, index=True, max_length=64)
|
||||
#: The run this one was made from, on a retry.
|
||||
parent_id: str | None = Field(default=None, max_length=64)
|
||||
#: api, hook, sweep or cli.
|
||||
#: Where it was asked for: api, cli, sdk, hook or sweep.
|
||||
cause: str = Field(default="api", max_length=32)
|
||||
#: Re-execute every node, whatever the stage cache holds for it.
|
||||
no_cache: bool = False
|
||||
|
||||
@@ -459,7 +459,11 @@ def cmd_run(args: argparse.Namespace, rest: list[str]) -> int:
|
||||
):
|
||||
params = _ask_params(definition)
|
||||
handle = client.submit(
|
||||
args.flow, params, seed=args.seed, no_cache=args.no_cache
|
||||
args.flow,
|
||||
params,
|
||||
seed=args.seed,
|
||||
no_cache=args.no_cache,
|
||||
cause="cli",
|
||||
)
|
||||
_say(f"{handle.id} queued {json.dumps(params)}")
|
||||
if not wait:
|
||||
|
||||
@@ -226,11 +226,19 @@ class Client:
|
||||
params: dict[str, Any] | None = None,
|
||||
seed: int | None = None,
|
||||
no_cache: bool = False,
|
||||
cause: str = "sdk",
|
||||
) -> RunHandle:
|
||||
"""Queue a run. ``cause`` is what the history records it as coming
|
||||
from — a script is the default, `fluksio run` says so itself."""
|
||||
row = self._call(
|
||||
"POST",
|
||||
f"/runs/flows/{flow}",
|
||||
json={"params": params or {}, "seed": seed, "no_cache": no_cache},
|
||||
json={
|
||||
"params": params or {},
|
||||
"seed": seed,
|
||||
"no_cache": no_cache,
|
||||
"cause": cause,
|
||||
},
|
||||
)
|
||||
return RunHandle(self, row["id"], row)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user