Skip to main content
Glama

OSWright

PyPI Tests Python License

Автоматизация рабочего стола для ИИ-агентов без оплаты скриншота на каждом шаге.

mcp-name: io.github.Ask-812/oswright

Это MCP-сервер, который позволяет LLM управлять реальными настольными приложениями — настольный аналог Playwright MCP. Он сохраняет модель экрана между действиями и повторно считывает только изменившиеся части, поэтому та же работа обходится на порядок дешевле по токенам.

OSWright переносит данные из счёта в форму расходов

Восемь полей считываются со счёта и вводятся в форму расходов; корректность проверяет само приложение. Та же задача, тот же результат — в 7.4× меньше контекста, чем при возврате скриншота после каждого действия. Каждое число на экране замеряется во время запуска — воспроизведите всё заново с помощью python benchmarks/record_demo.py.

Зачем это нужно

Большинство GUI-агентов заново воспринимают весь экран на каждом шаге: скриншот, OCR, передача изображения модели — и так по кругу. При замерах на живом рабочем столе медианное изменение занимает 0.012% пикселей экрана. Повторное чтение всего экрана делает гораздо больше работы, чем оправдано изменением, и обходится в ~2,800 токенов изображения независимо от того, произошло ли что-нибудь.

OSWright спрашивает у композитора, что изменилось, повторно сканирует только это и отвечает на запросы элементов из самого дешёвого источника, который может. Приведённые ниже утверждения измерены на этой машине и воспроизводимы из benchmarks/ — включая те, которые оказались не в его пользу.

Ключевые возможности

  • Кроссплатформенность. Windows (Win32 API), Linux (pynput/X11), macOS (pynput/Quartz).

  • Дерево специальных возможностей. Детерминированный поиск элементов по роли и имени через Windows UI Automation — точность 100%, мгновенно, без модели.

  • Быстрый OCR. Windows OCR (встроенный, мгновенный) с запасным вариантом EasyOCR для Linux/macOS. Результаты кэшируются автоматически.

  • Лёгкий на Windows. Без загрузки PyTorch — Windows использует встроенный OCR-движок, поэтому полная установка занимает несколько МБ, а не несколько ГБ.

  • Сопоставление изображений. Находит элементы по шаблонному изображению с помощью OpenCV.

  • Управление окнами. Список, фокус, сворачивание, закрытие и снятие скриншотов конкретных окон.

  • Сравнение скриншотов. Определение изменения экрана с помощью wait_for_change.

  • Доступ к буферу обмена. Чтение и запись системного буфера обмена для передачи данных.

  • Запуск приложений. Запуск приложений и ожидание их загрузки.

  • Автоснимок. Каждое действие возвращает скриншот, поэтому агент всегда видит текущее состояние.

  • 43 MCP-инструмента. Экран, OCR, UIA, мышь, клавиатура, окна, буфер обмена и составные действия.

  • Инкрементальное восприятие. Повторно сканирует только изменившиеся части экрана и может вернуть изменения вместо полного скриншота — ~21× меньше токенов на шаг.

  • Память экрана. Распознаёт ранее прочитанные экраны и переиспользует их, проверяя по пикселям — в 89 раз дешевле повторного чтения.

  • Спекулятивное восприятие. Изучает, что делают действия, и подтверждает ожидаемый результат вместо повторного чтения — в 19–23 раза дешевле, с отчётом surprise, когда интерфейс ведёт себя неожиданно.

  • Адаптивное ожидание. Ждёт, пока экран действительно установится, а не спит фиксированные 300 мс — экономия 11.9 с за задачу из 50 шагов.

  • Каскад разрешения запросов. Поиск элементов останавливается на самом дешёвом работающем методе; повторные запросы стоят ~0.05 мс.

  • Корректность DPI. Координаты везде в физических пикселях, поэтому клики попадают точно на масштабированных дисплеях.

  • Набор тестов. 237 автоматических тестов; тесты, управляющие рабочим столом, пропускают себя при отсутствии дисплея.

Требования

  • Python 3.10 или новее

  • VS Code, Cursor, Windsurf, Claude Desktop или любой другой MCP-клиент

