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
+28 -3
View File
@@ -96,7 +96,14 @@ def _decision_payload(**overrides: object) -> dict[str, object]:
def test_authenticated_host_resolves_planner_decision(tmp_path) -> None:
fake_client = _FakeToolCallingClient(
decision=ToolCallDecision(tool_name="tap", arguments={"x": 1, "y": 2})
decision=ToolCallDecision(
tool_name="tap",
arguments={"x": 1, "y": 2},
text_output="The login button is visible. Opening it.",
thinking="The next screen should be the account page.",
purpose="Open the login screen.",
expected_outcome="The login form is visible.",
)
)
client, fake_client, _pool = _build_client(tmp_path, fake_client=fake_client)
@@ -107,7 +114,14 @@ def test_authenticated_host_resolves_planner_decision(tmp_path) -> None:
)
assert response.status_code == 200
assert response.json() == {"tool_name": "tap", "arguments": {"x": 1, "y": 2}}
assert response.json() == {
"tool_name": "tap",
"arguments": {"x": 1, "y": 2},
"rationale": "The login button is visible. Opening it.",
"thinking": "The next screen should be the account page.",
"purpose": "Open the login screen.",
"expected_outcome": "The login form is visible.",
}
assert len(fake_client.calls) == 1
assert fake_client.calls[0]["system_prompt"] == "you are a planner"
assert fake_client.calls[0]["timeout"] == 30.0
@@ -232,7 +246,14 @@ def _seed_attempt(pool: DevicePool, task_id: str, host_id: str = "host-a") -> No
def test_successful_decision_is_persisted_with_correct_fields(tmp_path) -> None:
fake_client = _FakeToolCallingClient(
decision=ToolCallDecision(tool_name="tap", arguments={"x": 10, "y": 20})
decision=ToolCallDecision(
tool_name="tap",
arguments={"x": 10, "y": 20},
text_output="The settings tab is visible. Opening it.",
thinking="A tap should navigate to settings.",
purpose="Open settings.",
expected_outcome="The settings page is visible.",
)
)
client, fake_client, pool = _build_client(tmp_path, fake_client=fake_client)
_seed_attempt(pool, "task-log-1")
@@ -259,6 +280,10 @@ def test_successful_decision_is_persisted_with_correct_fields(tmp_path) -> None:
assert row.tool_name == "tap"
assert '"x": 10' in row.arguments_json
assert '"y": 20' in row.arguments_json
assert row.rationale == "The settings tab is visible. Opening it."
assert row.thinking == "A tap should navigate to settings."
assert row.purpose == "Open settings."
assert row.expected_outcome == "The settings page is visible."
def test_failed_decision_persists_nothing(tmp_path) -> None: