From e69cea024524d26784bb51fc5d31ad2ec3f67f90 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 21 Jul 2026 15:52:32 +0800 Subject: [PATCH] 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 --- api/mcp.py | 24 +++++++++---------- .../host_agent/assignment.py | 3 +-- apps/device-host-agent/host_agent/mcp_lock.py | 6 ++--- .../device-host-agent/host_agent/mcp_token.py | 4 +--- apps/device-host-agent/host_agent/web/mcp.py | 6 ++--- apps/device-host-agent/tests/test_app.py | 4 +--- .../tests/test_assignment.py | 9 ++++++- apps/device-host-agent/tests/test_cli.py | 4 +++- .../device-host-agent/tests/test_heartbeat.py | 24 ++++++++++++------- apps/device-host-agent/tests/test_mcp_lock.py | 10 +++----- apps/device-host-agent/tests/test_web_app.py | 4 +--- apps/device-host-agent/tests/test_web_mcp.py | 6 +++-- .../versions/0014_pooled_device_mcp_busy.py | 2 +- packages/cloud-platform/cloud/pool.py | 4 +--- packages/cloud-platform/tests/test_pool.py | 10 +++----- .../cloud-platform/tests/test_scheduler.py | 2 +- 16 files changed, 60 insertions(+), 62 deletions(-) diff --git a/api/mcp.py b/api/mcp.py index 17d9b9d..d9c3f85 100644 --- a/api/mcp.py +++ b/api/mcp.py @@ -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)} ), diff --git a/apps/device-host-agent/host_agent/assignment.py b/apps/device-host-agent/host_agent/assignment.py index 28ce190..cdea87b 100644 --- a/apps/device-host-agent/host_agent/assignment.py +++ b/apps/device-host-agent/host_agent/assignment.py @@ -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): diff --git a/apps/device-host-agent/host_agent/mcp_lock.py b/apps/device-host-agent/host_agent/mcp_lock.py index a3bd5ab..dd33399 100644 --- a/apps/device-host-agent/host_agent/mcp_lock.py +++ b/apps/device-host-agent/host_agent/mcp_lock.py @@ -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] \ No newline at end of file + del self._leases[device_id] diff --git a/apps/device-host-agent/host_agent/mcp_token.py b/apps/device-host-agent/host_agent/mcp_token.py index a4cb0ca..3238eb1 100644 --- a/apps/device-host-agent/host_agent/mcp_token.py +++ b/apps/device-host-agent/host_agent/mcp_token.py @@ -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( diff --git a/apps/device-host-agent/host_agent/web/mcp.py b/apps/device-host-agent/host_agent/web/mcp.py index 1846403..f41c91f 100644 --- a/apps/device-host-agent/host_agent/web/mcp.py +++ b/apps/device-host-agent/host_agent/web/mcp.py @@ -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) \ No newline at end of file + _TEST_SESSION_ID.reset(token) diff --git a/apps/device-host-agent/tests/test_app.py b/apps/device-host-agent/tests/test_app.py index 685c3de..08ec8f7 100644 --- a/apps/device-host-agent/tests/test_app.py +++ b/apps/device-host-agent/tests/test_app.py @@ -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( diff --git a/apps/device-host-agent/tests/test_assignment.py b/apps/device-host-agent/tests/test_assignment.py index b27180c..c1bdeaa 100644 --- a/apps/device-host-agent/tests/test_assignment.py +++ b/apps/device-host-agent/tests/test_assignment.py @@ -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( diff --git a/apps/device-host-agent/tests/test_cli.py b/apps/device-host-agent/tests/test_cli.py index 9061ade..a590c44 100644 --- a/apps/device-host-agent/tests/test_cli.py +++ b/apps/device-host-agent/tests/test_cli.py @@ -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 diff --git a/apps/device-host-agent/tests/test_heartbeat.py b/apps/device-host-agent/tests/test_heartbeat.py index d865de7..08a8a0f 100644 --- a/apps/device-host-agent/tests/test_heartbeat.py +++ b/apps/device-host-agent/tests/test_heartbeat.py @@ -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", diff --git a/apps/device-host-agent/tests/test_mcp_lock.py b/apps/device-host-agent/tests/test_mcp_lock.py index c02f9e9..c44ef1e 100644 --- a/apps/device-host-agent/tests/test_mcp_lock.py +++ b/apps/device-host-agent/tests/test_mcp_lock.py @@ -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() == [] \ No newline at end of file + assert tracker.busy_device_ids() == [] diff --git a/apps/device-host-agent/tests/test_web_app.py b/apps/device-host-agent/tests/test_web_app.py index 36062a7..a73fea6 100644 --- a/apps/device-host-agent/tests/test_web_app.py +++ b/apps/device-host-agent/tests/test_web_app.py @@ -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 diff --git a/apps/device-host-agent/tests/test_web_mcp.py b/apps/device-host-agent/tests/test_web_mcp.py index 140729a..e10f001 100644 --- a/apps/device-host-agent/tests/test_web_mcp.py +++ b/apps/device-host-agent/tests/test_web_mcp.py @@ -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" \ No newline at end of file + assert tool.context_kwarg == "ctx" diff --git a/packages/cloud-platform/cloud/migrations/versions/0014_pooled_device_mcp_busy.py b/packages/cloud-platform/cloud/migrations/versions/0014_pooled_device_mcp_busy.py index e8bd338..3fcce4c 100644 --- a/packages/cloud-platform/cloud/migrations/versions/0014_pooled_device_mcp_busy.py +++ b/packages/cloud-platform/cloud/migrations/versions/0014_pooled_device_mcp_busy.py @@ -25,4 +25,4 @@ def upgrade() -> None: def downgrade() -> None: - op.drop_column("pooled_devices", "mcp_busy") \ No newline at end of file + op.drop_column("pooled_devices", "mcp_busy") diff --git a/packages/cloud-platform/cloud/pool.py b/packages/cloud-platform/cloud/pool.py index ce09e63..a9ddabd 100644 --- a/packages/cloud-platform/cloud/pool.py +++ b/packages/cloud-platform/cloud/pool.py @@ -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: diff --git a/packages/cloud-platform/tests/test_pool.py b/packages/cloud-platform/tests/test_pool.py index cf85a53..7755306 100644 --- a/packages/cloud-platform/tests/test_pool.py +++ b/packages/cloud-platform/tests/test_pool.py @@ -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 \ No newline at end of file + assert devices[0].mcp_busy is False diff --git a/packages/cloud-platform/tests/test_scheduler.py b/packages/cloud-platform/tests/test_scheduler.py index c2425a9..ef78447 100644 --- a/packages/cloud-platform/tests/test_scheduler.py +++ b/packages/cloud-platform/tests/test_scheduler.py @@ -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" \ No newline at end of file + assert assignments[0].device_id == "dev-idle"