Начало работы

Сначала установите MCP-сервер OSWright в вашем клиенте.

Стандартная конфигурация работает в большинстве инструментов:

{
  "mcpServers": {
    "oswright": {
      "command": "uvx",
      "args": ["oswright"]
    }
  }
}

Примечание: Если у вас нет uvx, можно использовать pip install oswright, а затем указать "command": "oswright" напрямую.

Следуйте руководству по установке MCP, используйте стандартную конфигурацию выше.

claude mcp add oswright uvx oswright

Добавьте в ваш пользовательский или рабочий settings.json в раздел mcp.servers:

{
  "mcp": {
    "servers": {
      "oswright": {
        "command": "uvx",
        "args": ["oswright"]
      }
    }
  }
}

Или используйте CLI VS Code:

code --add-mcp '{"name":"oswright","command":"uvx","args":["oswright"]}'

Перейдите в Cursor Settings -> MCP -> Add new MCP Server. Назовите его oswright, используйте тип command с командой uvx oswright.

Следуйте документации Windsurf MCP. Используйте стандартную конфигурацию выше.

Добавьте в ваш cline_mcp_settings.json:

{
  "mcpServers": {
    "oswright": {
      "type": "stdio",
      "command": "uvx",
      "args": ["oswright"],
      "disabled": false
    }
  }
}

Перейдите в Advanced settings -> Extensions -> Add custom extension. Назовите его oswright, используйте тип STDIO и укажите command как uvx oswright.

Если вы предпочитаете обычную установку через pip:

pip install oswright

Затем используйте эту конфигурацию:

{
  "mcpServers": {
    "oswright": {
      "command": "oswright"
    }
  }
}

Или запустите напрямую:

python -m oswright

Related MCP server: AutoFlow

Инкрементальное восприятие

Большинство GUI-агентов заново воспринимают весь экран на каждом шаге: полный скриншот, полный OCR, затем передают модели свежее изображение. При замерах на живом рабочем столе медианное изменение составляет 0.012% пикселей — то есть полное повторное сканирование выполняет примерно в 240 раз больше работы, чем оправдано изменением, а возвращаемый скриншот стоит ~2,800 токенов изображения независимо от того, произошло ли что-то.

OSWright сохраняет модель экрана между наблюдениями и повторно сканирует только те области, которые действительно изменились.

observe()  ->  {"changed": true,
                "added":   [{"text": "Saved", "x": 812, "y": 447}],
                "removed": ["Unsaved changes"],
                "screen_fraction_scanned": 0.015}

Замерено на этой машине в цикле агента из 14 шагов:

v0.4.0 (полный OCR + скриншот)

инкрементальный

Медианная задержка на шаг

212 ms

33 ms

Токенов на наблюдение

~2,764

~49

Токенов за 14 шагов

38,696

1,025

Повторное чтение экрана

100%

16%

Чем насыщеннее экран, тем больше разрыв: полный OCR масштабируется от объёма текста на экране, тогда как инкрементальный путь — от того, сколько изменилось. То же сравнение показывает 6.5× на спокойном рабочем столе и 14.3× при открытой плотной веб-странице. Перепроверьте на benchmarks/, а не полагайтесь на эти цифры.

Однако стоимость — это лишь прокси, и более дешёвый путь восприятия, который незаметно ухудшает точность, был бы хуже, чем никакого. Поэтому он проверяется по завершению задач: скриптовые задачи, управляющие реальным интерфейсом в четырёх приложениях, оцениваются по состоянию самого приложения — UI Automation для Calculator и Explorer, заголовок окна для Chrome и VS Code — но никогда по OCR.

Конфигурация

Calculator

File Explorer

Chrome

токены

стиль v0.4 (полный скриншот)

9/9

3/3

3/3

118,858

только дельта

9/9

3/3

3/3

5,252

дельта + память

9/9

3/3

3/3

5,099

дельта + память + прогнозирование

9/9

3/3

3/3

7,981

Точность идентична во всех конфигурациях, при том что стоимость в токенах падает в 23 раза. Запустите это с помощью python benchmarks/bench_tasks.py.

