Перейти к содержимому

AI-агенты

tapstep отдаёт весь свой инструментарий — увидеть экран, тапнуть, запустить тест, починить селектор — AI-агентам. Есть три пути: от нулевой настройки до своего агента.

Иконка ✨ в десктоп-приложении открывает панель чата рядом с тестами. Агент видит рабочую область и устройство: он записывает шаги через snapshot/act, пишет файлы .flow.yaml, запускает их и чинит падающие селекторы. Каждая правка файла показывается как diff в переписке, а перед первым изменением сохраняется контрольная точка версии.

В чате нет выбора устройства: агент стартует на устройстве последнего прогона и переключается своим инструментом select_device, когда вы попросите (или когда флоу нужна другая платформа).

Чат — одна лента: шаги агента стоят прямо в переписке, там, где случились, а один переключатель Details открывает или закрывает вход и результат всех шагов сразу. Строка под перепиской называет фазу, в которой идёт терн, — Thinking, Working (и над чем именно) или Verifying, — а любой терн заканчивается done, чем бы он ни кончился.

Что даёт панель, коротко:

  • Fast / Thorough (⚡) — урезанное размышление ради быстрых шагов или полное размышление между шагами (Anthropic API и Claude Code; остальные провайдеры его игнорируют). На уровне машины.
  • Draft / Verified (✓) — в Verified терн обязан прогнать тест и чинить его до зелёного, прежде чем завершиться (стоит прогонов); Draft оставляет это на усмотрение модели.
  • Дозаправка — пишите, пока терн идёт: сообщение попадает в летящий терн; если провайдер не может принять его посреди терна, оно встаёт в очередь на следующий.
  • Вложения — картинки и текстовые файлы, кнопкой или drag-and-drop (до 4 картинок и 8 файлов на сообщение).
  • History / New chat — переписки сохраняются по проектам; New chat архивирует текущую, History возвращает любую.
  • Быстрые чипы под полем ввода — директивы в один тап: Re-runnable, Parameterize, Adapt to state, Run to green.
  • Счётчик расхода — входные / кэшированные / выходные токены за сессию. Только токены, без денег.

Шесть провайдеров, в меню чата ⋯ → AI settings:

  • Anthropic API key — хранится в связке ключей ОС. Endpoint и модель настраиваются (ai.endpoint, ai.model в config.yaml).

  • OpenAI-совместимый — любой endpoint chat/completions: локальный Ollama или LM Studio, свой vLLM или облачный API. Укажите, например, http://localhost:11434/v1 и модель с поддержкой инструментов — и ничего не покидает вашу машину. API-ключ опционален — локальным серверам он не нужен.

  • Claude Code — без API-ключа: чат управляет локально установленным Claude Code, залогиненным в вашу подписку Claude. Установите один раз — и готово:

    Terminal window
    npm install -g @anthropic-ai/claude-code
    claude # вход один раз
  • Codex — то же самое для планов ChatGPT: npm install -g @openai/codex, затем codex login.

  • Gemini CLInpm install -g @google/gemini-cli. Google закрыл бесплатный персональный вход, поэтому создайте API-ключ на aistudio.google.com/apikey (у него свой бесплатный лимит) и вставьте его в приложение — ключ хранится в связке ключей ОС и передаётся CLI при каждом запуске.

  • OpenCode — открытый терминальный агент, который приносит своего провайдера модели, так что чат стоит ровно столько, сколько стоит этот провайдер: npm install -g opencode-ai, затем opencode auth login. Приложение прописывает мост tapstep в opencode.json проекта.

Выбранный provider десктоп держит в том же блоке ai: файла config.yaml (для Anthropic API по умолчанию не пишется), рядом с endpoint, model и флагом privacy ниже. Ключи в файл не попадают.

