style: ruff format after MCP server integration
Reformat the files touched by Tasks 1-14 of the host-agent MCP server plan. No semantic changes; pre-existing format issues in unrelated files (test_templates, test_skill_sync_wiring, 0010_skill_management, test_skill_catalog_mcp) left untouched for a separate housekeeping pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+12
-12
@@ -40,15 +40,17 @@ def tool_handlers(
|
||||
device_id=device_id,
|
||||
manager=manager,
|
||||
),
|
||||
"swipe": lambda start_x, start_y, end_x, end_y, duration_ms=500, device_id=None: call_with_semantic_errors(
|
||||
swipe,
|
||||
start_x,
|
||||
start_y,
|
||||
end_x,
|
||||
end_y,
|
||||
duration_ms=duration_ms,
|
||||
device_id=device_id,
|
||||
manager=manager,
|
||||
"swipe": lambda start_x, start_y, end_x, end_y, duration_ms=500, device_id=None: (
|
||||
call_with_semantic_errors(
|
||||
swipe,
|
||||
start_x,
|
||||
start_y,
|
||||
end_x,
|
||||
end_y,
|
||||
duration_ms=duration_ms,
|
||||
device_id=device_id,
|
||||
manager=manager,
|
||||
)
|
||||
),
|
||||
"input_text": lambda text, device_id=None: call_with_semantic_errors(
|
||||
input_text,
|
||||
@@ -85,9 +87,7 @@ def tool_handlers(
|
||||
"describe_screen": lambda device_id=None: call_with_semantic_errors(
|
||||
lambda: describe_screen(device_id, manager=manager).to_dict()
|
||||
),
|
||||
"list_devices": lambda: [
|
||||
device.to_dict() for device in manager.list_devices()
|
||||
],
|
||||
"list_devices": lambda: [device.to_dict() for device in manager.list_devices()],
|
||||
"device_status": lambda device_id: call_with_semantic_errors(
|
||||
lambda: {"device_id": device_id, "status": manager.status(device_id)}
|
||||
),
|
||||
|
||||
@@ -51,8 +51,7 @@ class AssignmentExecutor:
|
||||
return AssignmentExecutionResult(
|
||||
status="failed",
|
||||
failure_reason=(
|
||||
f"device {assignment.device_id} is held by an active "
|
||||
"MCP session"
|
||||
f"device {assignment.device_id} is held by an active MCP session"
|
||||
),
|
||||
)
|
||||
with bind_planner_execution_context(assignment):
|
||||
|
||||
@@ -57,9 +57,7 @@ class McpBusyTracker:
|
||||
lease = McpDeviceLease(
|
||||
device_id=device_id,
|
||||
session_id=session_id,
|
||||
acquired_at=(
|
||||
existing.acquired_at if existing is not None else now
|
||||
),
|
||||
acquired_at=(existing.acquired_at if existing is not None else now),
|
||||
last_seen_at=now,
|
||||
)
|
||||
self._leases[device_id] = lease
|
||||
@@ -154,4 +152,4 @@ class McpBusyTracker:
|
||||
if (cutoff - lease.last_seen_at).total_seconds() > self._ttl
|
||||
]
|
||||
for device_id in expired:
|
||||
del self._leases[device_id]
|
||||
del self._leases[device_id]
|
||||
|
||||
@@ -74,9 +74,7 @@ class McpTokenStore:
|
||||
created_at=datetime.fromisoformat(str(data["created_at"])),
|
||||
)
|
||||
except (KeyError, TypeError, ValueError) as exc:
|
||||
raise McpTokenStoreError(
|
||||
f"MCP token file schema invalid: {exc}"
|
||||
) from exc
|
||||
raise McpTokenStoreError(f"MCP token file schema invalid: {exc}") from exc
|
||||
|
||||
def _generate_and_write(self) -> McpToken:
|
||||
token = McpToken(
|
||||
|
||||
@@ -141,9 +141,7 @@ def _wrap_tool(
|
||||
return _with_display_status(handler, status_tracker, *args, **kwargs)
|
||||
|
||||
if device_id is not None and tool_name not in _NON_DEVICE_TOOLS:
|
||||
_check_and_acquire(
|
||||
device_id, session_id, mcp_busy_tracker, status_tracker
|
||||
)
|
||||
_check_and_acquire(device_id, session_id, mcp_busy_tracker, status_tracker)
|
||||
|
||||
return handler(*args, **kwargs)
|
||||
|
||||
@@ -254,4 +252,4 @@ def _call_tool_sync(
|
||||
raise KeyError(f"tool {tool_name!r} has no callable")
|
||||
return fn(**arguments)
|
||||
finally:
|
||||
_TEST_SESSION_ID.reset(token)
|
||||
_TEST_SESSION_ID.reset(token)
|
||||
|
||||
@@ -697,9 +697,7 @@ def test_create_application_wires_mcp_components(tmp_path, monkeypatch) -> None:
|
||||
|
||||
# Build the same console app the production path builds and verify /mcp
|
||||
# is mounted (responds 401, not 404) without a bearer token.
|
||||
mcp_token_store = McpTokenStore(
|
||||
config.identity_path.parent / "host_mcp_token.json"
|
||||
)
|
||||
mcp_token_store = McpTokenStore(config.identity_path.parent / "host_mcp_token.json")
|
||||
mcp_token_store.load_or_create()
|
||||
mcp_busy_tracker = McpBusyTracker(ttl_seconds=60.0)
|
||||
mcp_server = build_mcp_server(
|
||||
|
||||
@@ -154,7 +154,14 @@ def test_workflow_assignment_maps_cancellation_stop_to_cancelled_status() -> Non
|
||||
return object() if definition_id == "workflow-a" else None
|
||||
|
||||
class FakeWorkflowRunner:
|
||||
def run(self, loaded_definition, device_id: str, *, should_stop=None, stop_reason=None):
|
||||
def run(
|
||||
self,
|
||||
loaded_definition,
|
||||
device_id: str,
|
||||
*,
|
||||
should_stop=None,
|
||||
stop_reason=None,
|
||||
):
|
||||
assert should_stop is not None and should_stop()
|
||||
assert stop_reason is not None
|
||||
return SimpleNamespace(
|
||||
|
||||
@@ -150,7 +150,9 @@ def test_duplicate_instance_exits_with_clear_error(
|
||||
|
||||
def test_mcp_token_subcommand_prints_token(tmp_path, capsys, monkeypatch) -> None:
|
||||
monkeypatch.setenv("HOST_AGENT_IDENTITY_PATH", str(tmp_path / "host_identity.json"))
|
||||
monkeypatch.setenv("HOST_AGENT_LOCAL_ACCOUNT_PATH", str(tmp_path / "host_local_account.json"))
|
||||
monkeypatch.setenv(
|
||||
"HOST_AGENT_LOCAL_ACCOUNT_PATH", str(tmp_path / "host_local_account.json")
|
||||
)
|
||||
# Also set control plane URL to satisfy config loading
|
||||
monkeypatch.setenv("HOST_AGENT_CONTROL_PLANE_URL", "https://cloud.example")
|
||||
from host_agent.cli import main
|
||||
|
||||
@@ -61,7 +61,9 @@ def test_heartbeat_synchronizer_runs_at_configured_interval_until_stopped() -> N
|
||||
calls: list[list[str]] = []
|
||||
|
||||
class FakeClient:
|
||||
async def heartbeat(self, devices, *, address=None, policy_revision=0, **kwargs):
|
||||
async def heartbeat(
|
||||
self, devices, *, address=None, policy_revision=0, **kwargs
|
||||
):
|
||||
calls.append([device.device_id for device in devices])
|
||||
return HeartbeatResponse(
|
||||
host_id="host-a",
|
||||
@@ -99,7 +101,9 @@ def test_sync_once_notifies_status_tracker_and_on_sync_with_device_count() -> No
|
||||
)
|
||||
|
||||
class FakeClient:
|
||||
async def heartbeat(self, devices, *, address=None, policy_revision=0, **kwargs):
|
||||
async def heartbeat(
|
||||
self, devices, *, address=None, policy_revision=0, **kwargs
|
||||
):
|
||||
return HeartbeatResponse(
|
||||
host_id="host-a",
|
||||
accepted_devices=len(devices),
|
||||
@@ -134,7 +138,9 @@ def test_heartbeat_caches_safe_host_policy_and_reuses_its_revision(tmp_path) ->
|
||||
revisions: list[int] = []
|
||||
|
||||
class UpdatingClient:
|
||||
async def heartbeat(self, devices, *, address=None, policy_revision=0, **kwargs):
|
||||
async def heartbeat(
|
||||
self, devices, *, address=None, policy_revision=0, **kwargs
|
||||
):
|
||||
revisions.append(policy_revision)
|
||||
return HeartbeatResponse(
|
||||
host_id="host-a",
|
||||
@@ -176,9 +182,7 @@ def test_heartbeat_caches_safe_host_policy_and_reuses_its_revision(tmp_path) ->
|
||||
|
||||
asyncio.run(scenario())
|
||||
assert revisions == [0]
|
||||
assert '"token":' not in (
|
||||
tmp_path / "host_policy.json"
|
||||
).read_text(encoding="utf-8")
|
||||
assert '"token":' not in (tmp_path / "host_policy.json").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_sync_once_passes_mcp_busy_device_ids_to_client() -> None:
|
||||
@@ -189,7 +193,9 @@ def test_sync_once_passes_mcp_busy_device_ids_to_client() -> None:
|
||||
last_kwargs: dict[str, object] = {}
|
||||
|
||||
class FakeClient:
|
||||
async def heartbeat(self, devices, *, address=None, policy_revision=0, **kwargs):
|
||||
async def heartbeat(
|
||||
self, devices, *, address=None, policy_revision=0, **kwargs
|
||||
):
|
||||
last_kwargs.update(kwargs)
|
||||
return HeartbeatResponse(
|
||||
host_id="host-a",
|
||||
@@ -216,7 +222,9 @@ def test_sync_once_passes_empty_when_tracker_is_none() -> None:
|
||||
last_kwargs: dict[str, object] = {}
|
||||
|
||||
class FakeClient:
|
||||
async def heartbeat(self, devices, *, address=None, policy_revision=0, **kwargs):
|
||||
async def heartbeat(
|
||||
self, devices, *, address=None, policy_revision=0, **kwargs
|
||||
):
|
||||
last_kwargs.update(kwargs)
|
||||
return HeartbeatResponse(
|
||||
host_id="host-a",
|
||||
|
||||
@@ -100,9 +100,7 @@ def test_snapshot_matches_busy_device_ids() -> None:
|
||||
|
||||
def test_wait_until_usable_succeeds_when_free() -> None:
|
||||
tracker, _ = _tracker_with_now()
|
||||
ok = tracker.wait_until_usable(
|
||||
"phone-1", "sess-a", timeout=1.0, poll_interval=0.01
|
||||
)
|
||||
ok = tracker.wait_until_usable("phone-1", "sess-a", timeout=1.0, poll_interval=0.01)
|
||||
assert ok is True
|
||||
assert "phone-1" in tracker.busy_device_ids()
|
||||
|
||||
@@ -110,9 +108,7 @@ def test_wait_until_usable_succeeds_when_free() -> None:
|
||||
def test_wait_until_usable_returns_false_on_timeout() -> None:
|
||||
tracker, _ = _tracker_with_now()
|
||||
tracker.acquire("phone-1", "sess-a")
|
||||
ok = tracker.wait_until_usable(
|
||||
"phone-1", "sess-b", timeout=0.1, poll_interval=0.02
|
||||
)
|
||||
ok = tracker.wait_until_usable("phone-1", "sess-b", timeout=0.1, poll_interval=0.02)
|
||||
assert ok is False
|
||||
|
||||
|
||||
@@ -147,4 +143,4 @@ def test_wait_until_usable_blocks_then_fails_when_cloud_remains_busy() -> None:
|
||||
cloud_busy_check=lambda: True,
|
||||
)
|
||||
assert ok is False
|
||||
assert tracker.busy_device_ids() == []
|
||||
assert tracker.busy_device_ids() == []
|
||||
|
||||
@@ -833,9 +833,7 @@ def _seed_local_task(
|
||||
source_task_id: str | None = "cloud-task-1",
|
||||
) -> str:
|
||||
task = Task(goal="open settings", device_id="dev-1", status=status)
|
||||
metadata_store.create_task(
|
||||
task, source_task_id=source_task_id, source_attempt=1
|
||||
)
|
||||
metadata_store.create_task(task, source_task_id=source_task_id, source_attempt=1)
|
||||
return task.id
|
||||
|
||||
|
||||
|
||||
@@ -52,7 +52,9 @@ class _FakeDriver(Driver):
|
||||
) -> None:
|
||||
return None
|
||||
|
||||
def swipe_path(self, waypoints: list[tuple[float, float]], duration_ms: int) -> None:
|
||||
def swipe_path(
|
||||
self, waypoints: list[tuple[float, float]], duration_ms: int
|
||||
) -> None:
|
||||
return None
|
||||
|
||||
def double_tap(self, x: float, y: float, interval_ms: int = 80) -> None:
|
||||
@@ -307,4 +309,4 @@ def test_wrapped_tool_accepts_context_kwarg() -> None:
|
||||
tool_manager = server._tool_manager # type: ignore[attr-defined]
|
||||
tool = tool_manager.get_tool("take_screenshot")
|
||||
assert tool is not None
|
||||
assert tool.context_kwarg == "ctx"
|
||||
assert tool.context_kwarg == "ctx"
|
||||
|
||||
@@ -25,4 +25,4 @@ def upgrade() -> None:
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("pooled_devices", "mcp_busy")
|
||||
op.drop_column("pooled_devices", "mcp_busy")
|
||||
|
||||
@@ -82,9 +82,7 @@ class DevicePool:
|
||||
)
|
||||
busy_set = set(mcp_busy_device_ids or [])
|
||||
devices = [
|
||||
self._to_pooled(
|
||||
device, host_id, now, mcp_busy=device.id in busy_set
|
||||
)
|
||||
self._to_pooled(device, host_id, now, mcp_busy=device.id in busy_set)
|
||||
for device in snapshot
|
||||
]
|
||||
if allow_device_takeover:
|
||||
|
||||
@@ -48,9 +48,7 @@ def test_sync_host_devices_marks_mcp_busy_devices(pool: DevicePool) -> None:
|
||||
|
||||
|
||||
def test_sync_host_devices_default_mcp_busy_is_false(pool: DevicePool) -> None:
|
||||
pool.sync_host_devices(
|
||||
"host-1", [_device("device-1", status="idle")]
|
||||
)
|
||||
pool.sync_host_devices("host-1", [_device("device-1", status="idle")])
|
||||
devices = pool.list_devices()
|
||||
assert devices[0].mcp_busy is False
|
||||
|
||||
@@ -65,8 +63,6 @@ def test_sync_host_devices_clears_mcp_busy_on_next_sync(
|
||||
[_device("device-1", status="idle")],
|
||||
mcp_busy_device_ids=["device-1"],
|
||||
)
|
||||
pool.sync_host_devices(
|
||||
"host-1", [_device("device-1", status="idle")]
|
||||
)
|
||||
pool.sync_host_devices("host-1", [_device("device-1", status="idle")])
|
||||
devices = pool.list_devices()
|
||||
assert devices[0].mcp_busy is False
|
||||
assert devices[0].mcp_busy is False
|
||||
|
||||
@@ -50,4 +50,4 @@ def test_mcp_busy_device_is_skipped_by_scheduler(pool: DevicePool) -> None:
|
||||
scheduler.submit(goal="test", constraints=TaskConstraints())
|
||||
assignments = scheduler.assign()
|
||||
assert len(assignments) == 1
|
||||
assert assignments[0].device_id == "dev-idle"
|
||||
assert assignments[0].device_id == "dev-idle"
|
||||
|
||||
Reference in New Issue
Block a user