Почему нужны и пиксели, и специальные возможности

Конструкция исходит из того, что ни один путь восприятия не выигрывает везде. Отключение каждой половины позволяет это измерить, а не просто утверждать:

Конфигурация

Calculator

File Explorer

Chrome

полный каскад

9/9

3/3

3/3

только специальные возможности

9/9

0/3

0/3

только пиксели

6/9

3/3

3/3

Подход «только специальные возможности» — которого придерживается большинство Windows-GUI-агентов — безупречен на XAML и слеп к представлению списка Win32 и веб-содержимому. При проверке на VS Code он видит 18 элементов — вся IDE является одним узлом с именем Chrome Legacy Window, тогда как OCR считывает 94 элемента, включая все имена файлов.

Подход «только пиксели» не справляется с кнопками Calculator, потому что кнопка, которую человек читает как 7, называется Seven, а Windows OCR вообще не возвращает цифры из Calculator.

Каскад — единственная конфигурация, которая проходит везде.

Каскад разрешения запросов

find_element и click_element останавливаются на первом методе, который может дать ответ, поэтому стоимость зависит от того, насколько нов запрос, а не от размера экрана:

Уровень

Метод

Типичная стоимость

0

Уже в модели экрана

~0.05 ms

1

Повторное сканирование только изменений

~70 ms

2

Дерево специальных возможностей (знает, что Button — это кнопка)

~40 ms

3

Собственный текстовый буфер приложения через UIA TextPattern — точные символы

~400 ms

4

Полноэкранный OCR

~250 ms

Поиск текста, который модель уже знает, обходится примерно в ~5,000 раз дешевле, чем путь v0.4.0 (0.05 мс против 244 мс). В ответе сообщается, какой уровень ответил, так что вы видите реальную стоимость задачи.

Уровень 3 стоит понять: TextRange.FindText из UIA ищет в собственном текстовом буфере приложения и возвращает точные ограничивающие прямоугольники. Он невосприимчив к шрифту, DPI, сглаживанию и ошибкам OCR. Он находится ниже пиксельных уровней только потому, что сканирование элементов окна для него стоит несколько сотен миллисекунд межпроцессного COM, — это точный уровень, а не быстрый.

Примечание о порядке. Уровни упорядочены по измерениям, а не по теории. Распространённый совет — делать дерево специальных возможностей основным, но в реальных приложениях оно не всегда дешевле: обход дерева Chrome здесь занял 537 мс, что медленнее полноэкранного прохода OCR, а VS Code открыл ему только 18 элементов. Ни пиксели, ни специальные возможности не выигрывают везде, поэтому это каскад, а не выбор.

Спрашиваем композитора вместо просмотра

В Windows композитор рабочего стола уже знает, какие пиксели изменились, и предоставляет их через DXGI Desktop Duplication. Запрос к нему стоит 0.14 мс и не передаёт ни одного пикселя, тогда как захват кадра и обнаружение его идентичности занимают десятки миллисекунд — поэтому в отсутствие изменений наблюдение пропускает захват полностью.

Когда что-то всё же изменилось, композитор остаётся с этим кадром, поэтому его пиксели читаются напрямую с GPU, а не захватываются повторно через другой API, — по замерам здесь это в 1.5–2.3 раза быстрее, чем mss.

Композитор используется только как быстрый отрицательный сигнал для обнаружения изменений. Когда он сообщает об изменении, грязные области по-прежнему получаются хэшированием захваченного кадра: эти два процесса измеряются на слегка разных интервалах, поэтому прямоугольники композитора могут занижать объём относительно реально захваченных пикселей, а заниженная область — это текст, который никогда не будет перечитан. Там, где Desktop Duplication недоступен, механизм незаметно деградирует до хэширования тайлов и обычного захвата.

Включите дельта-наблюдения для инструментов действий с помощью --observation-mode delta. По умолчанию остаётся screenshot для совместимости с существующими клиентами.

Воспроизведите всё это самостоятельно: см. benchmarks/. Обоснование каждого решения, включая тупиковые варианты, приведено в docs/ENGINEERING_LOG.md.

Конфигурация