Settings → AI → Privacy masking запускает on-device модель, которая заменяет имена, e-mail, телефоны и секреты стабильными псевдонимами до того, как запрос чата покинет машину; в переписке локально снова видны настоящие значения. Это значение по умолчанию для машины; проект переопределяет его через ai.privacy: true|false в config.yaml. С провайдерами-CLI-агентами маскируются только ваши реплики — их трафик инструментов идёт во внешнем CLI, куда маскирование не дотягивается.

В CLI то же маскирование для AI-шагов: tapstep privacy install один раз скачивает модель (~945 МБ), tapstep privacy status показывает, что включено, а TAPSTEP_PRIVACY=1 включает его на прогон.

Settings → AI → MCP server запускает локальный MCP-сервер, привязанный к устройству, — только localhost, защищён токеном. Та же строка копирует готовую команду:

Terminal window
claude mcp add --transport http tapstep http://127.0.0.1:PORT/mcp \
--header "Authorization: Bearer TOKEN"

Любой MCP-клиент работает так же (Cursor, Windsurf, …): наведите его на URL с этим заголовком. Агент получает snapshot, try, act, resolve, diff, run_flow, validate_flow, suggest, patch_flow и heal на выбранном устройстве, плюс собственные инструменты десктопа list_devices, select_device, list_runs, run_details и request_secret (спрашивает у вас креденшел в диалоге и пишет его в .env, так что значение не попадает в переписку).

CLI — тоже MCP-сервер:

Terminal window
tapstep mcp [--driver web|android|ios|app[:port]] [--browser …]

Он говорит по MCP через stdio — на него и указывает .mcp.json ниже — и, как любая другая команда, требует машину со входом. Без --driver берёт подключённое устройство, иначе браузер. Инструменты: snapshot, try, act, resolve, diff, run_flow, validate_flow, take_screenshot, cheat_sheet, list_devices, suggest, patch_flow, heal, convert_curl, request_to_curl, import_playwright, export_playwright и export_extester. run_flow разрешает defaultEnvironment проекта, а оба инструмента экспорта берут папку из настройки exports: проекта, когда вызов её не назвал.

