Add planner previews and streaming
Some checks failed
CI / test (push) Failing after 45s

This commit is contained in:
2026-04-05 19:33:24 +02:00
parent b1d2b6b321
commit 1b0b9cfdef
12 changed files with 332 additions and 31 deletions

View File

@@ -24,6 +24,32 @@ class DummySkill(ClickthroughSkill):
],
}
def plan_with_planner(
self,
grid_id: str,
preferred_label: str | None = None,
action: str = "click",
text: str | None = None,
comment: str | None = None,
) -> Dict[str, Any]:
cells = ["dummy-grid-1", "dummy-grid-2"]
if preferred_label == "target":
target = "dummy-grid-2"
else:
target = cells[len(cells) // 2]
plan = {
"grid_id": grid_id,
"target_cell": target,
"action": action,
"text": text,
"comment": comment,
}
return {
"plan": plan,
"result": {"success": True, "detail": "preview"},
"descriptor": {"grid_id": grid_id},
}
def plan_action(self, plan: ActionPlan) -> Dict[str, Any]:
self.last_plan = plan
return {"success": True, "target_cell": plan.target_cell}

32
tests/test_endpoints.py Normal file
View File

@@ -0,0 +1,32 @@
from fastapi.testclient import TestClient
from server.main import app, manager
test_client = TestClient(app)
def test_plan_endpoint(default_grid_request):
init_response = test_client.post("/grid/init", json=default_grid_request)
grid_id = init_response.json()["grid_id"]
plan_response = test_client.post(
f"/grid/{grid_id}/plan",
json={"preferred_label": None, "action": "click", "text": "hello"},
)
assert plan_response.status_code == 200
payload = plan_response.json()
assert payload["plan"]["grid_id"] == grid_id
assert payload["result"]["success"]
def test_refresh_endpoint(default_grid_request):
init_response = test_client.post("/grid/init", json=default_grid_request)
grid_id = init_response.json()["grid_id"]
refresh_response = test_client.post(
f"/grid/{grid_id}/refresh", json={"screenshot_base64": "AAA", "memo": "updated"}
)
assert refresh_response.status_code == 200
grid = manager.get_grid(grid_id)
assert grid.screenshot == "AAA"
assert grid.memo == "updated"

32
tests/test_planner.py Normal file
View File

@@ -0,0 +1,32 @@
from server.config import ServerSettings
from server.grid import GridManager
from server.planner import GridPlanner
from server.models import ActionType, GridInitRequest
def test_planner_preferred_label(default_grid_request):
settings = ServerSettings()
manager = GridManager(settings)
request = GridInitRequest(**default_grid_request)
grid = manager.create_grid(request)
descriptor = grid.describe()
descriptor.cells[0].label = "target"
planner = GridPlanner()
payload = planner.build_payload(descriptor, preferred_label="target", action=ActionType.CLICK)
assert payload.target_cell == descriptor.cells[0].cell_id
def test_planner_falls_back_to_center(default_grid_request):
settings = ServerSettings()
manager = GridManager(settings)
request = GridInitRequest(**default_grid_request)
grid = manager.create_grid(request)
descriptor = grid.describe()
planner = GridPlanner()
payload = planner.build_payload(descriptor, action=ActionType.CLICK)
assert payload.target_cell is not None
assert payload.grid_id == descriptor.grid_id

41
tests/test_streamer.py Normal file
View File

@@ -0,0 +1,41 @@
import asyncio
from server.streamer import ScreenshotStreamer
class DummyWebSocket:
def __init__(self):
self.sent = []
self.accepted = False
async def accept(self) -> None:
self.accepted = True
async def send_json(self, payload):
self.sent.append(payload)
def test_streamer_broadcasts_to_grid():
streamer = ScreenshotStreamer()
socket = DummyWebSocket()
async def scenario():
key = await streamer.connect(socket, "grid-123")
await streamer.broadcast("grid-123", {"frame": 1})
streamer.disconnect(socket, key)
asyncio.run(scenario())
assert socket.sent == [{"frame": 1}]
def test_streamer_wildcard_listener_receives_updates():
streamer = ScreenshotStreamer()
socket = DummyWebSocket()
async def scenario():
key = await streamer.connect(socket, None)
await streamer.broadcast("grid-456", {"frame": 2})
streamer.disconnect(socket, key)
asyncio.run(scenario())
assert socket.sent == [{"frame": 2}]