MCP-сервер OSWright поддерживает следующие аргументы. Их можно указать в JSON-конфигурации в составе списка "args":

Option

Description

Переменная окружения

--port <port>

Порт для SSE-транспорта. Если не указан, используется stdio (по умолчанию).

FASTMCP_PORT

--host <host>

Хост, к которому привязывается HTTP/SSE-сервер. По умолчанию: 127.0.0.1.

FASTMCP_HOST

--transport <mode>

Протокол транспорта: stdio, sse, streamable-http. Автоопределяется из --port.

--ocr-languages <langs>

Языки OCR (по умолчанию: en). Пример: --ocr-languages en es fr

OSWRIGHT_OCR_LANGUAGES

--timeout <seconds>

Тайм-аут по умолчанию для операций автоматического ожидания (по умолчанию: 10).

OSWRIGHT_TIMEOUT

--snapshot-max-width <px>

Уменьшает автоматический снимок, возвращаемый после каждого действия. 0 (по умолчанию) сохраняет полное разрешение. Меньшие значения значительно сокращают расход токенов.

OSWRIGHT_SNAPSHOT_MAX_WIDTH

--observation-mode <mode>

Что возвращают инструменты действий: screenshot (по умолчанию), delta (только изменившееся, ~30× меньше токенов) или both.

OSWRIGHT_OBSERVATION_MODE

--no-atlas

Не запоминать экраны между посещениями.

OSWRIGHT_NO_ATLAS

--no-speculate

Не предсказывать исход действий.

OSWRIGHT_NO_SPECULATE

--allow-remote

Требуется для привязки к адресу, отличному от loopback. См. Безопасность.

--log-level <level>

Уровень логирования: DEBUG, INFO, WARNING, ERROR. По умолчанию: INFO.

OSWRIGHT_LOG_LEVEL

Явный флаг командной строки всегда имеет приоритет над соответствующей переменной окружения.

Пример: многоязычный OCR

{
  "mcpServers": {
    "oswright": {
      "command": "uvx",
      "args": ["oswright", "--ocr-languages", "en", "es", "fr"]
    }
  }
}

Автономный MCP-сервер (SSE)

При запуске из рабочего процесса или с другой машины используйте SSE-транспорт:

uvx oswright --port 8931

Затем в конфигурации вашего MCP-клиента:

{
  "mcpServers": {
    "oswright": {
      "url": "http://127.0.0.1:8931/sse"
    }
  }
}

Безопасность

OSWright не имеет аутентификации. Любой, кто может подключиться к порту, получает полный контроль над клавиатурой, мышью, экраном и буфером обмена машины — это захват удалённого рабочего стола, а не изолированный API.

Поэтому сервер по умолчанию привязывается к 127.0.0.1 и отказывается запускаться на адресе, отличном от loopback, если вы не передадите --allow-remote. Чтобы подключиться к нему с другой машины, предпочтите SSH-туннель открытию порта:

ssh -L 8931:127.0.0.1:8931 user@desktop-host

Транспорт stdio (используемый по умолчанию во всех конфигурациях MCP-клиента выше) вообще не открыт для сети, и это рекомендуемый способ запуска OSWright.

Инструменты, которые могут уничтожить работу, помечены соответствующим образом: close_window отмечен как разрушительный, а launch_app запускает произвольные программы. Инструменты создания снимков отказываются перезаписывать существующий save_path.

Примечания о платформах

Platform

Input Backend

OCR Backend

Extra downloads

Windows

Win32 API (SendInput)

Windows OCR (мгновенный, встроенный)

Нет. PyTorch не нужен. UI Automation включён.

Linux

pynput (X11)

EasyOCR

PyTorch (~2.5 ГБ). Требуется X11; поддержка Wayland ограничена.

macOS

pynput (Quartz)

EasyOCR

PyTorch (~2.5 ГБ). Предоставьте разрешения для специальных возможностей в System Settings > Privacy > Accessibility.

В Windows EasyOCR не устанавливается, потому что встроенный движок Windows OCR быстрее и не требует загрузки модели. Устанавливайте его, только если вам нужен язык, который Windows OCR не поддерживает:

