Upload 6 files
Browse files- src/jobs.py +53 -0
- src/worker_payload.py +800 -0
src/jobs.py
CHANGED
|
@@ -13,6 +13,7 @@ from .worker_payload import (
|
|
| 13 |
encoded_pi_model_card_worker_script,
|
| 14 |
encoded_runtime_recommender_worker_script,
|
| 15 |
encoded_longcat_article_worker_script,
|
|
|
|
| 16 |
encoded_pi_space_worker_script,
|
| 17 |
encoded_worker_script,
|
| 18 |
python_decode_and_run_command,
|
|
@@ -305,6 +306,58 @@ def launch_longcat_article_job(
|
|
| 305 |
},
|
| 306 |
)
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
def inspect_job_safe(job_id: str, token: str | None = None) -> dict[str, Any]:
|
| 309 |
if not job_id:
|
| 310 |
return {"error": "Missing job_id"}
|
|
|
|
| 13 |
encoded_pi_model_card_worker_script,
|
| 14 |
encoded_runtime_recommender_worker_script,
|
| 15 |
encoded_longcat_article_worker_script,
|
| 16 |
+
encoded_universal_model_card_worker_script,
|
| 17 |
encoded_pi_space_worker_script,
|
| 18 |
encoded_worker_script,
|
| 19 |
python_decode_and_run_command,
|
|
|
|
| 306 |
},
|
| 307 |
)
|
| 308 |
|
| 309 |
+
|
| 310 |
+
def launch_universal_model_card_job(
|
| 311 |
+
*,
|
| 312 |
+
token: str,
|
| 313 |
+
username: str,
|
| 314 |
+
target_slug: str | None = None,
|
| 315 |
+
model_id: str | None = None,
|
| 316 |
+
pi_model: str | None = None,
|
| 317 |
+
preferred_space_hardware: str | None = None,
|
| 318 |
+
fallback_space_hardware: str | None = None,
|
| 319 |
+
allow_fixed_gpu_fallback: bool = True,
|
| 320 |
+
implementation_mode: str | None = None,
|
| 321 |
+
run_id: str | None = None,
|
| 322 |
+
) -> dict[str, Any]:
|
| 323 |
+
"""Launch Phase 10: universal model-card → private Space builder with Pi and gated validation."""
|
| 324 |
+
if not token:
|
| 325 |
+
raise ValueError("Missing OAuth token. Please sign in with Hugging Face first.")
|
| 326 |
+
safe_run_id = validate_run_id(run_id) if run_id else make_run_id("universal")
|
| 327 |
+
target_space_id = normalize_target_space(username=username, target_slug=target_slug, run_id=safe_run_id)
|
| 328 |
+
clean_model_id = (model_id or "").strip().replace("https://huggingface.co/", "").strip("/")
|
| 329 |
+
if "/" not in clean_model_id:
|
| 330 |
+
raise ValueError("Model ID must look like owner/model-name or a Hugging Face model URL.")
|
| 331 |
+
|
| 332 |
+
env = _base_env(
|
| 333 |
+
run_id=safe_run_id,
|
| 334 |
+
username=username,
|
| 335 |
+
worker_script_b64=encoded_universal_model_card_worker_script(),
|
| 336 |
+
)
|
| 337 |
+
env["TARGET_SPACE_ID"] = target_space_id
|
| 338 |
+
env["MODEL_ID"] = clean_model_id
|
| 339 |
+
env["PI_MODEL"] = (pi_model or "Qwen/Qwen3-Coder-Next").strip()
|
| 340 |
+
env["PREFERRED_SPACE_HARDWARE"] = (preferred_space_hardware or "cpu-basic").strip()
|
| 341 |
+
env["FALLBACK_SPACE_HARDWARE"] = (fallback_space_hardware or "l40sx1").strip()
|
| 342 |
+
env["ALLOW_FIXED_GPU_FALLBACK"] = "true" if allow_fixed_gpu_fallback else "false"
|
| 343 |
+
env["IMPLEMENTATION_MODE"] = (implementation_mode or "full-inference-gated").strip()
|
| 344 |
+
job = _launch_job(token=token, env=env, timeout="60m")
|
| 345 |
+
return _job_result(
|
| 346 |
+
job,
|
| 347 |
+
run_id=safe_run_id,
|
| 348 |
+
kind="universal_model_card_builder",
|
| 349 |
+
extra={
|
| 350 |
+
"target_space": target_space_id,
|
| 351 |
+
"target_space_url": f"https://huggingface.co/spaces/{target_space_id}",
|
| 352 |
+
"model_id": clean_model_id,
|
| 353 |
+
"pi_model": env["PI_MODEL"],
|
| 354 |
+
"preferred_space_hardware": env["PREFERRED_SPACE_HARDWARE"],
|
| 355 |
+
"fallback_space_hardware": env["FALLBACK_SPACE_HARDWARE"],
|
| 356 |
+
"allow_fixed_gpu_fallback": allow_fixed_gpu_fallback,
|
| 357 |
+
"implementation_mode": env["IMPLEMENTATION_MODE"],
|
| 358 |
+
},
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
def inspect_job_safe(job_id: str, token: str | None = None) -> dict[str, Any]:
|
| 362 |
if not job_id:
|
| 363 |
return {"error": "Missing job_id"}
|
src/worker_payload.py
CHANGED
|
@@ -1346,6 +1346,801 @@ if __name__ == "__main__":
|
|
| 1346 |
'''
|
| 1347 |
|
| 1348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1349 |
def encoded_worker_script() -> str:
|
| 1350 |
"""Return the base64-encoded Phase 1 hello worker script."""
|
| 1351 |
return _encode(HELLO_WORKER_SCRIPT)
|
|
@@ -1381,6 +2176,11 @@ def encoded_longcat_article_worker_script() -> str:
|
|
| 1381 |
"""Return the base64-encoded Phase 9 LongCat article reproduction worker script."""
|
| 1382 |
return _encode(LONGCAT_ARTICLE_WORKER_SCRIPT)
|
| 1383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1384 |
def python_decode_and_run_command() -> list[str]:
|
| 1385 |
"""Command list for `run_job`.
|
| 1386 |
|
|
|
|
| 1346 |
'''
|
| 1347 |
|
| 1348 |
|
| 1349 |
+
UNIVERSAL_MODEL_CARD_WORKER_SCRIPT = r'''
|
| 1350 |
+
|
| 1351 |
+
import json
|
| 1352 |
+
import os
|
| 1353 |
+
import re
|
| 1354 |
+
import shutil
|
| 1355 |
+
import subprocess
|
| 1356 |
+
import sys
|
| 1357 |
+
import time
|
| 1358 |
+
from datetime import datetime, timezone
|
| 1359 |
+
from pathlib import Path
|
| 1360 |
+
from textwrap import dedent
|
| 1361 |
+
|
| 1362 |
+
TARGET_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{1,95}/[A-Za-z0-9][A-Za-z0-9._-]{1,95}$")
|
| 1363 |
+
GIST_URL = "https://gist.github.com/gary149/2aba2962375fa9ca56bb9ef53f00b73d"
|
| 1364 |
+
DEFAULT_MODEL_ID = "sshleifer/tiny-gpt2"
|
| 1365 |
+
|
| 1366 |
+
|
| 1367 |
+
def now():
|
| 1368 |
+
return datetime.now(timezone.utc).isoformat()
|
| 1369 |
+
|
| 1370 |
+
|
| 1371 |
+
def write_json(path: Path, payload: dict):
|
| 1372 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 1373 |
+
path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
| 1374 |
+
|
| 1375 |
+
|
| 1376 |
+
def append_event(path: Path, step: str, status: str, message: str, data: dict | None = None):
|
| 1377 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 1378 |
+
event = {"ts": now(), "step": step, "status": status, "message": message, "data": data or {}}
|
| 1379 |
+
line = json.dumps(event, ensure_ascii=False)
|
| 1380 |
+
with path.open("a", encoding="utf-8") as f:
|
| 1381 |
+
f.write(line + "\n")
|
| 1382 |
+
print(line, flush=True)
|
| 1383 |
+
|
| 1384 |
+
|
| 1385 |
+
def redact_text(text: str | None) -> str:
|
| 1386 |
+
if not text:
|
| 1387 |
+
return ""
|
| 1388 |
+
value = text
|
| 1389 |
+
for secret_name in ["HF_TOKEN", "HUGGING_FACE_HUB_TOKEN"]:
|
| 1390 |
+
secret = os.environ.get(secret_name)
|
| 1391 |
+
if secret:
|
| 1392 |
+
value = value.replace(secret, "[REDACTED]")
|
| 1393 |
+
value = re.sub(r"Bearer\s+[A-Za-z0-9_\-.=]+", "Bearer [REDACTED]", value)
|
| 1394 |
+
value = re.sub(r"hf_[A-Za-z0-9_\-]{10,}", "hf_[REDACTED]", value)
|
| 1395 |
+
return value
|
| 1396 |
+
|
| 1397 |
+
|
| 1398 |
+
def safe_details(details: dict | None) -> dict:
|
| 1399 |
+
if not details:
|
| 1400 |
+
return {}
|
| 1401 |
+
try:
|
| 1402 |
+
return json.loads(redact_text(json.dumps(details, ensure_ascii=False)))
|
| 1403 |
+
except Exception:
|
| 1404 |
+
return {"redacted_details": redact_text(str(details))[-4000:]}
|
| 1405 |
+
|
| 1406 |
+
|
| 1407 |
+
def fail(run_dir: Path, events_path: Path, message: str, details: dict | None = None, status: str = "failed"):
|
| 1408 |
+
safe = safe_details(details)
|
| 1409 |
+
append_event(events_path, "failure", "failed", message, safe)
|
| 1410 |
+
write_json(run_dir / "state.json", {
|
| 1411 |
+
"run_id": os.environ.get("RUN_ID"),
|
| 1412 |
+
"kind": "universal_model_card_builder",
|
| 1413 |
+
"status": status,
|
| 1414 |
+
"message": message,
|
| 1415 |
+
"updated_at": now(),
|
| 1416 |
+
"details": safe,
|
| 1417 |
+
})
|
| 1418 |
+
report = f"""# Agentic Space Factory — model Article Reproduction Report
|
| 1419 |
+
|
| 1420 |
+
Status: **{status}**
|
| 1421 |
+
|
| 1422 |
+
{message}
|
| 1423 |
+
|
| 1424 |
+
```json
|
| 1425 |
+
{json.dumps(safe, indent=2, ensure_ascii=False)}
|
| 1426 |
+
```
|
| 1427 |
+
"""
|
| 1428 |
+
(run_dir / "report.md").write_text(report, encoding="utf-8")
|
| 1429 |
+
raise SystemExit(1)
|
| 1430 |
+
|
| 1431 |
+
|
| 1432 |
+
def run_cmd(cmd: list[str], *, cwd: Path | None = None, env: dict | None = None, timeout: int = 600):
|
| 1433 |
+
result = subprocess.run(cmd, cwd=str(cwd) if cwd else None, env=env, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=timeout)
|
| 1434 |
+
return result.returncode, redact_text(result.stdout)
|
| 1435 |
+
|
| 1436 |
+
|
| 1437 |
+
def install_python_deps(events_path: Path):
|
| 1438 |
+
append_event(events_path, "dependencies", "started", "Installing Python worker dependencies")
|
| 1439 |
+
code, out = run_cmd([sys.executable, "-m", "pip", "install", "-q", "--upgrade", "huggingface_hub>=1.0.0", "gradio_client>=2.0.0", "requests>=2.31.0"], timeout=600)
|
| 1440 |
+
if code != 0:
|
| 1441 |
+
append_event(events_path, "dependencies", "failed", "Python dependency installation failed", {"output_tail": out[-4000:]})
|
| 1442 |
+
raise RuntimeError(out)
|
| 1443 |
+
append_event(events_path, "dependencies", "success", "Python worker dependencies installed")
|
| 1444 |
+
|
| 1445 |
+
|
| 1446 |
+
def ensure_node(events_path: Path):
|
| 1447 |
+
node = shutil.which("node")
|
| 1448 |
+
npm = shutil.which("npm")
|
| 1449 |
+
if node and npm:
|
| 1450 |
+
_, node_v = run_cmd([node, "--version"], timeout=30)
|
| 1451 |
+
_, npm_v = run_cmd([npm, "--version"], timeout=30)
|
| 1452 |
+
append_event(events_path, "node", "success", "Node/npm already available", {"node": node_v.strip(), "npm": npm_v.strip()})
|
| 1453 |
+
return
|
| 1454 |
+
append_event(events_path, "node", "started", "Installing nodejs/npm through apt-get")
|
| 1455 |
+
code, out = run_cmd(["bash", "-lc", "apt-get update -qq && apt-get install -y -qq nodejs npm"], timeout=600)
|
| 1456 |
+
if code != 0:
|
| 1457 |
+
append_event(events_path, "node", "failed", "Could not install nodejs/npm", {"output_tail": out[-4000:]})
|
| 1458 |
+
raise RuntimeError(out)
|
| 1459 |
+
append_event(events_path, "node", "success", "Installed nodejs/npm")
|
| 1460 |
+
|
| 1461 |
+
|
| 1462 |
+
def install_pi(events_path: Path):
|
| 1463 |
+
ensure_node(events_path)
|
| 1464 |
+
append_event(events_path, "pi_install", "started", "Installing Pi coding agent from npm")
|
| 1465 |
+
code, out = run_cmd(["npm", "install", "-g", "@mariozechner/pi-coding-agent"], timeout=900)
|
| 1466 |
+
if code != 0:
|
| 1467 |
+
append_event(events_path, "pi_install", "failed", "Pi npm installation failed", {"output_tail": out[-4000:]})
|
| 1468 |
+
raise RuntimeError(out)
|
| 1469 |
+
code, version = run_cmd(["pi", "--version"], timeout=60)
|
| 1470 |
+
append_event(events_path, "pi_install", "success", "Pi installed", {"version_output": version.strip()[-300:]})
|
| 1471 |
+
|
| 1472 |
+
|
| 1473 |
+
def configure_pi(events_path: Path, model: str):
|
| 1474 |
+
pi_dir = Path.home() / ".pi" / "agent"
|
| 1475 |
+
pi_dir.mkdir(parents=True, exist_ok=True)
|
| 1476 |
+
(pi_dir / "auth.json").write_text(json.dumps({"huggingface": {"type": "api_key", "key": os.environ.get("HF_TOKEN", "")}}, indent=2), encoding="utf-8")
|
| 1477 |
+
(pi_dir / "settings.json").write_text(json.dumps({"model": model, "provider": "huggingface", "autoRun": True, "autoApply": True}, indent=2), encoding="utf-8")
|
| 1478 |
+
append_event(events_path, "pi_config", "success", "Configured Pi", {"model": model})
|
| 1479 |
+
|
| 1480 |
+
|
| 1481 |
+
def collect_pi_traces(run_dir: Path, events_path: Path):
|
| 1482 |
+
traces_dir = Path.home() / ".pi" / "agent" / "sessions"
|
| 1483 |
+
raw_dir = run_dir / "traces" / "raw"
|
| 1484 |
+
redacted_dir = run_dir / "traces" / "redacted"
|
| 1485 |
+
raw_dir.mkdir(parents=True, exist_ok=True)
|
| 1486 |
+
redacted_dir.mkdir(parents=True, exist_ok=True)
|
| 1487 |
+
count = 0
|
| 1488 |
+
if traces_dir.exists():
|
| 1489 |
+
for path in traces_dir.rglob("*.jsonl"):
|
| 1490 |
+
rel = path.relative_to(traces_dir)
|
| 1491 |
+
target_raw = raw_dir / rel
|
| 1492 |
+
target_raw.parent.mkdir(parents=True, exist_ok=True)
|
| 1493 |
+
text = path.read_text(encoding="utf-8", errors="ignore")
|
| 1494 |
+
target_raw.write_text(text, encoding="utf-8")
|
| 1495 |
+
target_redacted = redacted_dir / rel
|
| 1496 |
+
target_redacted.parent.mkdir(parents=True, exist_ok=True)
|
| 1497 |
+
target_redacted.write_text(redact_text(text), encoding="utf-8")
|
| 1498 |
+
count += 1
|
| 1499 |
+
append_event(events_path, "traces", "success", "Collected Pi traces", {"count": count})
|
| 1500 |
+
return count
|
| 1501 |
+
|
| 1502 |
+
|
| 1503 |
+
def sanitize_model_id(model_id: str) -> str:
|
| 1504 |
+
model_id = (model_id or DEFAULT_MODEL_ID).strip().replace("https://huggingface.co/", "")
|
| 1505 |
+
model_id = model_id.split("?", 1)[0].strip("/")
|
| 1506 |
+
if not re.match(r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$", model_id):
|
| 1507 |
+
raise ValueError("MODEL_ID must look like owner/model-name")
|
| 1508 |
+
return model_id
|
| 1509 |
+
|
| 1510 |
+
|
| 1511 |
+
def make_gradio_client(target_space_id: str, token: str):
|
| 1512 |
+
import inspect
|
| 1513 |
+
from gradio_client import Client
|
| 1514 |
+
params = inspect.signature(Client).parameters
|
| 1515 |
+
if "token" in params:
|
| 1516 |
+
return Client(target_space_id, token=token)
|
| 1517 |
+
if "hf_token" in params:
|
| 1518 |
+
return Client(target_space_id, hf_token=token)
|
| 1519 |
+
if "api_key" in params:
|
| 1520 |
+
return Client(target_space_id, api_key=token)
|
| 1521 |
+
if "headers" in params:
|
| 1522 |
+
return Client(target_space_id, headers={"Authorization": f"Bearer {token}"})
|
| 1523 |
+
return Client(target_space_id)
|
| 1524 |
+
|
| 1525 |
+
|
| 1526 |
+
def api_names_from_schema(schema) -> list[str]:
|
| 1527 |
+
names: list[str] = []
|
| 1528 |
+
if isinstance(schema, dict):
|
| 1529 |
+
endpoints = schema.get("named_endpoints") or schema.get("endpoints") or {}
|
| 1530 |
+
if isinstance(endpoints, dict):
|
| 1531 |
+
for key, value in endpoints.items():
|
| 1532 |
+
if isinstance(key, str) and key.startswith("/"):
|
| 1533 |
+
names.append(key)
|
| 1534 |
+
if isinstance(value, dict):
|
| 1535 |
+
api_name = value.get("api_name")
|
| 1536 |
+
if isinstance(api_name, str) and api_name.startswith("/"):
|
| 1537 |
+
names.append(api_name)
|
| 1538 |
+
if isinstance(schema.get("dependencies"), list):
|
| 1539 |
+
for dep in schema["dependencies"]:
|
| 1540 |
+
if isinstance(dep, dict):
|
| 1541 |
+
api_name = dep.get("api_name")
|
| 1542 |
+
if isinstance(api_name, str):
|
| 1543 |
+
names.append(api_name if api_name.startswith("/") else f"/{api_name}")
|
| 1544 |
+
return list(dict.fromkeys(names))
|
| 1545 |
+
|
| 1546 |
+
|
| 1547 |
+
def space_subdomain_url(target_space_id: str) -> str:
|
| 1548 |
+
owner, name = target_space_id.split("/", 1)
|
| 1549 |
+
# This matches the common Spaces app URL pattern. Keep conservative: our
|
| 1550 |
+
# generated slugs are ASCII and hyphen-friendly.
|
| 1551 |
+
return f"https://{owner}-{name}.hf.space".replace("_", "-").lower()
|
| 1552 |
+
|
| 1553 |
+
|
| 1554 |
+
def runtime_to_dict(runtime) -> dict:
|
| 1555 |
+
payload = {}
|
| 1556 |
+
for attr in ["stage", "hardware", "requested_hardware", "sleep_time", "storage", "gc_timeout"]:
|
| 1557 |
+
value = getattr(runtime, attr, None)
|
| 1558 |
+
payload[attr] = getattr(value, "value", value)
|
| 1559 |
+
return {k: str(v) if v is not None else None for k, v in payload.items()}
|
| 1560 |
+
|
| 1561 |
+
|
| 1562 |
+
def write_space_runtime(api, target_space_id: str, token: str, run_dir: Path, events_path: Path, attempt: int | None = None) -> dict:
|
| 1563 |
+
try:
|
| 1564 |
+
runtime = api.get_space_runtime(repo_id=target_space_id, token=token)
|
| 1565 |
+
payload = runtime_to_dict(runtime)
|
| 1566 |
+
payload["attempt"] = attempt
|
| 1567 |
+
write_json(run_dir / "space_runtime.json", payload)
|
| 1568 |
+
return payload
|
| 1569 |
+
except Exception as exc:
|
| 1570 |
+
payload = {"error": str(exc)[:2000], "attempt": attempt}
|
| 1571 |
+
write_json(run_dir / "space_runtime.json", payload)
|
| 1572 |
+
append_event(events_path, "space_runtime", "warning", "Could not fetch Space runtime", payload)
|
| 1573 |
+
return payload
|
| 1574 |
+
|
| 1575 |
+
|
| 1576 |
+
def collect_space_logs(target_space_id: str, token: str, run_dir: Path, events_path: Path):
|
| 1577 |
+
logs_dir = run_dir / "logs"
|
| 1578 |
+
logs_dir.mkdir(parents=True, exist_ok=True)
|
| 1579 |
+
env = os.environ.copy()
|
| 1580 |
+
env["HF_TOKEN"] = token
|
| 1581 |
+
commands = {
|
| 1582 |
+
"space_logs_runtime.txt": ["hf", "spaces", "logs", target_space_id],
|
| 1583 |
+
"space_logs_build.txt": ["hf", "spaces", "logs", target_space_id, "--build"],
|
| 1584 |
+
}
|
| 1585 |
+
written = []
|
| 1586 |
+
for filename, cmd in commands.items():
|
| 1587 |
+
try:
|
| 1588 |
+
code, out = run_cmd(cmd, env=env, timeout=75)
|
| 1589 |
+
(logs_dir / filename).write_text(out, encoding="utf-8")
|
| 1590 |
+
written.append({"file": filename, "returncode": code, "tail": out[-1000:]})
|
| 1591 |
+
except Exception as exc:
|
| 1592 |
+
written.append({"file": filename, "error": str(exc)[:1000]})
|
| 1593 |
+
append_event(events_path, "space_logs", "success", "Collected best-effort Space logs", {"files": written})
|
| 1594 |
+
return written
|
| 1595 |
+
|
| 1596 |
+
|
| 1597 |
+
def validate_http_health(target_space_id: str, token: str, run_dir: Path, events_path: Path, attempt: int):
|
| 1598 |
+
import requests
|
| 1599 |
+
base_url = space_subdomain_url(target_space_id)
|
| 1600 |
+
url = base_url.rstrip("/") + "/health"
|
| 1601 |
+
headers = {"Authorization": f"Bearer {token}", "Accept": "application/json,text/plain,*/*"}
|
| 1602 |
+
response = requests.get(url, headers=headers, timeout=20)
|
| 1603 |
+
payload = {
|
| 1604 |
+
"status": "success" if response.ok else "failed",
|
| 1605 |
+
"attempt": attempt,
|
| 1606 |
+
"url": url,
|
| 1607 |
+
"status_code": response.status_code,
|
| 1608 |
+
"content_type": response.headers.get("content-type"),
|
| 1609 |
+
"text": response.text[:2000],
|
| 1610 |
+
}
|
| 1611 |
+
if response.ok:
|
| 1612 |
+
try:
|
| 1613 |
+
payload["json"] = response.json()
|
| 1614 |
+
except Exception:
|
| 1615 |
+
pass
|
| 1616 |
+
write_json(run_dir / "tests" / "http_health.json", payload)
|
| 1617 |
+
write_json(run_dir / "tests" / "test_result.json", payload | {"validator": "http_get_health"})
|
| 1618 |
+
append_event(events_path, "api_validation", "success", "HTTP /health validation passed", {"attempt": attempt, "url": url, "status_code": response.status_code})
|
| 1619 |
+
return payload | {"validator": "http_get_health"}
|
| 1620 |
+
raise RuntimeError(f"HTTP /health returned {response.status_code}: {response.text[:500]}")
|
| 1621 |
+
|
| 1622 |
+
|
| 1623 |
+
def validate_gradio_api(target_space_id: str, token: str, run_dir: Path, events_path: Path, attempt: int):
|
| 1624 |
+
client = make_gradio_client(target_space_id, token)
|
| 1625 |
+
schema = client.view_api(return_format="dict")
|
| 1626 |
+
write_json(run_dir / "tests" / "api_schema.json", schema if isinstance(schema, dict) else {"schema": str(schema)})
|
| 1627 |
+
discovered = api_names_from_schema(schema)
|
| 1628 |
+
candidates = []
|
| 1629 |
+
for name in ["/health", "/predict", "/greet"] + discovered:
|
| 1630 |
+
if name not in candidates:
|
| 1631 |
+
candidates.append(name)
|
| 1632 |
+
errors = []
|
| 1633 |
+
for api_name in candidates:
|
| 1634 |
+
try:
|
| 1635 |
+
if api_name == "/greet":
|
| 1636 |
+
result = client.predict("Agentic Space Factory", api_name=api_name)
|
| 1637 |
+
else:
|
| 1638 |
+
result = client.predict(api_name=api_name)
|
| 1639 |
+
payload = {"status": "success", "attempt": attempt, "api_name": api_name, "discovered_api_names": discovered, "result_repr": repr(result)[:2000], "validator": "gradio_client"}
|
| 1640 |
+
write_json(run_dir / "tests" / "test_result.json", payload)
|
| 1641 |
+
append_event(events_path, "api_validation", "success", "Gradio API validation passed", {"attempt": attempt, "api_name": api_name, "discovered_api_names": discovered})
|
| 1642 |
+
return payload
|
| 1643 |
+
except Exception as exc:
|
| 1644 |
+
errors.append({"api_name": api_name, "error": str(exc)[:1000]})
|
| 1645 |
+
raise RuntimeError("; ".join(f"{e['api_name']}: {e['error']}" for e in errors[:5]) or "No callable API endpoints found")
|
| 1646 |
+
|
| 1647 |
+
|
| 1648 |
+
def validate_live_api(api, target_space_id: str, token: str, run_dir: Path, events_path: Path, timeout_s: int = 900):
|
| 1649 |
+
append_event(events_path, "api_validation", "started", "Waiting for live HTTP /health or Gradio API to become available")
|
| 1650 |
+
deadline = time.time() + timeout_s
|
| 1651 |
+
attempt = 0
|
| 1652 |
+
last_error = None
|
| 1653 |
+
runtime_error_count = 0
|
| 1654 |
+
while time.time() < deadline:
|
| 1655 |
+
attempt += 1
|
| 1656 |
+
runtime_payload = write_space_runtime(api, target_space_id, token, run_dir, events_path, attempt)
|
| 1657 |
+
stage = str(runtime_payload.get("stage") or "").upper()
|
| 1658 |
+
if "RUNTIME_ERROR" in stage:
|
| 1659 |
+
runtime_error_count += 1
|
| 1660 |
+
collect_space_logs(target_space_id, token, run_dir, events_path)
|
| 1661 |
+
last_error = f"Space runtime stage is {stage}"
|
| 1662 |
+
if runtime_error_count >= 2:
|
| 1663 |
+
raise RuntimeError(f"Space is in RUNTIME_ERROR. See logs/space_logs_runtime.txt and logs/space_logs_build.txt. Last runtime: {runtime_payload}")
|
| 1664 |
+
try:
|
| 1665 |
+
return validate_http_health(target_space_id, token, run_dir, events_path, attempt)
|
| 1666 |
+
except Exception as exc:
|
| 1667 |
+
last_error = f"HTTP /health failed: {exc}"
|
| 1668 |
+
try:
|
| 1669 |
+
return validate_gradio_api(target_space_id, token, run_dir, events_path, attempt)
|
| 1670 |
+
except Exception as exc:
|
| 1671 |
+
last_error = (last_error or "") + f"; Gradio API failed: {exc}"
|
| 1672 |
+
append_event(events_path, "api_validation", "waiting", "Live health/API not ready yet", {"attempt": attempt, "runtime": runtime_payload, "error": last_error[-1500:] if last_error else None})
|
| 1673 |
+
time.sleep(30)
|
| 1674 |
+
collect_space_logs(target_space_id, token, run_dir, events_path)
|
| 1675 |
+
raise RuntimeError(f"Live health/API validation did not pass before timeout: {last_error}")
|
| 1676 |
+
|
| 1677 |
+
|
| 1678 |
+
def request_hardware(api, target_space_id: str, hardware: str, token: str, events_path: Path, step: str, retries: int = 4):
|
| 1679 |
+
"""Best-effort hardware request.
|
| 1680 |
+
|
| 1681 |
+
OAuth tokens can create/write Spaces but may still be unable to trigger
|
| 1682 |
+
hardware changes, especially paid GPU upgrades. Treat 401/auth/billing
|
| 1683 |
+
failures as manual-action-required instead of burning retries.
|
| 1684 |
+
"""
|
| 1685 |
+
if not hardware:
|
| 1686 |
+
return {"requested": False, "hardware": hardware, "ok": False, "error": "empty hardware"}
|
| 1687 |
+
last_error = None
|
| 1688 |
+
for attempt in range(1, retries + 1):
|
| 1689 |
+
try:
|
| 1690 |
+
runtime = api.request_space_hardware(repo_id=target_space_id, hardware=hardware, token=token)
|
| 1691 |
+
payload = {
|
| 1692 |
+
"requested": True,
|
| 1693 |
+
"hardware": hardware,
|
| 1694 |
+
"ok": True,
|
| 1695 |
+
"attempt": attempt,
|
| 1696 |
+
"runtime_stage": getattr(getattr(runtime, "stage", None), "value", str(getattr(runtime, "stage", None))),
|
| 1697 |
+
"requested_hardware": getattr(runtime, "requested_hardware", None),
|
| 1698 |
+
"hardware_current": getattr(runtime, "hardware", None),
|
| 1699 |
+
}
|
| 1700 |
+
append_event(events_path, step, "success", f"Requested Space hardware {hardware}", payload)
|
| 1701 |
+
return payload
|
| 1702 |
+
except Exception as exc:
|
| 1703 |
+
last_error = str(exc)[:2000]
|
| 1704 |
+
auth_like = any(marker in last_error for marker in ["401", "Invalid username or password", "Unauthorized", "Repository Not Found"])
|
| 1705 |
+
payload = {"attempt": attempt, "hardware": hardware, "error": last_error, "manual_action_required": auth_like}
|
| 1706 |
+
append_event(events_path, step, "failed" if auth_like or attempt == retries else "waiting", f"Could not request Space hardware {hardware}", payload)
|
| 1707 |
+
if auth_like:
|
| 1708 |
+
return {"requested": True, "hardware": hardware, "ok": False, "attempts": attempt, "error": last_error, "manual_action_required": True}
|
| 1709 |
+
if attempt < retries:
|
| 1710 |
+
time.sleep(8 * attempt)
|
| 1711 |
+
return {"requested": True, "hardware": hardware, "ok": False, "attempts": retries, "error": last_error, "manual_action_required": False}
|
| 1712 |
+
|
| 1713 |
+
|
| 1714 |
+
def create_initial_workspace(workspace: Path, model_id: str, target_space_id: str, preferred_hardware: str, fallback_hardware: str, allow_fallback: bool, implementation_mode: str, model_analysis: dict | None = None):
|
| 1715 |
+
workspace.mkdir(parents=True, exist_ok=True)
|
| 1716 |
+
model_analysis = model_analysis or {}
|
| 1717 |
+
pipeline_tag = model_analysis.get("pipeline_tag")
|
| 1718 |
+
library_name = model_analysis.get("library_name")
|
| 1719 |
+
tags = model_analysis.get("tags", [])[:40]
|
| 1720 |
+
siblings = model_analysis.get("siblings", [])[:60]
|
| 1721 |
+
app_py = f"""import gradio as gr
|
| 1722 |
+
from huggingface_hub import model_info, list_repo_files
|
| 1723 |
+
|
| 1724 |
+
MODEL_ID = {model_id!r}
|
| 1725 |
+
TARGET_SPACE_ID = {target_space_id!r}
|
| 1726 |
+
|
| 1727 |
+
|
| 1728 |
+
def health():
|
| 1729 |
+
return {{
|
| 1730 |
+
"status": "booted",
|
| 1731 |
+
"model_id": MODEL_ID,
|
| 1732 |
+
"target_space_id": TARGET_SPACE_ID,
|
| 1733 |
+
"stage": "initial-scaffold",
|
| 1734 |
+
"note": "Pi should replace this scaffold with a model-specific demo while preserving a cheap health endpoint.",
|
| 1735 |
+
}}
|
| 1736 |
+
|
| 1737 |
+
|
| 1738 |
+
def placeholder(*args):
|
| 1739 |
+
return "Initial scaffold. Pi should replace this with a model-specific inference path, or write TECHNICAL_BLOCKERS.json."
|
| 1740 |
+
|
| 1741 |
+
with gr.Blocks(title="Generated Model Space — Agentic Space Factory") as demo:
|
| 1742 |
+
gr.Markdown("# Generated Model Space — Agentic Space Factory")
|
| 1743 |
+
gr.Markdown(f"Private generated Space for `{MODEL_ID}`.")
|
| 1744 |
+
gr.JSON(label="Health", value=health(), every=None)
|
| 1745 |
+
gr.Button("Health check").click(fn=health, inputs=None, outputs=gr.JSON(), api_name="health")
|
| 1746 |
+
gr.Textbox(label="Input", value="Hello from Agentic Space Factory").submit(fn=placeholder, inputs=None, outputs=gr.Textbox(), api_name="predict")
|
| 1747 |
+
gr.Button("Run placeholder").click(fn=placeholder, inputs=None, outputs=gr.Textbox(), api_name="predict")
|
| 1748 |
+
|
| 1749 |
+
if __name__ == "__main__":
|
| 1750 |
+
demo.launch()
|
| 1751 |
+
"""
|
| 1752 |
+
(workspace / "app.py").write_text(app_py, encoding="utf-8")
|
| 1753 |
+
req = """gradio>=5.0.0
|
| 1754 |
+
huggingface_hub>=0.34.0,<1.0.0
|
| 1755 |
+
spaces
|
| 1756 |
+
transformers>=4.45.0
|
| 1757 |
+
diffusers
|
| 1758 |
+
accelerate
|
| 1759 |
+
safetensors
|
| 1760 |
+
torch
|
| 1761 |
+
kernels
|
| 1762 |
+
pillow
|
| 1763 |
+
numpy
|
| 1764 |
+
requests
|
| 1765 |
+
"""
|
| 1766 |
+
(workspace / "requirements.txt").write_text(req, encoding="utf-8")
|
| 1767 |
+
readme = f"""---
|
| 1768 |
+
title: Generated Model Space
|
| 1769 |
+
sdk: gradio
|
| 1770 |
+
app_file: app.py
|
| 1771 |
+
python_version: "3.10"
|
| 1772 |
+
suggested_hardware: {preferred_hardware or fallback_hardware or "cpu-basic"}
|
| 1773 |
+
short_description: "Agent-built model demo"
|
| 1774 |
+
---
|
| 1775 |
+
|
| 1776 |
+
# Generated Model Space — Agentic Space Factory
|
| 1777 |
+
|
| 1778 |
+
Private generated Space for `{model_id}`.
|
| 1779 |
+
|
| 1780 |
+
This Space is created by Phase 10. It should remain private until manually reviewed.
|
| 1781 |
+
"""
|
| 1782 |
+
(workspace / "README.md").write_text(readme, encoding="utf-8")
|
| 1783 |
+
analysis_json = json.dumps({"pipeline_tag": pipeline_tag, "library_name": library_name, "tags": tags, "siblings": siblings}, indent=2, ensure_ascii=False)
|
| 1784 |
+
goal = f"""You are Pi running inside a Hugging Face Job for Agentic Space Factory Phase 10.
|
| 1785 |
+
|
| 1786 |
+
Goal: build the best possible private Hugging Face Space demo for an arbitrary model card.
|
| 1787 |
+
|
| 1788 |
+
MODEL_ID: {model_id}
|
| 1789 |
+
TARGET_SPACE_ID: {target_space_id}
|
| 1790 |
+
IMPLEMENTATION_MODE: {implementation_mode}
|
| 1791 |
+
MODEL_METADATA:
|
| 1792 |
+
```json
|
| 1793 |
+
{analysis_json}
|
| 1794 |
+
```
|
| 1795 |
+
|
| 1796 |
+
First read and follow the operational rules from this gist:
|
| 1797 |
+
{GIST_URL}
|
| 1798 |
+
|
| 1799 |
+
Non-negotiable safety and product constraints:
|
| 1800 |
+
- The target Space must remain private.
|
| 1801 |
+
- Do not delete any user resources.
|
| 1802 |
+
- Do not print secrets or tokens.
|
| 1803 |
+
- Work only inside the current workspace.
|
| 1804 |
+
- The wrapper will create the private Space, request hardware best-effort, upload files, and validate the live app. Do not create/delete repos yourself in this Phase 10 worker.
|
| 1805 |
+
- Preserve a cheap health endpoint named `health` with `api_name="health"`. It must not load weights, run GPU work, or download large files.
|
| 1806 |
+
- Keep the huggingface_hub pin in requirements.txt: huggingface_hub>=0.34.0,<1.0.0.
|
| 1807 |
+
- README.md frontmatter must remain valid; if it uses short_description, it must be 60 characters or fewer.
|
| 1808 |
+
|
| 1809 |
+
Implementation contract:
|
| 1810 |
+
- If IMPLEMENTATION_MODE is `full-inference-gated`, you are not allowed to silently replace generation with a placeholder and call it success.
|
| 1811 |
+
- Try to implement the closest real inference path for the model card using evidence from README, model metadata, config files, and repo files.
|
| 1812 |
+
- You may choose an appropriate Gradio UI for the task: text, image, audio, video, multimodal, embeddings, classification, etc.
|
| 1813 |
+
- If the model is standard and feasible, implement a real generate/predict function and expose it as a Gradio endpoint.
|
| 1814 |
+
- If the model requires GPU, add ZeroGPU-compatible `@spaces.GPU(...)` only around the inference function. Do not decorate health.
|
| 1815 |
+
- If the model requires special dependencies, include them only when needed and document risks.
|
| 1816 |
+
- Investigate compatibility fallbacks before declaring a blocker: PyTorch SDPA, xformers, HF Kernels where relevant, CPU/offload/lazy loading, smaller resolution/steps, safe smoke-test inputs.
|
| 1817 |
+
- If real inference is impossible or unsafe in a Space, write TECHNICAL_BLOCKERS.json with concrete evidence for every blocker.
|
| 1818 |
+
|
| 1819 |
+
Deliverables:
|
| 1820 |
+
- app.py must boot on Hugging Face Spaces.
|
| 1821 |
+
- app.py must expose health/api_name="health".
|
| 1822 |
+
- If real generation is implemented, generate/predict must attempt a real model call, not only return a textual diagnostic.
|
| 1823 |
+
- If real generation is not implemented, write TECHNICAL_BLOCKERS.json with: full_inference_implemented=false, blockers[], evidence[], minimum_runtime, and suggested_next_step.
|
| 1824 |
+
- Write INFERENCE_CONTRACT.json with: full_inference_implemented, health_endpoint, primary_api_name, expected_output_type, validation_level, requires_gpu, estimated_vram, and blockers_count.
|
| 1825 |
+
- README.md must explain the runtime strategy, task, limitations, and how to test.
|
| 1826 |
+
- Write a concise PI_SUMMARY.md with what you changed and whether full inference is implemented.
|
| 1827 |
+
"""
|
| 1828 |
+
(workspace / "GOAL.md").write_text(goal, encoding="utf-8")
|
| 1829 |
+
return ["app.py", "requirements.txt", "README.md", "GOAL.md"]
|
| 1830 |
+
|
| 1831 |
+
|
| 1832 |
+
def sanitize_readme_metadata(workspace: Path, events_path: Path):
|
| 1833 |
+
readme_path = workspace / "README.md"
|
| 1834 |
+
if not readme_path.exists():
|
| 1835 |
+
return
|
| 1836 |
+
text = readme_path.read_text(encoding="utf-8", errors="ignore")
|
| 1837 |
+
if not text.startswith("---"):
|
| 1838 |
+
return
|
| 1839 |
+
parts = text.split("---", 2)
|
| 1840 |
+
if len(parts) < 3:
|
| 1841 |
+
return
|
| 1842 |
+
_, frontmatter, body = parts
|
| 1843 |
+
changed = False
|
| 1844 |
+
sanitized_lines = []
|
| 1845 |
+
for line in frontmatter.splitlines():
|
| 1846 |
+
if line.strip().startswith("short_description:"):
|
| 1847 |
+
value = "model video avatar demo"
|
| 1848 |
+
sanitized_lines.append(f"short_description: {value}")
|
| 1849 |
+
changed = True
|
| 1850 |
+
else:
|
| 1851 |
+
sanitized_lines.append(line)
|
| 1852 |
+
# If Pi added other unexpectedly long one-line metadata values, leave them alone:
|
| 1853 |
+
# the known Hub validation blocker for this run was short_description > 60 chars.
|
| 1854 |
+
if changed:
|
| 1855 |
+
new_text = "---\n" + "\n".join(sanitized_lines).strip() + "\n---" + body
|
| 1856 |
+
readme_path.write_text(new_text, encoding="utf-8")
|
| 1857 |
+
append_event(events_path, "metadata_sanitize", "success", "Sanitized README metadata", {"short_description": "model video avatar demo"})
|
| 1858 |
+
|
| 1859 |
+
|
| 1860 |
+
def upload_workspace(api, workspace: Path, target_space_id: str, token: str, run_dir: Path, events_path: Path):
|
| 1861 |
+
sanitize_readme_metadata(workspace, events_path)
|
| 1862 |
+
append_event(events_path, "upload_files", "started", "Uploading generated universal model-card workspace recursively")
|
| 1863 |
+
gen_dir = run_dir / "generated"
|
| 1864 |
+
if gen_dir.exists():
|
| 1865 |
+
shutil.rmtree(gen_dir)
|
| 1866 |
+
shutil.copytree(workspace, gen_dir, ignore=shutil.ignore_patterns(".git", "node_modules", "__pycache__", "*.pyc"))
|
| 1867 |
+
for filename in ["app.py", "README.md", "requirements.txt"]:
|
| 1868 |
+
if not (workspace / filename).exists():
|
| 1869 |
+
raise RuntimeError(f"Missing required generated file: {filename}")
|
| 1870 |
+
api.upload_folder(
|
| 1871 |
+
folder_path=str(workspace),
|
| 1872 |
+
repo_id=target_space_id,
|
| 1873 |
+
repo_type="space",
|
| 1874 |
+
token=token,
|
| 1875 |
+
ignore_patterns=[".git/*", "node_modules/*", "__pycache__/*", "*.pyc", "GOAL.md"],
|
| 1876 |
+
)
|
| 1877 |
+
uploaded_files = sorted(str(p.relative_to(workspace)) for p in workspace.rglob("*") if p.is_file() and "node_modules" not in p.parts and "__pycache__" not in p.parts)
|
| 1878 |
+
append_event(events_path, "upload_files", "success", "Uploaded generated workspace folder", {"file_count": len(uploaded_files), "files_sample": uploaded_files[:50]})
|
| 1879 |
+
|
| 1880 |
+
|
| 1881 |
+
def load_json_if_exists(path: Path) -> dict:
|
| 1882 |
+
if not path.exists():
|
| 1883 |
+
return {}
|
| 1884 |
+
try:
|
| 1885 |
+
return json.loads(path.read_text(encoding="utf-8", errors="replace"))
|
| 1886 |
+
except Exception as exc:
|
| 1887 |
+
return {"parse_error": str(exc), "raw_tail": path.read_text(encoding="utf-8", errors="replace")[-2000:]}
|
| 1888 |
+
|
| 1889 |
+
|
| 1890 |
+
def infer_generation_gate(workspace: Path, implementation_mode: str, validation: dict, run_dir: Path, events_path: Path) -> dict:
|
| 1891 |
+
"""Classify the run separately from process success.
|
| 1892 |
+
|
| 1893 |
+
/health passing means the Space boots. It does not mean the generated Space
|
| 1894 |
+
performs model inference. In full-inference-gated mode we require either
|
| 1895 |
+
an actual implementation signal or a machine-readable blocker report.
|
| 1896 |
+
"""
|
| 1897 |
+
app_text = (workspace / "app.py").read_text(encoding="utf-8", errors="ignore") if (workspace / "app.py").exists() else ""
|
| 1898 |
+
summary_text = (workspace / "PI_SUMMARY.md").read_text(encoding="utf-8", errors="ignore") if (workspace / "PI_SUMMARY.md").exists() else ""
|
| 1899 |
+
req_text = (workspace / "requirements.txt").read_text(encoding="utf-8", errors="ignore") if (workspace / "requirements.txt").exists() else ""
|
| 1900 |
+
blockers_path = workspace / "TECHNICAL_BLOCKERS.json"
|
| 1901 |
+
blockers = load_json_if_exists(blockers_path)
|
| 1902 |
+
|
| 1903 |
+
combined = (app_text + "\n" + summary_text).lower()
|
| 1904 |
+
blocked_markers = [
|
| 1905 |
+
"full generation is not implemented",
|
| 1906 |
+
"full generation is intentionally not wired",
|
| 1907 |
+
"full inference is blocked",
|
| 1908 |
+
"returns a detailed diagnostic",
|
| 1909 |
+
"diagnostic report instead",
|
| 1910 |
+
"placeholder generator",
|
| 1911 |
+
"placeholder generation",
|
| 1912 |
+
"info-only",
|
| 1913 |
+
"not implemented",
|
| 1914 |
+
"cannot run in this environment",
|
| 1915 |
+
"out of scope",
|
| 1916 |
+
]
|
| 1917 |
+
blocker_detected = bool(blockers) or any(m in combined for m in blocked_markers)
|
| 1918 |
+
implementation_signals = {
|
| 1919 |
+
"has_spaces_gpu": "@spaces.GPU" in app_text,
|
| 1920 |
+
"has_torch": "torch" in req_text or "import torch" in app_text,
|
| 1921 |
+
"has_diffusers": "diffusers" in req_text or "diffusers" in app_text,
|
| 1922 |
+
"has_video_output_hint": any(x in app_text.lower() for x in ["gr.video", "video", ".mp4", "ffmpeg"]),
|
| 1923 |
+
"health_passed": validation.get("method") in {"http_health", "gradio"},
|
| 1924 |
+
}
|
| 1925 |
+
|
| 1926 |
+
if blocker_detected:
|
| 1927 |
+
status = "technical_blocker"
|
| 1928 |
+
message = "Space boots, but full model inference was not implemented. See TECHNICAL_BLOCKERS.json / PI_SUMMARY.md."
|
| 1929 |
+
elif implementation_mode in {"full-inference-gated", "full-inference-attempt"}:
|
| 1930 |
+
# Without a video smoke test, do not claim real inference success.
|
| 1931 |
+
status = "full_inference_candidate_health_passed"
|
| 1932 |
+
message = "Space boots and contains inference signals, but no generation smoke test has validated a real video output."
|
| 1933 |
+
else:
|
| 1934 |
+
status = "health_only"
|
| 1935 |
+
message = "Safe scaffold health validation passed. Full inference was not requested."
|
| 1936 |
+
|
| 1937 |
+
if blocker_detected and not blockers:
|
| 1938 |
+
blockers = {
|
| 1939 |
+
"full_inference_implemented": False,
|
| 1940 |
+
"source": "worker_heuristic_from_PI_SUMMARY_or_app.py",
|
| 1941 |
+
"blockers": [
|
| 1942 |
+
{
|
| 1943 |
+
"type": "agent_declared_or_detected_blocker",
|
| 1944 |
+
"claim": "Pi-generated artifacts state that full inference is blocked/not implemented or generation returns diagnostics/placeholders.",
|
| 1945 |
+
"evidence": "See PI_SUMMARY.md and app.py in generated artifacts.",
|
| 1946 |
+
"severity": "blocking",
|
| 1947 |
+
}
|
| 1948 |
+
],
|
| 1949 |
+
"required_investigations_for_next_run": [
|
| 1950 |
+
"Check whether PyTorch SDPA can replace flash-attn calls.",
|
| 1951 |
+
"Check whether HF Kernels flash-attn2/3/4 can replace required flash-attn APIs.",
|
| 1952 |
+
"Verify whether 2-GPU context parallelism is strictly required or can be reduced to a single-GPU smoke test.",
|
| 1953 |
+
],
|
| 1954 |
+
}
|
| 1955 |
+
(workspace / "TECHNICAL_BLOCKERS.json").write_text(json.dumps(blockers, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
| 1956 |
+
(run_dir / "generated" / "TECHNICAL_BLOCKERS.json").write_text(json.dumps(blockers, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
| 1957 |
+
|
| 1958 |
+
gate = {
|
| 1959 |
+
"status": status,
|
| 1960 |
+
"message": message,
|
| 1961 |
+
"implementation_mode": implementation_mode,
|
| 1962 |
+
"blocker_detected": blocker_detected,
|
| 1963 |
+
"implementation_signals": implementation_signals,
|
| 1964 |
+
"validation_method": validation.get("method"),
|
| 1965 |
+
"blockers": blockers,
|
| 1966 |
+
}
|
| 1967 |
+
write_json(run_dir / "inference_gate.json", gate)
|
| 1968 |
+
append_event(events_path, "inference_gate", status, message, gate)
|
| 1969 |
+
return gate
|
| 1970 |
+
|
| 1971 |
+
|
| 1972 |
+
def main():
|
| 1973 |
+
run_id = os.environ["RUN_ID"]
|
| 1974 |
+
hf_username = os.environ.get("HF_USERNAME", "unknown")
|
| 1975 |
+
bucket_source = os.environ.get("BUCKET_SOURCE", "unknown")
|
| 1976 |
+
output_root = Path(os.environ.get("OUTPUT_ROOT", "/output"))
|
| 1977 |
+
target_space_id = os.environ.get("TARGET_SPACE_ID", "")
|
| 1978 |
+
model_id = sanitize_model_id(os.environ.get("MODEL_ID", DEFAULT_MODEL_ID))
|
| 1979 |
+
pi_model = os.environ.get("PI_MODEL", "Qwen/Qwen3-Coder-Next")
|
| 1980 |
+
preferred_hardware = os.environ.get("PREFERRED_SPACE_HARDWARE", "zero-a10g")
|
| 1981 |
+
fallback_hardware = os.environ.get("FALLBACK_SPACE_HARDWARE", "l40sx1")
|
| 1982 |
+
allow_fixed_gpu_fallback = os.environ.get("ALLOW_FIXED_GPU_FALLBACK", "true").lower() in {"1", "true", "yes", "on"}
|
| 1983 |
+
implementation_mode = os.environ.get("IMPLEMENTATION_MODE", "full-inference-attempt")
|
| 1984 |
+
token = os.environ.get("HF_TOKEN")
|
| 1985 |
+
|
| 1986 |
+
run_dir = output_root / "runs" / run_id
|
| 1987 |
+
events_path = run_dir / "events.jsonl"
|
| 1988 |
+
state_path = run_dir / "state.json"
|
| 1989 |
+
workspace = Path("/tmp/universal_workspace")
|
| 1990 |
+
|
| 1991 |
+
append_event(events_path, "bootstrap", "started", "Universal model-card builder worker started", {"model_id": model_id, "target_space_id": target_space_id})
|
| 1992 |
+
write_json(state_path, {"run_id": run_id, "kind": "universal_model_card_builder", "status": "running", "message": "Attempting Universal model-card builderd Space creation", "model_id": model_id, "target_space": target_space_id, "created_by": hf_username, "bucket_source": bucket_source, "created_at": now(), "updated_at": now()})
|
| 1993 |
+
if not token:
|
| 1994 |
+
fail(run_dir, events_path, "HF_TOKEN is missing from Job secrets")
|
| 1995 |
+
if not TARGET_RE.match(target_space_id):
|
| 1996 |
+
fail(run_dir, events_path, "Invalid TARGET_SPACE_ID", {"target_space_id": target_space_id})
|
| 1997 |
+
|
| 1998 |
+
try:
|
| 1999 |
+
install_python_deps(events_path)
|
| 2000 |
+
from huggingface_hub import HfApi
|
| 2001 |
+
api = HfApi(token=token)
|
| 2002 |
+
whoami = api.whoami(token=token)
|
| 2003 |
+
append_event(events_path, "auth", "success", "Authenticated inside Job", {"whoami_name": whoami.get("name")})
|
| 2004 |
+
|
| 2005 |
+
append_event(events_path, "model_analysis", "started", "Fetching model metadata", {"model_id": model_id})
|
| 2006 |
+
info = api.model_info(model_id, token=token, files_metadata=True)
|
| 2007 |
+
siblings = [getattr(s, "rfilename", "") for s in (info.siblings or [])]
|
| 2008 |
+
analysis = {"model_id": model_id, "pipeline_tag": getattr(info, "pipeline_tag", None), "library_name": getattr(info, "library_name", None), "tags": list(getattr(info, "tags", []) or [])[:100], "siblings": siblings[:160], "default_model_target": model_id == DEFAULT_MODEL_ID, "preferred_hardware": preferred_hardware, "fallback_hardware": fallback_hardware, "allow_fixed_gpu_fallback": allow_fixed_gpu_fallback, "implementation_mode": implementation_mode}
|
| 2009 |
+
write_json(run_dir / "model_analysis.json", analysis)
|
| 2010 |
+
append_event(events_path, "model_analysis", "success", "Model metadata fetched", {"pipeline_tag": analysis["pipeline_tag"], "library_name": analysis["library_name"]})
|
| 2011 |
+
|
| 2012 |
+
create_initial_workspace(workspace, model_id, target_space_id, preferred_hardware, fallback_hardware, allow_fixed_gpu_fallback, implementation_mode, analysis)
|
| 2013 |
+
append_event(events_path, "workspace", "success", "Prepared universal model-card workspace", {"files": sorted(p.name for p in workspace.iterdir())})
|
| 2014 |
+
|
| 2015 |
+
install_pi(events_path)
|
| 2016 |
+
configure_pi(events_path, pi_model)
|
| 2017 |
+
append_event(events_path, "pi_run", "started", "Running Pi on universal model-card workspace", {"model": pi_model})
|
| 2018 |
+
code, pi_out = run_cmd(["pi", "-p", (workspace / "GOAL.md").read_text(encoding="utf-8")], cwd=workspace, timeout=2400)
|
| 2019 |
+
(run_dir / "logs").mkdir(parents=True, exist_ok=True)
|
| 2020 |
+
(run_dir / "logs" / "pi_output.txt").write_text(pi_out, encoding="utf-8")
|
| 2021 |
+
if code != 0:
|
| 2022 |
+
append_event(events_path, "pi_run", "failed", "Pi returned a non-zero exit code", {"returncode": code, "output_tail": pi_out[-4000:]})
|
| 2023 |
+
collect_pi_traces(run_dir, events_path)
|
| 2024 |
+
fail(run_dir, events_path, "Pi failed before Space upload", {"returncode": code, "output_tail": pi_out[-4000:]})
|
| 2025 |
+
append_event(events_path, "pi_run", "success", "Pi completed universal model-card workspace pass", {"output_tail": pi_out[-2000:]})
|
| 2026 |
+
if not (workspace / "PI_SUMMARY.md").exists():
|
| 2027 |
+
(workspace / "PI_SUMMARY.md").write_text("# Pi Summary\n\nPi did not create a PI_SUMMARY.md. See logs/pi_output.txt.\n", encoding="utf-8")
|
| 2028 |
+
|
| 2029 |
+
app_text = (workspace / "app.py").read_text(encoding="utf-8", errors="ignore")
|
| 2030 |
+
if "/health" not in app_text and "api_name=\"health\"" not in app_text and "api_name='health'" not in app_text:
|
| 2031 |
+
append_event(events_path, "pi_verification", "failed", "app.py does not appear to expose /health; injecting safe health endpoint is not implemented")
|
| 2032 |
+
fail(run_dir, events_path, "Pi output did not preserve a /health endpoint")
|
| 2033 |
+
append_event(events_path, "pi_verification", "success", "Pi output preserved health validation endpoint")
|
| 2034 |
+
|
| 2035 |
+
append_event(events_path, "create_space", "started", "Creating private target Space", {"target_space": target_space_id})
|
| 2036 |
+
api.create_repo(repo_id=target_space_id, repo_type="space", space_sdk="gradio", private=True, exist_ok=False, token=token)
|
| 2037 |
+
append_event(events_path, "create_space", "success", "Private target Space created", {"target_space": target_space_id})
|
| 2038 |
+
|
| 2039 |
+
# Upload before requesting hardware. Newly created private Spaces may not be
|
| 2040 |
+
# immediately available on the hardware endpoint; uploading first also ensures
|
| 2041 |
+
# the repo has valid Space metadata before any restart is triggered.
|
| 2042 |
+
upload_workspace(api, workspace, target_space_id, token, run_dir, events_path)
|
| 2043 |
+
|
| 2044 |
+
hardware_attempts = []
|
| 2045 |
+
preferred = request_hardware(api, target_space_id, preferred_hardware, token, events_path, "hardware_preferred")
|
| 2046 |
+
hardware_attempts.append(preferred)
|
| 2047 |
+
selected_hardware = preferred_hardware if preferred.get("ok") else None
|
| 2048 |
+
if not selected_hardware and allow_fixed_gpu_fallback and fallback_hardware:
|
| 2049 |
+
fallback = request_hardware(api, target_space_id, fallback_hardware, token, events_path, "hardware_fallback")
|
| 2050 |
+
hardware_attempts.append(fallback)
|
| 2051 |
+
selected_hardware = fallback_hardware if fallback.get("ok") else None
|
| 2052 |
+
if not selected_hardware:
|
| 2053 |
+
append_event(events_path, "hardware", "warning", "Could not request preferred/fallback hardware; Space may remain on default CPU", {"attempts": hardware_attempts})
|
| 2054 |
+
selected_hardware = "default-cpu-or-existing"
|
| 2055 |
+
write_json(run_dir / "hardware_attempts.json", {"selected_hardware": selected_hardware, "attempts": hardware_attempts})
|
| 2056 |
+
|
| 2057 |
+
validation = validate_live_api(api, target_space_id, token, run_dir, events_path, timeout_s=1200)
|
| 2058 |
+
inference_gate = infer_generation_gate(workspace, implementation_mode, validation, run_dir, events_path)
|
| 2059 |
+
collect_pi_traces(run_dir, events_path)
|
| 2060 |
+
|
| 2061 |
+
final_state = {
|
| 2062 |
+
"run_id": run_id,
|
| 2063 |
+
"kind": "universal_model_card_builder",
|
| 2064 |
+
"status": inference_gate["status"],
|
| 2065 |
+
"message": inference_gate["message"],
|
| 2066 |
+
"model_id": model_id,
|
| 2067 |
+
"target_space": target_space_id,
|
| 2068 |
+
"target_space_url": f"https://huggingface.co/spaces/{target_space_id}",
|
| 2069 |
+
"selected_hardware": selected_hardware,
|
| 2070 |
+
"hardware_attempts": hardware_attempts,
|
| 2071 |
+
"validation": validation,
|
| 2072 |
+
"inference_gate": inference_gate,
|
| 2073 |
+
"updated_at": now(),
|
| 2074 |
+
"created_by": hf_username,
|
| 2075 |
+
"bucket_source": bucket_source,
|
| 2076 |
+
}
|
| 2077 |
+
write_json(state_path, final_state)
|
| 2078 |
+
report = f"""# Agentic Space Factory — Universal Model-Card Builder Report
|
| 2079 |
+
|
| 2080 |
+
Run ID: `{run_id}`
|
| 2081 |
+
|
| 2082 |
+
Status: **{inference_gate['status']}**
|
| 2083 |
+
|
| 2084 |
+
{inference_gate['message']}
|
| 2085 |
+
|
| 2086 |
+
Target Space: https://huggingface.co/spaces/{target_space_id}
|
| 2087 |
+
|
| 2088 |
+
Model: `{model_id}`
|
| 2089 |
+
|
| 2090 |
+
## Hardware
|
| 2091 |
+
|
| 2092 |
+
Selected/requested hardware: `{selected_hardware}`
|
| 2093 |
+
|
| 2094 |
+
Hardware changes are best-effort with OAuth. If requests fail with 401/auth/billing errors, set the Space hardware manually and rerun validation.
|
| 2095 |
+
|
| 2096 |
+
```json
|
| 2097 |
+
{json.dumps(hardware_attempts, indent=2, ensure_ascii=False)}
|
| 2098 |
+
```
|
| 2099 |
+
|
| 2100 |
+
## Health validation
|
| 2101 |
+
|
| 2102 |
+
The wrapper validated the live Space using HTTP `/health` first, with Gradio Client as fallback. This only proves bootability.
|
| 2103 |
+
|
| 2104 |
+
```json
|
| 2105 |
+
{json.dumps(validation, indent=2, ensure_ascii=False)}
|
| 2106 |
+
```
|
| 2107 |
+
|
| 2108 |
+
## Full-inference gate
|
| 2109 |
+
|
| 2110 |
+
```json
|
| 2111 |
+
{json.dumps(inference_gate, indent=2, ensure_ascii=False)}
|
| 2112 |
+
```
|
| 2113 |
+
|
| 2114 |
+
## Pi summary
|
| 2115 |
+
|
| 2116 |
+
{(workspace / 'PI_SUMMARY.md').read_text(encoding='utf-8', errors='ignore') if (workspace / 'PI_SUMMARY.md').exists() else 'No PI_SUMMARY.md was produced.'}
|
| 2117 |
+
|
| 2118 |
+
## Safety
|
| 2119 |
+
|
| 2120 |
+
- The target Space was created private.
|
| 2121 |
+
- No public publication was attempted.
|
| 2122 |
+
- Raw traces should remain private; redacted traces are stored separately.
|
| 2123 |
+
- If fallback fixed GPU was used or selected manually, review billing/hardware settings manually after the run.
|
| 2124 |
+
"""
|
| 2125 |
+
(run_dir / "report.md").write_text(report, encoding="utf-8")
|
| 2126 |
+
append_event(events_path, "report_write", "success", "Wrote report.md")
|
| 2127 |
+
append_event(events_path, "done", inference_gate["status"], "Universal model-card builder completed", {"target_space": target_space_id, "selected_hardware": selected_hardware, "gate_status": inference_gate["status"]})
|
| 2128 |
+
except SystemExit:
|
| 2129 |
+
raise
|
| 2130 |
+
except Exception as exc:
|
| 2131 |
+
try:
|
| 2132 |
+
collect_pi_traces(run_dir, events_path)
|
| 2133 |
+
except Exception:
|
| 2134 |
+
pass
|
| 2135 |
+
fail(run_dir, events_path, "Universal model-card builder worker failed", {"error": str(exc)})
|
| 2136 |
+
|
| 2137 |
+
|
| 2138 |
+
if __name__ == "__main__":
|
| 2139 |
+
main()
|
| 2140 |
+
|
| 2141 |
+
'''
|
| 2142 |
+
|
| 2143 |
+
|
| 2144 |
def encoded_worker_script() -> str:
|
| 2145 |
"""Return the base64-encoded Phase 1 hello worker script."""
|
| 2146 |
return _encode(HELLO_WORKER_SCRIPT)
|
|
|
|
| 2176 |
"""Return the base64-encoded Phase 9 LongCat article reproduction worker script."""
|
| 2177 |
return _encode(LONGCAT_ARTICLE_WORKER_SCRIPT)
|
| 2178 |
|
| 2179 |
+
|
| 2180 |
+
def encoded_universal_model_card_worker_script() -> str:
|
| 2181 |
+
"""Return the base64-encoded Phase 10 universal model-card builder worker script."""
|
| 2182 |
+
return _encode(UNIVERSAL_MODEL_CARD_WORKER_SCRIPT)
|
| 2183 |
+
|
| 2184 |
def python_decode_and_run_command() -> list[str]:
|
| 2185 |
"""Command list for `run_job`.
|
| 2186 |
|