ライブイベントと画面
結果を待たずに、エージェントがいま行っていること、完了した各ステップ、ブラウザ画面を実行中にストリーミングで受け取ります。
1 回の実行には数秒から数分かかります。終わるまで待つ代わりに、ストリーミングで受け取りましょう。エージェントがいま何をしているか、各ステップの完了、実行状態の変化、そして必要ならブラウザ画面がわかります。ストリームは終了した実行で締めくくられ、answer、data、charge_usd が含まれます。
ストリームには Server-Sent Events(text/event-stream)を使います。LLM API のストリーミングと同じ形式です。実行の視聴は無料です。
新しい実行をストリーミングする#
実行を作成するときに "stream": true を追加します。レスポンスは 202 の JSON ではなく、ステータス 200 のイベントストリームになります。ブラウザ画面も受け取るには "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 を渡した場合は webhook_secret)が入っています。実行開始前のエラー(400、402、429 など)は、stream なしの場合と同じく、そのステータスの JSON で返ります。
進行中の実行を追跡する#
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"どのストリームも、完全な trace を含む run イベントから始まるため、再接続しても何も失われません。終了済みの実行では、その run イベント(screen 指定時は最後の画面も)に続いて end が送られます。
イベント#
| イベント | タイミング | data |
|---|---|---|
run | 最初、各ステップの後、一時停止の開始・終了時、そして最後 | charge_usd と reserved_usd 付きの実行オブジェクト。最初のものには trace が含まれます。 |
activity | エージェントが何かを始めたとき | step(進行中のステップ)、kind、text |
step | ステップが完了したとき | trace の 1 件:step、url、action、description、ms、error |
frame | screen 指定時:接続時と、ページが変わるたび | data(ブラウザの base64 JPEG)と at(ISO 8601) |
end | 実行が終わり、続いてストリームが閉じられるとき | id |
アクティビティの種類:
kind | エージェントが行っていること |
|---|---|
starting | ブラウザを起動する、または start_url を開く |
reading | ページを読み取る |
waiting | まだ読み込まれていないページを待つ、または再読み込みする |
deciding | 次のアクションを選ぶ |
thinking | 決める前によく確認する(高精度モードではスクリーンショットを使うことがあります) |
checking | 送信前にフォームの値を確認する |
acting | text が示すアクションを行う:クリック、入力、選択、アップロード |
answering | 結果を読み取り、回答を書く |
extracting | 読み取った内容を data にまとめる |
: で始まる行はキープアライブのコメントで、ほかに何も起きていない間は 15 秒ごとに送られます。無視してください。
画面を見る#
"screen": true(または ?screen=1)を指定すると、frame イベントがブラウザ画面を base64 JPEG で運びます。1 枚あたり通常 20〜60 KB です。接続時に 1 枚、その後はページが変わるたびに、最大で毎秒約 4 枚届きます。静止しているページでは新しいフレームは送られません。読み取りが追いつかない場合はフレームがスキップされますが、ほかのイベントがスキップされることはありません。
Web ページに表示するには、フレームを画像に入れます:
img.src = `data:image/jpeg;base64,${frame.data}`;ストリームを使わずに 1 枚だけ欲しい場合は、GET /v1/browser/runs/{id}/screenshot が現在の画面を返します。
人の対応待ち#
実行が waiting_for_human の間も、ストリームは開いたままです。一時停止を始める run イベントには needs が含まれます。どこからでも POST /v1/browser/runs/{id}/reply で返信すると、ストリームは running に戻った run イベントとともに続きます。screen を指定していれば、引き継ぎ中に人がブラウザで行う操作も見えます。人による確認を参照してください。
Web アプリでのストリーム#
API キーはサーバーに置いてください。ブラウザの EventSource は Authorization ヘッダーを送れないため、サーバーでストリームを開き、content-type: text/event-stream のまま手を加えずにページへ中継します。ページからは自分の URL に対して EventSource を使えます。
再接続#
ストリームは切れることがあります。ネットワークの瞬断、プロキシのタイムアウト、こちら側のデプロイなどです。実行は続いています。GET /v1/browser/runs/{id}/events を開き直し、最初の run イベントで状態を置き換えてください。EventSource は 3 秒後に自動で再接続します。end か、最終ステータスの run を受け取ったら終了してください。