pip install "oswright[easyocr]"

Координаты

Все координаты, возвращаемые OCR, сопоставлением изображений и UI Automation, — это абсолютные физические пиксели экрана, готовые для прямой передачи в mouse_click. Это справедливо для подобластей и для многомониторных конфигураций, где виртуальный рабочий стол начинается с отрицательного начала координат. screenshot также сообщает origin_x/origin_y — абсолютную позицию верхнего левого пикселя изображения, на случай если вы сами считываете координату с изображения.

Инструменты

  • screenshot -- Сделать снимок экрана или области. Возвращает изображение как нативное содержимое изображения MCP. При необходимости сохраняет в файл по указанному пути.

    • Только чтение: true

  • get_screen_info -- Получить размеры экрана и количество мониторов.

    • Только чтение: true

  • find_text_on_screen -- Найти все вхождения текста на экране с помощью OCR. Возвращает совпадения с координатами и уверенностью.

    • Параметры: text, exact, границы области, monitor

    • Только чтение: true

  • read_screen_text -- Прочитать ВЕСЬ видимый текст на экране с помощью OCR. Возвращает каждый обнаруженный текстовый элемент с позицией.

    • Параметры: границы области, monitor

    • Только чтение: true

  • find_image_on_screen -- Найти все вхождения шаблонного изображения на экране с помощью сопоставления шаблонов OpenCV.

    • Параметры: template_path, threshold, monitor

    • Только чтение: true

  • mouse_click -- Кликнуть мышью по координатам или в текущей позиции. Возвращает снимок экрана.

    • Параметры: x, y, button, clicks

  • mouse_double_click -- Дважды кликнуть по координатам или в текущей позиции. Возвращает снимок экрана.

  • mouse_move -- Переместить курсор мыши в координаты экрана.

  • mouse_scroll -- Прокрутить колесо мыши. Возвращает снимок экрана.

    • Параметры: amount, x, y

  • mouse_drag -- Перетащить из одной точки в другую. Возвращает снимок экрана.

    • Параметры: start_x, start_y, end_x, end_y, button, duration

  • get_mouse_position -- Получить текущую позицию курсора мыши.

    • Только чтение: true

  • type_text -- Ввести текст посимвольно. Возвращает снимок экрана.

    • Параметры: text, delay

  • press_key -- Нажать клавишу или комбинацию, например Enter, Ctrl+C, Alt+Tab. Возвращает снимок экрана.

    • Параметры: key

  • click_text -- Найти текст через OCR и кликнуть по нему. Автоматически повторяет попытки до обнаружения или истечения тайм-аута. Возвращает снимок экрана.

    • Параметры: text, exact, button, timeout, poll_interval, monitor

  • double_click_text -- Найти текст через OCR и дважды кликнуть по нему. Возвращает снимок экрана.

  • right_click_text -- Найти текст через OCR и кликнуть по нему правой кнопкой мыши. Возвращает снимок экрана.

  • hover_text -- Найти текст через OCR и навести на него курсор. Возвращает снимок экрана.

  • fill_field -- Найти метку, кликнуть по ней, очистить её и ввести значение. Возвращает снимок экрана.

    • Параметры: target_text, value, exact, timeout, monitor

  • fill_form -- Заполнить несколько полей за один вызов. Сокращает количество циклов запроса/ответа.

    • Параметры: fields (список из {label, value}), timeout, monitor

  • wait_for_text -- Ждать появления текста на экране. Опрашивает через OCR.

    • Параметры: text, exact, timeout, poll_interval, monitor

    • Только чтение: true

  • wait_for_text_gone -- Ждать исчезновения текста с экрана.

    • Параметры: text, exact, timeout, poll_interval, monitor

    • Только чтение: true

  • wait_for_time -- Ждать в течение указанного времени (не более 30 с), затем сделать снимок экрана.

  • list_windows -- Вывести список всех видимых окон. При необходимости фильтрует по подстроке заголовка.

    • Параметры: title_filter

    • Только чтение: true

  • focus_window -- Вывести окно на передний план по заголовку. Возвращает снимок экрана.

    • Параметры: title

  • close_window -- Закрыть окно по заголовку (отправляет WM_CLOSE). Возвращает снимок экрана.

    • Параметры: title

  • minimize_window -- Свернуть окно по заголовку. Возвращает снимок экрана.

    • Параметры: title

  • screenshot_window -- Сделать снимок экрана только одного окна.

    • Параметры: title, save_path

    • Только чтение: true

  • get_clipboard -- Получить текущее текстовое содержимое системного буфера обмена.

    • Только чтение: true

  • set_clipboard -- Скопировать текст в системный буфер обмена.

    • Параметры: text

  • launch_app -- Запустить приложение и при необходимости дождаться его загрузки. Запускает программу напрямую, без использования оболочки.

    • Параметры: command, args, wait_text, timeout

    • Сообщает wait_text_found, чтобы вы могли определить, действительно ли приложение загрузилось.

  • get_ocr_info -- Получить информацию об активном OCR-бэкенде и доступных бэкендах.

    • Только чтение: true

  • observe -- Сообщить, что изменилось на экране с момента последнего наблюдения. Повторно сканирует только области, которые изменились. Для отслеживания состояния предпочитайте этот инструмент screenshot.

    • Параметры: force_full

    • Только чтение: true

  • find_element -- Найти текст на экране самым экономичным методом, который может дать ответ. Сообщает, какая ступень каскада ответила.

    • Параметры: text, exact, window_title

    • Только чтение: true

  • click_element -- Найти текст через каскад и кликнуть по нему. Экономичная альтернатива click_text.

    • Параметры: text, exact, button, window_title

  • read_model_text -- Прочитать текст с экрана из инкрементальной модели без повторного OCR-сканирования дисплея.

    • Параметры: query, limit

    • Только чтение: true

  • perception_stats -- Сообщить, сколько работы по восприятию модель помогла избежать.

    • Только чтение: true

  • remember_screen -- Запомнить текущий экран, чтобы будущие посещения пропускали его чтение. Сохраняется между сеансами.

    • Только чтение: true

  • atlas_stats -- Сообщить, что запомнил атлас экрана и как часто он помогал.

    • Только чтение: true

  • get_ui_tree -- Получить дерево специальных возможностей сфокусированного окна. Возвращает все интерактивные элементы с именами, типами, позициями. Детерминированно и мгновенно.

    • Параметры: window_title, max_depth

    • Только чтение: true

  • click_ui_element -- Нажать элемент интерфейса, используя дерево специальных возможностей. Надёжнее, чем OCR.

    • Параметры: name, control_type, automation_id, window_title

  • fill_ui_element -- Задать значение элемента интерфейса (например, текстового поля). Надёжнее, чем заполнение через OCR.

    • Параметры: value, name, automation_id, window_title

  • get_active_window -- Получить информацию о текущем сфокусированном окне.

    • Только чтение: true

  • wait_for_change -- Ожидать визуального изменения экрана. Делает базовый снимок экрана и опрашивает, пока изображение не изменится.

    • Параметры: timeout, poll_interval

