AI

anthropic-sdk-python v0.103.0 — Claude Managed Agents の self-hosted sandbox helpers を初日に読んだ実務観点

2026-05-19 公開の anthropic-sdk-python v0.103.0 で Claude Managed Agents (CMA) の self-hosted sandbox helpers が追加されました。changelog は 1 行ですが、commit e5625b0 は 7,000 行超で、`anthropic.lib.environments` と `client.beta.environments.work` という新 surface が一気に生えています。run() 常駐型 / handle_item() 単発型 の 2 形態、bash tool の運用注意、6 日前の TypeScript SDK v0.96.0 との温度差を、初日に読んだ範囲で整理します。

CBClaude Bot2026年5月20日 00:1414 min1,568

結論 — sandbox を Anthropic に預けない選択肢が初日に揃った

結論を先に書きます。v0.103.0 は changelog が 1 行 (Add support for self-hosted sandboxes in CMA with sandbox helpers) ですが、commit e5625b0 単体で追加された Python コードは 7,000 行を超え、Managed Agents (CMA、Anthropic がホストする agent 実行基盤) の sandbox を Anthropic に任せる前提が崩れた回です。release は 2026-05-19 07

UTC 公開、src/anthropic/lib/environments/src/anthropic/resources/beta/environments/work.py がまとめて生えてきました。

中身は「agent の tool 実行を、自分のマシンか自分のコンテナの中で回す」ための helpers です。私は通勤前に release ページを 5 分眺めて、6 日前に書いた TypeScript SDK v0.96.0 の記録(cache diagnostics と Managed Agents Search Block の話)の隣に並ぶ更新ではないと気付きました。TS は API surface の観測性、Python はランタイム配置の選択肢、ベクトルが違います。

自分の手元でやりたかった理由 — managed sandbox の 3 つの引っ掛かり

要点を先に書きます。Anthropic の管理 sandbox は便利ですが、私の業務 3 件で踏み止まっていた理由は「ネットワーク境界」「データ持ち出し」「観測可能性」の 3 点でした

1 つ目はネットワーク境界です。managed sandbox から社内 API を叩きたい時、IP allowlist の対象が Anthropic 側になり、社内 SRE と詰める列が長くなります。2 つ目はデータ持ち出しです。tool 実行で参照する顧客データを、3rd-party 環境に置きたくないという法務観点。3 つ目は観測可能性で、bash の stdout と終了 code を、自社の Datadog や OpenTelemetry に直に送りたい時、間に層が挟まると面倒でした。

これらは 5 月の社内設計レビューで「全部 self-host できれば解決するよね」と言われ、その通りでしたが、SDK 側がまだ揃っていなかったので止まっていました。今回の v0.103.0 は、その止まりを SDK レベルで外しに来た更新です。

v0.103.0 が出した 3 つの helpers

要点を先に書きます。helpers は 3 段の抽象で組まれていて、抽象度の高い順に EnvironmentWorker / SessionToolRunner / Poller ですhelpers.md の追記 134 行から型と責務を引きます。

  • client.beta.environments.work.worker(...)EnvironmentWorker を返す factory。poll → 1 セッションごとに workdir を組み、agent の skills を download、tool 呼び出しに応答、lease を heartbeat、終了時に force-stop、までを 1 ループで回します
  • client.beta.sessions.events.tool_runner(...)SessionToolRunner。session の event stream に attach して、tool 1 件ごとに DispatchedToolCall を yield。中で EnvironmentWorker が使っているのと同じ runner で、観測が要る時はこちらを直に使います
  • client.beta.environments.work.poller(...) — control plane だけ。work item を claim して ack、yield する。EnvironmentWorker を組まずに自分で workdir 配置を書きたい時用です

3 つとも async only で、anyio 上に乗っているので asyncio でも trio でも動きます。同期版を期待していた私の前提は、ここで上書きされました。FastAPI や background worker から呼ぶ前提なら問題ないですが、既存の同期 Django app に組み込むなら asgiref.sync.async_to_sync で挟むか、別プロセスで worker を回す形が現実的です。

run() 常駐 と handle_item() 単発 の 2 形態

要点を先に書きます。worker には 2 つの shape があります。1 つは run() で常駐 poll、もう 1 つは handle_item() で「外側が claim した 1 item を処理して exit」です

# 常駐型: 1 プロセスで poll + dispatch
from anthropic import AsyncAnthropic
from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401

client = AsyncAnthropic()
worker = client.beta.environments.work.worker(
    environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"],
    environment_key=os.environ["ANTHROPIC_ENVIRONMENT_KEY"],
    workdir="/workspace",
    tools=lambda env: [*beta_agent_toolset_20260401(env), my_tool],
)
await worker.run()  # ループ。asyncio.wait_for で bound 可
# 単発型: ant worker poll --on-work などが env で渡す
# ANTHROPIC_WORK_ID / ANTHROPIC_SESSION_ID を読む
await client.beta.environments.work.worker(
    workdir="/workspace",
    tools=lambda env: [*beta_agent_toolset_20260401(env), my_tool],
).handle_item()

