Lovely RouterДокументация
Получить ключ
Браузерный агент

События и экран в реальном времени

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

Запуск длится от нескольких секунд до нескольких минут. Вместо того чтобы ждать конца, получайте его потоком: вы видите, что агент делает прямо сейчас, каждый шаг по мере завершения, состояние запуска при каждом изменении и, если попросите, экран браузера. Поток заканчивается завершённым запуском, включая answer, data и charge_usd.

Потоки используют Server-Sent Events (text/event-stream) — тот же формат, что и LLM API для потоковой передачи. Наблюдение за запуском бесплатно.

Поток для нового запуска#

Добавьте "stream": true при создании запуска. Ответом будет поток событий со статусом 200 вместо JSON со статусом 202. Добавьте "screen": true, чтобы получать ещё и экран браузера.

curl -N https://lovelyrouter.com/v1/browser/runs \
  -H "Authorization: Bearer $LOVELY_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "goal": "Find the price of the book \"A Light in the Attic\" and whether it is in stock.",
    "start_url": "https://books.toscrape.com/",
    "stream": true
  }'

Поток выглядит так (в сокращении):

SSE
event: run
data: {"id":"brun_3f9a1c7e0b2d4e6f8a9b0c1d","object":"browser_run","status":"running","steps":0,"trace":[],"poll":"/v1/browser/runs/brun_3f9a1c7e0b2d4e6f8a9b0c1d?wait=30","events":"/v1/browser/runs/brun_3f9a1c7e0b2d4e6f8a9b0c1d/events","charge_usd":null,"reserved_usd":0.445,…}

event: activity
data: {"step":0,"kind":"starting","text":"Opening https://books.toscrape.com/"}

event: activity
data: {"step":1,"kind":"reading","text":"Reading the page"}

event: activity
data: {"step":1,"kind":"acting","text":"click link \"A Light in the ...\" → https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"}

event: step
data: {"step":1,"url":"https://books.toscrape.com/","action":"click:e54","description":"click link \"A Light in the ...\" → https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html","ms":2140,"error":null}

event: run
data: {"id":"brun_3f9a1c7e0b2d4e6f8a9b0c1d","status":"running","steps":1,…}

event: activity
data: {"step":2,"kind":"answering","text":"Reading the result and writing the answer"}

event: step
data: {"step":2,"url":"https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html","action":"done","description":"Read the result and wrote the answer","ms":2875,"error":null}

event: run
data: {"id":"brun_3f9a1c7e0b2d4e6f8a9b0c1d","status":"succeeded","answer":"\"A Light in the Attic\" costs £51.77 and is in stock (22 available).","charge_usd":0.012,"reserved_usd":0,…}

event: end
data: {"id":"brun_3f9a1c7e0b2d4e6f8a9b0c1d"}

Первое событие run содержит то же, что вернул бы ответ 202: poll, events и webhook_secret, если вы передали webhook. Ошибки до старта запуска (400, 402, 429 и т. д.) возвращаются в виде JSON со своим статусом, так же как без stream.

Подключение к уже идущему запуску#

Открыть GET /v1/browser/runs/{id}/events можно в любой момент: из другого процесса, после обрыва соединения или для запуска, начатого без stream. Добавьте ?screen=1, чтобы получать экран. За одним запуском могут следить несколько потоков.

cURL
curl -N "https://lovelyrouter.com/v1/browser/runs/brun_3f9a1c7e0b2d4e6f8a9b0c1d/events?screen=1" \
  -H "Authorization: Bearer $LOVELY_API_KEY"

Каждый поток начинается с события run с полным trace, поэтому при переподключении ничего не теряется. Завершённый запуск отправляет это событие run (и, с screen, свой последний экран), а за ним end.

События#

СобытиеКогдаdata
runПервым, после каждого шага, при начале и окончании паузы и последнимОбъект запуска с charge_usd и reserved_usd. В первом есть trace.
activityАгент что-то начинаетstep (текущий шаг), kind и text
stepШаг завершёнОдна запись trace: step, url, action, description, ms, error
frameС screen: при подключении, затем при каждом изменении страницыdata — JPEG браузера в base64, и at (ISO 8601)
endЗапуск окончен; следом поток закрываетсяid

Виды активности:

kindАгент
startingзапускает браузер или открывает start_url
readingчитает страницу
waitingждёт страницу, которая не загрузилась, или загружает её снова
decidingвыбирает следующее действие
thinkingприсматривается внимательнее, прежде чем решить (точный режим может использовать скриншот)
checkingпроверяет значения формы перед отправкой
actingвыполняет действие, описанное в text: клик, ввод текста, выбор, загрузку
answeringчитает результат и пишет ответ
extractingпревращает прочитанное в data

Строки, начинающиеся с :, — это keep-alive-комментарии, которые отправляются каждые 15 секунд, пока больше ничего не происходит. Игнорируйте их.

Просмотр экрана#

С "screen": true (или ?screen=1) события frame несут экран браузера в виде JPEG в base64, обычно от 20 до 60 КБ каждый. Кадр приходит при подключении и при каждом изменении страницы, не чаще примерно 4 раз в секунду; неподвижная страница ничего нового не присылает. Если ваш читатель отстаёт, пропускаются кадры, но никогда не другие события.

Чтобы показать экран на веб-странице, поместите кадр в изображение:

JavaScript
img.src = `data:image/jpeg;base64,${frame.data}`;

Для одиночного снимка без потока GET /v1/browser/runs/{id}/screenshot возвращает экран в его текущем виде.

Паузы для человека#

Поток остаётся открытым, пока запуск находится в статусе waiting_for_human. Событие run, начинающее паузу, содержит needs; ответьте на него через POST /v1/browser/runs/{id}/reply откуда угодно, и поток продолжится событием run со статусом снова running. С screen вы также видите, что делает человек в браузере во время перехвата управления. См. Человек в контуре.

Потоки в веб-приложении#

Держите API-ключ на своём сервере. Браузерный EventSource не умеет отправлять заголовок Authorization, поэтому открывайте поток на своём сервере и передавайте его на страницу без изменений, с content-type: text/event-stream. Тогда страница сможет использовать EventSource на вашем собственном URL.

Переподключение#

Поток может оборваться: сбой сети, тайм-аут прокси, деплой на нашей стороне. Запуск продолжает работать. Снова откройте GET /v1/browser/runs/{id}/events и замените своё состояние первым событием run. EventSource переподключается сам через 3 секунды. Остановитесь, когда увидите end или run с финальным статусом.