Человек в контуре
Пусть агент задаёт вам вопросы, ждёт вашего подтверждения перед отправкой, передаёт вам браузер ради CAPTCHA и позволяет перехватить управление в любой момент.
Некоторым шагам нужен человек: одноразовый код, пришедший на ваш телефон, решение перед покупкой, CAPTCHA. Агент приостанавливает запуск, сообщает, что ему нужно, и продолжает после вашего ответа. Ваш код (или человек, который им пользуется) отвечает через один эндпоинт — POST /v1/browser/runs/{id}/reply.
| Запуску нужно | needs.kind | Вы отвечаете |
|---|---|---|
| Информация, которой у него нет | question | {"answer": "…"} или {"secret": "…"} |
| Ваше согласие перед отправкой | approval | {"approve": true} или {"approve": false, "reason": "…"} |
| Человек в браузере | takeover | Завершите действие в Live View, затем {"done": true} или {"failed": true} |
Как работает пауза#
Когда агенту нужны вы, status запуска становится waiting_for_human, а needs описывает, что требуется (в сокращении):
{
"id": "brun_5b7d9f1a3c5e7a9b1d3f5a7c",
"object": "browser_run",
"status": "waiting_for_human",
"steps": 6,
"current_url": "https://bank.example.com/verify",
"needs": {
"kind": "question",
"prompt": "What is the 6-digit code sent to your phone ending 42?",
"expects_secret": true,
"screenshot": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/screenshot",
"since": "2026-10-11T09:31:12.000Z",
"reply": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/reply"
}
}| Поле | Значение |
|---|---|
needs.kind | question, approval или takeover |
needs.prompt | Что нужно агенту, одним предложением, готовым для показа человеку |
needs.screenshot | Путь к JPEG-снимку страницы на момент начала паузы. Запрашивайте его со своим API-ключом. |
needs.since | Когда началась пауза |
needs.reply | Путь для ответа |
Пока запуск ждёт:
- Браузер остаётся открытым на той же странице, поэтому агент продолжает ровно с того места, где остановился.
- Запрос статуса с
?wait=возвращается сразу, не удерживаясь. Ответьте или опрашивайте со своей задержкой. - Если вы настроили вебхук, он получает событие
run.waiting. - Каждая пауза включает одну минуту. Сверх этого ожидание стоит $0.005 в минуту (цены).
- Если никто не ответит в течение
human_timeout_minutes(по умолчанию 30), запуск завершается статусомtimed_outс ошибкойno human response within 30 minutes.
Обработка пауз в коде#
Этот цикл запускает задачу, которая может запросить подтверждение или код, и спрашивает человека в терминале:
import os
import requests
API = "https://lovelyrouter.com/v1/browser"
H = {"Authorization": f"Bearer {os.environ['LOVELY_API_KEY']}"}
run = requests.post(f"{API}/runs", headers=H, json={
"goal": "In the rewards shop, redeem 500 points for the Blue Mug and tell me the order number.",
"start_url": "https://shop.example.com/rewards",
"profile": "shop-login",
"approve": "risky",
}).json()
while run["status"] in ("running", "waiting_for_human"):
if run["status"] == "waiting_for_human":
needs = run["needs"]
if needs["kind"] == "approval":
print(needs["prompt"], *needs["fields"], sep="\n ")
reply = {"approve": input("Approve? [y/N] ").strip().lower() == "y"}
elif needs["kind"] == "question":
value = input(needs["prompt"] + " ")
reply = {"secret": value} if needs["expects_secret"] else {"answer": value}
else: # takeover
print(needs["prompt"], "\nOpen:", needs["live_view_url"])
input("Press Enter when you are done. ")
reply = {"done": True}
# A 409 here means the run already moved on; the next status request shows where it is.
requests.post(f"{API}/runs/{run['id']}/reply", headers=H, json=reply)
run = requests.get(f"{API}/runs/{run['id']}", headers=H, params={"wait": 30}).json()
print(run["status"], run["answer"])Если человек не сидит за терминалом, отправьте ему needs.prompt (и скриншот или ссылку на Live View) через своё приложение, чат или email и отправьте его ответ, когда он придёт. Когда это делать, подскажет вебхук.
Ответ на вопрос#
Агент спрашивает, когда странице нужно то, чего нет в цели: код подтверждения, пришедший на телефон или email, недостающая деталь или выбор, который можете сделать только вы. Ответить можно двумя способами:
{"answer": "…"}— текст, который агент читает и использует, до 2000 символов. Подходит для деталей и выбора:{"answer": "Use the billing address, not the shipping one."}{"secret": "…"}— значение, которое агент вводит на страницу, никогда его не видя, до 4096 символов. Подходит для одноразовых кодов:{"secret": "481923"}
needs.expects_secret равен true, когда вопрос касается кода, пароля, PIN-кода или одноразового кода. Секретный ответ можно ввести только на том сайте, где был запуск в момент вопроса, в любое текстовое поле этого сайта, включая поля пароля и PIN-кода. Как и другие секреты, значение длиной от шести символов заменяется на [secret:<name>] везде, где оно появилось бы в выводе запуска, а само значение удаляется по завершении запуска. Пароли, которые нужны в каждом запуске, лучше сохранить в хранилище, чтобы агенту не приходилось спрашивать.
curl https://lovelyrouter.com/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/reply \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{"secret": "481923"}'Для кодов из приложения-аутентификатора лучше сохраните в хранилище TOTP-сид. Тогда агент сам вводит текущий код, и спрашивать ему не нужно. См. Коды двухфакторной аутентификации.
Подтверждение перед отправкой#
approve определяет, когда агент останавливается и ждёт вашего согласия перед действием, которое что-то отправляет: кнопкой, отправляющей форму, кнопкой с подписью о покупке, бронировании, оплате, сообщении или удалении («Buy now», «Book», «Pay», «Send», «Delete» и подобные), или нажатием Enter в поле формы, которая не является строкой поиска, — это отправляет форму. На ссылках агент никогда не останавливается: переход по ссылке лишь открывает страницу.
approve | Агент останавливается перед |
|---|---|
risky (по умолчанию) | Такими действиями, если считает их необратимыми или значимыми: оплата или покупка, заказ или бронирование, отправка сообщения или письма, удаление данных, подача заявки. Вход в аккаунт, поиск, навигация и промежуточные шаги формы выполняются без остановки. |
submit | Каждым из таких действий. |
none | Ничем. Агент отправляет всё сам. |
Любое другое значение отклоняется с 400. Пауза для подтверждения выглядит так:
{
"status": "waiting_for_human",
"needs": {
"kind": "approval",
"prompt": "Approve: click button \"Redeem 500 points\" on Blue Mug – Rewards?",
"fields": ["Quantity: \"1\"", "Ship to: \"Ada Lovelace, 12 Main St\"", "Gift wrap: unchecked"],
"action": "Redeem 500 points",
"screenshot": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/screenshot",
"since": "2026-10-11T09:33:40.000Z",
"reply": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/reply"
}
}fields перечисляет текущие значения формы, а action — подпись кнопки, которую агент хочет нажать. Ответьте:
{"approve": true}— агент нажимает эту кнопку следующим шагом.{"approve": false, "reason": "Wrong address"}— агент ничего не отправляет. Он читает вашу причину (до 500 символов) и пробует другой путь либо завершает работу и сообщает почему.{"deny": true}работает так же.
curl https://lovelyrouter.com/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/reply \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{"approve": true}'Передача управления ради CAPTCHA#
Агент не умеет решать CAPTCHA и проверки «подтвердите, что вы человек». Когда страница показывает такую проверку или шаг, который может выполнить только человек, агент передаёт вам браузер, и needs.kind становится takeover:
{
"status": "waiting_for_human",
"needs": {
"kind": "takeover",
"prompt": "Please solve the CAPTCHA and press Continue.",
"live_view_url": "https://…",
"live_view_expires_at": "2026-10-11T10:35:02.000Z",
"screenshot": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/screenshot",
"since": "2026-10-11T09:35:02.000Z",
"reply": "/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/reply"
}
}- Откройте
live_view_urlв браузере. Там в реальном времени видна вкладка браузера агента, и человек может кликать и вводить текст. Ссылка действует один час. - Человек делает то, что сказано в
prompt. - Ответьте
{"done": true}, при желании добавивnote(до 500 символов), которую прочитает агент, например"Solved the CAPTCHA, now on the search results". Если человек не справился, ответьте{"failed": true, "note": "…"}.
Если запуск сам замечает, что передача управления закончилась, он продолжает без вашего ответа, а более поздний ответ вернёт 409 — его можно игнорировать. Агент также передаёт управление, когда застревает: после трёх неудачных шагов подряд или после трёх повторов одного и того же действия без продвижения.
Страница с CAPTCHA или проверкой «подтвердите, что вы человек» передаётся человеку не более двух раз за запуск. Если после этого она всё ещё на месте или человек ответил {"failed": true}, запуск завершается статусом failed с ошибкой blocked by the website. То же происходит со страницей, которая полностью блокирует браузер (доступ запрещён, 403), ведь человек тоже не сможет её обойти, и с любой проверкой на человека, если запуск стартовал с "human": false.
Перехват управления вручную#
Вы можете забрать браузер в любой момент, например чтобы показать агенту дорогу или выполнить шаг вручную:
curl https://lovelyrouter.com/v1/browser/runs/brun_5b7d9f1a3c5e7a9b1d3f5a7c/takeover \
-H "Authorization: Bearer $LOVELY_API_KEY" \
-H "content-type: application/json" \
-d '{"instructions": "I will pick the delivery slot myself."}'Запрос сразу возвращает 202. Запуск приостанавливается после текущего шага, и следующий статус показывает needs.kind takeover с live_view_url. Сделайте нужное в Live View, затем верните управление ответом {"done": true, "note": "Picked Saturday 10–12"}. Агент продолжит со страницы, на которой вы его оставили.
instructions (необязательно, до 500 символов) становится prompt паузы. Если запуск уже ждёт ответа на вопрос или подтверждения, перехват начнётся после того, как вы ответите. Завершённый запуск возвращает 409 с This run has finished.
Настройка тайм-аута#
human_timeout_minutes задаёт, сколько каждая пауза ждёт ответа: от 1 до 1440 минут, по умолчанию 30 (5 для запуска, начатого облачным агентом, за которым обычно никто не наблюдает). Когда сессия облачного агента заканчивается, его незавершённые запуски браузера останавливаются. Таймер перезапускается на каждой паузе. Запуск, превысивший тайм-аут, завершается статусом timed_out, и с вас списывается плата за его шаги и оплачиваемое время ожидания.
Более длинный тайм-аут даёт людям больше времени на ответ, но резервирует больше вашего баланса: резерв включает одно ожидание до тайм-аута по $0.005 в минуту. См. Как работает резерв.
Запуск без человека#
Для заданий без присмотра отключите паузы:
{
"goal": "Get the current mortgage rates table.",
"start_url": "https://bank.example.com/rates",
"human": false,
"approve": "none"
}"human": false— агент никогда не задаёт вопросов и не передаёт управление. Если ему не хватает информации или он застрял, он продолжает как может, и запуск может завершиться статусомfailed."approve": "none"— агент отправляет формы, не дожидаясь подтверждения.
Если заданы оба параметра, запуск ничего не резервирует на время ожидания.
Справочник по ответам#
POST /v1/browser/runs/{id}/reply принимает ровно одно из следующих тел:
| Тело | Для needs.kind | Результат |
|---|---|---|
{"answer": "…"} | question | Агент читает ваш текст (до 2000 символов). |
{"secret": "…"} | question | Агент вводит значение на текущем сайте, не видя его (до 4096 символов). |
{"approve": true} | approval | Агент нажимает кнопку следующим шагом. |
{"approve": false, "reason": "…"} или {"deny": true, "reason": "…"} | approval | Агент ничего не отправляет и читает вашу причину. |
{"done": true, "note": "…"} | takeover | Агент продолжает с текущей страницы. |
{"failed": true, "note": "…"} | takeover | Агент продолжает, зная, что человек не смог закончить. |
Он возвращает запуск, status которого снова running. Ошибки:
| Статус | Сообщение | Причина |
|---|---|---|
400 | Reply with one of: … | Тело не соответствует ни одной из форм выше. |
404 | No such run | Неверный id, или запуск принадлежит другому аккаунту. |
409 | This run is not waiting for a reply | Запуск работает или уже завершён. |
409 | This run is waiting for a reply of kind "question" | Ответ не соответствует needs.kind (в сообщении указан ожидаемый вид). |