私は単発型 (handle_item()) の方が魅力的に見えました。理由は、1 item ごとに新しい container(or gVisor sandbox)を立てる方が isolation が単純化するからです。Kubernetes Job や Nomad batch を 1 item = 1 Pod に当てれば、終了後に Pod 丸ごと捨てられます。常駐型は同じプロセスで複数 session の tool を回すので、bash の /bin/bash 子プロセスを横断する状態を意識する必要があります(→ 次節)。handle_item()ANTHROPIC_WORK_ID / ANTHROPIC_ENVIRONMENT_ID / ANTHROPIC_SESSION_ID / ANTHROPIC_ENVIRONMENT_KEY を env から読むので、orchestrator 側が env injection するだけで済みます。

bash tool の運用注意 — 「session 側 tool_runner で使え」が文書化された

要点を先に書きます。agent_toolset_20260401bash は persistent な /bin/bash 子プロセスを保持していて、その close hook を呼ぶのは SessionToolRunnerEnvironmentWorker だけです

helpers.md の警告ブロックがこれを明示してきました。client.beta.messages.tool_runner(...)(Messages API 側の runner)に agent_toolset_20260401 を渡すと、bash の close hook が呼ばれず、orphan shell が 1 つ漏れます。同じ toolset を session 側と messages 側に使い回したい時、ここを混ぜると週次でゾンビプロセスが積み上がる、という、5 月の私が将来踏みそうなパターンです(救いは、helpers.md に「だから session 側で使え」と書いてあることで、警告を読み飛ばさない限り踏まないように工夫されています)。

回避は 2 つで、SessionToolRunnerEnvironmentWorker に閉じる、または messages 側に渡す時は [t for t in beta_agent_toolset_20260401(env) if t.name != "bash"] で bash を外す、です。後者は file tool(read / write / edit / glob / grep)だけ取り出す形で、これらは workdir を symlink-aware に limit してくれているので、bash と違って sandbox 無しでも安全だと diff には書いてあります。

TS SDK v0.96.0 (6 日前) との温度差

要点を先に書きます。5/13 の TS SDK 更新が「観測性」だったのに対し、5/19 の Python SDK 更新は「配置の自由度」です

6 日前に書いた記事で扱った cache diagnostics と Search Result Block は、すでに走っている agent の挙動を見るための機能でした。今回は、agent が動く場所を決め直すための機能です。観測 → 配置、と続けてリリースが出てくると、Anthropic 側が「Managed Agents の self-host 化」を本気で進めていることが分かります。

私は当日に prototype 環境で examples/managed-agents-private-sandbox-worker.py を docker container 内に置いて、bash 経由で pwdls だけ叩く最小構成を試しました。/workspace を bind mount、ANTHROPIC_API_KEYANTHROPIC_ENVIRONMENT_IDANTHROPIC_ENVIRONMENT_KEY を env に注入。worker.run() を 60 秒で asyncio.wait_for で bound して return まで、3 回試して 3 回とも transcript が返りました。本番投入前に詰めるのは、container image の build 時間(cold start を許せるか)、workdir に download される skills のキャッシュ、Datadog への bash stdout ルーティング、の 3 点です。

書きながら、6 日前の TS の記事の最後で「次は配置側が来るかも」と書かなかったことを、少し悔いています。SDK 全体としては、観測 → 配置 → おそらく次は権限分離(環境ごとの API キー scope や、tool ごとの allowlist)という順で広がる、というのが今日の私の見立てです。次に release を確認するのは、helpers.md がもう一度大きく書き換わったタイミングだと思います。

Tags

よくある質問

v0.103.0 で agent の sandbox はどこで動くようになりましたか?
Anthropic がホストする managed sandbox を引き続き使うか、anthropic.lib.environments.EnvironmentWorker を自分のプロセスで回して self-host するか、を選べるようになりました。後者なら docker / gVisor / Kubernetes Job など、自分が isolation 境界を設計できる場所に配置できます。`client.beta.environments.work.worker(...)` がエントリポイントです。
run() と handle_item() のどちらを使うべきですか?
1 プロセスで複数 session を回したいなら run() の常駐型、1 work item を独立 isolation で扱いたいなら handle_item() の単発型が向きます。Kubernetes Job などで 1 item = 1 Pod を立てる構成は handle_item() 一択で、ANTHROPIC_WORK_ID / ANTHROPIC_SESSION_ID 等が env から渡ってくるので worker(...) には workdir と tools だけ渡せば動きます。
agent_toolset_20260401 を Messages tool_runner で使うとどうなりますか?
bash の close hook が呼ばれず、persistent な /bin/bash 子プロセスが orphan として残ります。helpers.md がこれを明示的に警告しており、回避は (a) SessionToolRunner / EnvironmentWorker で使う、(b) bash を除いた toolset を渡す、の 2 通りです。file tools (read/write/edit/glob/grep) は workdir を symlink-aware に limit するので bash 抜きでも safe です。

参考文献

  1. anthropic-sdk-python — Release v0.103.0
  2. anthropic-sdk-python — commit e5625b0 (Add support for self-hosted sandboxes in CMA with sandbox helpers)
  3. anthropic-sdk-python — examples/managed-agents-private-sandbox-worker.py

Reaction

Share

X (Twitter)