Spaces:
Running on Zero
Running on Zero
| #!/usr/bin/env python3 | |
| """Capture evidence for the full-weight local 4B route.""" | |
| from __future__ import annotations | |
| import argparse | |
| from contextlib import contextmanager | |
| import hashlib | |
| import ipaddress | |
| import json | |
| import os | |
| from pathlib import Path | |
| import sys | |
| from time import gmtime, strftime | |
| from typing import Any | |
| import urllib.error | |
| import urllib.parse | |
| import urllib.request | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| if str(PROJECT_ROOT) not in sys.path: | |
| sys.path.insert(0, str(PROJECT_ROOT)) | |
| from figment.config import FigmentConfig, NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID # noqa: E402 | |
| from figment.trace import stable_hash # noqa: E402 | |
| from scripts.run_eval import run_eval # noqa: E402 | |
| from scripts.smoke_model_route import run_smoke # noqa: E402 | |
| DEFAULT_CASE_PATHS = ( | |
| Path("data/eval/initial_handwritten_cases.jsonl"), | |
| Path("data/eval/adversarial_strict_cases.jsonl"), | |
| Path("data/eval/comprehensive_hosted_cases.jsonl"), | |
| ) | |
| DEFAULT_BASE_URL = "http://127.0.0.1:8001/v1" | |
| DEFAULT_TIMEOUT_SECONDS = 45.0 | |
| FULL_WEIGHT_MODEL_REPO = "nvidia/NVIDIA-Nemotron-3-Nano-4B-BF16" | |
| FULL_WEIGHT_REVISION = "dfaf35de3e30f1867dd8dbc38a7fc9fb52d3914f" | |
| FULL_WEIGHT_SHA256 = "55d4e2519456c4a9bddf596b0748d630e3b2ce6ff6f4c2b7ed3e07e2b00dad42" | |
| FULL_WEIGHT_BYTES = 7_947_142_640 | |
| def run_evidence( | |
| *, | |
| base_url: str, | |
| model_id: str, | |
| output_dir: Path, | |
| case_paths: list[Path], | |
| limit: int | None, | |
| timeout_seconds: float, | |
| smoke_only: bool = False, | |
| force_eval: bool = False, | |
| ) -> dict[str, Any]: | |
| normalized_base_url = _normalize_base_url(base_url) | |
| output_dir.mkdir(parents=True, exist_ok=True) | |
| endpoint_metadata = _probe_models_endpoint(normalized_base_url, timeout_seconds) | |
| _write_json(output_dir / "endpoint_metadata.json", endpoint_metadata) | |
| summary: dict[str, Any] = { | |
| "status": "endpoint_unavailable" if endpoint_metadata["status"] != "passed" else "endpoint_available", | |
| "output_dir": str(output_dir), | |
| "base_url": normalized_base_url, | |
| "model_id": model_id, | |
| "full_weight_artifact": { | |
| "repo": FULL_WEIGHT_MODEL_REPO, | |
| "revision": FULL_WEIGHT_REVISION, | |
| "model_safetensors_bytes": FULL_WEIGHT_BYTES, | |
| "model_safetensors_sha256": FULL_WEIGHT_SHA256, | |
| }, | |
| "endpoint_metadata_path": str(output_dir / "endpoint_metadata.json"), | |
| "route_smoke_path": None, | |
| "eval_records_path": None, | |
| "eval_summary_path": None, | |
| "counts_as_no_cloud_route_proof": False, | |
| "counts_as_50_case_local_llm_competence": False, | |
| } | |
| if endpoint_metadata["status"] != "passed": | |
| _write_json(output_dir / "summary.json", summary) | |
| return summary | |
| with _local_4b_env(normalized_base_url, model_id, timeout_seconds): | |
| smoke = run_smoke() | |
| smoke_path = output_dir / "route_smoke.json" | |
| _write_json(smoke_path, smoke) | |
| summary["route_smoke_path"] = str(smoke_path) | |
| summary["route_smoke_status"] = smoke.get("status") | |
| summary["counts_as_no_cloud_route_proof"] = bool( | |
| (smoke.get("local_llm_evidence") or {}).get("counts_as_no_cloud_route_proof") | |
| ) | |
| if smoke_only: | |
| summary["status"] = "smoke_passed" if smoke.get("status") == "passed" else "smoke_failed" | |
| _write_json(output_dir / "summary.json", summary) | |
| return summary | |
| if smoke.get("status") != "passed" and not force_eval: | |
| summary["status"] = "smoke_failed_eval_skipped" | |
| summary["eval_skip_reason"] = "route smoke did not prove configured-model validation" | |
| _write_json(output_dir / "summary.json", summary) | |
| return summary | |
| eval_records_path = output_dir / "local_4b_eval.jsonl" | |
| config = FigmentConfig( | |
| figment_mode="local", | |
| model_stack="local_4b_parakeet", | |
| model_backend="llama_cpp", | |
| audio_backend="none", | |
| local_model_id=model_id, | |
| llama_base_url=normalized_base_url, | |
| ).validated() | |
| eval_summary = run_eval( | |
| case_paths=case_paths, | |
| output_path=eval_records_path, | |
| config=config, | |
| limit=limit, | |
| ) | |
| eval_summary_path = output_dir / "eval_summary.json" | |
| _write_json(eval_summary_path, eval_summary) | |
| eval_manifest = _build_eval_evidence_manifest( | |
| eval_records_path=eval_records_path, | |
| eval_summary=eval_summary, | |
| endpoint_metadata=endpoint_metadata, | |
| route_smoke=smoke, | |
| config=config, | |
| ) | |
| eval_manifest_path = output_dir / "eval_evidence_manifest.json" | |
| _write_json(eval_manifest_path, eval_manifest) | |
| local_evidence = eval_summary.get("local_llm_evidence") or {} | |
| summary.update( | |
| { | |
| "status": "eval_completed", | |
| "eval_records_path": str(eval_records_path), | |
| "eval_summary_path": str(eval_summary_path), | |
| "eval_evidence_manifest_path": str(eval_manifest_path), | |
| "total_cases": eval_summary.get("total_cases"), | |
| "competence_successes": eval_summary.get("competence_successes"), | |
| "fallback_uses": eval_summary.get("fallback_uses"), | |
| "final_validation_successes": eval_summary.get("final_validation_successes"), | |
| "latency_ms": eval_manifest.get("latency_ms"), | |
| "trace_hash_count": eval_manifest.get("trace_hash_count"), | |
| "missing_trace_hash_case_ids": eval_manifest.get("missing_trace_hash_case_ids"), | |
| "counts_as_50_case_local_llm_competence": bool( | |
| local_evidence.get("counts_as_50_case_local_llm_competence") | |
| ), | |
| } | |
| ) | |
| _write_json(output_dir / "summary.json", summary) | |
| return summary | |
| def _probe_models_endpoint(base_url: str, timeout_seconds: float) -> dict[str, Any]: | |
| models_url = _models_url(base_url) | |
| request = urllib.request.Request(models_url, method="GET") | |
| try: | |
| with urllib.request.urlopen(request, timeout=timeout_seconds) as response: | |
| payload = json.loads(response.read().decode("utf-8")) | |
| except (OSError, TimeoutError, urllib.error.URLError, json.JSONDecodeError) as exc: | |
| return { | |
| "status": "failed", | |
| "models_url": models_url, | |
| "error": str(exc), | |
| } | |
| return { | |
| "status": "passed", | |
| "models_url": models_url, | |
| "payload": payload, | |
| } | |
| def _normalize_base_url(base_url: str) -> str: | |
| stripped = base_url.strip().rstrip("/") | |
| if not stripped: | |
| return DEFAULT_BASE_URL | |
| parts = urllib.parse.urlsplit(stripped) | |
| path = parts.path.rstrip("/") | |
| for suffix in ("/chat/completions", "/models"): | |
| if path.endswith(suffix): | |
| path = path[: -len(suffix)] or "/" | |
| return urllib.parse.urlunsplit((parts.scheme, parts.netloc, path.rstrip("/"), "", "")) | |
| def _models_url(base_url: str) -> str: | |
| return f"{base_url.rstrip('/')}/models" | |
| def _build_eval_evidence_manifest( | |
| *, | |
| eval_records_path: Path, | |
| eval_summary: dict[str, Any], | |
| endpoint_metadata: dict[str, Any], | |
| route_smoke: dict[str, Any], | |
| config: FigmentConfig, | |
| ) -> dict[str, Any]: | |
| records = _read_eval_records(eval_records_path) | |
| endpoint_payload = endpoint_metadata.get("payload") if isinstance(endpoint_metadata.get("payload"), dict) else {} | |
| smoke_evidence = route_smoke.get("local_llm_evidence") if isinstance(route_smoke.get("local_llm_evidence"), dict) else {} | |
| local_evidence = ( | |
| eval_summary.get("local_llm_evidence") | |
| if isinstance(eval_summary.get("local_llm_evidence"), dict) | |
| else {} | |
| ) | |
| latency_values = [ | |
| float(record["latency_ms"]) | |
| for record in records | |
| if isinstance(record.get("latency_ms"), int | float) | |
| ] | |
| trace_entries = [ | |
| {"case_id": record.get("case_id"), "trace_hash": record.get("trace_hash")} | |
| for record in records | |
| if record.get("trace_hash") | |
| ] | |
| missing_trace_hash_case_ids = [ | |
| str(record.get("case_id")) | |
| for record in records | |
| if not record.get("trace_hash") | |
| ] | |
| return { | |
| "evidence_version": 1, | |
| "manifest_hash_inputs": { | |
| "eval_records_sha256": _file_sha256(eval_records_path), | |
| "endpoint_payload_hash": stable_hash(endpoint_payload), | |
| "route_smoke_hash": stable_hash(route_smoke), | |
| }, | |
| "model_server_metadata": { | |
| "base_url": config.llama_base_url, | |
| "models_url": endpoint_metadata.get("models_url"), | |
| "models_status": endpoint_metadata.get("status"), | |
| "advertised_model_ids": _advertised_model_ids(endpoint_payload), | |
| "models_payload_hash": stable_hash(endpoint_payload), | |
| }, | |
| "configured_route": { | |
| "figment_mode": config.figment_mode, | |
| "model_stack": config.model_stack, | |
| "model_backend": config.model_backend, | |
| "audio_backend": config.audio_backend, | |
| "active_model_id": config.active_model_id, | |
| "local_model_id": config.local_model_id, | |
| "llama_base_url": config.llama_base_url, | |
| "full_weight_artifact": { | |
| "repo": FULL_WEIGHT_MODEL_REPO, | |
| "revision": FULL_WEIGHT_REVISION, | |
| "model_safetensors_bytes": FULL_WEIGHT_BYTES, | |
| "model_safetensors_sha256": FULL_WEIGHT_SHA256, | |
| }, | |
| }, | |
| "no_cloud_evidence": { | |
| "model_backend_is_local_openai_compatible": config.model_backend == "llama_cpp", | |
| "hosted_backend_disabled_for_eval": config.model_backend != "hosted_omni", | |
| "endpoint_models_probe_passed": endpoint_metadata.get("status") == "passed", | |
| "route_smoke_counts_as_no_cloud_route_proof": bool( | |
| smoke_evidence.get("counts_as_no_cloud_route_proof") | |
| ), | |
| "counts_as_50_case_local_llm_eval": bool( | |
| local_evidence.get("counts_as_50_case_local_llm_eval") | |
| ), | |
| "counts_as_50_case_local_llm_competence": bool( | |
| local_evidence.get("counts_as_50_case_local_llm_competence") | |
| ), | |
| "base_url_host": _base_url_host(config.llama_base_url), | |
| "base_url_host_class": _base_url_host_class(config.llama_base_url), | |
| "note": ( | |
| "This manifest proves Figment used MODEL_BACKEND=llama_cpp against the configured " | |
| "OpenAI-compatible endpoint. For LAN or other local hosts, keep runtime evidence beside " | |
| "this bundle if judges need independent network-local attestation." | |
| ), | |
| }, | |
| "score_summary": { | |
| "total_cases": eval_summary.get("total_cases", len(records)), | |
| "raw_configured_model_successes": eval_summary.get("raw_configured_model_successes", 0), | |
| "repair_successes": eval_summary.get("repair_successes", 0), | |
| "competence_successes": eval_summary.get("competence_successes", 0), | |
| "fallback_uses": eval_summary.get("fallback_uses", 0), | |
| "canned_fallback_uses": eval_summary.get("canned_fallback_uses", 0), | |
| "final_validation_successes": eval_summary.get("final_validation_successes", 0), | |
| "expected_label_successes": eval_summary.get("expected_label_successes"), | |
| "expected_label_failures": eval_summary.get("expected_label_failures"), | |
| }, | |
| "case_ids": { | |
| "raw_success": _case_ids(records, "raw_configured_model_success"), | |
| "repair_success": _case_ids(records, "repair_success"), | |
| "full_fallback": _case_ids(records, "canned_fallback_used"), | |
| "competence_success": _case_ids(records, "competence_success"), | |
| }, | |
| "field_provenance": { | |
| "records_with_field_provenance": eval_summary.get("records_with_field_provenance", 0), | |
| "field_provenance_fields": eval_summary.get("field_provenance_fields", 0), | |
| "field_provenance_counts": eval_summary.get("field_provenance_counts", {}), | |
| "model_retained_field_count": eval_summary.get("model_retained_field_count", 0), | |
| "visible_field_provenance_count": eval_summary.get("visible_field_provenance_count", 0), | |
| "model_visible_field_count": eval_summary.get("model_visible_field_count", 0), | |
| "deterministic_patch_count": eval_summary.get("deterministic_patch_count", 0), | |
| "model_field_pass_rate": eval_summary.get("model_field_pass_rate", 0), | |
| "model_visible_fields_retained": eval_summary.get("model_visible_fields_retained", 0), | |
| }, | |
| "latency_ms": _latency_summary(latency_values), | |
| "trace_hash_count": len(trace_entries), | |
| "trace_hashes": trace_entries, | |
| "missing_trace_hash_case_ids": missing_trace_hash_case_ids, | |
| } | |
| def _read_eval_records(path: Path) -> list[dict[str, Any]]: | |
| if not path.exists(): | |
| return [] | |
| records: list[dict[str, Any]] = [] | |
| for line in path.read_text(encoding="utf-8").splitlines(): | |
| if line.strip(): | |
| records.append(json.loads(line)) | |
| return records | |
| def _file_sha256(path: Path) -> str | None: | |
| if not path.exists(): | |
| return None | |
| digest = hashlib.sha256() | |
| with path.open("rb") as handle: | |
| for chunk in iter(lambda: handle.read(1024 * 1024), b""): | |
| digest.update(chunk) | |
| return digest.hexdigest() | |
| def _advertised_model_ids(endpoint_payload: dict[str, Any]) -> list[str]: | |
| data = endpoint_payload.get("data") | |
| if not isinstance(data, list): | |
| return [] | |
| ids: list[str] = [] | |
| for item in data: | |
| if isinstance(item, dict) and item.get("id"): | |
| ids.append(str(item["id"])) | |
| return ids | |
| def _base_url_host(base_url: str) -> str | None: | |
| return urllib.parse.urlsplit(base_url).hostname | |
| def _base_url_host_class(base_url: str) -> str: | |
| host = _base_url_host(base_url) | |
| if not host: | |
| return "unknown" | |
| try: | |
| address = ipaddress.ip_address(host) | |
| except ValueError: | |
| lowered = host.lower() | |
| if lowered == "localhost" or lowered.endswith(".localhost"): | |
| return "loopback" | |
| if lowered.endswith(".local"): | |
| return "mdns_local" | |
| return "dns_name_unclassified" | |
| if address.is_loopback: | |
| return "loopback" | |
| if address.is_private: | |
| return "private_lan" | |
| if address.is_link_local: | |
| return "link_local" | |
| return "public_or_unclassified_ip" | |
| def _case_ids(records: list[dict[str, Any]], flag: str) -> list[str]: | |
| return [str(record.get("case_id")) for record in records if record.get(flag)] | |
| def _latency_summary(values: list[float]) -> dict[str, Any]: | |
| if not values: | |
| return { | |
| "case_count": 0, | |
| "min": None, | |
| "mean": None, | |
| "p50": None, | |
| "p95": None, | |
| "max": None, | |
| } | |
| sorted_values = sorted(values) | |
| return { | |
| "case_count": len(values), | |
| "min": round(sorted_values[0], 3), | |
| "mean": round(sum(sorted_values) / len(sorted_values), 3), | |
| "p50": round(_percentile(sorted_values, 0.50), 3), | |
| "p95": round(_percentile(sorted_values, 0.95), 3), | |
| "max": round(sorted_values[-1], 3), | |
| } | |
| def _percentile(sorted_values: list[float], percentile: float) -> float: | |
| if len(sorted_values) == 1: | |
| return sorted_values[0] | |
| index = percentile * (len(sorted_values) - 1) | |
| lower = int(index) | |
| upper = min(lower + 1, len(sorted_values) - 1) | |
| fraction = index - lower | |
| return sorted_values[lower] + (sorted_values[upper] - sorted_values[lower]) * fraction | |
| def _local_4b_env(base_url: str, model_id: str, timeout_seconds: float) -> Any: | |
| overrides = { | |
| "PYTHON_DOTENV_DISABLED": "true", | |
| "FIGMENT_MODE": "local", | |
| "MODEL_STACK": "local_4b_parakeet", | |
| "MODEL_BACKEND": "llama_cpp", | |
| "AUDIO_BACKEND": "none", | |
| "LOCAL_MODEL_ID": model_id, | |
| "LLAMA_BASE_URL": base_url, | |
| "FIGMENT_SMOKE_ALLOW_NETWORK": "true", | |
| "FIGMENT_MODEL_TIMEOUT_SECONDS": str(timeout_seconds), | |
| } | |
| previous = {key: os.environ.get(key) for key in overrides} | |
| os.environ.update(overrides) | |
| try: | |
| yield | |
| finally: | |
| for key, value in previous.items(): | |
| if value is None: | |
| os.environ.pop(key, None) | |
| else: | |
| os.environ[key] = value | |
| def _write_json(path: Path, payload: dict[str, Any]) -> None: | |
| path.write_text(f"{json.dumps(payload, indent=2, sort_keys=True)}\n", encoding="utf-8") | |
| def _default_output_dir() -> Path: | |
| stamp = strftime("%Y%m%dT%H%M%SZ", gmtime()) | |
| return Path("traces") / f"local_4b_evidence_{stamp}" | |
| def main(argv: list[str] | None = None) -> int: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--base-url", default=os.getenv("LLAMA_BASE_URL", DEFAULT_BASE_URL)) | |
| parser.add_argument("--model-id", default=NVIDIA_NEMOTRON_3_NANO_4B_BF16_MODEL_ID) | |
| parser.add_argument("--output-dir", type=Path, default=None) | |
| parser.add_argument("--cases", action="append", default=None, help="JSONL eval case path. Repeatable.") | |
| parser.add_argument("--limit", type=int, default=None) | |
| parser.add_argument("--timeout-seconds", type=float, default=DEFAULT_TIMEOUT_SECONDS) | |
| parser.add_argument("--smoke-only", action="store_true") | |
| parser.add_argument("--force-eval", action="store_true") | |
| args = parser.parse_args(argv) | |
| output_dir = args.output_dir or _default_output_dir() | |
| case_paths = [Path(path) for path in args.cases] if args.cases else list(DEFAULT_CASE_PATHS) | |
| summary = run_evidence( | |
| base_url=args.base_url, | |
| model_id=args.model_id, | |
| output_dir=output_dir, | |
| case_paths=case_paths, | |
| limit=args.limit, | |
| timeout_seconds=args.timeout_seconds, | |
| smoke_only=args.smoke_only, | |
| force_eval=args.force_eval, | |
| ) | |
| print(json.dumps(summary, indent=2, sort_keys=True)) | |
| if summary["status"] in {"eval_completed", "smoke_passed"}: | |
| return 0 | |
| if summary["status"] == "endpoint_unavailable": | |
| return 2 | |
| return 1 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |