Pivot persistent APIs to workspaces

Replace the public persistent-sandbox contract with workspace-first naming across CLI, SDK, MCP, payloads, and on-disk state.

Rename the task surface to workspace equivalents, switch create-time seeding to `seed_path`, and store records under `workspaces/<workspace_id>/workspace.json` without carrying legacy task aliases or migrating old local task state.

Keep `pyro run` and `vm_*` unchanged. Validation covered `uv lock`, focused public-contract/API/CLI/manager tests, `UV_CACHE_DIR=.uv-cache make check`, and `UV_CACHE_DIR=.uv-cache make dist-check`.
This commit is contained in:
Thales Maciel 2026-03-12 01:21:49 -03:00
parent f57454bcb4
commit 48b82d8386
13 changed files with 743 additions and 618 deletions

View file

@ -31,9 +31,9 @@ def test_create_server_registers_vm_tools(tmp_path: Path) -> None:
assert "vm_network_info" in tool_names
assert "vm_run" in tool_names
assert "vm_status" in tool_names
assert "task_create" in tool_names
assert "task_logs" in tool_names
assert "task_sync_push" in tool_names
assert "workspace_create" in tool_names
assert "workspace_logs" in tool_names
assert "workspace_sync_push" in tool_names
def test_vm_run_round_trip(tmp_path: Path) -> None:
@ -166,7 +166,7 @@ def test_server_main_runs_stdio_transport(monkeypatch: pytest.MonkeyPatch) -> No
assert called == {"transport": "stdio"}
def test_task_tools_round_trip(tmp_path: Path) -> None:
def test_workspace_tools_round_trip(tmp_path: Path) -> None:
manager = VmManager(
backend_name="mock",
base_dir=tmp_path / "vms",
@ -194,23 +194,23 @@ def test_task_tools_round_trip(tmp_path: Path) -> None:
server = create_server(manager=manager)
created = _extract_structured(
await server.call_tool(
"task_create",
"workspace_create",
{
"environment": "debian:12-base",
"allow_host_compat": True,
"source_path": str(source_dir),
"seed_path": str(source_dir),
},
)
)
task_id = str(created["task_id"])
workspace_id = str(created["workspace_id"])
update_dir = tmp_path / "update"
update_dir.mkdir()
(update_dir / "more.txt").write_text("more\n", encoding="utf-8")
synced = _extract_structured(
await server.call_tool(
"task_sync_push",
"workspace_sync_push",
{
"task_id": task_id,
"workspace_id": workspace_id,
"source_path": str(update_dir),
"dest": "subdir",
},
@ -218,15 +218,19 @@ def test_task_tools_round_trip(tmp_path: Path) -> None:
)
executed = _extract_structured(
await server.call_tool(
"task_exec",
"workspace_exec",
{
"task_id": task_id,
"workspace_id": workspace_id,
"command": "cat subdir/more.txt",
},
)
)
logs = _extract_structured(await server.call_tool("task_logs", {"task_id": task_id}))
deleted = _extract_structured(await server.call_tool("task_delete", {"task_id": task_id}))
logs = _extract_structured(
await server.call_tool("workspace_logs", {"workspace_id": workspace_id})
)
deleted = _extract_structured(
await server.call_tool("workspace_delete", {"workspace_id": workspace_id})
)
return created, synced, executed, logs, deleted
created, synced, executed, logs, deleted = asyncio.run(_run())