Read results
After a turn that solves there are three things to read: the execution record, the files the run wrote, and the snapshot it froze.
The latest execution
Section titled “The latest execution”listExecutions returns newest-first, so index 0 is the most recent run.
const executions = await aura.listExecutions(project.id);const [latest] = executions;
console.log(latest.status); // e.g. "completed"console.log(latest.execution_time_ms);console.log(latest.output_summary); // the solver's own summaryconsole.log(latest.error_message); // set when the run failedexecutions = await aura.list_executions(project.id)latest = executions[0]
print(latest.status) # e.g. "completed"print(latest.execution_time_ms)print(latest.output_summary) # the solver's own summaryprint(latest.error_message) # set when the run failedFetch one by id with getExecution / get_execution — useful when you kept the id from an earlier
poll rather than re-listing.
File containers
Section titled “File containers”Every file operation names the container it targets, so the same four verbs — listFiles,
readFile, uploadFile, deleteFile — reach all three:
| Container | Holds | Mutable |
|---|---|---|
deployment |
The published model and data a project starts from | Yes |
workspace |
One project’s live files — the deployment’s, plus whatever the agent wrote | Yes |
snapshot |
One run’s captured state | No — writes are rejected with a 409 |
{ source: "deployment", deploymentName }{ source: "workspace", projectId }{ source: "snapshot", projectId, snapshotId }DeploymentFiles(deployment_name=...)WorkspaceFiles(project_id=...)SnapshotFiles(project_id=..., snapshot_id=...)This mirrors the server’s FileContainerRef, which requires exactly the identifiers a source needs
and rejects anything else. Modelling it as a union rather than a source string means an invalid
combination — a workspace carrying a snapshotId, say — fails to type-check instead of returning a
422.
Which container you want turns on when: the workspace is live and the next run overwrites it, a
snapshot is frozen, which is what keeps an old run’s solution retrievable.
Files the run wrote
Section titled “Files the run wrote”const workspace = { source: "workspace", projectId: project.id } as const;
// everything under run/output/const outputs = await aura.listFiles(workspace, "run/output/");for (const entry of outputs) console.log(entry.path, entry.size);
const solution = await aura.readFile(workspace, "run/output/solution.json");const parsed = JSON.parse(solution.text ?? "{}");import jsonfrom aura_sdk import WorkspaceFiles
workspace = WorkspaceFiles(project_id=project.id)
outputs = await aura.list_files(workspace, path_prefix="run/output/")for entry in outputs: print(entry.path, entry.size)
solution = await aura.read_file(workspace, "run/output/solution.json")parsed = json.loads(solution.text or "{}")A file read returns text for textual content and base64 for binary, with content_type naming
which. Check content_type rather than assuming text is populated.
Waiting for a solve to land
Section titled “Waiting for a solve to land”The agent runs the solver as part of a turn, so the usual shape is chat, then read.
const reply = await aura.chat(project.id, "Solve with the current inputs.", { timeoutMs: 15 * 60_000,});
const [execution] = await aura.listExecutions(project.id);if (execution.status !== "completed") { throw new Error(`Solve ${execution.status}: ${execution.error_message ?? "no detail"}`);}
const solution = await aura.readFile( { source: "workspace", projectId: project.id }, "run/output/solution.json",);reply = await aura.chat(project.id, "Solve with the current inputs.", timeout=15 * 60)
execution = (await aura.list_executions(project.id))[0]if execution.status != "completed": raise RuntimeError(f"Solve {execution.status}: {execution.error_message or 'no detail'}")
solution = await aura.read_file( WorkspaceFiles(project_id=project.id), "run/output/solution.json")Comparing two runs
Section titled “Comparing two runs”Every completed solve freezes a snapshot, so comparing runs means comparing snapshots rather than racing the live workspace.
const snapshots = await aura.listSnapshots(project.id); // newest firstconst [current, previous] = snapshots;
console.log(current.solution_summary, previous.solution_summary);
// each snapshot's own frozen copy, at the path that run recordedconst [a, b] = await Promise.all( [current, previous].map((snapshot) => aura.readFile( { source: "snapshot", projectId: project.id, snapshotId: snapshot.id }, snapshot.solution_path ?? "solutions/out.json", ), ),);from aura_sdk import SnapshotFiles
snapshots = await aura.list_snapshots(project.id) # newest firstcurrent, previous = snapshots[0], snapshots[1]
print(current.solution_summary, previous.solution_summary)
# each snapshot's own frozen copy, at the path that run recordeda, b = [ await aura.read_file( SnapshotFiles(project_id=project.id, snapshot_id=snapshot.id), snapshot.solution_path or "solutions/out.json", ) for snapshot in (current, previous)]Reading through the snapshot container rather than the workspace is what makes this a comparison
rather than a race: the live workspace holds only the most recent run’s output, so the older
solution exists nowhere else.
solution_path is the path the solver recorded for that run. A solution is JSON by convention only
— a solver may write any format — so treat the extension as data, not a guarantee.
Snapshots and tags covers naming the good ones and loading one back.