События и экран в реальном времени
Получайте поток того, что делает агент, — каждый шаг по мере завершения и экран браузера во время работы запуска — вместо ожидания результата.
Запуск длится от нескольких секунд до нескольких минут. Вместо того чтобы ждать конца, получайте его потоком: вы видите, что агент делает прямо сейчас, каждый шаг по мере завершения, состояние запуска при каждом изменении и, если попросите, экран браузера. Поток заканчивается завершённым запуском, включая 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
}'Поток выглядит так (в сокращении):
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 -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 раз в секунду; неподвижная страница ничего нового не присылает. Если ваш читатель отстаёт, пропускаются кадры, но никогда не другие события.
Чтобы показать экран на веб-странице, поместите кадр в изображение:
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 с финальным статусом.