サンドボックスクライアント
サンドボックスでの作業をどこで実行するかを選択するには、このページを使用してください。ほとんどの場合、SandboxAgent の定義はそのままで、sandbox 実行オプション内のサンドボックスクライアントとクライアント固有のオプションのみを変更します。
| 目的 | 最初の選択肢 | 理由 |
|---|---|---|
| macOS または Linux で最速のローカルイテレーション | UnixLocalSandboxClient | 追加のサービス依存関係がなく、シンプルなローカルファイルシステムのワークフローを利用できます。 |
| 基本的なコンテナ分離 | DockerSandboxClient | 指定したイメージを使用して Docker 内で作業を実行します。 |
| ホステッド実行または本番環境相当の分離 | ホステッドサンドボックスクライアント | ワークスペースの境界をプロバイダー管理の環境へ移します。 |
ローカルクライアント
Section titled “ローカルクライアント”ほとんどのユーザーは、次の 2 つのサンドボックスクライアントのいずれかから始めることをおすすめします。
| クライアント | インストール | 選択する状況 |
|---|---|---|
UnixLocalSandboxClient | なし | macOS または Linux で最速のローカルイテレーションが必要な場合。ローカル開発に適したデフォルトです。 |
DockerSandboxClient | ローカルで Docker CLI が利用可能 | コンテナ分離が必要な場合、またはローカル環境と同等にするために特定のイメージを使用したい場合。 |
Unix ローカルは、ローカルファイルシステムを対象とする開発を始める最も簡単な方法です。より強力な環境分離や本番環境相当の構成が必要になったら、Docker またはホステッドプロバイダーへ移行してください。
Unix ローカルから Docker へ切り替えるには、エージェント定義はそのままにして、クライアントのみを変更します。
import { run } from '@openai/agents';import { SandboxAgent } from '@openai/agents/sandbox';import { DockerSandboxClient } from '@openai/agents/sandbox/local';
const agent = new SandboxAgent({ name: 'Workspace reviewer', model: 'gpt-5.6-sol', instructions: 'Inspect the sandbox workspace before answering.',});
const result = await run(agent, 'Inspect the workspace.', { sandbox: { client: new DockerSandboxClient({ image: 'node:22-bookworm-slim' }), },});
console.log(result.finalOutput);通常、同じエージェントをどちらのローカルクライアントでも実行できます。
import { DockerSandboxClient, UnixLocalSandboxClient,} from '@openai/agents/sandbox/local';
const client = process.env.USE_DOCKER ? new DockerSandboxClient({ image: 'node:22-bookworm-slim' }) : new UnixLocalSandboxClient();セッションの所有権
Section titled “セッションの所有権”ライフサイクルには 2 つの方式があります。
| 方式 | 渡すもの | セッションを閉じる主体 | 使用する状況 |
|---|---|---|---|
| SDK 管理 | sandbox: { client } | Runner | サンドボックスを 1 回の実行中だけ存続させればよい場合。 |
| 開発者管理 | sandbox: { session } | アプリケーションコード | 後でファイルを確認する場合、同じライブセッションを再利用する場合、または複数の実行を連携させる場合。 |
正常終了時または失敗時には、Runner が SDK 管理のセッションを閉じます。承認による中断で実行が一時停止した場合や、未完了のストリーミング実行がキャンセルされた場合は、同じ実行を継続できるように、管理対象のサンドボックス状態を RunState に保持します。
セッションを自分で作成した場合は、自分で閉じてください。
import { run } from '@openai/agents';import { Manifest, SandboxAgent } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();const agent = new SandboxAgent({ name: 'Workspace reviewer', model: 'gpt-5.6-sol', instructions: 'Inspect the sandbox workspace before answering.',});
const client = new UnixLocalSandboxClient();const session = await client.create({ manifest });
try { await run(agent, 'First pass.', { sandbox: { session } }); await run(agent, 'Follow-up pass.', { sandbox: { session } });} finally { await session.close?.();}再開とスナップショット
Section titled “再開とスナップショット”サンドボックスの状態と会話の状態は別々です。
- SDK の会話状態は、
result.history、SDK のSession、conversationId、またはpreviousResponseIdに保存されます。 - サンドボックスの状態は、ライブサンドボックスセッション、シリアライズされた
sessionState、RunStateのサンドボックスペイロード、またはスナップショットに保存されます。
サンドボックスクライアントを介して同じバックエンドセッションへ再接続する場合は、sessionState を使用します。保存済みのワークスペース内容を初期状態として新しいセッションを作成する場合は、スナップショットを使用します。
import { Manifest } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const manifest = new Manifest();const client = new UnixLocalSandboxClient({ snapshot: { type: 'local', baseDir: '/tmp/my-sandbox-snapshots' },});
const session = await client.create({ manifest });const state = await client.serializeSessionState?.(session.state);await session.close?.();
if (state) { const restored = await client.resume?.( await client.deserializeSessionState!(state), ); await restored?.close?.();}より大きなワークフローを一時停止または再開するときは、RunState で Runner 管理のサンドボックス状態を保持することもできます。シリアライズされた実行とは別にサンドボックスのライフサイクルを管理する場合は、明示的な sessionState を使用してください。
Docker では、同じインメモリの RunState から再開する場合、SDK がコンテナの ID を検証し、現在のマニフェスト、環境、パス権限を再検証した後にのみ、ライブコンテナを再利用できます。ライブ再利用が利用できない場合や拒否された場合、Docker は復元可能なスナップショットへフォールバックします。RunState.fromString(...) でシリアライズ後に再構築された RunState には、信頼済みのライブコンテナ権限が含まれないため、Docker はシリアライズされたコンテナ ID に接続せず、スナップショットから復元します。復元可能なスナップショットが設定されていない場合は、未検証のコンテナへ接続するのではなく、再開が失敗します。
明示的な baseDir を指定せずにローカルスナップショットを使用する場合は、OPENAI_AGENTS_SANDBOX_SNAPSHOT_DIR を設定して保存先ディレクトリを上書きします。それ以外の場合、SDK は macOS では ~/Library/Application Support/openai-agents-js/sandbox-snapshots、Windows では %LOCALAPPDATA%\openai-agents-js\sandbox-snapshots、その他のプラットフォームでは $XDG_STATE_HOME/openai-agents-js/sandbox-snapshots を使用します。これらの場所を利用できない場合は、ホームディレクトリまたは一時ディレクトリへフォールバックします。
マニフェストの展開
Section titled “マニフェストの展開”マニフェストのエントリは、エージェントの実行前に準備されます。展開時の並行処理数は、実行ごと、またはクライアントの作成呼び出しごとに調整できます。
import { run } from '@openai/agents';import { SandboxAgent } from '@openai/agents/sandbox';import { UnixLocalSandboxClient } from '@openai/agents/sandbox/local';
const agent = new SandboxAgent({ name: 'Repository inspector', model: 'gpt-5.6-sol', instructions: 'Inspect the repository before answering.',});
await run(agent, 'Inspect the repo.', { sandbox: { client: new UnixLocalSandboxClient(), concurrencyLimits: { manifestEntries: 4, localDirFiles: 16, }, },});manifestEntries は、トップレベルのエントリを並行処理する数を制限します。localDirFiles は、localDir() エントリ内のファイルコピーの並行処理数を制限します。
ファイルシステムの存在確認
Section titled “ファイルシステムの存在確認”セッションが pathExists() を実装している場合、false は、そのパスが存在しないことをバックエンドが確認したことを意味します。権限エラー、I/O 障害、プロバイダーによる確認処理の失敗は、パスが存在しないものとして扱われず、プロバイダーエラーとして拒否されます。これにより、存在する可能性はあるもののアクセスできないパスを、エディター、マニフェスト、メモリの処理が上書きまたは置換することを防ぎます。
マウントとリモートストレージ
Section titled “マウントとリモートストレージ”マウントエントリは公開するストレージを記述し、マウント戦略はサンドボックスバックエンドがそのストレージを接続する方法を記述します。組み込みのマウントエントリと汎用戦略は、@openai/agents/sandbox からインポートします。
一般的なマウントオプションは次のとおりです。
mountPath:サンドボックス内でストレージを公開する場所。相対パスはマニフェストルートを基準に解決され、絶対パスはそのまま使用されます。readOnly:サンドボックスからマウント済みストレージへ書き戻さない場合に設定します。mountStrategy:マウントエントリとサンドボックスバックエンドの両方に適合する戦略を使用します。
マウントは一時的なワークスペースエントリとして扱われます。スナップショットと永続化の処理では、マウント済みのリモートストレージを保存対象のワークスペースへコピーせず、マウントされたパスを切り離すかスキップします。
汎用的なローカル/コンテナ戦略は次のとおりです。
| 戦略またはパターン | 使用する状況 | 注記 |
|---|---|---|
inContainerMountStrategy(...) | サンドボックスイメージで rclone、mount-s3、blobfuse2 などのマウントコマンドを実行できる場合。 | 汎用戦略として利用できます。対応状況はバックエンドによって異なります。 |
dockerVolumeMountStrategy(...) | コンテナの起動前に、Docker でボリュームドライバーを使用したマウントを接続する場合。 | Docker 専用です。 |
localBindMountStrategy() | ローカルバックエンドで、ローカルの絶対パスをワークスペースへバインドする場合。 | 許可されている場合、ローカルワークスペースの展開で対応します。 |
バックエンドの対応状況は、意図的に明示されています。
| バックエンド | マウントに関する注記 |
|---|---|
UnixLocalSandboxClient | ローカルワークスペースモデルを通じて、ローカルのバインド形式のマウントに対応します。 |
DockerSandboxClient | Docker がストレージを接続できる場合、ローカルバインドマウントと Docker ボリューム形式の戦略に対応します。 |
| ホステッドプロバイダー | プロバイダー固有の戦略は、各プロバイダーの実装に含まれています。対応するマウントと必要なセットアップについては、そのプロバイダーのドキュメントを確認してください。 |
マウントエントリがすべてのバックエンドで動作するとは限りません。クライアントがマニフェストのメタデータ、ID、またはマウント動作を適用できない場合、マニフェストの該当部分を暗黙的に無視するのではなく、早期に失敗する必要があります。
対応するホステッドプラットフォーム
Section titled “対応するホステッドプラットフォーム”ホステッド環境が必要な場合でも、通常は同じ SandboxAgent 定義を引き続き使用でき、sandbox 実行オプション内のサンドボックスクライアントのみを変更します。
ホステッドプロバイダーの実装は、@openai/agents-extensions のプロバイダー別サブパスから利用できます。正確な環境変数、実行可能なコード例、ポート動作、PTY 対応、スナップショット動作、クリーンアップ動作については、プロバイダーのドキュメントを確認してください。
@openai/agents-extensions をインストールし、そのパッケージレベルのピア依存関係を満たしてください。各プロバイダーでは、プロバイダー SDK パッケージまたはバックエンドのセットアップも必要になる場合があります。
| クライアント | インポートパス | プロバイダーの要件 |
|---|---|---|
BlaxelSandboxClient | @openai/agents-extensions/sandbox/blaxel | npm ピア:@blaxel/core |
CloudflareSandboxClient | @openai/agents-extensions/sandbox/cloudflare | Cloudflare Sandbox ブリッジの Worker URL と Worker 認証 |
DaytonaSandboxClient | @openai/agents-extensions/sandbox/daytona | npm ピア:@daytonaio/sdk |
E2BSandboxClient | @openai/agents-extensions/sandbox/e2b | npm ピア:e2b または @e2b/code-interpreter |
ModalSandboxClient | @openai/agents-extensions/sandbox/modal | npm ピア:modal |
RunloopSandboxClient | @openai/agents-extensions/sandbox/runloop | npm ピア:@runloop/api-client |
VercelSandboxClient | @openai/agents-extensions/sandbox/vercel | npm ピア:@vercel/sandbox |
CloudflareSandboxClient は Cloudflare の npm SDK をインポートしません。代わりに、デプロイ済みの Cloudflare Sandbox ブリッジ Worker と HTTP 経由で通信します。
VercelSandboxClient は、各 PAT 認証情報フィールドを、作成ごとのオプション、コンストラクターオプション、VERCEL_PROJECT_ID、VERCEL_TEAM_ID、VERCEL_TOKEN の順で解決します。解決後の projectId、teamId、token がすべて空でない場合にのみ、認証情報を転送します。それ以外の場合は 3 つのフィールドをすべて省略し、プラットフォーム OIDC やローカルプロバイダーの認証情報を含め、@vercel/sandbox に認証の解決を委ねます。完全に解決された認証情報は、セッションのシリアライズおよび再開時にも保持されます。シリアライズされた認証情報は完全な 3 要素の組として扱われ、現在のオプションや環境変数とは組み合わされません。不完全なシリアライズ済み認証情報は破棄され、その後フォールバックとして現在の設定が解決されます。シリアライズされたセッション状態にはトークンが残るため、その状態は安全に保存してください。
ホステッドサンドボックスクライアントは、プロバイダー固有のマウント戦略を公開します。ストレージプロバイダーに最適なバックエンドとマウント戦略を選択してください。
サンドボックス内でヘルパーを実行する、認証情報を伴うマウントは、モデルが制御するコードからそのヘルパープロセスの認証情報へアクセスできるため、デフォルトでは拒否されます。これには、対応するマウントフィールドを通じて指定された認証情報、環境内の AWS または GCP 認証情報、RCLONE_CONFIG_* の値、ワークロード ID またはマネージド ID の検出が含まれます。認証情報を使用しない rclone およびマウントポイントのヘルパーは、環境またはメタデータによる認証を無効にし、バックエンドが対応している場合は匿名アクセスを使用します。Docker ボリューム、Modal クラウドバケット、Cloudflare バケットマウントなど、外部戦略またはプロバイダーのネイティブ戦略を優先してください。
サンドボックス内ヘルパーが必要な場合は、アプリケーションが作成したマニフェスト上で、信頼する実効マウントパスをそれぞれ承認してください。型付きマウントフィールドを通じて直接指定するマウント単位の認証情報には、manifest.withInContainerMountCredentialExposureAcknowledged('mounted/path') が返すマニフェストを使用します。環境内の認証情報、ワークロード ID またはマネージド ID、外部の認証情報ファイルまたは設定ファイルには、manifest.withInContainerMountBroadCredentialExposureAcknowledged('mounted/path') が返すマニフェストが必要です。両方の種類の権限情報を使用するマウントには、両方の承認が必要です。これらの完全一致パスに対する承認は実行時のみ有効であり、マニフェストの初期化オブジェクトやシリアライズされたマニフェストデータからは決して受け入れられません。承認により、選択したヘルパーが認証情報を受け取れるようになりますが、その認証情報の使用範囲がマウントパス内に制限されるわけではありません。そのため、同じサンドボックス内でモデルが制御する他のコードから認証情報を取得できる可能性があります。サンドボックス単位で、短期間のみ有効かつ最小権限の認証情報を使用してください。
マウントが参照する認証情報ファイルは、直接またはシンボリックリンク経由で、シリアライズ可能なマニフェストエントリへ解決されてはなりません。動的なマニフェスト変更はセッションごとにシリアライズされます。プロバイダー側の処理が開始された可能性がある状態で、特権マウントへの切り替えまたは置換に伴うアンマウントに失敗した場合、SDK は曖昧な状態を再利用または永続化せず、そのセッションを無効化して終了します。
シリアライズされたサンドボックス状態では、サンドボックス内のマウントヘルパーが選択した環境内の認証情報を含め、マウント認証情報が省略されます。永続化されたマウントトポロジーを使用するには、再開前に現在の信頼済みマニフェストが必要です。再開可能な外部マウントまたはプロバイダーのネイティブマウントでは、認証情報を除いた現在のマウントトポロジーと永続化済みのマウントトポロジーが一致した後にのみ、SDK が認証情報を復元します。明示的な sessionState で既存のプロバイダーネイティブマウントへ再接続できるのは、マスキングされていないライブ権限情報が現在の信頼済みマニフェストと引き続き一致する場合だけです。権限情報がマスキング、ローテーション、または削除されている場合は、新しいサンドボックスが必要です。認証情報を含まないトポロジーと分離できない不透明な設定は、再開できません。Runner が、サンドボックス内のマウントヘルパーを使用していたシリアライズ済み RunState エントリを復元する場合、保存済みセッションを破棄し、現在の信頼済み設定から新しいサンドボックスを作成します。呼び出し元が指定した明示的な sessionState とプロバイダーからの直接再開では、コンテナ内のマウント状態が拒否されます。新しいサンドボックスを明示的に開始してください。不透明な secretRefs を通じて指定された Runloop の認証情報ファイル変数は、コンテナ内マウントでは拒否されます。SDK がマウント前に実効パスを検証できるように、現在の信頼済みパスを managedSecrets で指定してください。
| バックエンド | マウントに関する注記 |
|---|---|
| Docker | inContainerMountStrategy() や dockerVolumeMountStrategy() などのローカル戦略を使用する s3Mount()、gcsMount()、r2Mount()、azureBlobMount()、boxMount()、s3FilesMount() に対応します。 |
ModalSandboxClient | S3、R2、HMAC 認証済み GCS のマウントエントリで、ModalCloudBucketMountStrategy を使用したクラウドバケットマウントに対応します。 |
CloudflareSandboxClient | S3、R2、HMAC 認証済み GCS のマウントエントリで、CloudflareBucketMountStrategy を使用した Cloudflare バケットマウントに対応します。 |
BlaxelSandboxClient | S3、R2、GCS のマウントエントリで、BlaxelCloudBucketMountStrategy を使用したクラウドバケットマウントに対応します。認証情報を伴うクラウドマウントには SDK 管理のサンドボックスが必要です。SDK が所有しない再利用済みの名前付きサンドボックスでは、認証情報を使用しないクラウドマウント、または BlaxelDriveMount と BlaxelDriveMountStrategy を使用する永続的な Blaxel Drives を利用できます。 |
DaytonaSandboxClient | S3、GCS、R2、Azure Blob、Box のマウントエントリで、DaytonaCloudBucketMountStrategy を使用した rclone ベースのマウントに対応します。 |
E2BSandboxClient | S3、GCS、R2、Azure Blob、Box のマウントエントリで、E2BCloudBucketMountStrategy を使用した rclone ベースのマウントに対応します。 |
RunloopSandboxClient | S3、GCS、R2、Azure Blob、Box のマウントエントリで、RunloopCloudBucketMountStrategy を使用した rclone ベースのマウントに対応します。 |
VercelSandboxClient | VercelCloudBucketMountStrategy を使用した作成時の S3 マウントに対応します。新しいコードでは、各マウントの完全一致パスに対して withInContainerMountCredentialExposureAcknowledged() を使用し、インライン認証情報を承認してください。非推奨の allowS3CredentialExposure: true オプションは、リリース済みのインライン S3 認証情報設定との互換性のために引き続き受け入れられますが、環境内の認証情報やその他の広範な権限情報は許可しません。シリアライズされたマウント状態は直接再開できないため、マウント済みのライブセッションを再利用してください。 |
E2B および Runloop の rclone ベースのマウントでは、利用可能な場合、SDK は既存の rclone バイナリを使用します。それ以外の場合、SHA-256 チェックサムを検証した後にのみ、SDK でバージョン固定された Linux アーカイブをインストールします。対応していないアーキテクチャやチェックサムの検証失敗があると、マウントは中止されます。
次の表は、各バックエンドが直接マウントできるリモートストレージエントリをまとめたものです。
| バックエンド | AWS S3 | Cloudflare R2 | GCS | Azure Blob Storage | Box | S3 Files |
|---|---|---|---|---|---|---|
| Docker | はい | はい | はい | はい | はい | はい |
ModalSandboxClient | はい | はい | はい | いいえ | いいえ | いいえ |
CloudflareSandboxClient | はい | はい | はい | いいえ | いいえ | いいえ |
BlaxelSandboxClient | はい | はい | はい | いいえ | いいえ | いいえ |
DaytonaSandboxClient | はい | はい | はい | はい | はい | いいえ |
E2BSandboxClient | はい | はい | はい | はい | はい | いいえ |
RunloopSandboxClient | はい | はい | はい | はい | はい | いいえ |
VercelSandboxClient | はい | いいえ | いいえ | いいえ | いいえ | いいえ |
「はい」は、そのバックエンドが該当するストレージマウント形式を実行できることを意味します。前述の認証情報の境界を回避できるという意味ではありません。Docker の dockerVolumeMountStrategy()、Modal のクラウドバケットマウント、Cloudflare のバケットマウントでは、マウント認証情報がモデル制御のサンドボックス外に保持されます。Docker の inContainerMountStrategy() と Daytona、E2B、Runloop の rclone 戦略では、認証情報を受け取るたびに完全一致パスの承認が必要です。Box マウントには認証が必要なため、Box の権限情報を型付きマウントフィールドから指定するか、外部の認証情報ファイルまたは設定ファイルから指定するかに応じて、適切な承認を選択してください。Docker の S3 Files マウントは広範なワークロード ID を使用するため、withInContainerMountBroadCredentialExposureAcknowledged() が必要です。
バックエンドが対応している場合、サンドボックスクライアントは resolveExposedPort(port) を通じてエンドポイントを公開できます。
| クライアント | 動作 |
|---|---|
UnixLocalSandboxClient | 設定されたポートを 127.0.0.1 に解決します。 |
DockerSandboxClient | 設定されたコンテナポートを公開し、対応するホスト側エンドポイントを解決します。 |
バックエンドで許可リストを適用する必要がある場合は、クライアントオプションでポートを宣言します。
import { DockerSandboxClient } from '@openai/agents/sandbox/local';
const client = new DockerSandboxClient({ image: 'node:22-bookworm-slim', exposedPorts: [3000],});対応機能マトリクス
Section titled “対応機能マトリクス”| 機能 | Unix ローカル | Docker |
|---|---|---|
exec_command | 対応 | 対応 |
PTY write_stdin | 対応 | 対応 |
apply_patch | 対応 | ワークスペースファイル API を通じて対応 |
view_image | 対応 | ワークスペースファイル API を通じて対応 |
コマンドの runAs | ホストがユーザーを解決して切り替えられる場合に対応 | コンテナ/ユーザー設定による制限あり |
| ローカルスナップショット | 対応 | 対応 |
| ローカル/Docker マウント | ローカルバインド形式に対応 | バインド形式と Docker ボリューム形式に対応 |
ローカル PTY 対応では、SDK プロセス内で小規模な Python 3 ブリッジを使用します。このブリッジは tty: true のセッションでのみ使用されます。この場合、Node.js には組み込みの PTY API がなく、SDK が対話型 stdin、シグナル処理、終了ステータスの報告に標準的な POSIX PTY の動作を必要とします。SDK コードを実行する環境に python3 をインストールするか、OPENAI_AGENTS_PYTHON に Python 3 の実行ファイルを設定してください。これは、Docker サンドボックスイメージ内にインストールされている Python のバージョンとは別のものです。
ホステッドプロバイダーの対応状況は、プロバイダーごとに異なります。正確なオプション、環境変数、ポート動作、PTY 対応、スナップショット動作、クリーンアップ動作については、プロバイダー固有のドキュメントを確認してください。