Голосовые системы

Действия страницы через run_js

Основной Chat Agent 2.3.0 предоставляет модели один инструмент страницы: run_js({code}). code — тело async-функции с явным JSON-возвратом. История остаётся общей для сайта, выполнение привязано к исходной вкладке и документу.

Схема 1
Схема 1 · Открыть в полном размере
Исходный Mermaid
flowchart LR
  Model[Модель] -->|"run_js: code"| Agent
  Agent -->|"существующая доставка NATS"| LocalMcp
  LocalMcp --> Background
  Background -->|"Chrome userScripts.execute / documentId"| Script[USER_SCRIPT]
  Script <-->|"Chrome messages: dom.find/get/set/act"| DOM[Общий DOM runtime / collector]
  Script -->|"JSON: ok, value / error"| Background
  Background --> LocalMcp
  LocalMcp -->|"browser_tool_result"| Agent
  Agent --> Model

Включение

Нужен Chrome 138+. Обновите основной пакет по прежнему пути и включите «Разрешить пользовательские скрипты» в настройках расширения. Нажатие значка на HTTP/HTTPS-странице выдаёт временный activeTab доступ именно этой странице. Объявленные optional host permissions не выдают доступ всем сайтам. Смена CSP страницы не нужна. Проверка доступности — «Проверить JavaScript» в шестерёнке панели; она не вызывает модель и не меняет страницу.

DOM API

Все четыре метода асинхронные. Ссылки выдаёт общий ограниченный реестр collector; удалённая ссылка никогда не назначается другому узлу.

Метод Назначение
dom.find({selector,text,role,scope,limit,offset,include_hidden}) Порция элементов и признак продолжения; условия соединяются И
dom.get([ref], [property], {limit,offset}) Нужные свойства, constraints, контекст и порции options
dom.set([{ref,property,value}]) Предварительная проверка, native setters, события и фактический результат
dom.act(ref, 'click' / 'scroll') Ограниченное действие над найденным элементом

Например, изменить единственный h1, сохранив заголовок вкладки:

const found = await dom.find({selector: 'h1', limit: 2});
if (found.items.length !== 1 || found.has_more) {
  return {ok: false, reason: 'Нужен один однозначный заголовок'};
}
return await dom.set([{ref: found.items[0].ref, property: 'textContent', value: 'Новый заголовок'}]);

Формы используют value, checked, selected_values; заголовок вкладки — {ref:'@document', property:'title'}. Метаданные доступны через attr:name, attr:property, attr:content, стили — style:<property> и computed:<property>. Helper обходит доступные iframe и открытый/закрытый Shadow DOM. Новая поддержка кросс-доменных iframe в этот выпуск не входит. Ручной «Собрать поля» сохранён.

Инструменты приложения

await pageTools.list() возвращает JSON-каталог текущего документа с name, description, inputSchema. await pageTools.call(name, args) вызывает инструмент с JSON-объектом аргументов. Сначала читайте каталог, затем используйте имя и схему из него; не разбирайте имя на модуль и метод самостоятельно.

const tools = await pageTools.list();
if (!tools.some(tool => tool.name === 'Measure.GetActive')) return {available: false};
return {active: await pageTools.call('Measure.GetActive', {})};

Непустой каталог document.modelContext текущего документа имеет приоритет. Нативный вызов выполняется в USER_SCRIPT; формат аргументов выбирается до вызова: Chrome до 155 получает JSON-строку, 155+ — объект. Строковая схема каталога преобразуется в JSON-объект. Инструменты дочерних документов не включаются.

Если нативный каталог пуст или API отсутствует, фиксированная операция читает window.webMcp в MAIN. Используется существующий chrome.userScripts.execute и тот же валидатор JSON, без eval/Function, изменения CSP и новых разрешений. В MAIN передаются только операция, имя и JSON-аргументы; код модели остаётся в USER_SCRIPT. moduleName/apiName берутся из актуального каталога страницы.

Поддерживаются JSON, Promise и void (возвращается null). Observable выдаёт явную ошибку: автоматические подписки не создаются. Ошибка вызова не приводит к повтору через другой API или DOM. Каталог и результаты не кэшируются между вызовами. Действуют существующие deadline и привязка к исходному документу; отмена прекращает ожидание, но не обещает остановку уже запущенной функции.

На SPPI API включается штатно: «Настройки карты → Feature flags → webMcpEnabled». Дождитесь загрузки каталога. Это настройка SPPI в браузере, расширение не включает её автоматически.

Результаты и пределы

Исполнитель возвращает {ok:true,value} либо {ok:false,error,message,effect}. Нужно проверить также внутренние value.ok и value.errors: выполненный JS сам по себе не означает успешное изменение поля. JSON и код раскрываются в панели; просмотр истории и Monitor ничего не исполняет.

Пределы: код 16 000 символов, поиск 20 элементов по умолчанию / максимум 100, запись 100 изменений, реестр 1000 ссылок. Результат клиента ограничен 96 000 байт с запасом под серверный конверт 98 304 байта. На вопрос: 12 вызовов модели, 10 инструментов, 120 секунд. Ожидание JS — 4,5 секунды, серверное — 5 секунд.

Один незавершённый запуск на документ. Повторная доставка того же tool_call_id возвращает прежний исход. Отметка chrome.storage.session переживает остановку background. При неизвестном исходе нужна перезагрузка документа. Тайм-аут и отмена прекращают ожидание и дальнейшие шаги Agent; произвольный JS принудительно не останавливается, уже сделанные изменения не откатываются автоматически.

Каталог сервера принимает только run_js; локальные message/cancel остаются служебными командами. Результаты доступны внутри вопроса и не сохраняются между независимыми вопросами. Таблица widget_cache хранит каталог по (session_id, context_id); старый столбец results и история физически сохранены.

Источники реализации: extensions/chrome/src/runJs.ts, domRuntime.ts, form-collector.js, src_agent/widget_requests.py, src_shared/browser_tools.py. Отдельный аудит и измерения: RUN_JS_AUDIT_2026-10-28.

Исходник

Скачать Markdown · К материалам исследования