Python-библиотека

OSWright также работает как самостоятельная Python-библиотека с API в стиле Playwright:

from oswright import OSWright

with OSWright() as ow:
    screen = ow.screen()
    screen.click(text="Start")
    screen.type_text("Hello World")
    screen.press("Ctrl+S")
    screen.screenshot("desktop.png")

Дополнительные примеры см. в каталоге examples/.

Архитектура

oswright/
  __init__.py          # Package entry point (single source of __version__)
  core.py              # OSWright class (= Browser)
  screen.py            # Screen class (= Page)
  locator.py           # Locator + Assertions (= Locator + expect)
  capture.py           # Screen capture (mss - cross-platform, thread-safe)
  dirty.py             # Change detection - which parts of the screen moved
  screenmodel.py       # Persistent screen model, updated incrementally
  cascade.py           # Resolution cascade - cheapest method that can answer
  atlas.py             # Remembers screens across visits and sessions
  settle.py            # Knowing when the screen has finished responding
  speculate.py         # Predicting what an action does, instead of looking
  textprovider.py      # Exact text from the app itself via UIA TextPattern
  detect.py            # OCR dispatcher with caching (auto-selects best backend)
  _ocr_windows.py      # Windows OCR backend (instant, built-in)
  accessibility.py     # Windows UI Automation (deterministic element finding)
  cache.py             # Screenshot diffing, image hashing, OCR result cache
  _dpi.py              # Process DPI awareness (keeps every API in physical pixels)
  _dxgi_windows.py     # Compositor dirty rectangles via DXGI Desktop Duplication
  input.py             # Platform dispatcher for input backends
  _input_windows.py    # Windows input backend (Win32 API)
  _input_pynput.py     # Linux/macOS input backend (pynput)
  window.py            # Window management (list, focus, close)
  clipboard.py         # Clipboard read/write (cross-platform)
  mcp_server.py        # MCP server (43 tools for AI agents)
