ボックスの状態
ボックスがいつ凍結し、起き、完全に止まるか。何が使用に数えられ、何がボックスを起こしておくか。使っている会話がまだ作業中かを、アプリがどう示すか。
claimed → ready → takeover(任意)→ stopping → terminated
↕
frozen
アイドル規則。sandbox_start の説明の原文(英語)は次のとおりです:
An idle box is frozen after 10 minutes without a call, with /work kept; the next call thaws it. A frozen box is stopped for good 24 hours after its last use. idleTimeoutMin sets your own limit instead of these: the box stops for good after that many minutes without a call, frozen or not. It is capped at 10080 minutes (7 days). An attached phone freezes and thaws with its box (an iPhone restarts its apps); while frozen it holds no device slot and is not billed. A pending sandbox_review keeps neither the box nor its phone awake: they freeze and are stopped by these same rules, and opening the review wakes a frozen box. Commands started with background: true (a dev server, a long build) count as activity for up to 1 hour after your last call; after that a box freezes anyway (they carry on when the next call thaws it). Requests through the box's URLs count as activity for up to 2 hours after the last call; after that the box freezes, and the next page load in a browser wakes it again (a few seconds). Background fetches from an open tab don't wake it. With no room on any host it fails with "no box capacity right now" (HTTP 503 over REST); waitForCapacitySec waits for room instead.
詳しく:
- 使用:このページで「使用」(「最後に使われて」など)と書くときは、ボックスに作用するツール呼び出しと復帰を指します。ボックスに作用するツール呼び出しは
sandbox_start、sandbox_exec、sandbox_sync、sandbox_get(sandbox_pullも)、sandbox_shot(urlsで複数ページをまとめて撮るものは除く)、sandbox_scene、sandbox_wire、sandbox_procs、ボックスを指定したsandbox_secretsとsandbox_buildです。人の引き継ぎ(引き継ぎ画面への接続、そこでの入力やクリック)と、別のボックスからのリンク接続も数えます。状態を見るだけ、または伝言を残すだけのsandbox_status、sandbox_list、sandbox_say、sandbox_feedbackは数えません。sandbox_review、sandbox_device、sandbox_takeoverとurlsを使ったsandbox_shotも数えませんが、凍結したボックスに対してはまず復帰させるので(listを指定したsandbox_deviceは除く)、その復帰は数えます。最後に使われた時刻は、これらの呼び出しが最後に始まったか終わった時刻か最後の復帰の、いちばん遅いもので、sandbox_statusとsandbox_listのlastUsedAtです。ボックスに作用する呼び出しは始まった時点で使用として数えるので、実行中のsandbox_syncやsandbox_getの途中でボックスが凍結されることはありません(フォアグラウンドのsandbox_execは実行中ずっとボックスを起こしておきます)。また、どの呼び出しも凍結処理の最中に届いたときは、凍結が終わる数秒を待ってからボックスを復帰させて実行し、失敗しません。 - ボックスは、活動が 10 分ないと
frozenになります。メモリをスナップショットに保存し、/workは残り、ボックス時間の課金が止まります。活動とは、使用(前の項目)か、最後に使われてから 2 時間以内にボックスの URL を通ったリクエスト(HTTP リクエストはすべて、WebSocket は開いたときに 1 回)です。人がwebUrlを使っていれば、その間ボックスは起きたままです。アプリの画面のライブ表示や、ボックス一覧のライブのサムネイルは数えません(どちらも人が見ている間だけ送られてくるもので、保存されません。クレジット のボックスの画像とは別物です)。2 時間を過ぎると URL へのリクエストではボックスは起きたままにならないので、ページを使い続けていても途中でボックスが凍結することがあります。その人が次にページを読み込めば復帰します(下記)。人が引き継ぎ中、フォアグラウンドのコマンドが実行中、起きている別のボックスがリンクで接続中の間は凍結されません。録画中も凍結されませんが、最後に使われてからまる 1 時間までです。それを過ぎ、ここに挙げたほかのものがどれもボックスを起こしていなければ、録画はアップロードされずに止められます(sandbox_shotを参照)。background: trueで起動したコマンド(dev server、長いビルド)がボックスを起こしておけるのは、最後に使われてから 1 時間までです。その後はボックスはそのまま凍結され、そのプロセスは次の呼び出しで復帰したときに続きから動きます。sandbox_statusのfreezeが、at(状況が変わらなければ凍結する時刻)とblockedBy[](今ボックスを起こしているもの。background、url、recordingはそれぞれ数える期限until付き、takeover、foreground、link、phoneは終わるまでで、そのときはatなし)を示します。アイドルが 10 分をとうに過ぎてもreadyのボックスは、このどれかに起こされています。 - 凍結したボックスは数秒で復帰します(スマホがつながっていれば、先にスマホが戻るので 1 分ほどかかります)。復帰させるのは、そのボックスを指定したツール呼び出し(
sandbox_status、sandbox_say、sandbox_feedback、sandbox_stop、listを指定したsandbox_deviceは除く)、別のボックスからのリンク接続、人がブラウザでそのページを読み込むこと(次の項目)、アカウントにサインインしている人がアプリのボックスのページで押す「画面を見る」ボタン(凍結したときにボックスの画面に何か表示されていた場合だけページにあります。どの会話がボックスを使っているかのposterUrlを参照)、API キーを付けたPOST /v1/boxes/{id}/wakeです。復帰は使用として数えます。復帰にはアカウントにクレジットが必要です(ないと 402)。sandbox_stopも凍結中のボックスに有効です。何も失われません。 - 凍結中のボックスのページをブラウザで読み込むと、ボックスは復帰します。対象は
Sec-Fetch-Mode: navigateのGETかHEAD(URL の入力、リンク、再読み込み)と、Sec-Fetch-Modeを送らないブラウザからのAcceptにtext/htmlを含むリクエストです。エッジはボックスの復帰を依頼し、小さなページ「Waking this box… This page reloads by itself in a few seconds.」(503、Retry-After: 3、Cache-Control: no-store)を返します。ページはアプリが表示されるまで自動で再読み込みを続け、全体で 10 秒ほどかかります。この復帰は使用として数えます。復帰の依頼は 1 つのボックスにつき 15 秒に 1 回までで、その間のページ読み込みには同じページが返ります。- URL を通るそれ以外のリクエストでは復帰しません。開いているページからの
fetchや XHR、画像やスクリプト、WebSocket、POSTには 503{"error":"box is frozen","status":"frozen"}が返ります。開きっぱなしでポーリングしているタブは、ボックスを復帰させることも、上の 2 時間を超えて起こしておくこともできません。 - アカウントのクレジットが尽きているときは「This box is paused」というページ(402)が表示され、自動では再読み込みされません。アプリでクレジットを追加してから再読み込みしてください。
- 停止したボックスはこの方法では戻りません。その URL は 503
box is terminatedを返し、新しいボックスには新しい URL が付きます。
- URL を通るそれ以外のリクエストでは復帰しません。開いているページからの
- ボックスの URL は凍結と復帰をまたいでも変わりません。URL が変わるのは新しいボックスだけです。
- 復帰後に大きなプログラムを初めて起動すると、いつもより遅く、数倍かかることもよくあります(3 秒で開く Electron アプリが 12 秒かかるなど)。そのファイルがボックスのメモリキャッシュから外れているためです。コールドスタートを計測・録画する前に、一度起動して温めてください。
- 復帰後、boxd は凍結前から開いていた環境のアドレスとリンクへの接続を閉じます(復帰には 15 秒ほどで気づきます)。復帰後に開いた接続はそのままです。プログラムは接続し直す必要があります。データベースの接続プールはたいてい自分で接続し直し、長く接続を保つクライアントは再試行するようにしてください。
- 凍結したボックスは、最後に使われてから 24 時間で完全に停止します(
/workは消えます)。凍結した時刻のほうが遅ければそこから数えるので、クレジット切れで凍結したボックスは 24 時間まるごと残ります。sandbox_reviewで渡して「確認待ち」で人を待っているボックスも同じ規則で凍結・停止します。確認待ちは何も起こしておきません。凍結中なら人がレビューを開くと起き、すでに停止していればレビューはそこで終わり、新しいボックスで渡し直す必要があります。停止したボックスもアプリの「停止済み(過去 7 日)」に表示され、撮影後 7 日以内の画像と動画を開けます。idleTimeoutMinのあるボックスは、代わりに使用がその分数ないと、凍結中かどうかにかかわらず停止します。ページの読み込みで復帰すると、ほかの復帰と同じく数え直しになります。 sandbox_statusとsandbox_listのstopsAtは、それまでに使われなければこの規則がボックスを完全に止める時刻です(止めることがなければ出ません)。stopsAtの 30 分前からは、そのボックスを使った会話、またはそのボックスを指定した呼び出しのツール結果の最後に、box <id>: the idle rules stop it for good at <時刻> (in 25 minutes) unless something uses it before then, and /work goes with it.のような 1 行が付きます。ボックスに作用する呼び出しはstopsAtを先に延ばしますが、sandbox_statusとsandbox_listは延ばしません。まだ要るものはその前に取り出してください。- この規則で止まった凍結ボックスは、凍結コピーがさらに 24 時間残ります。
sandbox_statusのrestorableUntil(all: trueを付けたsandbox_listにも)がいつまでかを示し、止まったボックスを指定した呼び出しも戻し方を伝えます。sandbox_start { "restore": "<id>", "goal": "<その goal>" }は、その同じボックスを凍結した時点のまま、/work、動いていたプログラム、id、URL ごと戻します(sandbox_start)。つないでいたスマホは残りません。sandbox_stopで止めたボックスにはコピーが残りません。 - ボックスを試している人のために、あなたがすることはありません。その人が URL を使っていれば、最後に使われてから 2 時間まではボックスは起きたままです。それを過ぎると、使っている途中でもボックスは凍結します。次にページを読み込めば 10 秒ほどで復帰し、その復帰は使用として数えるので、また 2 時間続きます(昼食から戻ったときも同じです)。独自の期限が必要なら
idleTimeoutMinを設定してください。シーン以外のページを自分で見るには、sandbox_shot { "id": "<id>", "target": "url", "url": "http://127.0.0.1:8082/" }がボックス内の新しい Chromium でそのページを開いてスクリーンショットを返します。sandbox_execでcurlすれば HTML が得られます。 - つながっているスマホはボックスと一緒に凍結されます。スマホが凍結されるのはボックスが凍結されるときだけで、ボックスを起こしておくものはスマホも動かしたままにします。スマホの凍結が終わってからボックスが凍結され、凍結中のスマホはデバイスの枠を使わず課金もされません。ボックスを解凍する呼び出しでスマホも戻り、同じ
deviceIdとserialでつながります(Android エミュレーターはメモリのスナップショットから続き、iPhone シミュレーターはアプリとデータを残したまま起動し直し、アプリは再起動します)。そのときデバイスホストに空きがなければスマホは凍結されたままで、空きが出しだいつながります(sandbox_deviceを参照)。そのアプリのboxのsandbox_reviewが人を待っていても同じで、待っている間もスマホはいつもどおりボックスと一緒に凍結され、人がレビューを開くとボックスと一緒に戻ります。
これらの規則で停止したボックスの statusReason にはそう書かれます。たとえば frozen and unused for … や unused for …, over idleTimeoutMin … です。
人がボックスの画面を使っている間(引き継ぎ、または開いた box の確認)は、sandbox_sync と sandbox_exec(readOnly を除く)が 423 を返し、人がいつから使っているか、なぜか(自分で引き継いだ、sandbox_takeover が頼んだ、あなたの渡した確認を試している)、遅くともいつ戻るかを伝えます。sandbox_get、sandbox_procs、画面・ウィンドウ・URL の sandbox_shot、sandbox_status、sandbox_say は使えます(古いイメージのボックスでは sandbox_get と sandbox_shot も 423 になり、エラーでそう伝えます)。その間も作業を続けるなら、別のボックスを起動してコードを同期してください。
どの状態からも interrupted になり得ます。ボックスの下のホストがなくなった状態です(クラウドに回収された、または故障した)。sandbox_status が理由を報告し、そのボックスへの次のツール呼び出しも同じ内容を返します。新しいボックスを起動してやり直してください。クラウドが予告してからマシンを回収するときは、その上のボックスは先に凍結・保存され、次の呼び出しで別のホストで解凍されるので、中断にはなりません。丸ごとは保存できなかったボックスでも /work は保存されていることがあり、そのときエラーに Its /work was saved at <時刻> と出ます。中断されたボックスで sandbox_get か sandbox_pull にパス /work を渡すと、そのコピーが work.tar.gz で返ります(node_modules、キャッシュ、64 MiB を超えるファイルは含まず、その時刻より後の変更もありません)。それ以外は、中断されたボックス上のものは何も残りません。
どの会話がボックスを使っているか
stdio アダプター(parallelsandbox-mcp 0.3.0 以降)は、自分の会話がまだ開いているかを ParallelSandbox に伝えます。
- 起動時にランダムな id を選び、MCP と REST のすべての呼び出しに
X-Psbx-Agentヘッダーとして付けます。 - 最初のツール呼び出しのあと、60 秒ごとに
POST /v1/agents/<id>/heartbeatを{"client": "<MCP クライアント名>"}で送ります。 - 会話が閉じられると(stdin の終了、または SIGTERM、SIGINT、SIGHUP)
POST /v1/agents/<id>/leaveを送ります。それを送らずに終わった会話(kill -9、スリープしたノート PC)は、最後のハートビートから 3 分で終了したとみなされます。leave のあとにハートビートが来れば、同じ id が戻ったとみなします。 - ほかには何も送りません。プロンプトも会話の記録も送りません。
ボックスは、最後にツールを呼んだエージェントの id を覚えます。ヘッダーのない呼び出しでは前の id のままです。id は英数字、-、_ の 1〜64 文字です。2 つのエンドポイントはそれ以外に 400 agent id: letters, digits, - and _ only, at most 64 を返し、規則に合わないヘッダーは無視されます。HTTP エンドポイントや REST API を直接呼ぶクライアントも同じことができます。自分で X-Psbx-Agent を送り、OAuth access token または API キーで 2 つのエンドポイントを呼びます(どちらも {"ok":true} を返します)。どちらも送らないクライアントでは、ボックスの AI の状態はアイドル時間だけで決まり、left にはなりません。
GET /v1/boxes、sandbox_list、sandbox_status は、動いている各ボックス(起動中、ready、引き継ぎ中、凍結中)に agent オブジェクト { "state": "working", "idleSec": 42 } を付けます。停止中、停止済み、interrupted のボックスにはありません。sandbox_list と sandbox_status では、ボックスの最後の agent id が呼び出し元の会話のものなら thisConversation: true も付きます。idleSec は、ボックスが最後に使われて(ツール呼び出し、復帰、人による画面の操作、リンク接続)から、または起動してからの秒数です。state は次の順に判定します。
left:ボックスの最後のエージェントが leave を送った、または 3 分を超えてハートビートを送っていない。idle:ボックスが 1 時間以上使われていない(会話がまだ開いているかどうかは問わない)。away:ボックスが凍結中、または凍結までの時間(10 分)使われておらず、会話はまだ開いている。working:それ以外。
同じ一覧は、ボックスの画面に何があるかも示します。
screenInUse:仮想ディスプレイに何か(ブラウザ、エミュレーター)が表示されている。ビルドやテストだけを動かすボックスでは false。screenActive:ボックスがreadyで、screenInUseが true のときに true。画面が最近変化したかどうかは見ません。AI がテストを走らせていて画面が止まっているボックスも含みます。posterUrl:ボックスが凍結したときの画面の画像(署名付き、1 時間有効)。そのとき画面に何か表示されていた場合だけ付きます。ビルドやテストだけを動かすボックスには、黒いデスクトップの代わりに何も付きません。凍結するたびに以前の画像を置き換え、最新の 1 枚だけを保存します(クレジット)。ボックスを止めたあとも、GET /v1/boxes?all=1では最新の 1 枚が付きます。
アプリはこれらのフィールドで、動いているボックスを振り分けます。
- 「確認待ち」:人を待っているボックス。
sandbox_reviewのカードかsandbox_takeoverが人を待っているもの。 - 「AI がテスト中」:
screenActiveが true でagent.stateがworking、かつ人を待っていないボックスだけ。 - 「すべて」:動作中のボックスと過去 7 日に停止したボックス。それぞれに「AI が使用中」(
working)、「AI は別の作業中」(away)、「AI は手を止めました · 会話は終了」(left)、「AI は手を止めました · 1 時間未使用」(idle)のいずれかが付きます。AI が手を止め、人を待っていないボックスには「続きを頼む」と「片付ける」のボタンがあります(別の会話が残したボックスを引き継ぐ)。
「凍結中」は、もう人に見せる状態ではありません。一覧では凍結中のボックスは「AI は別の作業中」か「AI は手を止めました」で、ボックスのページには「AI はこのボックスを使っていません」と表示され、次のツール呼び出しで復帰します。
すべてのツールとトピックはツールリファレンスに並んでいます。