
こんにちは。よっしーです(^^)
背景
この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。
1. 一言でいうと
Python 版 Agent SDK のすべての関数・クラス・型を並べた、公式の完全リファレンスです。中心は、1回きりの問い合わせに使う query() と、会話を続けるための ClaudeSDKClient クラスの2本立てで、そこに ClaudeAgentOptions、メッセージとコンテンツブロックの型、例外の型、フックの型、組み込みツールの入出力の型、サンドボックスの設定が続きます。第104回の TypeScript リファレンスと同じ役割のページですが、Python 特有の作法と、TypeScript とは既定値が逆になっている箇所があり、そこを知らずに使うと危ない、というのがこの回の要点です。
原文は約4,000行、コードブロックは169本あります。第104回と同じく、この記事は地図と、これまでの回に出てこなかった情報、そしてTypeScript との違いに絞ります。
2. どういう場面で役立つか
シーン1:query() と ClaudeSDKClient のどちらを使うか決める
これまでの回で何度も「Python では ClaudeSDKClient が必要」と書いてきました(第79回の制御メソッド、第84回の MCP の再接続、第91回の複数ターンなど)。このページの比較表で、どちらを使うかを一度で判断できます。
シーン2:例外とエラーの結果を正しく見分ける
ResultError の属性と、「subtype が success なのに失敗している」場合の見分け方が、このページで明確に書かれています。第97回・第98回で見た判定のしかたを、もう一段正確にする情報です。
シーン3:TypeScript で書いた知識を Python に移す
TypeScript と Python でオプション名、取り出し方、既定値が違う箇所を確かめる場面です。特にサンドボックスの既定値は逆なので、移植のときに見落とすと守りが外れます(3-6)。
不要・向かないケース
- TypeScript を使っている:第104回の TypeScript リファレンスを引きます。
- SDK を初めて使う:辞書なので最初に読むものではありません。第78回のクイックスタートと機能ごとのガイドから入ります。
- セッションストアを使う関数を探している:第93回で見た
list_sessions_from_store()などのストア対応の関数は、今回貼られたページの見出しには出てきません。それらは第93回のセッションストレージのページで確かめる必要があります(筆者の確認)。
3. コードと仕組みの解説
原文の fenced コードブロックは169本です。大半は型の定義なので、この記事では9本だけを引用し、残りは表と散文に圧縮します。引用するのは、(1) インストールと中心の定義(query()、ClaudeSDKClient)、(2) このページで初めて出てくる書き方(TypedDict によるツールの入力スキーマ、割り込み)、(3) エラーの扱い(ResultError とその使い方)、(4) TypeScript と既定値が違うサンドボックスの例です。コードは原文から機械的に抜き出したもので、入れ子に由来する先頭インデントを外した以外は変えていません。原文は注記で、シグネチャのブロックや、裸の async for/async with の断片は説明用で、実行するには async def main(): ... で包んで asyncio.run(main()) を呼ぶ必要がある、と書いています。
3-0. この記事に出てくる主なバージョン要件
| 機能 | バージョン |
|---|---|
ResultError、forward_subagent_text、ToolAnnotations の snake_case 名と型付きの maxResultSizeChars | Python Agent SDK 0.2.140 以降 |
resume_session_at・resume_drops_turn、ResultMessage の origin | Python Agent SDK 0.2.137 以降 |
verbatim_prompts | Python Agent SDK 0.2.158 以降と Claude Code v2.1.248 以降 |
skills の不正な名前を事前に拒否 | Python Agent SDK 0.2.129 以降 |
model_usage の thinkingTokens | Python Agent SDK 0.2.150 以降 |
maxResultSizeChars をキーワード引数で渡せる | Python Agent SDK 0.1.55〜0.2.139 |
3-1. インストール
原文は、仮想環境に入れるよう書いています。最近の Debian・Ubuntu・Homebrew の Python では、システムの Python に pip install すると error: externally-managed-environment で失敗するからです。
python3 -m venv .venv
source .venv/bin/activate
pip install claude-agent-sdk
uv や Windows の PowerShell、API キーの設定は、第78回のクイックスタートに回されています。
3-2. query() と ClaudeSDKClient の選び方
原文の比較表です。
| 機能 | query() | ClaudeSDKClient |
|---|---|---|
| セッション | 既定で新しいセッションを作る | 同じセッションを使い回す |
| 会話 | 1回のやりとり | 同じ文脈での複数のやりとり |
| 接続 | 自動で管理 | 手動で制御 |
| ストリーミング入力 | 対応 | 対応 |
| 割り込み | 非対応 | 対応 |
| フック | 対応 | 対応 |
| カスタムツール | 対応 | 対応 |
| 会話を続ける | continue_conversation か resume で手動 | 自動 |
| 用途 | 1回きりのタスク | 続く会話 |
チャット画面のような対話型のアプリや、次の動きが Claude の応答次第で変わる場合は ClaudeSDKClient を使う、というのが原文の指針です。
query() の定義です。
async def query(
*,
prompt: str | AsyncIterable[dict[str, Any]],
options: ClaudeAgentOptions | None = None,
transport: Transport | None = None
) -> AsyncIterator[Message]
transport は、CLI のプロセスとの通信を差し替えるための引数です(3-4)。各 query() 呼び出しは、continue_conversation=True か resume を渡さない限り、前のやりとりを覚えていません(第87回)。
ClaudeSDKClient
原文は ClaudeSDKClient を「TypeScript SDK の query() 関数が内部でどう動いているかの Python 版」と説明しています。第104回の TypeScript の Query オブジェクトが持っていた制御メソッドは、Python ではこのクラスにあります。
class ClaudeSDKClient:
def __init__(self, options: ClaudeAgentOptions | None = None, transport: Transport | None = None)
async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
async def receive_messages(self) -> AsyncIterator[Message]
async def receive_response(self) -> AsyncIterator[Message]
async def interrupt(self) -> None
async def set_permission_mode(self, mode: PermissionMode) -> None
async def set_model(self, model: str | None = None) -> None
async def rewind_files(self, user_message_id: str) -> None
async def get_mcp_status(self) -> McpStatusResponse
async def get_context_usage(self) -> ContextUsageResponse
async def reconnect_mcp_server(self, server_name: str) -> None
async def toggle_mcp_server(self, server_name: str, enabled: bool) -> None
async def stop_task(self, task_id: str) -> None
async def get_server_info(self) -> dict[str, Any] | None
async def disconnect(self) -> None
TypeScript の Query のメソッドとの対応を整理します。
Python(ClaudeSDKClient) | TypeScript(Query) | 備考 |
|---|---|---|
interrupt() | interrupt() | ストリーミングモードでのみ |
set_permission_mode()・set_model() | setPermissionMode()・setModel() | set_model に None を渡すと既定のモデルに戻る |
rewind_files() | rewindFiles() | enable_file_checkpointing=True が必要(第88回) |
get_mcp_status()・reconnect_mcp_server()・toggle_mcp_server() | mcpServerStatus()・reconnectMcpServer()・toggleMcpServer() | 第84回 |
get_context_usage() | getContextUsage() | /context と同じデータ |
stop_task() | stopTask() | 停止すると "stopped" の TaskNotificationMessage が続く |
get_server_info() | initializationResult() | コマンドや出力スタイルなどの初期化情報 |
| (なし) | applyFlagSettings()・updateSettings()・readFile()・reloadPlugins() など | TypeScript だけにある |
表は筆者の整理です。Python には、第104回で見た startup()・prewarm()・resolveSettings() に当たる関数も、このページには見当たりません(第93回で「startup() は Python に無い」と見たとおり)。
ClaudeSDKClient は async with で使えば接続の管理を任せられます。原文はここで1つ注意しています。メッセージを読んでいる途中で break で抜けるのは避ける。asyncio の後片付けの問題を起こしうるので、最後まで読み切るか、目的のものを見つけたかをフラグで記録します。
割り込みの後は「読み切る」
このページで初めて詳しく出てくるのが、割り込みの扱いです。
import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions, ResultMessage
async def interruptible_task():
options = ClaudeAgentOptions(allowed_tools=["Bash"], permission_mode="acceptEdits")
async with ClaudeSDKClient(options=options) as client:
# Start a long-running task
await client.query("Count from 1 to 100 slowly, using the bash sleep command")
# Let it run for a bit
await asyncio.sleep(2)
# Interrupt the task
await client.interrupt()
print("Task interrupted!")
# Drain the interrupted task's messages (including its ResultMessage)
async for message in client.receive_response():
if isinstance(message, ResultMessage):
print(f"Interrupted task: terminal_reason={message.terminal_reason!r}")
# terminal_reason is "aborted_streaming" or "aborted_tools"
# for interrupted turns
# Send a new command
await client.query("Just say hello instead")
# Now receive the new response
async for message in client.receive_response():
if isinstance(message, ResultMessage) and message.subtype == "success":
print(f"New result: {message.result}")
asyncio.run(interruptible_task())
原文の注記が要点です。interrupt() は停止の合図を送るだけで、メッセージのバッファは空にしません。 割り込まれたタスクがすでに出したメッセージ(その ResultMessage を含む)はストリームに残ります。だから例は、割り込みの後でいったん receive_response() で読み切り(ドレイン)、それから新しい query() を送っています。割り込みの直後に新しい問い合わせを送って receive_response() を1回だけ呼ぶと、受け取るのは割り込まれたタスクのメッセージで、新しい問い合わせの応答ではありません。
割り込まれたターンの terminal_reason は "aborted_streaming" か "aborted_tools" です。原文によれば、interrupt=True 付きの PermissionResultDeny を返す権限コールバックも、同じく中止の原因になります。
原文の「高度な権限制御」の例には、コメントで「ゲートしたいツールを allowed_tools にも書かない。許可ルールは can_use_tool より先に呼び出しを承認する」と書かれています。第80回の評価順序の、最もよくある落とし穴です。
3-3. ツール:入力スキーマに TypedDict が使える
第83回で、Python のツールの入力スキーマは「名前→型の dict(全部必須、列挙は書けない)か、完全な JSON Schema」と見ました。このページには、3つ目の書き方として TypedDict が載っています。
from typing import Annotated, Any, NotRequired, TypedDict
from claude_agent_sdk import tool
class ForecastArgs(TypedDict):
latitude: Annotated[float, "Latitude coordinate"]
hours: NotRequired[Annotated[int, "How many hours of forecast to return"]]
@tool("get_forecast", "Get the hourly forecast for a location", ForecastArgs)
async def get_forecast(args: dict[str, Any]) -> dict[str, Any]:
hours = args.get("hours", 12)
return {"content": [{"type": "text", "text": f"{hours}-hour forecast for {args['latitude']}"}]}
NotRequired で包んだキーは required から外れるので、省略できる引数を型で表せます。Annotated[type, "description"] の形で包むと、フィールドの説明も付けられます(簡単な dict 形式でも使える)。Python 3.11 以降は typing から、3.10 は typing_extensions から TypedDict と NotRequired を import します(3.10 では SDK が typing_extensions を入れる)。
第83回では「省略可能な引数はスキーマから外して説明文に書き、args.get() で読む」のが Python の作法でしたが、TypedDict を使えば、省略可能であることをスキーマとして Claude に伝えられます(筆者の対応づけ)。例でも hours を args.get("hours", 12) で読んでいる点は同じです。
ツールの注釈 ToolAnnotations には、maxResultSizeChars という Claude Code 独自の項目があります。テキストの結果を、ファイルに保存せずに会話の中にそのまま置いておく文字数の上限(最大 500,000)で、第84回で見た「大きな結果はファイルに保存される」の、ツール単位の調整です。原文は、注釈はヒントであってセキュリティの判断に使ってはならないとも書いています。
一方、Python の create_sdk_mcp_server() の引数は name・version・tools の3つで、第104回の TypeScript にあった instructions・alwaysLoad・timeout はありません。tool() にも searchHint・alwaysLoad がありません(筆者の比較)。
3-4. 型:dataclass と TypedDict の違い
原文は型の節の冒頭で、Python 特有の注意を置いています。
| 種類 | 例 | 実行時の姿 | 読み方 |
|---|---|---|---|
@dataclass | ResultMessage、AgentDefinition、TextBlock | オブジェクト | 属性:msg.result |
TypedDict | ThinkingConfigEnabled、McpStdioServerConfig、SyncHookJSONOutput | ただの辞書 | キー:config["budget_tokens"](config.budget_tokens ではない) |
ClassName(field=value) の書き方はどちらでも通りますが、属性を持つオブジェクトになるのは dataclass だけです。TypedDict の値を属性で読もうとすると失敗するので、型の定義を見てどちらかを確かめる必要があります。第92回で見た model_usage の値(ModelUsage)も TypedDict で、キーは CLI から来たままの camelCase(inputTokens など)です。
ClaudeAgentOptions の、このページで初めて出てくる項目
ClaudeAgentOptions は約50の項目を持つ dataclass です。これまでの回で扱っていないもの、または新しい注意が付いたものを拾います。
| 項目 | 内容 |
|---|---|
user | POSIX で、Claude Code のサブプロセスを動かす OS のユーザー。親プロセスの環境(HOME を含む)を保ち、cwd で動く |
max_buffer_size | CLI の標準出力をバッファするときの最大バイト数 |
mcp_servers | 辞書のほか、設定ファイルへのパスも渡せる |
session_id | 有効な UUID であること。fork_session が無い限り、continue_conversation や resume と組み合わせられない |
setting_sources | skills を設定してこの項目を設定しないと、ユーザーとプロジェクトのソースだけが読まれる。ローカル設定も読ませたいなら明示する |
system_prompt | 文字列・プリセット・{"type": "custom", "prompt": "..."} に加え、{"type": "file", "path": "..."} で大きなプロンプトをファイルから読む(第86回の Argument list too long 対策) |
task_budget | API 側のトークン予算。task-budgets-2026-03-13 のベータヘッダーで送られる |
debug_stderr | 非推奨で、SDK は値を無視する。stderr コールバックを使う |
env | 引き継いだ環境の上に重ねる(TypeScript は置き換え) |
表は筆者の整理です。setting_sources の注意は、第100回の「省略は ["user", "project", "local"] と同じ」に対する Python の例外です。skills を指定しただけで、.claude/settings.local.json と CLAUDE.local.md が読まれなくなることになります(筆者の指摘)。ローカルの権限ルールやフックに頼っている場合は、setting_sources を明示する必要があります。
debug_stderr が無視される点も、第97回の「本当のエラー出力は stderr コールバックで取る」と合わせて覚えておく価値があります。古いコードで debug_stderr に頼っていると、何も記録されません。
Transport は、CLI のプロセスとの通信をリモート接続などに差し替えるための抽象基底クラスです。原文は低レベルの内部 API で、将来インターフェースが変わりうると警告しています。
ToolPermissionContext(can_use_tool の第3引数)には、第81回では出てこなかった title(「Claude wants to read foo.txt」のような完全な確認文)、display_name(「Read file」のような短い名詞句。ボタンの文言向き)、description(確認画面の副題)があります。確認画面を自分で作るときの文言に使えます。
3-5. メッセージと例外
「success なのに失敗」を見分ける
このページで最も重要な情報の1つが、ResultMessage の is_error の説明です。
is_errorは、error_*の subtype では常にTrue。subtype="success"でも、最後のモデルへのリクエストが失敗した場合はTrue。エージェントのループは完了したが、最後の API 呼び出しがエラーを返した、という状態です。- そのとき
resultには API エラーの文字列が入ることがありますが、空のこともあるので、api_error_statusと直前のAssistantMessageを確かめます。
Python の dataclass は全種類の結果を1つの形にまとめているので、その subtype に関係のないフィールドは None になります。
例外の側では、ResultError がこれを反映しています。
class ResultError(ProcessError):
subtype: str | None # "error_max_turns", "error_during_execution", ...; "success" when the run ended on a failed request
errors: list[str] # an empty list when the result message reported none
result: str | None
api_error_status: int | None
terminal_reason: str | None # "max_turns", "api_error", ...; check this before subtype
session_id: str | None
data: dict[str, Any] # the raw result message payload
コメントにあるとおり、subtype の前に terminal_reason を確かめます。最後のリクエストが失敗した(API エラーなど)場合、Claude Code は subtype を "success" と報告し、原因を terminal_reason("api_error" など)に書きます。設定した上限(max_turns や max_budget_usd)で終わった場合は error_* の subtype になります。
筆者の指摘:第97回・第98回では「成功の判定は subtype が success であることと、structured_output があることの両方」と見ました。このページの情報を加えると、subtype が success でも is_error が True なら失敗です。結果の判定は、subtype・is_error・terminal_reason を合わせて見るのが確実です。原文の書き方からは TypeScript の結果メッセージも同じ形(is_error と terminal_reason を持つ)なので、言語を問わず当てはまると考えられます。
例外の型の階層は次のとおりです。
| 例外 | 親 | いつ |
|---|---|---|
ClaudeSDKError | Exception | すべての SDK エラーの基底 |
CLIConnectionError | ClaudeSDKError | Claude Code に接続できない |
CLINotFoundError | CLIConnectionError | CLI が入っていない・見つからない |
ProcessError | ClaudeSDKError | プロセスが失敗した(exit_code・stderr) |
ResultError | ProcessError | エラーの結果メッセージで終わった(0.2.140 以降) |
CLIJSONDecodeError | ClaudeSDKError | JSON の解析に失敗(line・original_error) |
表は原文の定義から筆者が整理したものです。CLINotFoundError が CLIConnectionError の子である点は、第97回の「接続の失敗」と「見つからない」を同じ CLIConnectionError の except 節で受けられる、ということです。
原文のエラー処理の例は、4種類の例外を順に受けます。
import asyncio
from claude_agent_sdk import (
query,
CLINotFoundError,
ProcessError,
ResultError,
CLIJSONDecodeError,
)
async def main():
try:
async for message in query(prompt="Hello"):
print(message)
except CLINotFoundError:
print(
"Claude Code CLI not found. Try reinstalling: pip install --force-reinstall claude-agent-sdk"
)
# Catch ResultError before ProcessError, which it subclasses. Its message
# carries the error text. A failed final request, such as an API error,
# arrives with subtype "success", so branch on terminal_reason first.
except ResultError as e:
if e.terminal_reason == "api_error":
print(f"API request failed: {e}")
else:
print(f"Query ended with an error result ({e.terminal_reason or e.subtype}): {e}")
except ProcessError as e:
print(f"Process failed with exit code: {e.exit_code}")
except CLIJSONDecodeError as e:
print(f"Failed to parse response: {e}")
asyncio.run(main())
ResultError を ProcessError より先に書いているのは、第97回のとおり、子のクラスを先に捕まえないと親の節で受け取られてしまうからです。
その他のメッセージの注意
| 型 | 注意 |
|---|---|
SystemMessage | 専用の dataclass を持たない subtype はすべてこれで届く(subtype と data)。ターン間のセッションの状態を追うには CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS=1 を設定し、session_state_changed の message.data["state"] を読む。receive_response() は ResultMessage で止まり、状態のメッセージは結果の後に来ることがあるので receive_messages() で読む |
StreamEvent | parent_tool_use_id は常に None(第101回) |
ResultMessage の origin | ストリーミング入力で、自分のプロンプトへの結果(None か {"kind": "human"})と、バックグラウンドタスクの通知などで差し込まれたターンの結果を見分ける |
ResultMessage の usage | メインループだけ。トークンと費用の集計は model_usage を使う(第92回) |
HookEvent は Python では10種類(PreToolUse・PostToolUse・PostToolUseFailure・UserPromptSubmit・Stop・SubagentStop・PreCompact・Notification・SubagentStart・PermissionRequest)で、第82回・第104回で見た TypeScript の33種類より少ないことが、型の定義でも確かめられます。
3-6. サンドボックス:既定値が TypeScript と逆
このページで最も注意すべき違いがここです。原文の注記をそのまま要約します。
- サンドボックスはプラットフォームの対応に依存し、Linux では
bubblewrapやsocatなどが要る。 - Python では既定で、
enabledがTrueでもサンドボックスが起動できない場合、コマンドはサンドボックスなしで実行され、stderr に警告が出るだけ。 - これは TypeScript SDK と違う。TypeScript では
failIfUnavailableが既定でtrue(第104回)。 - 止めたいなら、サンドボックスの設定に
"failIfUnavailable": Trueを入れる。SDK は宣言されたフィールドと一緒にfailIfUnavailableを Claude Code に渡し、起動できなければerror_during_executionの結果を出す(1回きりのquery()ならその後に例外)。
原文の使用例は、この failIfUnavailable を明示しています。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
sandbox_settings = {
"enabled": True,
"autoAllowBashIfSandboxed": True,
"failIfUnavailable": True,
"network": {"allowLocalBinding": True},
}
async def main():
try:
async for message in query(
prompt="Build and test my project",
options=ClaudeAgentOptions(sandbox=sandbox_settings),
):
print(message)
except Exception as error:
# A single-shot query() raises after yielding an error result,
# such as when failIfUnavailable is set and the sandbox can't start.
print(f"Session ended with an error: {error}")
asyncio.run(main())
SandboxSettings は TypedDict で、宣言されているのは enabled・autoAllowBashIfSandboxed・excludedCommands・allowUnsandboxedCommands・network・ignoreViolations・enableWeakerNestedSandbox です。failIfUnavailable と filesystem は宣言には入っていませんが、SDK が Claude Code に渡す、と原文は書いています。サンドボックスのコマンドに特定のファイルを書かせないなら、filesystem の denyWrite に絶対パス(例:"/home/user/project/.env")を書きます。
autoAllowBashIfSandboxed と allowUnsandboxedCommands の既定が True なのは TypeScript と同じです。サンドボックスの外での実行を求める要求(dangerouslyDisableSandbox)は権限システムに回るので、can_use_tool で判断します。
import asyncio
from claude_agent_sdk import (
query,
ClaudeAgentOptions,
HookMatcher,
PermissionResultAllow,
PermissionResultDeny,
ToolPermissionContext,
)
def is_command_authorized(command: str | None) -> bool:
# Replace with your own authorization logic
return False
async def can_use_tool(
tool: str, input: dict, context: ToolPermissionContext
) -> PermissionResultAllow | PermissionResultDeny:
# Check if the model is requesting to bypass the sandbox
if tool == "Bash" and input.get("dangerouslyDisableSandbox"):
# The model is requesting to run this command outside the sandbox
print(f"Unsandboxed command requested: {input.get('command')}")
if is_command_authorized(input.get("command")):
return PermissionResultAllow()
return PermissionResultDeny(
message="Command not authorized for unsandboxed execution"
)
return PermissionResultAllow()
# Required: dummy hook keeps the stream open for can_use_tool
async def dummy_hook(input_data, tool_use_id, context):
return {"continue_": True}
async def prompt_stream():
yield {
"type": "user",
"message": {"role": "user", "content": "Deploy my application"},
}
async def main():
async for message in query(
prompt=prompt_stream(),
options=ClaudeAgentOptions(
sandbox={
"enabled": True,
"allowUnsandboxedCommands": True, # Model can request unsandboxed execution
},
permission_mode="default",
can_use_tool=can_use_tool,
hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
),
):
print(message)
asyncio.run(main())
この例には、第81回で見た Python の「必須の回避策」がそのまま入っています。can_use_tool を使うために、{"continue_": True} を返すだけのダミーの PreToolUse フック(コメントは「can_use_tool のためにストリームを開いたままにする」)と、プロンプトをジェネレーター(prompt_stream())で渡す形です。認可の判定 is_command_authorized は、例では常に False を返すので、サンドボックスの外での実行はすべて拒否されます。原文の警告は第104回と同じで、bypassPermissions と allowUnsandboxedCommands が両方有効だと、モデルは確認なしにサンドボックスの外へ静かに抜け出せます。
筆者の指摘:Python では、守りを効かせるために明示すべき値が TypeScript より1つ多いことになります。
| 確認する値 | Python の既定 | TypeScript の既定 | 守りとして使うなら |
|---|---|---|---|
failIfUnavailable | 実質 False(起動できなければサンドボックスなしで実行) | true | True を明示 |
allowUnsandboxedCommands | True | true | False を明示 |
autoAllowBashIfSandboxed | True | true | サンドボックスが確実に動く前提でのみ任せる |
表は筆者の整理です。特に1行目は、サンドボックスが入っていない環境(コンテナの中に bubblewrap が無い、など)で、警告だけを出してサンドボックスなしで Bash を動かし、しかも autoAllowBashIfSandboxed の既定で自動承認する、という組み合わせになりえます。第97回で「stderr コールバックを最初から付ける」としたのは、こうした警告を拾うためでもあります。TypeScript から Python に移植するときは、必ずこの表を確かめるべきです。
3-7. 圧縮したその他の節
| 節 | 何が載っているか | いつ引くか |
|---|---|---|
| セッション操作の関数 | list_sessions()・get_session_messages()・get_session_info()・rename_session()・tag_session()・fork_session() | 第87回の操作を Python で書くとき |
AgentDefinition・McpServerConfig・SdkPluginConfig | サブエージェント・MCP サーバー・プラグインの設定の型(SdkPluginConfig は type と path だけで、TypeScript の skipMcpDiscovery は無い) | 第89回・第84回・第99回 |
ThinkingConfig・EffortLevel・TaskBudget | 思考と effort の設定、タスク予算 | モデルの振る舞いを調整するとき |
| コンテンツブロック型 | TextBlock・ThinkingBlock・ToolUseBlock・ToolResultBlock | AssistantMessage・UserMessage の中身を読むとき(第102回) |
| Hook 型 | HookCallback・HookContext・HookMatcher・各入力型・HookJSONOutput | 第82回 |
| ツール入出力型 | 組み込みツールごとの入力と出力(Agent・Bash・Read・TaskCreate など) | tool_use の入力や結果を読むとき |
| 継続的な会話の例 | ClaudeSDKClient を1つ接続したまま、new で切断・再接続して新しいセッション、exit で終了する対話プログラム | チャット型のアプリの雛形 |
表は筆者の整理です。継続的な会話の例は、disconnect() してから connect() し直すと前の文脈が消えて新しいセッションになる、という使い方を示しています。
4. まとめ
- Python SDK の入口は
query()(1回きり、割り込み不可)とClaudeSDKClient(会話を続ける、割り込み可)。ClaudeSDKClientは TypeScript のquery()の内部の Python 版で、制御メソッドはここにある。startup()・prewarm()・resolveSettings()・applyFlagSettings()に当たるものはこのページに無い。 - インストールは仮想環境で(システムの Python は
externally-managed-environmentで失敗)。 interrupt()はバッファを空にしない。割り込みの後はreceive_response()で読み切ってから次を送る。breakで途中で抜けない。- ツールの入力スキーマに TypedDict(
NotRequired・Annotated) が使え、省略可能な引数を表せる。maxResultSizeCharsで結果のインライン上限を調整。 - dataclass は属性、TypedDict は辞書のキーで読む。
ClaudeAgentOptions:user、mcp_serversにファイルパス、skillsだけ設定するとsetting_sourcesはユーザーとプロジェクトのみ、debug_stderrは無視される、envは重ねる。subtype="success"でもis_error=Trueなら失敗。ResultErrorはterminal_reasonを先に見る。例外はResultErrorをProcessErrorより先に捕まえる。HookEventは Python では10種類。- サンドボックスは起動できないと既定でサンドボックスなしで動く(TypeScript と逆)。守りにするなら
failIfUnavailableをTrue、allowUnsandboxedCommandsをFalseと明示する。
次回予告
次回は 「Agent SDK の例」(agent-sdk/examples) を取り上げる予定です。
第76回から続けてきた Agent SDK の回は、機能ごとのガイドと、今回までの2つのリファレンスでほぼ一巡しました。次回は、これらの機能を組み合わせて実際に動くエージェントを作った例を通じて、ここまでの部品が1つのアプリの中でどう組み合わさるのかを見ていきます。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)

コメント