tests/
  conftest.py          # Fixtures that skip when no display/OCR is available
  test_core.py         # Unit tests (no desktop required)
  test_perception.py   # Incremental perception (stubbed, runs headless)
  test_atlas.py        # Screen memory and its failure modes (headless)
  test_speculate.py    # Prediction, settling, and their limits (headless)
  test_e2e.py          # End-to-end tests against the real desktop (marked `e2e`)

Запоминание экранов

Приложения детерминированы — один и тот же диалог каждый раз имеет одинаковую раскладку. OSWright запоминает экраны, которые он уже прочитал, и повторно использует их при следующем посещении, между сеансами: 125 мс холодное чтение → 1.4 мс тёплое воспроизведение (89×).

Запомненному экрану никогда не доверяют только на основании распознавания. Несколько областей выборочно проверяются по пикселям, прежде чем раскладка будет использована повторно, поэтому экран, который изменился, отклоняется, а не используется. Проверка безопасна при сбое: экран с нечем проверять вообще не запоминается.

Отключается флагом --no-atlas. Запомненные экраны хранятся в ~/.oswright/atlas.json.

Предсказание действий вместо их наблюдения

Приложения детерминированы — нажатие кнопки Save каждый раз приводит к одному и тому же диалогу — поэтому после первого наблюдения исход действия уже известен. OSWright изучает, что делают действия, и подтверждает ожидаемый экран, а не читает его заново: в 19–23 раза дешевле, чем наблюдение (2.3 мс против 43–50 мс).

Предсказание должно подтвердиться дважды, прежде чем ему доверят; оно отменяется, если оказывается неверным, и проверяется теми же двумя способами, что и запомненный экран. Неудачное предсказание сообщается агенту как surprise — интерфейс сделал что-то, чего обычно не делает, и об этом стоит знать, а не молча принимать.

Что гарантирует подтверждённое предсказание: раскладку — те же элементы управления на тех же местах. Не то, что каждый символ идентичен. Изменение одной цифры затрагивает меньше пикселей, чем мигающий курсор, поэтому никакая проверка всего экрана не может их различить ни при каком разрешении. Используйте observe(force_full=True), когда важен точный текст.

Отключается флагом --no-speculate.

Ожидание ровно столько, сколько нужно

Раньше инструменты действий спали фиксированные 300 мс, выбранные по самому медленному случаю, поэтому каждое действие платило за худший случай. Композитор знает, когда экран перестаёт меняться, так что теперь ожидание заканчивается, когда интерфейс действительно устаканивается:

Прежний фиксированный сон

300 мс

Медианное фактическое ожидание

61.5 мс

Сэкономлено за задачу из 50 шагов

11.9 с

«Устаканилось» означает отсутствие значительных изменений в последнее время, а не отсутствие изменений вообще: настоящий рабочий стол никогда не стоит на месте — курсор и часы порождают событие изменения каждые ~18 мс, затрагивающее около 32 пикселей, тогда как настоящие изменения интерфейса затрагивают десятки тысяч.

Что ещё не сделано

  • Внедрение ввода в Wayland, а также macOS AXTextMarker как эквивалент TextPattern.

  • Ступень на основе зрительной модели для поверхностей, которые не являются ни доступными через специальные возможности, ни читаемыми по тексту: игры, холсты, графические редакторы.

  • Переходы, зависящие не только от предыдущего экрана, для действий, чей результат зависит от состояния, которое не видно.

