feat(planner): persist reusable action semantics
Tests / Test passed: 879

This commit is contained in:
2026-07-15 18:14:28 +08:00
parent 361dada276
commit d69be48f96
41 changed files with 733 additions and 116 deletions
+43 -4
View File
@@ -94,6 +94,44 @@ def test_unknown_task_id_returns_404(tmp_path) -> None:
assert resp.status_code == 404, resp.text
def test_planner_decision_history_returns_reusable_action_metadata(tmp_path) -> None:
app, pool, scheduler, _ = _build_app(tmp_path)
task_id = scheduler.submit(goal="open settings")
pool.store.record_planner_decision(
host_id="host-a",
task_id=task_id,
attempt=0,
system_prompt="system",
user_prompt="open settings",
tool_name="tap",
arguments_json='{"x": 12, "y": 34}',
now=datetime.now(UTC),
rationale="The settings tab is visible. Opening it.",
thinking="A tap should navigate to settings.",
purpose="Open settings.",
expected_outcome="The settings page is visible.",
)
response = _client_for(app).get(f"/v1/tasks/{task_id}/planner-decisions?attempt=0")
assert response.status_code == 200, response.text
assert response.json()["items"] == [
{
"step_index": 1,
"attempt": 0,
"system_prompt": "system",
"user_prompt": "open settings",
"tool_name": "tap",
"arguments": {"x": 12, "y": 34},
"rationale": "The settings tab is visible. Opening it.",
"thinking": "A tap should navigate to settings.",
"purpose": "Open settings.",
"expected_outcome": "The settings page is visible.",
"created_at": response.json()["items"][0]["created_at"],
}
]
def test_task_status_exposes_distributed_metadata_without_lease_secret(
tmp_path,
) -> None:
@@ -299,7 +337,10 @@ def test_submit_with_explicit_target_is_listed_and_not_rerouted(tmp_path) -> Non
assert task["assigned_host_id"] == "host-b"
assert task["assigned_device_id"] == "device-b"
listed = client.get("/v1/tasks").json()["items"]
assert next(item for item in listed if item["id"] == task_id)["target_host_id"] == "host-b"
assert (
next(item for item in listed if item["id"] == task_id)["target_host_id"]
== "host-b"
)
def test_submit_rejects_incomplete_or_foreign_target(tmp_path) -> None:
@@ -429,9 +470,7 @@ def test_list_tasks_returns_summary_with_pagination_and_status_filter(
assert [item["id"] for item in queued_only["items"]] == [second_id]
assert all(item["status"] == "queued" for item in queued_only["items"])
assigned_only = client.get(
"/v1/tasks", params={"status": "assigned"}
).json()
assigned_only = client.get("/v1/tasks", params={"status": "assigned"}).json()
assert assigned_only["total"] == 1
assert [item["id"] for item in assigned_only["items"]] == [assigned_id]