ボックスの状態

ボックスがいつ凍結し、起き、完全に止まるか。何が使用に数えられ、何がボックスを起こしておくか。使っている会話がまだ作業中かを、アプリがどう示すか。

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 が変わるのは新しいボックスだけです。
  • 復帰後に大きなプログラムを初めて起動すると、いつもより遅く、数倍かかることもよくあります(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 は次の順に判定します。

  1. left:ボックスの最後のエージェントが leave を送った、または 3 分を超えてハートビートを送っていない。
  2. idle:ボックスが 1 時間以上使われていない(会話がまだ開いているかどうかは問わない)。
  3. away:ボックスが凍結中、または凍結までの時間(10 分)使われておらず、会話はまだ開いている。
  4. 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 はこのボックスを使っていません」と表示され、次のツール呼び出しで復帰します。


すべてのツールとトピックはツールリファレンスに並んでいます。