Что измеряется, а что нет

Стоимость восприятия и успешность выполнения задач измеряются на этой машине и воспроизводимы через benchmarks/ — на четырёх приложениях более дешёвое восприятие не стоит точности, и разбиение на пиксели/специальные возможности измерено, а не декларируется.

Сравнение с Windows-MCP

Те же задачи, четыре сценария, каждый оценивается самим приложением. Ни один инструмент не оценивает себя сам, а Windows-MCP работает с настройками по умолчанию:

Калькулятор

Проводник

Chrome

Chrome, 2 шага

пройдено

токены

oswright

5/5

4/5

5/5

5/5

19/20

832

Windows-MCP, снимок на каждое действие

5/5

5/5

5/5

5/5

20/20

14,053

Windows-MCP, один снимок

5/5

5/5

5/5

5/5

20/20

8,214

Честно прочитаем эти цифры: Windows-MCP оказался надёжнее, а oswright — в 16.9 раза дешевле. oswright потерял один клик из двадцати на окне, которое только что открылось.

Разница в стоимости структурная, а не результат настройки. Windows-MCP возвращает экран агенту — Snapshot представляет дерево специальных возможностей как (x,y) button "Seven" [action: click] — и принимает координаты обратно, поэтому описание экрана списывается в контекст модели при каждом действии. oswright принимает текст и возвращает результат.

Разрыв в надёжности может быть вызван скоростью: oswright распознаёт и кликает за ~100 мс, иногда до того, как только что сфокусированное окно готово к вводу, тогда как более медленный цикл даёт приложению время, которое оно никогда не просило. Это гипотеза, а не вывод — добавление паузы перед действием не дало измеримой разницы за десять попыток, поэтому это зафиксировано, а не исправлено.

Сценарий Chrome, 2 steps существует потому, что все остальные задачи здесь достаточно коротки, чтобы инструмент мог прочитать экран один раз и повторно использовать эти координаты. Там первый клик перемещает элементы управления на 325 px вниз по странице, и конфигурации с одним снимком пришлось перечитать экран — поэтому для задач, чей интерфейс двигается, её дешёвого показателя не существует, а реальная стоимость — это стоимость одного действия.

Воспроизводится командой python benchmarks/bench_head_to_head.py (настройка в docstring файла).

Чего это не доказывает: четыре короткие задачи на одном ноутбуке. Ничего о долгой многошаговой работе, восстановлении или зрелости продукта — у Windows-MCP есть OAuth, аналитика, watchdog и установщик; у oswright нет ничего из этого. Его обход дерева специальных возможностей также читает содержимое страниц Chrome, чего собственный уровень специальных возможностей oswright не делает. «Существенно дешевле за действие, ценой небольшой потери надёжности» — вот утверждение. «Лучший продукт» — нет.

Разработка

pip install -e ".[dev]"

pytest tests/                # everything available on this machine
pytest tests/ -m "not e2e"   # unit tests only, no desktop needed
ruff check oswright tests    # lint
python benchmarks/bench_pipeline.py   # reproduce the performance numbers
python benchmarks/bench_tasks.py      # task success (opens Calculator repeatedly)

Проектные решения, измерения и тупики зафиксированы в docs/ENGINEERING_LOG.md.

Лицензия

MIT

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI coding agents to automate Windows desktop applications through semantic UI Automation instead of brittle coordinate clicks, with tools for discovering windows, finding controls by stable identifiers, and verifying actions.
    1
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    AutoFlow enables AI agents to automate Windows desktop tasks by visually recognizing screen elements and simulating keyboard and mouse actions, with 18 MCP tools for workflow control.
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to query Windows process, window, and console information via structured JSON instead of screenshots, reducing token usage by 94-98%.
    20
    51
    1
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables low-cost agent models to control Windows applications through a compact, state-safe proxy over Open Computer Use, reducing model-visible context by up to 99.8% with support for record/replay and reusable UI component memory.
    5
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Ask-812/oswright'

If you have feedback or need assistance with the MCP directory API, please join our Discord server