snapshot отвечает в компактной нотации — по строке на элемент, с тем, что стабильно ($testId / #id), сколько на странице дубликатов (x6), значением и состоянием поля и тем, в какой строке или диалоге он стоит, — под шапкой страницы, которая говорит, устоялся ли экран. Полностью описана на странице Нотация снапшота, и та же легенда едет в описании самого инструмента и в cheat_sheet, так что агенту не нужно объяснять. snapshot { detail: "regions" } — дешёвый обзор того же экрана: по строке на контейнер, а не на элемент.

Читать весь экран перед каждым шагом — дорогой способ его вести. Дешёвый цикл — два вызова:

  1. snapshot { detail: "regions" } по прибытии — обзор. По строке на контейнер с тем, что в нём лежит (header: 2 buttons, 1 link "Log in", table "Orders": 20 rows, nav: 4 links), затем управляющие элементы, которые не держит ни один контейнер. Около 25 строк, каким бы ни был экран; перечитывать после смены страницы, а не перед каждым шагом.
  2. try { step: … } — сам шаг. step — одна команда в YAML флоу, ровно та, что лежит в .flow.yaml: tapOn, inputText, scroll — так что шаг, который сработал здесь, и есть строка для вставки во флоу.

try разрешает селектор шага так же, как его разрешает прогон, и действует только когда тот называет ровно один элемент. Тогда в ответе идут квитанция (done tapOn e41 button "Create order" in:header), события, которые доказали два экрана (went, dialog opened, toast, focus, value, error), и строка net: с запросами, которые вызвало действие.

Не совпало ничего — none "Create Order!" — или совпало несколько — ambiguous "Save": 3 — и экран не тронут: в ответе до пяти кандидатов с якорями, которые их различают, а via:exact|norm|sub|score у каждого говорит, насколько пришлось растянуть имя, чтобы до него дотянуться. Сузьте шаг (index:/of:, rightOf:, childOf:) и попробуйте снова; полный snapshot читайте только после того, как try дважды ответил none или ambiguous про один и тот же экран.

expect — необязательная команда assert*, которая выполняется сразу после шага, когда важен исход; она возвращается в том же ответе как expect: ok или expect: failed — …, и провалившаяся проверка — не провалившийся вызов: действие произошло. ref называет элемент из прошлого шага вместо того, чтобы описывать его заново: try { ref: "e7", step: "tapOn: '-'" } действует на e7, что бы ни говорил собственный селектор шага. Шаги request, sql и assertTrue тоже идут через try — им экран не нужен, поэтому он и не читается.

В репозитории один раз разложите конфиг агента:

Terminal window
tapstep init --agents

Это создаёт .mcp.json (чтобы Claude Code в этой папке сам подхватывал инструменты tapstep — он запускает tapstep mcp) и шпаргалку AGENTS.md с конвенциями flow-файла.

Есть и скилл агента — подробный плейбук (справочник CLI и flow-файла, рабочие конвенции), который агент подгружает по необходимости:

Terminal window
tapstep skill install

Ставится для каждого найденного агента — Claude Code (~/.claude/skills), Codex (~/.codex/skills), Gemini CLI (~/.gemini/skills), Cursor (~/.cursor/skills), OpenCode (~/.config/opencode/skills) — плюс общая копия ~/.agents/skills, которую читают и Codex, и Gemini CLI, и Cursor, и OpenCode. Хотя бы одна из этих домашних папок должна существовать, и нужен вход. Идемпотентно. tapstep skill status говорит по каждому агенту, установлена ли копия и совпадает ли она с этим бинарём; tapstep skill refresh пересинхронизирует установленные копии и сам запускается после tapstep update. В десктопе та же установка — в Settings → AI → Agent skill.

Десктоп-приложение также поставляется со встроенным терминалом (кнопка Terminal в статус-баре или Ctrl+</kbd>) — удобно запускать claudeилиtapstep` прямо в рабочей области.

Три команды спрашивают модель о текущем экране — текст снимка плюс скриншот, когда он есть у драйвера:

- assertWithAI: "the cart shows exactly one item" # голая форма: optional
- assertWithAI: { assertion: "no error banner", optional: false }
- assertNoDefectsWithAI # дефекты вёрстки/визуала
- extractTextWithAI: "the order number" # → ${aiText}
- extractTextWithAI: { query: "the total", into: total, pattern: "\\d+\\.\\d{2}" }

Голые формы — это optional: true: упавшая проверка (или ошибка AI) — это предупреждение в отчёте, а не упавший шаг; optional: false роняет флоу. extractTextWithAI пишет в into (по умолчанию aiText); с pattern значение обязано совпасть с этим регэкспом (одна повторная попытка, затем шаг падает). Подробности: assertWithAI и соседи в справочнике команд.

Подключение берётся из config.yaml (через --config; блок с обоими endpoint и model побеждает окружение) или из окружения:

ai:
endpoint: https://api.anthropic.com # или любой OpenAI-совместимый базовый URL
model: claude-opus-4-8
key: sk-ant-… # опционально; ключ sk-ant-… означает Anthropic
Terminal window
TAPSTEP_AI_ENDPOINT=http://localhost:11434/v1 TAPSTEP_AI_MODEL=qwen2.5 tapstep test flows/

Ключ sk-ant-… выбирает Anthropic Messages API (с переменными окружения TAPSTEP_AI_ENDPOINT тогда можно опустить); всё остальное считается OpenAI-совместимым chat/completions. tapstep test --analyze тем же подключением разбирает упавшие флоу после прогона.

В десктопе AI-шаги используют подключение чата — Anthropic API-ключ или OpenAI-совместимый endpoint проекта. У провайдеров-CLI-агентов (Claude Code, Codex, Gemini CLI) нет HTTP-endpoint’а, который можно вызвать, поэтому с ними assertWithAI и компания падают как ненастроенные (AI commands need a model endpoint).