Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Upload 6 files
Browse files- CHANGELOG.md +8 -0
- README.md +5 -0
- app.py +26 -2
CHANGELOG.md
CHANGED
|
@@ -210,3 +210,11 @@
|
|
| 210 |
- Persisted `launch.json`, `summary.json`, and a minimal `state.json` immediately after a Job launch, so running Jobs appear in the Run Explorer before the worker writes final artifacts.
|
| 211 |
- Progress polling now falls back to launch metadata when `state.json`/`events.jsonl` are not ready yet.
|
| 212 |
- Job links are preserved or reconstructed from launch metadata for active and historical runs.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
- Persisted `launch.json`, `summary.json`, and a minimal `state.json` immediately after a Job launch, so running Jobs appear in the Run Explorer before the worker writes final artifacts.
|
| 211 |
- Progress polling now falls back to launch metadata when `state.json`/`events.jsonl` are not ready yet.
|
| 212 |
- Job links are preserved or reconstructed from launch metadata for active and historical runs.
|
| 213 |
+
|
| 214 |
+
## v43 — Canonical run view model + mockup-oriented dashboard
|
| 215 |
+
|
| 216 |
+
- Added a canonical Run View Model that normalizes heterogeneous worker/bucket statuses into stable product states.
|
| 217 |
+
- Added `/api/runs/resumable` and `/api/runs/{run_id}/view` endpoints for bucket-led recovery and UI rendering.
|
| 218 |
+
- Enriched `/api/runs/{run_id}/progress` with the new `view` payload while preserving the previous progress contract.
|
| 219 |
+
- Reworked the custom UI toward the product mockup: sidebar, run summary header, product pipeline stepper, agent activity feed, diagnostics panel, and Space Test preview.
|
| 220 |
+
- Added explicit tests for running, manual hardware, success, stale, and resumable run selection states.
|
README.md
CHANGED
|
@@ -173,3 +173,8 @@ The Run Explorer reads launch metadata, summary metadata, state, gate files, and
|
|
| 173 |
|
| 174 |
The live progress timeline is designed to avoid horizontal scrolling and uses explicit step states: completed, active, pending, and failed. Historical run Job links are reconstructed from `job_id` when possible, so the Job button should remain available even when older summaries did not store a full `job_url`.
|
| 175 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
|
| 174 |
The live progress timeline is designed to avoid horizontal scrolling and uses explicit step states: completed, active, pending, and failed. Historical run Job links are reconstructed from `job_id` when possible, so the Job button should remain available even when older summaries did not store a full `job_url`.
|
| 175 |
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
## v45 Simple Custom Dashboard
|
| 179 |
+
|
| 180 |
+
This version keeps the working Agentic Space Factory workflows and presents them in a simpler custom interface: Build on the left, Runs & Progress on the right, plus a full Run Explorer and Space Test view.
|
app.py
CHANGED
|
@@ -20,6 +20,7 @@ from src.jobs import (
|
|
| 20 |
)
|
| 21 |
from src.runs import make_run_id, validate_run_id
|
| 22 |
from src.progress import progress_from_events
|
|
|
|
| 23 |
from src.security import redact
|
| 24 |
|
| 25 |
|
|
@@ -149,7 +150,7 @@ def register_custom_routes(fastapi_app: FastAPI) -> None:
|
|
| 149 |
return JSONResponse(
|
| 150 |
{
|
| 151 |
"name": "Agentic Space Factory",
|
| 152 |
-
"version": "
|
| 153 |
"bucket_default": settings.bucket_name,
|
| 154 |
"workflows": ["build_from_model_card", "validate_existing_space", "runs_explorer"],
|
| 155 |
"custom_ui_status": "root_custom_ui",
|
|
@@ -317,13 +318,35 @@ def register_custom_routes(fastapi_app: FastAPI) -> None:
|
|
| 317 |
}
|
| 318 |
)
|
| 319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
@fastapi_app.get("/api/runs/{run_id}")
|
| 321 |
async def api_run_detail(request: Request, run_id: str, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
| 322 |
ctx = _oauth_context_from_request(request)
|
| 323 |
run_id = validate_run_id(run_id)
|
| 324 |
bucket_source = user_bucket_source(username=ctx["username"], bucket_name=bucket_name)
|
| 325 |
bundle = read_run_bundle(run_id, bucket_source=bucket_source, token=ctx["token"])
|
| 326 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
|
| 328 |
@fastapi_app.get("/api/runs/{run_id}/progress")
|
| 329 |
async def api_run_progress(request: Request, run_id: str, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
|
@@ -348,6 +371,7 @@ def register_custom_routes(fastapi_app: FastAPI) -> None:
|
|
| 348 |
"hardware_strategy": bundle.get("hardware_strategy") or {},
|
| 349 |
"technical_blockers": bundle.get("technical_blockers") or {},
|
| 350 |
"events": events[-20:],
|
|
|
|
| 351 |
"links": _api_links(
|
| 352 |
run_id=run_id,
|
| 353 |
bucket_source=bucket_source,
|
|
|
|
| 20 |
)
|
| 21 |
from src.runs import make_run_id, validate_run_id
|
| 22 |
from src.progress import progress_from_events
|
| 23 |
+
from src.view_models import build_run_view_model, find_latest_resumable_run
|
| 24 |
from src.security import redact
|
| 25 |
|
| 26 |
|
|
|
|
| 150 |
return JSONResponse(
|
| 151 |
{
|
| 152 |
"name": "Agentic Space Factory",
|
| 153 |
+
"version": "v45-simple-custom-dashboard",
|
| 154 |
"bucket_default": settings.bucket_name,
|
| 155 |
"workflows": ["build_from_model_card", "validate_existing_space", "runs_explorer"],
|
| 156 |
"custom_ui_status": "root_custom_ui",
|
|
|
|
| 318 |
}
|
| 319 |
)
|
| 320 |
|
| 321 |
+
@fastapi_app.get("/api/runs/resumable")
|
| 322 |
+
async def api_resumable_run(request: Request, bucket_name: str = settings.bucket_name, limit: int = 100): # type: ignore[no-untyped-def]
|
| 323 |
+
ctx = _oauth_context_from_request(request)
|
| 324 |
+
bucket_source = user_bucket_source(username=ctx["username"], bucket_name=bucket_name)
|
| 325 |
+
runs = list_recent_runs(bucket_source=bucket_source, token=ctx["token"], limit=limit)
|
| 326 |
+
resumable = find_latest_resumable_run(runs)
|
| 327 |
+
if not resumable:
|
| 328 |
+
return JSONResponse({"run": None, "view": None, "bucket_source": bucket_source, "reason": "no_resumable_run"})
|
| 329 |
+
run_id = validate_run_id(str(resumable.get("run_id")))
|
| 330 |
+
bundle = read_run_bundle(run_id, bucket_source=bucket_source, token=ctx["token"])
|
| 331 |
+
view = build_run_view_model(run_id, bundle, bucket_source=bucket_source)
|
| 332 |
+
return JSONResponse({"run": resumable, "view": view, "bucket_source": bucket_source, "reason": "latest_resumable_run"})
|
| 333 |
+
|
| 334 |
@fastapi_app.get("/api/runs/{run_id}")
|
| 335 |
async def api_run_detail(request: Request, run_id: str, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
| 336 |
ctx = _oauth_context_from_request(request)
|
| 337 |
run_id = validate_run_id(run_id)
|
| 338 |
bucket_source = user_bucket_source(username=ctx["username"], bucket_name=bucket_name)
|
| 339 |
bundle = read_run_bundle(run_id, bucket_source=bucket_source, token=ctx["token"])
|
| 340 |
+
view = build_run_view_model(run_id, bundle, bucket_source=bucket_source)
|
| 341 |
+
return JSONResponse({"run_id": run_id, "bucket_source": bucket_source, "view": view, **bundle})
|
| 342 |
+
|
| 343 |
+
@fastapi_app.get("/api/runs/{run_id}/view")
|
| 344 |
+
async def api_run_view(request: Request, run_id: str, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
| 345 |
+
ctx = _oauth_context_from_request(request)
|
| 346 |
+
run_id = validate_run_id(run_id)
|
| 347 |
+
bucket_source = user_bucket_source(username=ctx["username"], bucket_name=bucket_name)
|
| 348 |
+
bundle = read_run_bundle(run_id, bucket_source=bucket_source, token=ctx["token"])
|
| 349 |
+
return JSONResponse(build_run_view_model(run_id, bundle, bucket_source=bucket_source))
|
| 350 |
|
| 351 |
@fastapi_app.get("/api/runs/{run_id}/progress")
|
| 352 |
async def api_run_progress(request: Request, run_id: str, bucket_name: str = settings.bucket_name): # type: ignore[no-untyped-def]
|
|
|
|
| 371 |
"hardware_strategy": bundle.get("hardware_strategy") or {},
|
| 372 |
"technical_blockers": bundle.get("technical_blockers") or {},
|
| 373 |
"events": events[-20:],
|
| 374 |
+
"view": build_run_view_model(run_id, bundle, bucket_source=bucket_source),
|
| 375 |
"links": _api_links(
|
| 376 |
run_id=run_id,
|
| 377 |
bucket_source=bucket_source,
|