---
title: SDKツールセットによるブラウザ使用とコンピュータ使用
url: https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk
description: PythonまたはTypeScript SDKからブラウザ使用ツールまたはコンピュータ使用ツールを実行します。SDKはループと設定したチェックを実行し、ブラウザまたはデスクトップはユーザー側で用意します。
---

PythonおよびTypeScript SDKのブラウザツールセットとコンピュータツールセットを使用すると、Webブラウザ上またはデスクトップ上で作業するエージェントを構築できます。エージェントは、プログラムから操作するためのインターフェースを持たないアプリケーションも使用できます。[ブラウザ使用ツール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool)を通じて、ClaudeはWebページを移動し、読み取り、操作します。[コンピュータ使用ツール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool)を通じて、Claudeはスクリーンショットでデスクトップを確認し、マウスとキーボードを使用します。

SDKはClaudeをブラウザまたはデスクトップに接続します。SDKは、`navigate`に対するURLポリシーや承認コールバックなど、設定したチェックを実行します。チェックを通過した各呼び出しを「driver」（ドライバー）に送信し、ドライバーが返した内容から`tool_result`を構築します。[ツールランナー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/tool-runner)を使えば、エージェントループを代わりに実行させることができます。

ブラウザまたはデスクトップを操作するドライバーは、ユーザーが用意します。まずは[プロバイダーのドライバー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#use-a-driver-from-a-provider)から始めてください。それを使えば、数行のコードでエージェントを作成できます。適したものがない場合は、Playwrightなどのブラウザ自動化ライブラリを使って独自のドライバーを作成してください。

このページの大部分はブラウザツールセットについて説明しています。[コンピュータツールセット](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#computer-toolset)では、異なる点を説明します。

独自のドライバーの作成は高度なケースであり、[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)で説明しています。claude-quickstartsリポジトリには、PythonとTypeScriptによる[ブラウザドライバーの例](https://github.com/anthropics/claude-quickstarts/tree/main/browser-toolset)もあります。これは「Chrome DevTools Protocol」、すなわちCDPを通じてChromiumを制御するもので、本番用のコードではありません。

<Note>
  ブラウザツールセットクラスはベータ版で、[Python SDK](https://github.com/anthropics/anthropic-sdk-python/blob/main/browser-toolset.md)と[TypeScript SDK](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/browser-toolset.md)で利用できます。コンピュータツールセットクラスも同じSDKでベータ版として提供されており、[Pythonコンピュータツールセットガイド](https://github.com/anthropics/anthropic-sdk-python/blob/main/computer-toolset.md)と[TypeScriptコンピュータツールセットガイド](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/computer-toolset.md)があります。
</Note>

## プロバイダーのドライバーを使用する

[パートナー統合](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#partner-integrations)に掲載されているものなど、プロバイダーのドライバーを使えば、数行のコードでエージェントを構築できます。この例のプロバイダーは架空のものです。`example_browser_provider` (typescript: `example-browser-provider`)と`ExampleBrowser`を[実際のプロバイダーの](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#partner-integrations)パッケージとドライバークラスに置き換え、プロバイダーのドキュメントの説明に従ってセットアップしてください。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic import Anthropic
  from example_browser_provider import ExampleBrowser  # made-up provider

  client = Anthropic()
  with ExampleBrowser() as browser:
      runner = client.beta.messages.tool_runner(
          model="claude-opus-5-5",
          max_tokens=1024,
          tools=[browser],
          messages=[
              {"role": "user", "content": "Open example.com and tell me its heading."}
          ],
      )
      for message in runner:
          print(message)
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { ExampleBrowser } from "example-browser-provider"; // made-up provider

  const client = new Anthropic();
  const browser = new ExampleBrowser();
  try {
    const runner = client.beta.messages.toolRunner({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: [browser],
      messages: [{ role: "user", content: "Open example.com and tell me its heading." }]
    });
    for await (const message of runner) {
      console.log(message);
    }
  } finally {
    await browser.close();
  }
  ```
</CodeGroup>

ドライバーのインスタンスそのものを`tools`のエントリとして渡します。ランナーはツールセットを閉じないため、1つのインスタンスで複数の実行に対応できます。使い終わったら閉じてください。

独自のドライバーを作成するには、[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)を参照してください。

## パートナー統合

Browser Use、Browserbase、Daytona、E2Bは、SDKツールセット用の独自のドライバーを公開しています。

<CardGroup cols={2}>
  <Card id="browser-use" title="Browser Use" image="https://platform.claude.com/docs/images/partner-logos/browser-use.svg" imageDark="https://platform.claude.com/docs/images/partner-logos/browser-use-dark.svg" href="https://docs.browser-use.com/open-source/customize/integrations/toolsets-for-claude">
    ブラウザツールセット用のBrowser Useドライバー。
  </Card>

  <Card id="browserbase" title="Browserbase" image="https://platform.claude.com/docs/images/partner-logos/browserbase.svg" imageDark="https://platform.claude.com/docs/images/partner-logos/browserbase-dark.svg" href="https://docs.stagehand.dev/v4/integrations/agent-frameworks/claude-cua-toolset-quickstart">
    ブラウザツールセット用のBrowserbase Stagehandドライバー。
  </Card>

  <Card id="daytona" title="Daytona" image="https://platform.claude.com/docs/images/partner-logos/daytona.svg" imageDark="https://platform.claude.com/docs/images/partner-logos/daytona-dark.svg" href="https://www.daytona.io/docs/en/guides/claude/claude-draws-daytona-sandbox/">
    コンピュータツールセット用のDaytonaドライバー。
  </Card>

  <Card id="e2-b" title="E2B" image="https://platform.claude.com/docs/images/partner-logos/e2b.svg" imageDark="https://platform.claude.com/docs/images/partner-logos/e2b-dark.svg" href="https://docs.e2b.dev/agents/claude-toolsets">
    ブラウザツールセットとコンピュータツールセット用のE2Bドライバー。
  </Card>
</CardGroup>

パートナーはGitHubでもコードを公開しています：[Browser Useクイックスタート](https://github.com/browser-use/browser-use/tree/main/examples/integrations/toolsets-for-claude)、[Browserbaseツールセット](https://github.com/browserbase/claude-cua-toolset)、[E2Bの例](https://github.com/e2b-dev/e2b-cookbook/tree/main/examples/anthropic-computer-use-orangehrm-js)です。

<Warning>
  使い捨てのブラウザ以外に対してドライバーを実行する前に、次の2つを行ってください：

  * [URLポリシーを記述します](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)。ポリシーがない場合、SDKはURLを一切チェックしません。プロバイダーがホストするブラウザの場合は、[リモートブラウザとホスト型ブラウザ](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#remote-and-hosted-browsers)もお読みください。
  * Claudeに委ねたくないデータや操作を持つアカウントにサインインしていないブラウザプロファイルを使用します。[ブラウザホストを分離する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#isolate-the-browser-host)を参照してください。

  その他の事項は[ツールセットを安全に実行する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#run-the-toolset-safely)で説明しています。
</Warning>

## ドライバーをカスタマイズする

このセクションの例では、このページの後半にある[高度な例](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#quick-start)のドライバーである`MyBrowser`を使用します。

### メンバーを有効化または無効化する

`configs`は、[ツールセットを設定する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#configure-the-toolset)で説明されているメンバーごとの設定を受け取ります。変更するメンバーのみを列挙します：

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  # read_console も実装した MyBrowser
  browser = MyBrowser(
      backend, configs={"read_console": {"enabled": True}, "navigate": {"enabled": False}}
  )
  ```

  ```typescript TypeScript
  // read_console も実装する MyBrowser です
  const browser = new MyBrowser(backend, {
    configs: { read_console: { enabled: true }, navigate: { enabled: false } }
  });
  ```
</CodeGroup>

SDKは、無効化されたメンバーへの呼び出しを、コードが実行される前に拒否します。クラスが実装していないメンバーを有効にすると、クラスが`execute`をオーバーライドしていない限り、設定エラーになります。

### 前後のフックを追加する

`execute`をオーバーライドし、親の`execute`を呼び出します。その呼び出しの前のコードは、[URLポリシー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)、[ファイルポリシー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#confine-uploads-and-downloads)、[`confirm`](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#gate-consequential-members)の後に実行され、入力を変更できます。SDKは変更された入力を再度チェックしません。呼び出しの後のコードは結果を受け取り、結果を変更できます。呼び出しを拒否するには`ToolError`を送出します（TypeScriptではthrowします）。

`execute`をオーバーライドすると、Claudeに提示されるメンバーが変わります。SDKはすべてのメンバーを実装済みとみなすため、デフォルトで有効なすべてのメンバーがClaudeに提示されます。[高度な例](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#quick-start)の`MyBrowser`は3つのメンバーに対応しているため、次の`TracedBrowser`は対応できないメンバーをClaudeに提示してしまいます。使用する前に、`configs`でそれらのメンバーを無効にしてください。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  import time


  class TracedBrowser(MyBrowser):
      def execute(self, context, name, input):
          started = time.monotonic()
          result = super().execute(context, name, input)
          elapsed_ms = (time.monotonic() - started) * 1000
          call_id = context.tool_use.id if context.tool_use else "-"
          log.info("%s %s %.0fms", call_id, name, elapsed_ms)
          return redact(result) if name == "get_page_text" else result
  ```

  ```typescript TypeScript
  import type { BetaToolsetCallContext } from "@anthropic-ai/sdk/helpers/beta/toolsets";
  import type {
    BetaBrowserMemberInput,
    BetaBrowserMemberName
  } from "@anthropic-ai/sdk/resources/beta";

  class TracedBrowser extends MyBrowser {
    protected override async execute(
      ctx: BetaToolsetCallContext,
      name: BetaBrowserMemberName,
      input: BetaBrowserMemberInput
    ) {
      const started = performance.now();
      const result = await super.execute(ctx, name, input);
      log.info(`${ctx.toolUse?.id ?? "-"} ${name} ${Math.round(performance.now() - started)}ms`);
      return name === "get_page_text" ? redact(result as string) : result;
    }
  }
  ```
</CodeGroup>

## ドライバーを実装する

ドライバーは、`BetaAbstractBrowserToolset20260801`のサブクラスです。その中で、ブラウザが対応するメンバーをオーバーライドします。実装していないメンバーは、無効としてAPIに送信されます。それでもClaudeがそのメンバーを呼び出した場合、SDKはエラーを返し、実行は継続します。`execute`をオーバーライドすると、無効として送信されるメンバーが変わります（[前後のフックを追加する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#add-before-and-after-hooks)）。各メンバーは、呼び出しコンテキストと、`BetaBrowserNavigateInput`のような型付きオブジェクトとしてのメンバーの入力を受け取ります。入力の型は`anthropic.types.beta` (typescript: `@anthropic-ai/sdk/resources/beta`)から提供されます。各入力のフィールドは[メンバーツール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#member-tools)に記載されています。

TypeScriptでは、SDKがプロトタイプ上でメンバーを検出するため、メンバーはアロー関数フィールドではなくメソッドとして記述してください。TypeScriptでは`type`メンバーを`type_`と記述します。Pythonでは`type`です。

### 結果を返す

メンバーが返すものによって、Claudeが読み取る内容が決まります。成功した結果は、状態レポートから構築された`browser_state`ブロックで終わります。エラー結果にはブロックは含まれません。

| メンバー                                                                               | 戻り値                                                                           | Claudeが読み取る内容                                    |
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------ |
| `screenshot`、`zoom`                                                                | `BetaScreenshotResult`                                                        | 1つの画像ブロック                                        |
| `navigate`                                                                         | `BetaBrowserNavigateResult`                                                   | `Navigated to {url} — {title} (HTTP {status})`   |
| `new_tab`、`switch_tab`、`list_tabs`、`close_tab`                                     | タブエントリ（`new_tab`、`switch_tab`）、タブエントリのリスト（`list_tabs`）、または何も返さない（`close_tab`） | `browser_state`ブロックのみ                            |
| `read_page`、`get_page_text`、`find`、`read_console`、`read_network`、`javascript_exec` | 文字列                                                                           | その文字列、または空文字列の場合は`(empty)`                       |
| その他すべてのメンバー                                                                        | 何も返さない、または1行のテキスト                                                             | `Clicked.`などの短い確認メッセージと、それに続く独立したテキストブロック内の返された行 |

### ブラウザの状態を報告する

SDKは、拒否された呼び出しや失敗した呼び出しを含め、結果を返す各呼び出しの後に`_browser_state` (typescript: `browserState`)を呼び出します。開いているすべてのタブと、前回のレポート以降に変化した内容を返してください。

* 開かれたタブとダウンロードイベント。
* [リクエストフック](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#intercept-requests-in-the-driver)がブロックした各ナビゲーションに対する`BetaNavigationRefused`。
* ドライバーが閉じた各ネイティブダイアログに対する`BetaDialogDismissed`。

これらすべてを`state_changes`に入れます。Pythonでは、`BetaNavigationRefused()`と`BetaDialogDismissed(kind=..., message=...)`は`anthropic.tools.browser`から提供されます。TypeScriptでは、`{ type: "navigation_refused" }`と`{ type: "dialog_dismissed", kind, message }`です。

最後の2つはAPIの状態変化ではありません。SDKはこれらを`browser_state`ブロックの外側のテキストとしてClaudeに報告します。拒否されたすべてのナビゲーションについては1行（URLは含まれません）、閉じられたダイアログについては最初の3つそれぞれに1行ずつ、その後に残りの件数が報告されます。

いずれかのタブが開いている場合、アクティブなタブはちょうど1つでなければなりません。`tab_id`を受け取るすべてのメンバーは、指定されたタブに対して動作する必要があります。レポートに関するAPIの制限は、[`browser_state`でタブを追跡する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#track-tabs-and-page-state)に記載されています。

Claudeは、各タブのURL、各ダウンロードのURL、`navigate`が返すURLを、ドライバーが書いたとおりに読み取ります。SDKはこれらのURLを解析しません。改行やその他の制御文字をスペースに変換し、両端をトリムし、各URLを4,096文字で切り詰めます。そのため、`data:` URLの内容、`file:` URLのパス、URL内のユーザー名やパスワードはすべてClaudeに届きます。

### エラーを処理する

| メンバーまたはSDKが送出するもの   | Claudeが読み取る内容                                                       | 実行 |
| ------------------- | ------------------------------------------------------------------- | -- |
| `ToolError`         | そのメッセージ（エラー結果として）                                                   | 継続 |
| `ToolsetUsageError` | なし                                                                  | 停止 |
| その他の例外              | Pythonでは`ClassName: message`、TypeScriptでは`Error: message`（エラー結果として） | 継続 |

SDKは、設定エラー、呼び出し中のSDKの誤用、または`close`後の呼び出しに対して`ToolsetUsageError`を送出します。また、`_browser_state` (typescript: `browserState`)が何らかの例外（`ToolError`であっても）を送出した場合にも送出します。ツールランナーと`tool_result` (typescript: `toolResult`)はこれをキャッチしないため、呼び出し元に到達します。

SDKは、メンバーのエラーテキスト、`left_click`などのアクションが返す行、失敗したダウンロードのエラー、閉じられたダイアログのメッセージに含まれるローカルパスを隠しません。

URLポリシー、ファイルポリシー、または`confirm`呼び出し可能オブジェクトからの`ToolError`は、書かれたとおりにClaudeに届くため、そのテキストにローカルパスを含めないでください。メンバー内で例外をキャッチし、独自のテキストで`ToolError`を送出してください（TypeScriptではthrowします）。

### レスポンスのストリーミング中に呼び出しを開始する

デフォルトでは、ツールランナーはClaudeのレスポンスが終了した後にそのターンの呼び出しを実行します。「early start」（早期開始）を使用すると、レスポンスがまだストリーミング中でもブラウザまたはコンピュータの呼び出しを開始できます。

有効にするには、[高度な例](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#quick-start)のように、`stream=True` (typescript: `stream: true`)と`run_tools_eagerly=True` (typescript: `runToolsEagerly: true`)をツールランナーに渡します。`stream`を指定すると、ランナーに対するループの各反復で、メッセージではなくストリームが得られます。

早期開始によって変わるのは呼び出しを開始できるタイミングであり、ツールセットがそれを実行する方法ではありません。

* **チェックは引き続き先に実行されます：** SDKは呼び出しを実行する前に、URLポリシー、ファイルポリシー、`confirm`を呼び出します。早期開始では、レスポンスがまだストリーミング中に`confirm`を呼び出すことがあります。
* **呼び出しは引き続き1つずつ実行されます：** ツールセットは、Claudeが書いた順序で呼び出しを実行します。失敗した呼び出しは、引き続きそのターンにおけるそのツールセットの後続の呼び出しを停止させます。
* **開始された呼び出しは取り消せません：** その後レスポンスが（たとえば`max_tokens`で）途中で切れた場合や、ループが早期に停止した場合でも、アクションは実行され、Claudeはその結果を読み取ることはありません。

### ツールランナーなしで実行する

インスタンスを`tools`に渡し（TypeScriptでは`browser.toJSON()`）、各メンバー呼び出しに`tool_result` (typescript: `toolResult`)で応答します。ブラウザ使用ツールでは、最初に失敗した呼び出しで停止する必要があります（[バッチアクション](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#batch-actions)）。

このループは、[高度な例](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#quick-start)の`MyBrowser`とURLポリシーを使用します。失敗した呼び出しの後は、そのターンの後続の呼び出しを実行せずに応答します：

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic.types.beta import BetaMessageParam, BetaToolResultBlockParam

  NOT_EXECUTED = "Not executed: an earlier action in this turn failed."
  MAX_TURNS = 10

  with MyBrowser(backend, url_policy=url_policy) as browser:
      messages: list[BetaMessageParam] = [{"role": "user", "content": "Open example.com"}]
      for _ in range(MAX_TURNS):
          response = client.beta.messages.create(
              model="claude-opus-5-5",
              max_tokens=1024,
              tools=[browser],
              messages=messages,
          )
          messages.append({"role": "assistant", "content": response.content})
          calls = [
              block
              for block in response.content
              if block.type == "tool_use" and block.toolset_name == browser.toolset_name
          ]
          if not calls:
              break
          results: list[BetaToolResultBlockParam] = []
          failed = False
          for call in calls:
              if failed:
                  # 呼び出しが失敗した後、そのターンの残りの呼び出しは実行されず、応答のみが返されます。
                  results.append(
                      {
                          "type": "tool_result",
                          "tool_use_id": call.id,
                          "toolset_name": call.toolset_name,
                          "content": NOT_EXECUTED,
                          "is_error": True,
                      }
                  )
                  continue
              result = browser.tool_result(call)
              failed = bool(result.get("is_error"))
              results.append(result)
          messages.append({"role": "user", "content": results})
  ```

  ```typescript TypeScript
  const NOT_EXECUTED = "Not executed: an earlier action in this turn failed.";
  const MAX_TURNS = 10;

  const browser = new MyBrowser(backend, { urlPolicy });
  try {
    const messages: Anthropic.Beta.BetaMessageParam[] = [
      { role: "user", content: "Open example.com" }
    ];
    for (let turn = 0; turn < MAX_TURNS; turn++) {
      const response = await client.beta.messages.create({
        model: "claude-opus-5-5",
        max_tokens: 1024,
        tools: [browser.toJSON()],
        messages
      });
      messages.push({ role: "assistant", content: response.content });
      const calls = response.content.filter(
        (block): block is Anthropic.Beta.BetaToolUseBlock =>
          block.type === "tool_use" && block.toolset_name === browser.toolsetName
      );
      if (calls.length === 0) {
        break;
      }
      const results: Anthropic.Beta.BetaToolResultBlockParam[] = [];
      let failed = false;
      for (const call of calls) {
        if (failed) {
          // 呼び出しが失敗した後、そのターンの残りは実行されず、応答のみが返されます。
          results.push({
            type: "tool_result",
            tool_use_id: call.id,
            toolset_name: call.toolset_name,
            content: NOT_EXECUTED,
            is_error: true
          });
          continue;
        }
        const result = await browser.toolResult(call);
        failed = result.is_error === true;
        results.push(result);
      }
      messages.push({ role: "user", content: results });
    }
  } finally {
    await browser.close();
  }
  ```
</CodeGroup>

スキップされた呼び出しへの各応答には、`is_error`、呼び出しの`toolset_name`、および[バッチアクション](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#batch-actions)で求められる正確なテキストが含まれます。ツールランナーも同じ応答を送信します。

## 高度な例：独自のドライバーを作成する

この例では、[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)の主要な部分を1つのドライバー`MyBrowser`にまとめ、ツールランナーと[早期開始](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#start-calls-while-the-response-streams)で実行します。`MyBrowser`は`navigate`、`screenshot`、`left_click`に加えて、すべてのドライバーに必要な状態レポートである`_browser_state` (typescript: `browserState`)を実装しています。

`backend`は、Playwrightなどのブラウザ自動化ライブラリをラップした独自のラッパーを表します。URLポリシーは一例です。[URLポリシーを記述する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)で説明しています。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  import re
  from urllib.parse import urlsplit

  from anthropic import Anthropic
  from anthropic.tools import ToolError
  from anthropic.tools.browser import (
      BetaAbstractBrowserToolset20260801,
      BetaBrowserNavigateResult,
      BetaBrowserState,
      BetaScreenshotResult,
      BetaToolsetCallContext,
      BetaURLContext,
  )
  from anthropic.types.beta import (
      BetaBrowserLeftClickInput,
      BetaBrowserNavigateInput,
      BetaBrowserScreenshotInput,
      BetaBrowserStateTabEntryParam,
  )


  class MyBrowser(BetaAbstractBrowserToolset20260801):
      def __init__(self, backend, **options):
          super().__init__(**options)
          self.backend = backend

      def _browser_state(self, context: BetaToolsetCallContext) -> BetaBrowserState:
          return BetaBrowserState(
              tabs=[
                  BetaBrowserStateTabEntryParam(
                      tab_id=tab.id,
                      title=tab.title,
                      url=tab.url,
                      active=tab.id == self.backend.active,
                  )
                  for tab in self.backend.tabs()
              ],
              state_changes=self.backend.drain_changes(),
          )

      def navigate(
          self, context: BetaToolsetCallContext, input: BetaBrowserNavigateInput
      ) -> BetaBrowserNavigateResult:
          # input.url は "back"、"forward"、"reload"、または URL ポリシーが
          # 許可した URL で、Claude が書いたままの形です。is_allowed と同様に、backend.goto は
          # スキームで始まらない URL に https:// を付加します。
          page = self.backend.goto(input.url, input.tab_id)
          return BetaBrowserNavigateResult(
              url=page.url, status=page.status, title=page.title
          )

      def screenshot(
          self, context: BetaToolsetCallContext, input: BetaBrowserScreenshotInput
      ) -> BetaScreenshotResult:
          data = self.backend.png_base64(input.tab_id)
          return BetaScreenshotResult(data=data, media_type="image/png")

      def left_click(
          self, context: BetaToolsetCallContext, input: BetaBrowserLeftClickInput
      ) -> None:
          # 返す値はありません。Claude には "Clicked." と表示されます
          self.backend.click(input.target, input.tab_id)

      def close(self) -> None:
          super().close()  # first, so no call is still using the browser when it closes
          if not self.backend.closed:
              self.backend.close()


  ALLOWED_HOSTS = ("example.com", "iana.org")
  SCHEME_PREFIX = re.compile(r"[a-z][a-z0-9+.-]*:", re.IGNORECASE)


  def is_allowed(url: str) -> bool:
      # これは例であり、本番用のポリシーではありません。「URL ポリシーを書く」を参照してください。
      if url.lower() == "about:blank":
          return True
      with_scheme = url if SCHEME_PREFIX.match(url) else f"https://{url}"
      # ブラウザは Web URL 内の "\" を "/" として解釈します。
      try:
          parts = urlsplit(with_scheme.replace("\\", "/"))
      except ValueError:
          return False
      host = parts.hostname or ""
      listed = any(host == name or host.endswith(f".{name}") for name in ALLOWED_HOSTS)
      return parts.scheme in ("http", "https") and listed


  def url_policy(context: BetaURLContext, url: str) -> None:
      if not is_allowed(url):
          raise ToolError(f"blocked: {url} is not on an allowed host")


  client = Anthropic()
  with MyBrowser(backend, url_policy=url_policy) as browser:
      runner = client.beta.messages.tool_runner(
          model="claude-opus-5-5",
          max_tokens=1024,
          tools=[browser],
          messages=[
              {
                  "role": "user",
                  "content": "Open example.com and tell me the page heading.",
              }
          ],
          stream=True,
          run_tools_eagerly=True,  # so a call can start before the response ends
      )
      for stream in runner:
          print(stream.get_final_message())
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import {
    BetaAbstractBrowserToolset20260801,
    type BetaBrowserNavigateResult,
    type BetaBrowserToolsetOptions,
    type BetaScreenshotResult,
    type BetaToolsetCallContext,
    type BetaURLContext,
    ToolError
  } from "@anthropic-ai/sdk/helpers/beta/toolsets";
  import type {
    BetaBrowserLeftClickInput,
    BetaBrowserNavigateInput,
    BetaBrowserScreenshotInput
  } from "@anthropic-ai/sdk/resources/beta";

  class MyBrowser extends BetaAbstractBrowserToolset20260801 {
    constructor(
      private backend: Backend,
      options: Omit<BetaBrowserToolsetOptions, "browserState"> = {}
    ) {
      super({
        ...options,
        // 必須: 開いているすべてのタブと、前回のレポート以降の変更点。
        browserState: () => ({
          tabs: backend.tabs().map((tab) => ({
            tab_id: tab.id,
            title: tab.title,
            url: tab.url,
            active: tab.id === backend.active
          })),
          state_changes: backend.drainChanges()
        })
      });
    }

    protected override async navigate(
      ctx: BetaToolsetCallContext,
      input: BetaBrowserNavigateInput
    ): Promise<BetaBrowserNavigateResult> {
      // input.url は "back"、"forward"、"reload"、または URL ポリシーが
      // 許可した URL で、Claude が書いたままの形です。isAllowed と同様に、backend.goto は
      // スキームで始まらない URL に https:// を付加します。
      const page = await this.backend.goto(input.url, input.tab_id);
      return { url: page.url, status: page.status, title: page.title };
    }

    protected override async screenshot(
      ctx: BetaToolsetCallContext,
      input: BetaBrowserScreenshotInput
    ): Promise<BetaScreenshotResult> {
      return { data: await this.backend.pngBase64(input.tab_id), mediaType: "image/png" };
    }

    protected override async left_click(
      ctx: BetaToolsetCallContext,
      input: BetaBrowserLeftClickInput
    ): Promise<void> {
      // 返す値はありません: Claude には "Clicked." と表示されます。
      await this.backend.click(input.target, input.tab_id);
    }

    override async close(): Promise<void> {
      await super.close(); // first, so no call is still using the browser when it closes
      if (!this.backend.closed) {
        await this.backend.close();
      }
    }
  }

  const ALLOWED_HOSTS = ["example.com", "iana.org"];
  const SCHEME_PREFIX = /^[a-z][a-z0-9+.-]*:/i;

  // 本番用ポリシーではなく例です。"Write a URL policy" を参照してください。
  function isAllowed(url: string): boolean {
    if (url.toLowerCase() === "about:blank") {
      return true;
    }
    const withScheme = SCHEME_PREFIX.test(url) ? url : `https://${url}`;
    // ブラウザは Web URL 内の "\" を "/" として解釈します。
    const parsed = URL.parse(withScheme.replaceAll("\\", "/"));
    const host = parsed?.hostname ?? "";
    const listed = ALLOWED_HOSTS.some((name) => host === name || host.endsWith(`.${name}`));
    return (parsed?.protocol === "http:" || parsed?.protocol === "https:") && listed;
  }

  function urlPolicy(ctx: BetaURLContext, url: string): void {
    if (!isAllowed(url)) {
      throw new ToolError(`blocked: ${url} is not on an allowed host`);
    }
  }

  const client = new Anthropic();
  const browser = new MyBrowser(backend, { urlPolicy });
  try {
    const runner = client.beta.messages.toolRunner({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: [browser],
      messages: [{ role: "user", content: "Open example.com and tell me the page heading." }],
      stream: true,
      runToolsEagerly: true // so a call can start before the response ends
    });
    for await (const stream of runner) {
      console.log(await stream.finalMessage());
    }
  } finally {
    await browser.close();
  }
  ```
</CodeGroup>

## ツールセットを安全に実行する

Claudeの次のアクションは、読み取るページに依存します。ページ、またはページに注入されたテキストは、内部サービスへのアクセスやホストからのファイルの持ち出しを試みる可能性があります。また、実際の影響を伴うアクションを引き起こそうとする可能性もあります。使い捨てのブラウザ以外に対してドライバーを実行する前に、次の6つの手順を実行してください：

1. タスクに不要なすべての`navigate` URLを拒否する[URLポリシーを記述します](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)。
2. [ドライバーでリクエストをインターセプトし](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#intercept-requests-in-the-driver)、同じルールで各リクエストをチェックします。
3. [コンテナに「egress policy」（エグレスポリシー）を適用し](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#put-egress-policy-on-the-container)、ドライバーが認識できないものをネットワークでブロックします。
4. [アップロードとダウンロードを制限する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#confine-uploads-and-downloads)か、アップロードを無効のままにします。
5. `confirm`で[影響の大きいメンバーを制限します](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#gate-consequential-members)。
6. セッションごとに専用のコンテナまたはVMで[ブラウザホストを分離します](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#isolate-the-browser-host)。

SDKは、渡されたポリシーと呼び出し可能オブジェクトを通じて手順1、4、5を適用します。手順2、3、6はドライバーとデプロイメント側の責任です。[セキュリティに関する考慮事項](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#security-considerations)の注意事項も適用されます。

<Note>
  [セキュリティ上の考慮事項](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#security-considerations)で説明されているAnthropicの「prompt-injection classifier」（プロンプトインジェクション分類器）は、現在、Amazon Bedrock経由で送信されたブラウザツールセットのリクエストでは実行されません。
</Note>

### URLポリシーを記述する

<Warning>
  URLポリシーがない場合、SDKはどのURLもチェックせず、APIもClaudeが開くURLをフィルタリングしません。ポリシーがあっても、Claudeがクリックするリンクやリダイレクトによって、ブラウザがループバック（`localhost`、`127.0.0.1`）、クラウドメタデータアドレス`169.254.169.254`などのリンクローカルアドレス、プライベートネットワーク範囲に移動する可能性があります。[コンテナのエグレスルール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#put-egress-policy-on-the-container)でリンクローカルアドレスとプライベートアドレスをブロックできます。コンテナ外で適用されるルールではループバックをブロックできません。

  SDKはURLのスキームをチェックしないため、ドライバーは`javascript:`、`view-source:`、`data:`、`file:`など、開くつもりのないすべてのスキームを拒否する必要があります。ほとんどのドライバーに必要なのは`http`と`https`だけです。以下のポリシーの例では、`http`と`https`のURLに加えて`about:blank`のみを許可しています。

  `file:` URLを使うと、Claudeはブラウザホスト上のファイルを読み取れます。`javascript:` URLは、`javascript_exec`が無効であっても、現在のページでスクリプトを実行します。エグレスルールではどちらも防げません。
</Warning>

URLポリシーは、`url_policy` (typescript: `urlPolicy`)として渡す関数です。ポリシーはユーザー自身が記述し、本番環境に対応させる責任もユーザーにあります。`navigate`が実行される前に、SDKは呼び出しのコンテキストと、Claudeが書いたとおりのURLを引数としてポリシーを呼び出します。

URLを許可するには何も返しません。拒否するには`ToolError`を送出します（TypeScriptではthrowします）。Claudeはエラーのメッセージを読み取り、`navigate`は実行されません。ポリシーは各`navigate`呼び出しのURLのみをチェックします。ネットワーク制御ではありません。

これは[高度な例](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#quick-start)のポリシーです。`about:blank`に加えて、2つのサイトとそのサブドメインを`http`と`https`で許可します：

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  import re
  from urllib.parse import urlsplit

  from anthropic.tools import ToolError
  from anthropic.tools.browser import BetaURLContext

  ALLOWED_HOSTS = ("example.com", "iana.org")
  SCHEME_PREFIX = re.compile(r"[a-z][a-z0-9+.-]*:", re.IGNORECASE)


  def is_allowed(url: str) -> bool:
      # これは例であり、本番環境向けのポリシーではありません。
      if url.lower() == "about:blank":
          return True
      with_scheme = url if SCHEME_PREFIX.match(url) else f"https://{url}"
      # ブラウザは Web URL 内の "\" を "/" として解釈します。
      try:
          parts = urlsplit(with_scheme.replace("\\", "/"))
      except ValueError:
          return False
      host = parts.hostname or ""
      listed = any(host == name or host.endswith(f".{name}") for name in ALLOWED_HOSTS)
      return parts.scheme in ("http", "https") and listed


  def url_policy(context: BetaURLContext, url: str) -> None:
      if not is_allowed(url):
          raise ToolError(f"blocked: {url} is not on an allowed host")


  browser = MyBrowser(backend, url_policy=url_policy)
  ```

  ```typescript TypeScript
  import { type BetaURLContext, ToolError } from "@anthropic-ai/sdk/helpers/beta/toolsets";

  const ALLOWED_HOSTS = ["example.com", "iana.org"];
  const SCHEME_PREFIX = /^[a-z][a-z0-9+.-]*:/i;

  // これは例であり、本番環境向けのポリシーではありません。
  function isAllowed(url: string): boolean {
    if (url.toLowerCase() === "about:blank") {
      return true;
    }
    const withScheme = SCHEME_PREFIX.test(url) ? url : `https://${url}`;
    // ブラウザは Web URL 内の "\" を "/" として解釈します。
    const parsed = URL.parse(withScheme.replaceAll("\\", "/"));
    const host = parsed?.hostname ?? "";
    const listed = ALLOWED_HOSTS.some((name) => host === name || host.endsWith(`.${name}`));
    return (parsed?.protocol === "http:" || parsed?.protocol === "https:") && listed;
  }

  function urlPolicy(ctx: BetaURLContext, url: string): void {
    if (!isAllowed(url)) {
      throw new ToolError(`blocked: ${url} is not on an allowed host`);
    }
  }

  const browser = new MyBrowser(backend, { urlPolicy });
  ```
</CodeGroup>

SDKは`navigate`に対してのみポリシーを呼び出し、`"back"`、`"forward"`、`"reload"`に対しては呼び出しません。Claudeは`example.com`のようにスキームを省略することがあるため、この例ではホストを読み取る前に、スキームで始まらないURLに`https://`を付加しています。`navigate`はClaudeが書いたとおりのURLを受け取ります。ポリシーがチェックしたURLをブラウザが開くように、そこでも同じテストでスキームを付加してください。

この例は本番品質ではありません。本番用のポリシーには、次のような領域でさらに多くの対応が必要です。

* Claudeがクリックするリンク、送信するフォーム、リダイレクト、ページが自ら行うリクエスト。これらを認識できるのはドライバーだけです。[ドライバーでリクエストをインターセプトする](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#intercept-requests-in-the-driver)を参照してください。
* 攻撃者が選択できる、ページコンテンツ由来のホスト名とURL。
* 単純な文字列分割でホスト名を見つけるのではなく、ブラウザと同じ方法で各URLを解析すること。
* URLスキーム。SDKはこれをチェックしないため、ドライバーが開くつもりのないすべてのスキームを拒否してください。
* どのURLチェックでも認識できないものに対する、コンテナのエグレスルール。[コンテナにエグレスポリシーを適用する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#put-egress-policy-on-the-container)を参照してください。

`url_policy=None` (typescript: `urlPolicy: null`)を渡すと、SDKはURLへのすべての`navigate`を拒否します。そのため、設定から読み込まれた`None` (typescript: `null`)によって、誤ってURLがチェックされないままになることはありません。TypeScriptでは、`undefined`はオプションを未設定のままにし、渡さない場合と同じになります。

### ドライバーでリクエストをインターセプトする

URLポリシーが判断するのは、`navigate`呼び出しのURLだけです。Claudeがクリックするリンク、送信するフォーム、リダイレクト、または許可されたページ上の画像やスクリプトは、ポリシーが拒否するはずのホストに到達する可能性があります。それらのホストをブロックするには[エグレスルール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#put-egress-policy-on-the-container)を使用してください。

リクエストインターセプトを備えたドライバーは、リクエストフック（自動化ライブラリが各リクエストの前に呼び出す関数）でそれらのリクエストをチェックすることもできます。ルールを一度だけ記述すれば済むように、ポリシーが使用する関数を呼び出してください。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  class MyBrowser(BetaAbstractBrowserToolset20260801):
      ...

      # context.route("**/*", self._guard) で Playwright のブラウザコンテキストに登録します
      def _guard(self, route):
          # is_allowed は「Write a URL policy」で定義した関数です
          if not is_allowed(route.request.url):
              return route.abort("blockedbyclient")
          route.continue_()
  ```

  ```typescript TypeScript
  // ドライバークラス内で、Playwright のブラウザコンテキストに対して設定します。
  // isAllowed は「Write a URL policy」で作成した関数です。
  await context.route("**/*", (route) =>
    isAllowed(route.request().url()) ? route.continue() : route.abort("blockedbyclient")
  );
  ```
</CodeGroup>

このようなリクエストフックは、WebSocketハンドシェイク、Service Workerのリクエスト、リダイレクトのホップを認識しません。Service Workerはブロックしてください。WebSocketハンドシェイクとリダイレクトのホップは、それらを認識できるフックでチェックしてください。ポリシーの例は`ws://`と`wss://`のURLを拒否するため、WebSocket URLを`is_allowed` (typescript: `isAllowed`)に渡す前に、`ws://`を`http://`に、`wss://`を`https://`に変更してください。

### コンテナにエグレスポリシーを適用する

インターセプトではブラウザが行うすべてのリクエストを認識できず、URLポリシーは名前の解決先を認識しません。コンテナのネットワークが適用するエグレスポリシーは、その両方をカバーします：

* IPv4とIPv6のリンクローカルおよびプライベートアドレス範囲をブロックします。これにはクラウドメタデータアドレス`169.254.169.254`も含まれます。
* タスクに必要なホストへのアウトバウンド接続のみを許可します。ルールがIPアドレスで照合する場合は、コンテナの起動時に許可するホスト名を解決してください。
* DNSはコンテナのリゾルバーへのみ許可します。

Kubernetes NetworkPolicyやクラウドファイアウォールなど、ブラウザのコンテナ外で適用されるルールは、コンテナ内のループバックを認識しません。それらのルールだけでは、ページはそこでリッスンしているあらゆるものに到達できます。これにはDevToolsポートも含まれ、そこではブラウザの開いているタブの一覧と、各タブを制御するアドレスが表示されます。

### アップロードとダウンロードを制限する

`file_upload`はデフォルトで無効です。`file_policy` (typescript: `filePolicy`)がない場合、SDKはパスまたは[ドキュメントID](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool#upload-files)を指定するすべてのアップロードを拒否します。アップロードを有効にするには、タスクのファイルのみを保持する1つのアップロードディレクトリを指定した`BetaLocalFilePolicy` (typescript: `BetaNodeFilePolicy`)を渡します：

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic.tools.browser import BetaLocalFilePolicy

  # file_upload も実装する MyBrowser です
  browser = MyBrowser(
      backend,
      configs={"file_upload": {"enabled": True}},
      confirm=make_confirm(),  # required for file_upload; see Gate consequential members
      url_policy=url_policy,
      file_policy=BetaLocalFilePolicy(
          upload_roots=["/task/uploads"],
          download_dir="/task/downloads",
          expose_download_paths=False,
      ),
  )
  ```

  ```typescript TypeScript
  import { BetaNodeFilePolicy } from "@anthropic-ai/sdk/helpers/beta/toolsets/node";

  // file_upload も実装する MyBrowser です
  const browser = new MyBrowser(backend, {
    configs: { file_upload: { enabled: true } },
    confirm: makeConfirm(), // required for file_upload; see Gate consequential members
    urlPolicy,
    filePolicy: new BetaNodeFilePolicy({
      uploadRoots: ["/task/uploads"],
      downloadDir: "/task/downloads",
      exposeDownloadPaths: false
    })
  });
  ```
</CodeGroup>

SDKはシンボリックリンクをたどって各アップロードパスを解決し、アップロードルート外のパスを拒否します。ファイルポリシーは、ダウンロードディレクトリがアップロードルートである場合、アップロードルート内にある場合、またはアップロードルートを含む場合に設定エラーを送出します。このチェックはシンボリックリンクを見逃す可能性があるため、シンボリックリンクによってダウンロードディレクトリがアップロードルートと同じになったり、一方が他方の中に入ったりしないようにしてください。SDKは、`expose_download_paths` (typescript: `exposeDownloadPaths`)がtrueで、かつファイルがダウンロードディレクトリ内にある場合にのみ、ダウンロードの`path`を状態レポートに含めます。

同梱のファイルポリシーは、SDKを実行するプロセスのファイルシステム上のパスをチェックします。保護されるのは、そのファイルシステムを共有するブラウザのみです。リモートブラウザの場合は、代わりに[リモートブラウザとホスト型ブラウザ](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#remote-and-hosted-browsers)に従ってください。

ダウンロードは次のように設定します：

* ダウンロードディレクトリはモード`0700`で自分で作成し、`noexec,nosuid,nodev`でマウントします。
* シェルやファイルツールなど、Claudeが呼び出せる他のツールからディレクトリにアクセスできないようにします。
* `download_failed`状態変更では、`error`を固定のフレーズとして記述します。例外のテキストにはパスやURLが含まれる可能性があります。
* 人が判断するまで、ダウンロードしたファイルを会話に読み込んだり実行したりしないでください。

### 影響の大きいメンバーを制限する

`javascript_exec`と`file_upload`はデフォルトで無効です。`confirm`呼び出し可能オブジェクトなしでいずれかを有効にすると、コンストラクターは設定エラーを送出します。`confirm`呼び出し可能オブジェクトがある場合、SDKは実行されようとしているすべての呼び出しの前にそれを呼び出します。ない場合は、何も問い合わせません。TypeScriptでは、`confirm: null`は設定エラーを送出せず、SDKはすべてのメンバーへのすべての呼び出しを拒否します。

呼び出しを実行するには`True` (typescript: `true`)を、拒否するには`False` (typescript: `false`)を返します。呼び出し可能オブジェクトが人に問い合わせる場合は、メンバー、ページのURL、呼び出しの入力を表示してください。その際、URLと入力はどちらもページ由来のテキストを含む可能性があるため、まず印字可能なASCII以外のすべての文字をエスケープしてください。

この例では、独自の`ask_user` (typescript: `askUser`)関数を通じて2つの制御対象メンバーについて問い合わせ、残りは承認します。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  import json
  from collections.abc import Callable
  from urllib.parse import urlsplit

  from anthropic.tools.browser import BetaConfirmContext

  GATED = {"javascript_exec", "file_upload"}


  def shown(value: object) -> str:
      """A value as JSON, with every character outside printable ASCII escaped."""
      return json.dumps(value, ensure_ascii=True, indent=2)


  def make_confirm() -> Callable[[BetaConfirmContext], bool]:
      granted: set[tuple[str, str, str]] = set()

      def confirm(context: BetaConfirmContext) -> bool:
          name = context.member
          if name not in GATED:
              return True
          detail = shown(context.input.to_dict())
          page = context.tab_url
          where = shown(page) if page else "a tab with no URL"
          question = f"Allow {name} on {where}?\n{detail}"
          if page is None or urlsplit(page).scheme not in ("http", "https"):
              return ask_user(question)  # no web origin: ask every time
          # 承認は、このページ上のこの入力そのものにのみ適用されます。
          key = (name, page, detail)
          if key not in granted and ask_user(question):
              granted.add(key)
          return key in granted

      return confirm


  # javascript_exec と file_upload も実装した MyBrowser
  # file_upload には「Confine uploads and downloads」の file_policy も必要です
  browser = MyBrowser(
      backend,
      configs={"javascript_exec": {"enabled": True}, "file_upload": {"enabled": True}},
      confirm=make_confirm(),
      url_policy=url_policy,
  )
  ```

  ```typescript TypeScript
  import type { BetaConfirmContext } from "@anthropic-ai/sdk/helpers/beta/toolsets";

  const GATED = new Set(["javascript_exec", "file_upload"]);

  /** A value as JSON, with every character outside printable ASCII escaped. */
  const shown = (value: unknown): string =>
    JSON.stringify(value, null, 2).replace(
      /[^\n\x20-\x7e]/g,
      (match) => `\\u${match.charCodeAt(0).toString(16).padStart(4, "0")}`
    );

  const makeConfirm = () => {
    const granted = new Set<string>();
    return async (ctx: BetaConfirmContext): Promise<boolean> => {
      const name = ctx.member;
      if (!GATED.has(name)) {
        return true;
      }
      const detail = shown(ctx.input);
      const page = ctx.tabURL;
      const where = page ? shown(page) : "a tab with no URL";
      const question = `Allow ${name} on ${where}?\n${detail}`;
      const scheme = page === undefined ? undefined : URL.parse(page)?.protocol;
      if (scheme !== "http:" && scheme !== "https:") {
        return askUser(question); // no web origin: ask every time
      }
      // 承認は、このページ上のこの入力そのものにのみ適用されます。
      const key = `${name} ${page} ${detail}`;
      if (!granted.has(key) && (await askUser(question))) {
        granted.add(key);
      }
      return granted.has(key);
    };
  };

  // javascript_exec と file_upload も実装した MyBrowser
  // file_upload には「Confine uploads and downloads」の filePolicy も必要です
  const browser = new MyBrowser(backend, {
    configs: { javascript_exec: { enabled: true }, file_upload: { enabled: true } },
    confirm: makeConfirm(),
    urlPolicy
  });
  ```
</CodeGroup>

`make_confirm()` (typescript: `makeConfirm()`)を呼び出すたびに、承認を持たない呼び出し可能オブジェクトが返されます。ツールセットごとに1回呼び出し、各ユーザーに専用のツールセットを割り当ててください。

承認の対象は、最後の状態レポートが示した時点のページであり、呼び出しが実行される前にページが変わる可能性があります。購入、メッセージの送信、規約への同意は、`left_click`や`type`などの通常のメンバーを通じて行われるため、`confirm`はそれらを名前で識別できません。人にそれらを承認させるには、それらのメンバーについても確認してください。

[エグレスルール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#put-egress-policy-on-the-container)によってブラウザのアウトバウンド接続がタスクに必要なホストに制限されていない限り、`javascript_exec`を有効にしないでください。スクリプトは、ブラウザが到達できる任意のアドレスにページのコンテンツを送信できます。

`navigate`呼び出し内の`javascript:` URLも、`javascript_exec`が無効であっても、現在のページでスクリプトを実行します。`confirm`はその呼び出しを`navigate`として認識するため、この例の`confirm`呼び出し可能オブジェクトはそれを承認してしまいます。ドライバーは`javascript:` URLを拒否する必要があります。この例では、`confirm`が実行される前に[URLポリシー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)がそれらを拒否します。

### ブラウザホストを分離する

セッションごとに、専用の最小権限のコンテナまたはVMでブラウザを実行します：

* 非rootユーザーとして実行し、ブラウザが許容する場合は読み取り専用のルートファイルシステムを使用します。
* 設定したアップロードおよびダウンロードディレクトリ（ある場合）以外は、ホストから何もマウントしません。
* 認証情報を環境に含めず、新しいブラウザプロファイルから開始します。
* Claudeが呼び出せる他のツールとファイルシステムを共有しません。

<Warning>
  ブラウザプロファイルは、Claudeに委ねたくないデータや操作を持つアカウントにサインインしていてはなりません。`javascript_exec`はページ自体の権限（そのCookie、ストレージ、サインイン済みセッション）で実行されます。
</Warning>

APIを呼び出すコードは、APIキーと会話を保持しているため、ブラウザのコンテナの外で実行してください。ツールランナーと`tool_result` (typescript: `toolResult`)はどちらもそのコードのプロセス内でツールセットを実行するため、ブラウザはツールセットのファイルシステムを共有しません。ブラウザはリモートとして扱ってください。[リモートブラウザとホスト型ブラウザ](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#remote-and-hosted-browsers)が適用されます。

ページテキスト、スクリーンショット、コンソールとネットワークのエントリ、タブのタイトル、ダウンロード名など、ページが返すものはすべて信頼できないものとして扱ってください。

### リモートブラウザとホスト型ブラウザ

一部のブラウザは、SDKを実行するプロセスとファイルシステムを共有しません。例としては、別のコンテナ内のブラウザ、DevTools URLでアクセスするブラウザ、ホスト型ブラウザサービスのブラウザがあります。これらの場合でも、URLポリシー、リクエストのインターセプト、`confirm`は引き続き自分のプロセス内で実行されます。

ホスト型ブラウザでは、プロバイダーがエグレスとホストの分離を制御します。独自のエグレスポリシーはそこには適用されないため、ドライバーのリクエストフックがブラウザのリクエストに対する唯一のチェックになります。ブラウザのネットワークが何にアクセスできるかを確認してください。

同梱のパスチェックはリモートブラウザを保護しません。`BetaLocalFilePolicy` (typescript: `BetaNodeFilePolicy`)はSDKを実行するプロセスのファイルシステム上のパスをチェックしますが、ブラウザは自身のファイルシステムを読み書きします。

SDKはブラウザがリモートであることを検出できません。そのため、リモートブラウザの場合は、ドライバーが独自の`BetaFilePolicy`を使ってブラウザが実行される場所でアップロードパスをチェックしない限り、`file_upload`を無効のままにしてください。`BetaFilePolicy`は、各アップロードのパスとドキュメントIDを検査し、Claudeがダウンロードのパスを見られるかどうかを決定します。

リモートブラウザ自体のホストに[アップロードとダウンロードを制限する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#confine-uploads-and-downloads)のダウンロード設定がない限り、リモートブラウザにはダウンロードを拒否させてください。

プロバイダーのAPIキーと、キーを含む可能性のあるセッションの接続URLは、ログ、ツール結果、エラーテキストに含めないでください。プロバイダーがセッションを記録する場合、その記録はClaudeが見て入力したすべてのもののもう1つのコピーとなり、プロバイダーの保持条件が適用されます。

## コンピュータツールセット

`BetaAbstractComputerToolset20260801`は[コンピューター使用ツール](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool)用のクラスです。ドライバーは、`screenshot`や`left_click`など、ツールごとに1つのメソッドを持つサブクラスです。[パートナー統合](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#partner-integrations)にあるパートナーのドライバーから始めてください。独自に作成する場合は、claude-quickstartsリポジトリにPythonとTypeScriptの[最小限のVNCの例](https://github.com/anthropics/claude-quickstarts/tree/main/computer-toolset)があります。これはVNC経由でデスクトップを制御するもので、本番用のコードではありません。

このクラスは`configs`、`confirm`、`tool_configs` (typescript: `toolConfigs`)を受け取り、ブラウザクラスと同じように渡します。[ドライバーをカスタマイズする](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#customize-a-driver)、[エラーを処理する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#handle-errors)、[レスポンスのストリーミング中に呼び出しを開始する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#start-calls-while-the-response-streams)、[ツールランナーなしで実行する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#run-without-the-tool-runner)もこのクラスに適用されますが、次の相違点があります。

* **ブラウザ専用のオプション：** このクラスには[URLポリシー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)、[ファイルポリシー](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#confine-uploads-and-downloads)、[状態レポート](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#report-browser-state)はありません。
* **`configs`：** 実装したすべてのツールはデフォルトで有効です。ツールごとの設定は[ツールパラメータ](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#tool-parameters)に記載されています。
* **`confirm`：** クラスが`type`、`key`、または`hold_key`を実装している場合、`confirm`呼び出し可能オブジェクトを渡すか、`configs`でそれらのツールを無効にしない限り、コンストラクターは設定エラーを送出します。`execute`をオーバーライドするクラスは、3つすべてを実装しているとみなされます。
* **スキップされた呼び出し：** コンピュータ呼び出しが失敗した後、ツールランナーはそのターンの後続のコンピュータ呼び出しに`Not executed: an earlier computer action in this turn failed.`で応答します。ブラウザ呼び出しには別のテキストが使われます。自分で記述したループでは、スキップされたコンピュータ呼び出しにその正確なテキストで応答してください（[バッチアクション](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#batch-actions)）。
* **`execute`：** TypeScriptでは、`execute`のオーバーライドは`name`を`BetaComputerMemberName`として、`input`を`BetaComputerMemberInput`として型付けします。どちらも`@anthropic-ai/sdk/resources/beta`から提供されます。
* **エラーテキスト：** SDKは、コンピュータツールのエラーテキストやツールが返すテキストに含まれるローカルパスを隠しません。Claudeはその両方を4,096文字で切り詰めて読み取ります。ツール内で例外をキャッチし、独自のテキストで`ToolError`を送出してください（TypeScriptではthrowします）。

### デスクトップドライバーを記述する

このドライバーは、[利用可能なアクション](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#available-actions)に記載されている17個のツールのうち5個を実装しています。[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)で説明しているように、実装していないツールは無効としてAPIに送信されます。この例では、`display`はVNCクライアントや`xdotool`など、デスクトップを制御するものを包む独自のラッパーを表し、`ask_user` (typescript: `askUser`)は人に確認する独自の関数を表します。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic import Anthropic
  from anthropic.tools.computer import (
      BetaAbstractComputerToolset20260801,
      BetaComputerCursorPositionResult,
      BetaScreenshotResult,
      BetaToolsetCallContext,
  )
  from anthropic.types.beta import (
      BetaComputerCursorPositionInput,
      BetaComputerKeyInput,
      BetaComputerLeftClickInput,
      BetaComputerScreenshotInput,
      BetaComputerTypeInput,
  )


  class MyDesktop(BetaAbstractComputerToolset20260801):
      def __init__(self, display, **options):
          super().__init__(**options)
          self.display = display

      def screenshot(
          self, context: BetaToolsetCallContext, input: BetaComputerScreenshotInput
      ) -> BetaScreenshotResult:
          # Claude の座標は、この画像内のピクセル位置です。
          data = self.display.png_base64()
          return BetaScreenshotResult(data=data, media_type="image/png")

      def cursor_position(
          self, context: BetaToolsetCallContext, input: BetaComputerCursorPositionInput
      ) -> BetaComputerCursorPositionResult:
          x, y = self.display.cursor()
          return BetaComputerCursorPositionResult(x=x, y=y)

      def left_click(
          self, context: BetaToolsetCallContext, input: BetaComputerLeftClickInput
      ) -> None:
          # input.coordinate は [x, y] で、カーソル位置でクリックする場合は None です。input.text は
          # 押したままにする修飾キー（"shift" など）です。戻り値は不要です。Claude は "Clicked." を読み取ります
          self.display.click(input.coordinate, input.text)

      def type(
          self, context: BetaToolsetCallContext, input: BetaComputerTypeInput
      ) -> None:
          self.display.type(input.text)

      def key(self, context: BetaToolsetCallContext, input: BetaComputerKeyInput) -> None:
          self.display.press(input.text, input.repeat or 1)

      def close(self) -> None:
          super().close()  # first, so no call is still using the desktop when it closes
          self.display.close()


  client = Anthropic()
  with MyDesktop(
      display,
      # type と key では必須です。「Run the computer toolset safely」を参照してください
      confirm=lambda context: ask_user(f'Allow the "{context.member}" tool?'),
  ) as desktop:
      runner = client.beta.messages.tool_runner(
          model="claude-opus-5-5",
          max_tokens=1024,
          tools=[desktop],
          messages=[
              {"role": "user", "content": "Open the calculator and compute 17 * 23."}
          ],
      )
      for message in runner:
          print(message)
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import {
    BetaAbstractComputerToolset20260801,
    type BetaComputerCursorPositionResult,
    type BetaComputerToolsetOptions,
    type BetaScreenshotResult,
    type BetaToolsetCallContext
  } from "@anthropic-ai/sdk/helpers/beta/toolsets";
  import type {
    BetaComputerCursorPositionInput,
    BetaComputerKeyInput,
    BetaComputerLeftClickInput,
    BetaComputerScreenshotInput,
    BetaComputerTypeInput
  } from "@anthropic-ai/sdk/resources/beta";

  class MyDesktop extends BetaAbstractComputerToolset20260801 {
    constructor(
      private display: Display,
      options: BetaComputerToolsetOptions = {}
    ) {
      super(options);
    }

    protected override async screenshot(
      ctx: BetaToolsetCallContext,
      input: BetaComputerScreenshotInput
    ): Promise<BetaScreenshotResult> {
      // Claude の座標は、この画像内のピクセル位置です。
      return { data: await this.display.pngBase64(), mediaType: "image/png" };
    }

    protected override async cursor_position(
      ctx: BetaToolsetCallContext,
      input: BetaComputerCursorPositionInput
    ): Promise<BetaComputerCursorPositionResult> {
      const { x, y } = await this.display.cursor();
      return { x, y };
    }

    protected override async left_click(
      ctx: BetaToolsetCallContext,
      input: BetaComputerLeftClickInput
    ): Promise<void> {
      // input.coordinate は [x, y] で、カーソル位置でクリックする場合は null または undefined です。input.text
      // は押したままにする修飾キー（"shift" など）です。戻り値は不要で、Claude には "Clicked." が返ります
      await this.display.click(input.coordinate, input.text);
    }

    // type ツールは TypeScript では type_ と表記します。
    protected override async type_(
      ctx: BetaToolsetCallContext,
      input: BetaComputerTypeInput
    ): Promise<void> {
      await this.display.type(input.text);
    }

    protected override async key(
      ctx: BetaToolsetCallContext,
      input: BetaComputerKeyInput
    ): Promise<void> {
      await this.display.press(input.text, input.repeat ?? 1);
    }

    override async close(): Promise<void> {
      await super.close(); // first, so no call is still using the desktop when it closes
      await this.display.close();
    }
  }

  const client = new Anthropic();
  const desktop = new MyDesktop(display, {
    // type と key では必須です。「Run the computer toolset safely」を参照してください
    confirm: (ctx) => askUser(`Allow the "${ctx.member}" tool?`)
  });
  try {
    const runner = client.beta.messages.toolRunner({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: [desktop],
      messages: [{ role: "user", content: "Open the calculator and compute 17 * 23." }]
    });
    for await (const message of runner) {
      console.log(message);
    }
  } finally {
    await desktop.close();
  }
  ```
</CodeGroup>

<Warning>
  この例の`confirm`は、ドライバーが実行するすべての呼び出しの前に人に問い合わせます。使い捨てのマシン以外に対してドライバーを実行する前に、[コンピュータツールセットを安全に実行する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#run-the-computer-toolset-safely)をお読みください。
</Warning>

`screenshot`、`cursor_position`、`left_mouse_down`、`left_mouse_up`の4つのツールには入力フィールドがありません。これらを含むすべての入力型は、`anthropic.types.beta` (typescript: `@anthropic-ai/sdk/resources/beta`)から提供されます。

TypeScriptでは、ツールはアロー関数フィールドではなくメソッドとして記述してください。理由は[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)で説明しています。

### 座標のスケーリングと画像のサイズ調整

Claudeが送信するすべての点は、あなたが返すスクリーンショット内のピクセル位置です。これには、各`coordinate`と`start_coordinate`、および`zoom`の`region`の両方の角が含まれます。SDKはこれらを変更せずにツールに渡します。

スクリーンショットのサイズがディスプレイと異なる場合は、ドライバー内で双方向の変換を行ってください。Claudeの点をディスプレイのピクセルに、報告するカーソル位置をスクリーンショットのピクセルに変換します。スクリーンショットのサイズはセッション全体を通じて同じに保ち、ディスプレイのアスペクト比に合わせてください。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic.tools import ToolError

  SCREENSHOT_SIZE = (1280, 720)  # the size of every full screenshot the driver returns
  DISPLAY_SIZE = (2560, 1440)


  def to_display(coordinate: list[int]) -> tuple[int, int]:
      x, y = coordinate
      width, height = SCREENSHOT_SIZE
      if not (0 <= x < width and 0 <= y < height):
          # この座標は拒否します。範囲内に移動すると、Claude が選択していない位置をクリックすることになります。
          raise ToolError(f"[{x}, {y}] is outside the {width}x{height} screenshot")
      return x * DISPLAY_SIZE[0] // width, y * DISPLAY_SIZE[1] // height


  def to_screenshot(x: int, y: int) -> tuple[int, int]:
      width, height = DISPLAY_SIZE
      return x * SCREENSHOT_SIZE[0] // width, y * SCREENSHOT_SIZE[1] // height


  to_display([640, 360])  # (1280, 720)
  ```

  ```typescript TypeScript
  import { ToolError } from "@anthropic-ai/sdk/helpers/beta/toolsets";

  const SCREENSHOT_SIZE = { width: 1280, height: 720 }; // the size of every full screenshot
  const DISPLAY_SIZE = { width: 2560, height: 1440 };

  function toDisplay(coordinate: number[]): [number, number] {
    const [x, y] = coordinate;
    const { width, height } = SCREENSHOT_SIZE;
    if (x < 0 || x >= width || y < 0 || y >= height) {
      // この座標は拒否します。範囲内に移動すると、Claude が選択していない位置をクリックすることになります。
      throw new ToolError(`[${x}, ${y}] is outside the ${width}x${height} screenshot`);
    }
    return [
      Math.floor((x * DISPLAY_SIZE.width) / width),
      Math.floor((y * DISPLAY_SIZE.height) / height)
    ];
  }

  function toScreenshot(x: number, y: number): [number, number] {
    return [
      Math.floor((x * SCREENSHOT_SIZE.width) / DISPLAY_SIZE.width),
      Math.floor((y * SCREENSHOT_SIZE.height) / DISPLAY_SIZE.height)
    ];
  }

  toDisplay([640, 360]); // [1280, 720]
  ```
</CodeGroup>

各`coordinate`と`start_coordinate`に対しては、それに基づいて操作する前に`to_display` (typescript: `toDisplay`)を呼び出し、`cursor_position`が報告する位置に対しては`to_screenshot` (typescript: `toScreenshot`)を呼び出してください。`coordinate`のないクリックやスクロールはカーソル位置で動作するため、変換するものはありません。`zoom`の`region`も同じ係数でスケーリングしてください。`zoom`画像があってもこれは変わりません。Claudeが次に送信する点は、引き続きフルスクリーンショット内のピクセル位置です。

SDKは画像を読み取ったりリサイズしたりすることはありません。APIはモデルの制限を超える画像を拒否し、その場合は実行が終了します。各スクリーンショットと`zoom`画像はドライバー内でスケーリングしてください。[画像の制限に収まるようにスクリーンショットのサイズを調整する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#handle-coordinate-scaling-for-higher-resolutions)を参照してください。長時間の実行では、1つのリクエストに20枚を超える画像が含まれることがあり、その場合APIは各画像により厳しい制限を適用します。[スクリーンショット履歴を管理する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#manage-screenshot-history)を参照してください。

### 入力チェックと結果

呼び出しの入力チェックをSDKに頼らないでください。ドライバーで使用するフィールドをチェックし、実行できない呼び出しは拒否してください。その際は`ToolError`を送出します（TypeScriptではthrowします）。Claudeはそのメッセージを読み、修正した呼び出しを送信できます。

どちらのSDKも、`duration`、`repeat`の回数、`scroll_amount`を制限しません。これらについては[コンピュータツールセットを安全に実行する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#run-the-computer-toolset-safely)のステップ4で説明しています。

ツールが返すものによって、Claudeが読む内容が決まります。

| ツール                 | 戻り値                                | Claudeが読む内容                                      |
| ------------------- | ---------------------------------- | ------------------------------------------------ |
| `screenshot`、`zoom` | `BetaScreenshotResult`             | 1つの画像ブロック                                        |
| `cursor_position`   | `BetaComputerCursorPositionResult` | `X={x},Y={y}`                                    |
| その他すべてのツール          | なし、または1行のテキスト                      | `Clicked.`などの短い確認メッセージと、それに続く独立したテキストブロック内の返された行 |

### コンピュータツールセットを安全に実行する

画面に表示されている内容が、Claudeの次のアクションを左右します。ページや通知が、Claudeに誤ったウィンドウへ入力させたり、実際の影響を伴うアクションを実行させたりしようとする可能性があります。

<Warning>
  `type`、`key`、または`hold_key`を実装するドライバーには、`confirm`呼び出し可能オブジェクトが必要です。これがない場合、`configs`でそれらのツールを無効にしていない限り、コンストラクターは設定エラーを送出します。SDK自体は誰にも確認を求めません。`confirm`が承認したすべての呼び出しを実行し、`confirm`がない場合はすべてのクリックを含むすべての呼び出しを実行します。実装したすべてのコンピュータツールは、デフォルトで有効になっています。
</Warning>

使い捨てのマシン以外に対してドライバーを実行する前に、次の5つのステップを実行してください。

1. デスクトップを隔離します。セッションごとに、認証情報やホストマウントのない、専用の最小権限のコンテナまたはVMで実行してください。タスクに必要なアプリケーションのみをインストールします。APIを呼び出すコードはその外部で実行してください。
2. 実際の影響を伴うアクションを`confirm`で制御します。購入やメッセージ送信は通常の`left_click`、`type`、または`key`であり、`confirm`が受け取るのはツールとその入力であって、画面ではありません。そのため、Claudeがデスクトップ上でアクセスできるアプリケーションに基づいて、承認が必要なツールを選択してください。
3. タスクで必要な場合を除き、ターミナル、実行ダイアログ、ランチャーをデスクトップに置かないでください。これらのいずれかにキーボードフォーカスがあると、`type`、`key`、`hold_key`はClaudeが入力したものを何でも実行し、クリックでプログラムが起動する可能性があります。タスクでこれらが必要な場合は、キーボード入力とクリックの前に人に確認し、コマンドがタスクに必要な範囲を超えて到達できないようにデスクトップを隔離してください。
4. スクリーンショット外の点、数分間の`wait`、非常に大きな`repeat`や`scroll_amount`など、デスクトップが受け付けるべきでない入力は拒否してください。値を範囲内に収めるのではなく、`ToolError`を送出してください（TypeScriptではthrowします）。
5. ウィンドウタイトルやクリップボードのテキストを含め、画面上のすべてを信頼できないものとして扱ってください。チェックせずに実行したり、受け渡したりしないでください。

SDKは、渡された呼び出し可能オブジェクトを通じてステップ2を適用します。その他のステップは、ドライバーとデプロイメントに委ねられます。[セキュリティに関する考慮事項](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool#security-considerations)に記載されている予防措置も適用されます。

次の`confirm`は、独自の`ask_user` (typescript: `askUser`)関数を通じて、キーボード入力の前に人に確認し、その他のすべての呼び出しを承認します。`context.member` (typescript: `ctx.member`)はツールの名前です。クリックも人に承認させるには、`ASK_FIRST`を`KEYBOARD | CLICKS` (typescript: `new Set([...KEYBOARD, ...CLICKS])`)に設定してください。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  from anthropic.tools.computer import BetaComputerConfirmContext

  KEYBOARD = {"type", "key", "hold_key"}
  CLICKS = {
      "left_click",
      "right_click",
      "middle_click",
      "double_click",
      "triple_click",
      "left_click_drag",
      "left_mouse_down",
      "left_mouse_up",
  }
  ASK_FIRST = KEYBOARD


  def confirm(context: BetaComputerConfirmContext) -> bool:
      if context.member not in ASK_FIRST:
          return True
      # ここに示すのは「Gate consequential members」の関数です。
      detail = shown(context.input.to_dict())
      return ask_user(f'Allow the "{context.member}" tool with this input?\n{detail}')


  desktop = MyDesktop(display, confirm=confirm)
  ```

  ```typescript TypeScript
  import type { BetaComputerConfirmContext } from "@anthropic-ai/sdk/helpers/beta/toolsets";

  const KEYBOARD = ["type", "key", "hold_key"];
  const CLICKS = [
    "left_click",
    "right_click",
    "middle_click",
    "double_click",
    "triple_click",
    "left_click_drag",
    "left_mouse_down",
    "left_mouse_up"
  ];
  const ASK_FIRST = new Set(KEYBOARD);

  async function confirm(ctx: BetaComputerConfirmContext): Promise<boolean> {
    if (!ASK_FIRST.has(ctx.member)) {
      return true;
    }
    // ここに示すのは「Gate consequential members」の関数です。
    return askUser(`Allow the "${ctx.member}" tool with this input?\n${shown(ctx.input)}`);
  }

  const desktop = new MyDesktop(display, { confirm });
  ```
</CodeGroup>

拒否された呼び出しはエラー結果を受け取り、実行は継続します。拒否された`type`呼び出しの場合、Claudeは`The user did not grant permission to run 'type'. Do not retry it unless the user asks you to.`を読みます。

この`confirm`は、後から追加するツールも含め、`ASK_FIRST`に含まれないすべてのツールを承認します。フェイルクローズにするには、デスクトップに影響を与えないツール（`screenshot`、`zoom`、`cursor_position`、`wait`）のみを承認し、その他のすべてのツールについて確認を求めてください。

### 1つのリクエストで両方のツールセットを使用する

両方のインスタンスを`tools`に渡します。各呼び出しには`toolset_name`（`browser`または`computer`）が含まれており、ツールランナーは呼び出しを対応するインスタンスに送信します。呼び出しが失敗した後、ツールランナーはそのターン内の同じツールセットへの後続の呼び出しのみをスキップするため、コンピュータ呼び出しが失敗しても、そのターンのブラウザ呼び出しはスキップされません。

<CodeGroup exclude="shell:cURL, shell:CLI, csharp, go, java, php, ruby">
  ```python Python
  # MyBrowser、backend、url_policy は高度な例で定義したものです。
  # confirm は「Run the computer toolset safely」で定義した関数です。
  with (
      MyBrowser(backend, url_policy=url_policy) as browser,
      MyDesktop(display, confirm=confirm) as desktop,
  ):
      runner = client.beta.messages.tool_runner(
          model="claude-opus-5-5",
          max_tokens=1024,
          tools=[browser, desktop],
          messages=[
              {
                  "role": "user",
                  "content": "Copy the heading on example.com into the open text editor.",
              }
          ],
          stream=True,
          run_tools_eagerly=True,  # so a call can start before the response ends
      )
      for stream in runner:
          print(stream.get_final_message())
  ```

  ```typescript TypeScript
  // MyBrowser、backend、urlPolicy は応用例で定義したものです。
  // confirm は「Run the computer toolset safely」で定義した関数です。
  const browser = new MyBrowser(backend, { urlPolicy });
  const desktop = new MyDesktop(display, { confirm });
  try {
    const runner = client.beta.messages.toolRunner({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: [browser, desktop],
      messages: [
        { role: "user", content: "Copy the heading on example.com into the open text editor." }
      ],
      stream: true,
      runToolsEagerly: true // so a call can start before the response ends
    });
    for await (const stream of runner) {
      console.log(await stream.finalMessage());
    }
  } finally {
    await Promise.all([browser.close(), desktop.close()]);
  }
  ```
</CodeGroup>

自分で記述するループでは、`toolset_name` (typescript: `toolsetName`)が呼び出しの`toolset_name`と一致するインスタンスの`tool_result` (typescript: `toolResult`)で各呼び出しに応答してください。各ターンで、失敗した呼び出しをツールセットごとに個別に追跡し、スキップされた呼び出しにはそのツールセット固有のテキストで応答してください。ブラウザのテキストは[ツールランナーなしで実行する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#run-without-the-tool-runner)に、コンピュータのテキストはこのセクションの冒頭にあるスキップされた呼び出しの項目に記載されています。

## リファレンス

コンストラクターのオプションは、両方のSDKで同じ意味を持ちます：

| Python               | TypeScript     | 設定内容                                     |
| -------------------- | -------------- | ---------------------------------------- |
| `configs`            | `configs`      | 有効にするメンバー                                |
| `confirm`            | `confirm`      | 各呼び出しを承認または拒否する呼び出し可能オブジェクト              |
| `url_policy`         | `urlPolicy`    | URLポリシー。SDKはURLへの各`navigate`の前にこれを呼び出します |
| `file_policy`        | `filePolicy`   | アップロードのルートとダウンロードパスの公開                   |
| `tool_configs`       | `toolConfigs`  | `cache_control`など、`tools`エントリのフィールド      |
| `_browser_state`メソッド | `browserState` | 状態レポート                                   |

ブラウザクラスは表内のすべてのオプションを受け取ります。コンピュータクラスは`configs`、`confirm`、`tool_configs` (typescript: `toolConfigs`)を受け取ります。

構築後にオプションを変更することはできません。各オプションについては、[Pythonブラウザツールセットガイド](https://github.com/anthropics/anthropic-sdk-python/blob/main/browser-toolset.md)、[TypeScriptブラウザツールセットガイド](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/browser-toolset.md)、[Pythonコンピュータツールセットガイド](https://github.com/anthropics/anthropic-sdk-python/blob/main/computer-toolset.md)、[TypeScriptコンピュータツールセットガイド](https://github.com/anthropics/anthropic-sdk-typescript/blob/main/computer-toolset.md)で説明しています。Pythonのガイドでは、非同期クラスである`BetaAsyncAbstractBrowserToolset20260801`と`BetaAsyncAbstractComputerToolset20260801`についても説明しています。

## 制限事項

* **SDKにはブラウザ、デスクトップ、既製のドライバー、URLポリシーは含まれていません：** これらはユーザー側で用意します。[パートナー統合](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#partner-integrations)、[ドライバーを実装する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#implement-a-driver)、[URLポリシーを記述する](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#write-a-url-policy)を参照してください。
* **URLポリシーは`navigate`呼び出しのみを認識します：** ページが行うリクエストや、Claudeがクリックしたリンクやリダイレクトなど、その他の方法で開かれるページは認識しません。[ドライバーでリクエストをインターセプトする](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#intercept-requests-in-the-driver)を参照してください。
* **承認は最後の状態レポートに基づきます：** そのレポートの後にページが変わる可能性があります。SDKは呼び出しが実行される前にページを再度チェックしません。
* **1つのツールセットに対する呼び出しは一度に1つずつ実行されます：** これを無効にすることはできません。
* **SDKはタブIDが一意であるかどうかやタブの数をチェックせず、アクティブなタブが1つであることも常にチェックするわけではありません：** APIはこれらのルールに違反するレポートを拒否します。
* **コンピュータ呼び出しの場合、`confirm`が受け取るのはツールとその入力であって、画面ではありません：** それらからは、特定の点でのクリックが何を行うかを判断できません。
* **SDKはコンピュータツールセットの画像をリサイズしません：** APIはモデルの制限を超える画像を拒否します。[座標のスケーリングと画像のサイズ調整](https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-sdk#scale-coordinates-and-size-images)を参照してください。

## 次のステップ

<CardGroup cols={2}>
  <Card title="ブラウザ使用ツール" icon="browser" href="https://platform.claude.com/docs/ja/agents-and-tools/tool-use/browser-use-tool">
    メンバーツール、`browser_state`ブロック、およびツールのセキュリティに関する考慮事項。
  </Card>

  <Card title="コンピューター使用ツール" icon="computer" href="https://platform.claude.com/docs/ja/agents-and-tools/tool-use/computer-use-tool">
    17個のツール、座標と画像の制限、およびツールのセキュリティに関する考慮事項。
  </Card>

  <Card title="ツールランナー（SDK）" icon="arrows-clockwise" href="https://platform.claude.com/docs/ja/agents-and-tools/tool-use/tool-runner">
    SDKがループを実行する方法と、送信するメッセージを変更する方法。
  </Card>

  <Card title="ジェイルブレイクとプロンプトインジェクションを軽減する" icon="shield" href="https://platform.claude.com/docs/ja/test-and-evaluate/strengthen-guardrails/mitigate-jailbreaks">
    信頼できないコンテンツを読み取るあらゆるアプリケーションのためのガードレール。
  </Card>
</CardGroup>
