Skip to content

Code Examples

These examples show the common ways to run uisurf-agent from Python and from the CLI. They assume dependencies are installed with uv sync and model credentials are available in the environment.

Browser Agent From Python

Use BrowserAgent when the task lives inside websites or web applications.

import asyncio

from uisurf_agent import BrowserAgent


async def main() -> None:
    async with BrowserAgent(
        auto_mode=True,
        headless=True,
        fast_mode=True,
        max_observation_images=2,
        observation_scale=0.75,
    ) as agent:
        async for event in agent.run(
            "Open https://example.com and summarize the page.",
            max_steps=12,
        ):
            print(event.eventType, event.payload, "final=", event.isFinal)


if __name__ == "__main__":
    asyncio.run(main())

Run the same kind of task from the CLI:

uv run uisurf_agent run browser_agent \
  --task "Open https://example.com and summarize the page" \
  --headless \
  --fast-mode \
  --auto-mode \
  --max-steps 12

Desktop Agent From Python

Use DesktopAgent when the task needs local operating-system UI control, terminal windows, file dialogs, or native applications.

import asyncio

from uisurf_agent import DesktopAgent


async def main() -> None:
    async with DesktopAgent(
        auto_mode=True,
        observation_delay_ms=750,
        max_observation_images=2,
        observation_scale=0.75,
    ) as agent:
        async for event in agent.run(
            "Open Terminal and run pwd.",
            max_steps=10,
        ):
            print(event.eventType, event.payload, "final=", event.isFinal)


if __name__ == "__main__":
    asyncio.run(main())

Run the same kind of task from the CLI:

uv run uisurf_agent run desktop_agent \
  --task "Open Terminal and run pwd" \
  --desktop-observation-delay-ms 750 \
  --auto-mode \
  --max-steps 10

Mobile Agent From Python

Use MobileAgent when the task depends on an Android device or emulator. If serial is omitted, the controller uses the first authorized ADB device.

import asyncio

from uisurf_agent import MobileAgent


async def main() -> None:
    async with MobileAgent(
        auto_mode=True,
        serial=None,
        observation_delay_ms=500,
        max_observation_images=2,
        observation_scale=0.75,
    ) as agent:
        async for event in agent.run(
            "Open Android Settings and report what is visible.",
            max_steps=10,
        ):
            print(event.eventType, event.payload, "final=", event.isFinal)


if __name__ == "__main__":
    asyncio.run(main())

Run the same kind of task from the CLI:

uv run uisurf_agent run mobile_agent \
  --task "Open Android Settings and report what is visible" \
  --mobile-serial 5C060DLCR002MM \
  --mobile-observation-delay-ms 500 \
  --auto-mode \
  --max-steps 10

Omit --mobile-serial to use the first authorized ADB device.

Choose An Agent At Runtime

For local scripts, a small dispatcher is often enough. This keeps the task text and shared runtime options in one place while selecting the UI surface from the command line.

import argparse
import asyncio

from uisurf_agent import BrowserAgent, DesktopAgent, MobileAgent


async def stream_run(agent_name: str, task: str) -> None:
    agent_options = {
        "auto_mode": True,
        "max_observation_images": 2,
        "observation_scale": 0.75,
    }

    if agent_name == "browser":
        agent_context = BrowserAgent(
            headless=True,
            fast_mode=True,
            **agent_options,
        )
    elif agent_name == "desktop":
        agent_context = DesktopAgent(
            observation_delay_ms=750,
            **agent_options,
        )
    else:
        agent_context = MobileAgent(
            serial=None,
            observation_delay_ms=500,
            **agent_options,
        )

    async with agent_context as agent:
        async for event in agent.run(task, max_steps=15):
            print(event.eventType, event.payload, "final=", event.isFinal)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument("agent", choices=("browser", "desktop", "mobile"))
    parser.add_argument("task")
    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()
    asyncio.run(stream_run(args.agent, args.task))

Example runs:

uv run python run_agent.py browser "Open example.com and summarize it"
uv run python run_agent.py desktop "Open Terminal and run pwd"
uv run python run_agent.py mobile "Open Android Settings and report what is visible"

Run Agents As A2A Servers

Use A2A mode when another process will send tasks to the agent. Each server is long-running.

uv run uisurf_agent run browser_agent \
  --mode a2a \
  --host 0.0.0.0 \
  --port 8001 \
  --fast-mode

uv run uisurf_agent run desktop_agent \
  --mode a2a \
  --host 0.0.0.0 \
  --port 8002 \
  --desktop-observation-delay-ms 750

uv run uisurf_agent run mobile_agent \
  --mode a2a \
  --host 0.0.0.0 \
  --port 8003 \
  --mobile-serial 5C060DLCR002MM

The repository also includes convenience targets for local server runs:

make run-browser
make run-desktop
make run-mobile
make run-all

See A2A Servers for server URLs, environment variables, and orchestration notes.