【Claude Code 連載 第104回】TypeScript SDK リファレンスの歩き方(agent-sdk/typescript)

スポンサーリンク
【Claude Code 連載 第104回】TypeScript SDK リファレンスの歩き方(agent-sdk/typescript) 用語解説
【Claude Code 連載 第104回】TypeScript SDK リファレンスの歩き方(agent-sdk/typescript)
この記事は約43分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

スポンサーリンク

背景

この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。

公式ドキュメント:https://code.claude.com/docs/ja/agent-sdk/typescript

1. 一言でいうと

TypeScript 版 Agent SDK のすべての関数・型・インターフェースを並べた、公式の完全リファレンスです。query() などの関数、query() に渡す Options、query() が返す Query オブジェクトのメソッド、ストリームに流れてくる30を超えるメッセージの型、30種類を超えるフックの入力の型、組み込みツールの入出力の型、権限とサンドボックスの型までが1ページに入っています。これまでの Agent SDK の回で「詳しくは TypeScript リファレンス」と先送りしてきたものの、行き先がここです。

このページは、元のドキュメントで6,000行を超え、コードブロックが239本ある、連載で最大のページです。全部を日本語に置き換えると、元のページを読むのと変わらない長さになります。そこでこの記事は、リファレンスの「地図」と、これまでの回では出てこなかった情報に絞ります。個々の型の細かい定義は、必要になったときに原文で引けるよう、どこに何があるかを示します。


2. どういう場面で役立つか

シーン1:オプションやメソッドの正確な名前と既定値を確かめる

「maxBudgetUsd は何を数えるのか」「setModel() に undefined を渡すとどうなるか」のように、これまでの回で見た機能の正確な仕様を確かめる場面です。Options の表と Query のメソッドの表がその役目を果たします。

シーン2:メッセージの種類ごとに分岐を書く

ストリームから届く SDKMessage は、30を超える型の合併(ユニオン)です。アプリでメッセージを処理する分岐を書くとき、どんな型がありうるのか、それぞれにどんなフィールドがあるのかを確かめます。

シーン3:これまでの回に出てこなかった機能を探す

このページには、resolveSettings()、prewarm()、projectConfigRoot、toolAliases のように、ガイドのページでは扱われていない関数やオプションが載っています。何ができるかを一通り知っておく価値があります。

不要・向かないケース

  • SDK を初めて使う:リファレンスは辞書なので、最初に読むものではありません。第78回のクイックスタートと、機能ごとのガイド(第77〜103回)から入るのが近道です。
  • Python を使っている:別に Python リファレンスがあります。このページの型や関数には TypeScript にしかないもの(applyFlagSettings() など)が含まれます。
  • 全部を暗記する:意味がありません。エディタの補完と型チェックで足りる部分も多く、このページは「迷ったときに引く」ためのものです。

3. コードと仕組みの解説

原文の fenced コードブロックは239本です。大半は型定義そのものなので、この記事では10本だけを引用し、残りは表と散文に圧縮します。引用するのは、(1) 中心の入口である query() と Query と SDKMessage の定義、(2) これまでの回とつながる使い方の例(単一実行ファイル、prewarm()、タイムアウトの環境変数)、(3) このページで初めて出てくる機能の例(resolveSettings())、(4) 安全上の注意が付いた例(権限モードの型、サンドボックス)です。コードは原文から機械的に抜き出したもので、変えていません。圧縮した型定義の名前は原文の見出しにそのまま対応しているので、原文で引けます。

3-0. この記事に出てくる主なバージョン要件

このページには非常に多くのバージョン要件があります。この記事で触れるものだけを挙げます。

機能バージョン
extractFromBunfs()(単一実行ファイル用)@anthropic-ai/claude-agent-sdk v0.3.144 以降
/core エントリ、prewarm()TypeScript Agent SDK v0.3.282 以降(/core の型は TypeScript 5.0 以降)
Yarn 1.x などで両方の libc の版が入っても正しい方を起動Agent SDK v0.2.141 以降
CanUseTool の requestId と null を返す動作Claude Code v2.1.199 以降
CanUseTool の defaultToNo・suppressAlwaysAllowRuleAgent SDK v0.3.268 以降
SDKSystemMessage の capabilitiesClaude Code v2.1.205 以降
projectConfigRootClaude Code v2.1.275 以降
startup_failure_reasonAgent SDK v0.3.274 以降
plugin_errors の型の宣言Agent SDK v0.3.283 以降

原文は冒頭で、SDK のバージョンは同梱の Claude Code のバージョンを追うと書いています。例として SDK v0.3.191 は Claude Code v2.1.191 を同梱しているので、「Claude Code v2.1.X 以降が必要」と書かれた機能には、同じパッチ番号以降の SDK が要ります。第94回の「SDK を更新することが CLI を更新する方法」の、具体的な対応の規則です。

3-1. ページの地図

原文の構成を、これまでの回との対応とあわせて示します。

節中身主に関係する回
インストール同梱バイナリ、単一実行ファイル、/core エントリ第78回・第97回
関数query()・startup()・prewarm()・tool()・createSdkMcpServer()・セッション操作7種・resolveSettings()第83回・第87回・第94回
型Options、Query、WarmQuery、SpareProcess、制御レスポンス群、AgentDefinition、SettingSource、PermissionMode、CanUseTool、McpServerConfig、SdkPluginConfig など第79〜100回
メッセージタイプSDKMessage とその構成要素(結果、初期化、部分メッセージ、圧縮境界など)第77回・第92回・第101回
フック型HookEvent(33種)と各イベントの入力型、HookJSONOutput第82回
ツール入力型/ツール出力タイプ組み込みツールごとの入力と出力の型(@anthropic-ai/claude-agent-sdk/sdk-tools から export)第62回・第102回
パーミッション型PermissionUpdate・PermissionBehavior・PermissionUpdateDestination・PermissionRuleValue第80回・第81回
その他のタイプModelUsage・McpServerStatus・RewindFilesResult・タスクやフックの進捗メッセージなど各回
サンドボックス設定SandboxSettings・ネットワーク・ファイルシステム・サンドボックス外コマンドの扱い第95回

「主に関係する回」の列は筆者が足したものです。

3-2. インストールと配布

インストールは1行です。SDK は、プラットフォーム用のネイティブの Claude Code バイナリを、@anthropic-ai/claude-agent-sdk-darwin-arm64 のような**任意依存(optional dependencies)**として同梱しています。パッケージマネージャーが任意依存を飛ばすと、Native CLI binary for <platform>-<arch> not found が出ます(第97回で見たとおり)。その場合は、別にインストールした claude を pathToClaudeCodeExecutable で指します。

このページで新しく出てくる配布上の注意が3つあります。

(a) Linux の libc の版が二重に入る:npm の libc フィールドを適用しないパッケージマネージャー(Yarn 1.x など)では、Linux で glibc 用と musl 用の両方のパッケージが入り、インストールサイズがおよそ2倍になります。v0.2.141 以降の SDK は正しい方を起動するので、動作には問題ありません。コンテナイメージを小さくしたいなら、合わない方(たとえば glibc の x64 なら rm -rf node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl)を消せます。

(b) 単一の実行ファイルにコンパイルする:bun build --compile でアプリを1ファイルにまとめると、SDK は実行時に同梱のバイナリを見つけられません(require.resolve がコンパイル後の $bunfs という仮想ファイルシステムの中では動かないため)。第97回で「別の原因」として TypeScript リファレンスに回されていたのがこれです。回避策は、バイナリをファイルとして埋め込み、起動時に extractFromBunfs() で実際のパスに取り出して pathToClaudeCodeExecutable に渡すことです。

import binPath from "@anthropic-ai/claude-agent-sdk-darwin-arm64/claude" with { type: "file" };
import { extractFromBunfs } from "@anthropic-ai/claude-agent-sdk/extract";
import { query } from "@anthropic-ai/claude-agent-sdk";

const cliPath = extractFromBunfs(binPath);

for await (const message of query({
  prompt: "Hello",
  options: { pathToClaudeCodeExecutable: cliPath },
})) {
  console.log(message);
}

extractFromBunfs() は、埋め込まれたバイナリをユーザーごとの一時ディレクトリにコピーして実際のパスを返します。コンパイルしていない環境では入力のパスをそのまま返すので、同じコードが開発環境でも動きます。1つの実行ファイルに埋め込めるのは1プラットフォーム分のバイナリで、import するプラットフォームのパッケージを --target と合わせます。クロスコンパイルなら合わないプラットフォームのパッケージを npm install @anthropic-ai/claude-agent-sdk-linux-x64 --force のように入れ、Windows ではバイナリのサブパスが claude.exe になります。

(c) 自分でバンドルするなら /core から import する:アプリが SDK を他の依存と一緒にバンドルするなら、パッケージのルートではなく @anthropic-ai/claude-agent-sdk/core から import します。ルートのエントリは zod と @modelcontextprotocol/sdk の自前のコピーを中に持っていますが、/core は node_modules のものを使うので、バンドルに二重のコピーが入りません。/core には prewarm()、InMemorySessionStore、セッションの一覧・読み取り・fork などのヘルパーが含まれないので、それらが要るならルートを使います。同じプロセスでルートと /core の両方から import してはいけません。別のバンドルなので、SDK のクラスと状態が2組できてしまいます。

3-3. 関数

中心の関数 query() の定義です。

function query({
  prompt,
  options
}: {
  prompt: string | AsyncIterable<SDKUserMessage>;
  options?: Options;
}): Query;

prompt は文字列(1回きり)か、SDKUserMessage の非同期反復可能オブジェクト(ストリーミング入力、第91回)です。戻り値の Query は、SDKMessage を流す非同期ジェネレーターに、追加のメソッドを足したものです(3-5)。

その他の関数を表にまとめます。

関数役割主な注意
startup()CLI のサブプロセスを事前に起動し、初期化まで済ませた WarmQuery を返す。最初の query() が起動の待ち時間を払わずに済むinitializeTimeoutMs の既定は 60000。WarmQuery の query() は1回だけ呼べる
prewarm()アルファ版。どのセッションに使うか決まる前に、予備のプロセス(SpareProcess)を起動しておき、後で claim() でセッションに結びつけるv0.3.282 以降。待機中に約230〜260MB のメモリを使う
tool()SDK MCP サーバー用の型安全なツール定義を作る(第83回)extras に annotations・searchHint・alwaysLoad。Zod 3 と 4 の両方に対応
createSdkMcpServer()アプリと同じプロセスで動く MCP サーバーを作る(第83回)instructions、alwaysLoad、timeout(1000以上の整数、v0.3.248 以降)
listSessions()・getSessionMessages()・getSessionInfo()・renameSession()・tagSession()・forkSession()セッションの一覧・読み取り・名前付け・タグ・fork(第87回)forkSession() は元のファイルチェックポイントを含まない
resolveSettings()アルファ版。CLI を起動せずに、指定ディレクトリで有効になる設定を、CLI と同じ合成の仕組みで求める実際のセッションとずれる点が3つある(後述)

prewarm():作業ディレクトリが決まる前に温めておく

第94回で「セッションの作業ディレクトリが最初のリクエストまで分からないなら prewarm()」とだけ触れた関数です。

import { prewarm } from "@anthropic-ai/claude-agent-sdk";

// アプリケーション起動時、セッションのフォルダがわかる前
const spare = await prewarm({ options: { maxTurns: 3 } });

// 後で、ユーザーがフォルダでセッションを開始したら
const claimedQuery = spare.claim({
  prompt: "What files are here?",
  options: { cwd: "/path/to/project" },
});

spare.claimed.catch((error: Error) => {
  // メッセージが「option_not_applied」で始まらない限り、プロンプトは実行されませんでした。
  // 代わりにこのセッションを query() で開始してください
  console.error("Claim failed:", error.message);
});

try {
  for await (const message of claimedQuery) {
    console.log(message);
  }
} catch (error) {
  // クレームが拒否された場合、クレームされたクエリはエラー結果を生成した後にスローします
  console.error(`Session ended with an error: ${error}`);
}

prewarm() で起動したプロセスは、options.cwd を設定していればそこで、なければ設定ディレクトリの下の一時ディレクトリで待機します。セッションの作業ディレクトリ、その SessionStart フック、stdio の MCP サーバー、CLAUDE.md、git の情報は、claim されるまで決まりません。

claim で設定できないもの(mcpServers、hooks、canUseTool、settingSources、systemPrompt、plugins など)は予備プロセスの一生のあいだ固定です。原文は、これらの組み合わせごとに予備を1つ持ち、変えたら温め直すよう書いています。また、resume・continue・forkSession を指定すると prewarm() は例外を出します(予備にはまだセッションが無いため)。

claim の失敗の扱いには注意があります。例のコメントにあるとおり、claimed が option_not_applied で始まるメッセージで失敗した場合は、セッションは要求した model か maxThinkingTokens なしで動いています。それ以外の失敗ではプロンプトは実行されていないので、query() で始め直します。原文によれば、存在しないフォルダや、プロジェクト設定で env・agent・model を設定しているフォルダでは、claim が拒否されることがあります。

resolveSettings():実際に動かす前に設定を確かめる

このページで初めて出てくる関数です。query() がどんな設定で動くかを、呼ぶ前に調べられます。

import { resolveSettings } from "@anthropic-ai/claude-agent-sdk";

const { effective, provenance } = await resolveSettings({
  cwd: "/path/to/project",
  settingSources: ["user", "project", "local"],
});

console.log(`Cleanup period: ${effective.cleanupPeriodDays} days`);
console.log(`Set by: ${provenance.cleanupPeriodDays?.source}`);

戻り値は、合成後の設定(effective)、各キーがどのソースから来たか(provenance)、ソースごとの生の設定(sources、優先順位の低い順)です。設定ファイルで cleanupPeriodDays を設定していないマシンでは、両方の行に undefined が出ますが、原文によればそれは想定どおりです。

ただし、実際のセッションとずれる点が3つあります。

項目ずれ方
policyHelperMDM のソース(macOS の plist、Windows のレジストリ)は読むが、管理者が設定した policyHelper のサブプロセスは実行しない
サーバー管理設定取得しない。含めたいなら options.serverManagedSettings として渡す
defaultModepermissions.defaultMode を全階層からそのまま返すので、実際のセッションが無視するプロジェクト・ローカル設定の 'auto' や 'bypassPermissions' も含みうる

3行目から、プロジェクトやローカルの設定ファイルに bypassPermissions を書いても、実際のセッションはそれを開始モードとして採用しないことが読み取れます(筆者の解釈)。リポジトリに置かれた設定でいきなり権限確認を外されない、という安全策です。resolveSettings() の結果だけを見てそれが効くと思い込まないよう注意が要ります。第100回の「settingSources が制御しないもの」を調べる道具としても使えますが、上の3つのずれがある点は割り引いて読む必要があります(筆者の指摘)。

3-4. Options

query() の設定オブジェクト Options は、原文では60を超える行の表です。これまでの回で扱ったものは各回に譲り、このページで初めて出てくるもの、または新しい注意が付いているものを拾います。

初めて出てくるオプション

オプション役割
agentProgressSummariesサブエージェントの1行の進捗要約を作り、task_progress イベントの summary で送る
forwardSubagentTextサブエージェントのテキストと思考を、parent_tool_use_id 付きの完全なメッセージとして転送する(無いとフォアグラウンドのサブエージェントのテキストは省かれる)
includeHookEventsフックの開始・進行・応答をメッセージとして流す
onElicitationMCP サーバーがユーザー入力を求めたときのコールバック。無ければ処理されなかった要求は自動で拒否
planModeInstructionsplan モードの既定のワークフロー本文を置き換える(読み取り専用を強制する前文と ExitPlanMode の決まりは残る)
projectConfigRootcwd がその worktree である信頼済みのチェックアウトの絶対パス。プロジェクト設定・.mcp.json・.claude/ の各種定義をここから読む。CLAUDE.md と .claude/rules/ は引き続き cwd から(v2.1.275 以降)
promptSuggestionsターンの後に、次のユーザープロンプトの予測を prompt_suggestion メッセージで出す
resumeSessionAt・resumeDropsTurn特定のメッセージ UUID の時点で再開する。切り詰めて再開するときに捨てるターンを指定する
sessionId・titleセッションの UUID と表示タイトルを自分で決める
spawnClaudeCodeProcessClaude Code のプロセスを起動する関数を差し替える(VM・コンテナ・リモートで動かすとき)
taskBudgetアルファ版。API 側のトークン単位のタスク予算。モデルに残りを伝え、上限前に作業をまとめさせる
toolAliases組み込みツール名を MCP ツール名に対応づける。例:{ Bash: 'mcp__workspace__bash' }
verbatimPromptsすべてのプロンプトを書かれたとおりに渡す(エンドユーザーが入力していない内容を含むとき)

表は筆者の整理です。projectConfigRoot は、第100回で見た「モノレポで cwd を下位に置くとルートの settings.json が読まれない」問題に対する、公式の答えの1つと読めます(筆者の解釈)。worktree で作業させつつ、設定は元のチェックアウトから読ませる、という使い方です。toolAliases は、たとえば Bash をサンドボックスの中で動く自前の MCP ツールに差し替える、といった使い方ができます。

既知のオプションに付いた新しい注意

オプションこのページでの注意
allowedTools自動承認の対象からネットワークパスからの読み取りは除かれる。タスク追跡ツールを名指しすると、その機能も有効になる(第102回)
canUseToolallowedTools・許可ルール・permissionMode で自動承認された呼び出しでは呼ばれない(第80回)。許可ルールは「どのモードでも自動承認されない操作」を事前承認しない
disallowedTools"Bash" のような名前だけならツールをコンテキストから消す。"Bash(rm *)" のようなスコープ付きはツールを残し、bypassPermissions を含むすべてのモードで一致する呼び出しを拒否する
env設定すると環境を置き換える。User-Agent でアプリを識別するには CLAUDE_AGENT_SDK_CLIENT_APP
permissionMode省略すると auto モードで始まる可能性がある
strictMcpConfigmcpServers のサーバーだけを使い、.mcp.json・ユーザー設定・プラグイン・claude.ai コネクタを無視する(第100回)
systemPrompt{ type: 'custom' } 形式と snapshot は v0.3.257 以降(第86回)

permissionMode の注意は重要です。第75回では「claude -p は全プランで Manual で始まる」と見ましたが、SDK で permissionMode を省略した場合は auto(モデルの分類器がシェルコマンドやネットワーク要求を審査するモード)で始まる可能性がある、と原文は書いています。どのモードで始まるかを当てにせず、permissionMode は明示するのが確実です(筆者の指摘)。

遅い・止まった API 応答の扱い

CLI のサブプロセスは、API のタイムアウトと停止の検知を、環境変数で調整できます。

import { query } from "@anthropic-ai/claude-agent-sdk";

const result = query({
  prompt: "Analyze this code",
  options: {
    env: {
      ...process.env,
      API_TIMEOUT_MS: "120000",
      CLAUDE_CODE_MAX_RETRIES: "2",
      CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS: "120000",
    },
  },
});
環境変数既定意味
API_TIMEOUT_MS600000リクエストごとのタイムアウト(ミリ秒)。メインループとすべてのサブエージェントに適用
CLAUDE_CODE_MAX_RETRIES10(上限 15)API の最大再試行回数。再試行ごとに API_TIMEOUT_MS の時間枠がある
CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MSストリームの監視がオンなら CLAUDE_STREAM_IDLE_TIMEOUT_MS +5分(通常 600000)サブエージェントの停止の監視。ストリームのイベントごとにリセット。止まるとサブエージェントを中止して親に報告
CLAUDE_ENABLE_STREAM_WATCHDOG・CLAUDE_STREAM_IDLE_TIMEOUT_MS監視は既定でオン、300000(これが最小値)ヘッダーは届いたが本文のストリーミングが止まったリクエストを中止する

表は原文の箇条書きを筆者が整理したものです。無人の実行で長い障害のあいだも待ち続けたいなら CLAUDE_CODE_RETRY_WATCHDOG=1 を設定します。第94回の既知の制限の表に出てきた CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS の既定値が、ここで初めて具体的に示されています。

また、ANTHROPIC_BASE_URL の背後のゲートウェイがキープアライブの ping で応答をつないでいるあいだ、includePartialMessages を設定したアプリは ping のストリームイベントを受け取り続けます。原文は、無音を理由にセッションをタイムアウトさせるのではなく、これを生存確認として扱うよう書いています。

3-5. Query オブジェクト

query() が返すオブジェクトのインターフェースです。これまでの回で見たメソッドが一か所に並んでいます。

interface Query extends AsyncGenerator<SDKMessage, void> {
  interrupt(): Promise<SDKControlInterruptResponse | undefined>;
  rewindFiles(
    userMessageId: string,
    options?: { dryRun?: boolean }
  ): Promise<RewindFilesResult>;
  setPermissionMode(mode: PermissionMode): Promise<void>;
  setModel(model?: string): Promise<void>;
  setMaxThinkingTokens(maxThinkingTokens: number | null): Promise<void>;
  applyFlagSettings(settings: {
    [K in keyof Settings]?: K extends 'effortLevel'
      ? 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null
      : Settings[K] | null;
  }): Promise<void>;
  updateSettings(
    source: 'localSettings' | 'userSettings',
    settings: Record<string, unknown>,
  ): Promise<void>;
  initializationResult(): Promise<SDKControlInitializeResponse>;
  reinitialize(): Promise<SDKControlInitializeResponse>;
  supportedCommands(): Promise<SlashCommand[]>;
  supportedModels(): Promise<ModelInfo[]>;
  supportedAgents(): Promise<AgentInfo[]>;
  mcpServerStatus(): Promise<McpServerStatus[]>;
  getContextUsage(opts?: {
    detail?: 'summary' | 'full';
  }): Promise<SDKControlGetContextUsageResponse>;
  readFile(
    path: string,
    options?: { maxBytes?: number; encoding?: 'utf-8' | 'base64' }
  ): Promise<SDKControlReadFileResponse | null>;
  reloadPlugins(options?: {
    holdOnCacheImpact?: boolean;
  }): Promise<SDKControlReloadPluginsResponse>;
  reloadSkills(): Promise<SDKControlReloadSkillsResponse>;
  reloadOutputStyles(): Promise<SDKControlReloadOutputStylesResponse>;
  accountInfo(): Promise<AccountInfo>;
  reconnectMcpServer(serverName: string): Promise<void>;
  toggleMcpServer(serverName: string, enabled: boolean): Promise<void>;
  setMcpServers(servers: Record<string, McpServerConfig>): Promise<McpSetServersResult>;
  readMcpResource(serverName: string, uri: string): Promise<SDKControlMcpReadResourceResponse>;
  streamInput(stream: AsyncIterable<SDKUserMessage>): Promise<void>;
  stopTask(taskId: string): Promise<void>;
  close(): void;
}

メソッドを用途で分けます。

用途メソッド
実行の制御interrupt()、stopTask(taskId)、close()、streamInput(stream)
実行中の設定変更setPermissionMode()、setModel()、setMaxThinkingTokens()(非推奨)、applyFlagSettings()、updateSettings()
情報の取得initializationResult()、reinitialize()、supportedCommands()、supportedModels()、supportedAgents()、mcpServerStatus()、getContextUsage()、accountInfo()
ファイルrewindFiles()(第88回)、readFile()
再読み込みreloadPlugins()、reloadSkills()、reloadOutputStyles()
MCPreconnectMcpServer()、toggleMcpServer()、setMcpServers()、readMcpResource()(アルファ版)

表は筆者の整理です。このページで初めて詳しく出てくる点を挙げます。

  • reinitialize():切断後にセッションに付け直すときなどに使うと、保留中の権限リクエストが再び canUseTool に届きます。応答が失われたリクエストはもう一度送られるので、コールバックはリクエスト ID ごとに冪等(何度呼ばれても同じ結果)にする必要があります(v2.1.195 以降)。
  • readFile():セッションのファイルシステムからファイルを読みます。読める範囲は Read ツールより狭く、セッションの作業ディレクトリ(cwd や additionalDirectories)の通常のファイルと、Claude Code 自身のセッション用ファイルの一部だけです。広い Read の許可ルールを設定しても、それ以外は開きません。Read の拒否・確認ルールにも従います。
  • getContextUsage():対話セッションの /context と同じデータを返します。メッセージのストリームには出ないトークン数計算の API リクエストで求めます(第70回の内訳の、プログラムからの入口)。
  • applyFlagSettings()(TypeScript 専用、第79回):反映のタイミングがキーで違います。effortLevel・ultracode・permissions・hooks・skillOverrides・fastMode・agent は次のターンから、model は現在のターンの途中から(v2.1.212 以降)、システムプロンプトのオプションはセッション中は効果なしです。連続して呼ぶとトップレベルのキーは浅く合成されるので、permissions を2回渡すと前のオブジェクトは丸ごと置き換わります。原文は、エージェントが信頼できない入力を読んだ後に permissions を厳しくする、という使い方を例に挙げています。

3-6. 権限・サンドボックスまわりの型

PermissionMode

type PermissionMode =
  | "default" // Standard permission behavior
  | "acceptEdits" // Auto-accept file edits
  | "bypassPermissions" // Bypass permission checks; explicit ask rules still prompt
  | "plan" // Planning mode - explore without editing
  | "dontAsk" // Don't prompt for permissions, deny if not pre-approved
  | "auto"; // A model classifier reviews actions such as shell commands and network requests

コメントにあるとおり、bypassPermissions でも明示的な ask ルールは確認を出し、auto はモデルの分類器がシェルコマンドやネットワーク要求などを審査するモードです(第80回)。

CanUseTool の新しい情報

canUseTool のコールバックが受け取る options には、第81回では出てこなかった項目があります。

項目意味
mcpServermcp__* ツールのとき、提供している MCP サーバーとその定義の出どころ(v0.3.274 以降)
defaultToNotrue なら、1回の誤ったキー入力で承認されてはならない。確認画面は拒否を選んだ状態で開き、1キーの承認ショートカットも出さない(v0.3.268 以降)
suppressAlwaysAllowRuletrue なら「常に許可」の選択肢を出さない(v0.3.268 以降)
requestId制御リクエストの ID。アプリが SDK の外から応答を送るとき(署名付きの HTTP POST など)は、この値をそのまま返す

そして重い注意が1つあります。コールバックが null を返してよいのは、アプリが requestId を付けた応答をすでに自分の経路で送った場合だけです。それ以外で null を返すと応答が一切送られず、権限の確認はタイムアウトしないので、ツール呼び出しが無期限に止まります(v2.1.199 以降の動作)。第81回で見た「canUseTool は返るまで無期限に実行を止める」と同じ性質が、ここではバグとして現れる形です(筆者の対応づけ)。

defaultToNo と suppressAlwaysAllowRule は、承認画面を自分で作るアプリへの指示です。Claude Code が「慎重に扱うべき」と判断した操作で、誤承認や恒久的な許可を作らせないための合図と読めます(筆者の解釈)。

サンドボックス設定

sandbox オプションで、コマンドのサンドボックスをプログラムから設定できます(第95回の「組み込みの守り」のサンドボックスモード)。

import { query } from "@anthropic-ai/claude-agent-sdk";

try {
  for await (const message of query({
    prompt: "Build and test my project",
    options: {
      sandbox: {
        enabled: true,
        autoAllowBashIfSandboxed: true,
        network: {
          allowLocalBinding: true
        }
      }
    }
  })) {
    if ("result" in message) console.log(message.result);
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result,
  // such as when the sandbox can't start (failIfUnavailable defaults to true).
  console.log(`Session ended with an error: ${error}`);
}

SandboxSettings の主なプロパティと既定値です。

プロパティ既定意味
enabledfalseコマンドのサンドボックスを有効にする
failIfUnavailabletrue有効なのに起動できなければ止まる。false なら警告を出してサンドボックス外で動く
autoAllowBashIfSandboxedtrueサンドボックスが有効なら Bash コマンドを自動承認する
excludedCommands[]サンドボックスを迂回するコマンド(例:['docker *'])。モデルの関与なしに外で動く
allowUnsandboxedCommandstrueモデルがサンドボックス外での実行を求めることを許す(dangerouslyDisableSandbox を設定でき、権限システムに回る)

サンドボックスは、Linux では bubblewrap や socat などが要るなど、プラットフォームの対応に依存します。有効にしたのに起動できなければ、query() は error_during_execution の結果を出し、1回きりの呼び出しならその後に例外を出します(上の例が try で包んでいる理由)。

ネットワークの設定(SandboxNetworkConfig)には、allowedDomains・deniedDomains(こちらが優先)・strictAllowlist・allowManagedDomainsOnly・allowLocalBinding・allowUnixSockets などがあります。ここには2つの警告が付いています。

  • Unix ソケット:/var/run/docker.sock を許可すると、Docker の API を通じてホスト全体に触れられることになり、サンドボックスの分離を事実上迂回されます。
  • ドメインの許可リスト:組み込みのプロキシは要求されたホスト名で照合するだけで TLS を検査しないので、ドメインフロンティングで迂回されうる(第95回で見たとおり)。また、これらのネットワーク設定はサンドボックス化された Bash コマンドにだけ効き、WebFetch ツールには効きません(WebFetch は権限ルールで制御する)。

ファイルシステムの設定(SandboxFilesystemConfig)は allowWrite・denyWrite・denyRead です。作業ディレクトリの中のファイルへの書き込みを止めたいなら、denyWrite に絶対パスで書きます。

サンドボックス外コマンドの扱い

allowUnsandboxedCommands が有効だと、モデルはツールの入力に dangerouslyDisableSandbox: true を入れて、サンドボックス外での実行を求められます。この要求は権限システムに回るので、canUseTool で独自に判断できます。

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Deploy my application",
  options: {
    sandbox: {
      enabled: true,
      allowUnsandboxedCommands: true // Model can request unsandboxed execution
    },
    permissionMode: "default",
    canUseTool: async (tool, input) => {
      // Check if the model is requesting to bypass the sandbox
      if (tool === "Bash" && input.dangerouslyDisableSandbox) {
        // The model is requesting to run this command outside the sandbox
        console.log(`Unsandboxed command requested: ${input.command}`);

        if (isCommandAuthorized(input.command)) {
          return { behavior: "allow" as const, updatedInput: input };
        }
        return {
          behavior: "deny" as const,
          message: "Command not authorized for unsandboxed execution"
        };
      }
      return { behavior: "allow" as const, updatedInput: input };
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}

コメントにあるとおり、isCommandAuthorized は自分で書く認可の判定の代わりです。原文の警告は2つです。

  • dangerouslyDisableSandbox: true で動くコマンドはシステムへの完全なアクセスを持つ。canUseTool で慎重に検証する。
  • permissionMode が bypassPermissions で、allowUnsandboxedCommands が有効だと、モデルは「どのモードでも自動承認されない操作」を除き、確認なしにサンドボックス外でコマンドを実行できる。この組み合わせでモデルは静かにサンドボックスから抜け出せる。

筆者の指摘:上の表のとおり、allowUnsandboxedCommands の既定は true です。つまり sandbox で enabled だけを true にして bypassPermissions で動かすと、原文が警告する「静かに抜け出せる」組み合わせに既定のまま入ります。サンドボックスを守りとして使うなら、allowUnsandboxedCommands を false と明示するか、bypassPermissions を使わないのが確実です。第95回で見た「多層防御」の1層として数えるなら、この既定値は必ず確認すべき項目です。

3-7. メッセージの型

query() のストリームに流れてくる SDKMessage は、次の型の合併です。

type SDKMessage =
  | SDKAssistantMessage
  | SDKUserMessage
  | SDKUserMessageReplay
  | SDKResultMessage
  | SDKSystemMessage
  | SDKPartialAssistantMessage
  | SDKCompactBoundaryMessage
  | SDKStatusMessage
  | SDKLocalCommandOutputMessage
  | SDKHookStartedMessage
  | SDKHookProgressMessage
  | SDKHookResponseMessage
  | SDKPluginInstallMessage
  | SDKToolProgressMessage
  | SDKAuthStatusMessage
  | SDKTaskNotificationMessage
  | SDKTaskStartedMessage
  | SDKTaskProgressMessage
  | SDKTaskUpdatedMessage
  | SDKBackgroundTasksChangedMessage
  | SDKThinkingTokensMessage
  | SDKSessionStateChangedMessage
  | SDKWorkerShuttingDownMessage
  | SDKCommandsChangedMessage
  | SDKNotificationMessage
  | SDKFilesPersistedEvent
  | SDKToolUseSummaryMessage
  | SDKMemoryRecallMessage
  | SDKRateLimitEvent
  | SDKElicitationCompleteMessage
  | SDKPermissionDeniedMessage
  | SDKPromptSuggestionMessage
  | SDKAPIRetryMessage
  | SDKMirrorErrorMessage
  | SDKInformationalMessage
  | SDKConversationResetMessage;

これまでの回で扱った型を中心に、主なものを整理します。

型中身関係する回
SDKAssistantMessage・SDKUserMessageアシスタントとユーザーのメッセージ第77回・第102回
SDKResultMessage最終結果。success と4種のエラーの subtype第77回・第92回・第98回
SDKSystemMessage初期化(init)メッセージ第84回・第90回・第99回
SDKPartialAssistantMessageストリーミングの部分メッセージ第101回
SDKCompactBoundaryMessage圧縮の境界第90回・第101回
SDKMirrorErrorMessageセッションストアへの写しの失敗第93回
SDKTaskNotificationMessage ほかタスク系バックグラウンドのタスク第102回
SDKConversationResetMessage/clear などによる会話のリセット第92回

表は筆者の整理です。以下、このページで初めて詳しく出てくる点です。

結果メッセージの診断フィールド

SDKResultMessage には、subtype 以上の情報を持つフィールドが多数あります。いくつかを挙げます。

フィールド意味
api_error_status会話を終わらせた API エラーの HTTP ステータス
ttft_ms・ttft_stream_ms最初のトークンまでの時間(完成したメッセージ基準とストリーム基準)
terminal_reasonループが終わった理由。completed・max_turns・tool_deferred・hook_stopped・budget_exhausted・structured_output_retry_exhausted など19種
deferred_tool_usePreToolUse フックが defer を返したとき、保留されたツールの id・name・input(第81回・第82回の defer の受け取り口)
result_index結果の通し番号。欠番があれば結果が失われたことを意味する
originこの結果を起こしたメッセージの出どころ。完了したバックグラウンドタスクへの自動の追加ターンなら kind: "task-notification"
startup_failure_reason既知の起動失敗の理由(19種)。再試行ではなく直し方を示せるようにするもの

startup_failure_reason の値には、組織の固定設定と API キーの衝突(org_pin_api_key_conflict)、許可されていないプロバイダー(provider_not_allowed)、作業ディレクトリが消えた(cwd_unavailable)、root で bypassPermissions を求めた(bypass_root) などがあります。ただし、すべての理由で結果メッセージが出るようにするには env で CLAUDE_CODE_STARTUP_FAILURE_RESULTS を 1 に設定する必要があり、無いと一部の失敗以外は stderr と非ゼロの終了だけで終わります。第97回の「stderr コールバックを最初から付けておく」とあわせて設定しておく価値があります(筆者の指摘)。

origin については、kind だけで結果を捨てないよう原文が注意しています。アプリが自分で宣言したスケジュール実行の結果も kind: "task-notification" になるからです。

初期化メッセージの capabilities

SDKSystemMessage(init)の capabilities 配列は、この CLI が実装しているプロトコルの動作を示します。claude_code_version の文字列を比べる代わりに、機能の有無で判定するためのものです(v2.1.205 以降)。第75回の「バージョン判定は文字列比較でなく capabilities 配列で」の、SDK 側の姿です。たとえば interrupt_receipt_v1 があれば、interrupt() は中断の時点で保留中だったメッセージを列挙した受領書で解決されます。原文は、知らない値は無視し、頼りたい動作に対応する値があるかだけを確かめるよう書いています。

同じメッセージの plugin_errors は、第99回で見た「プラグインが読み込まれない理由」の正体です。エントリは plugin・type(path-not-found・manifest-validation-error など)・message・path を持ち、plugins オプションで渡したディレクトリそのものの読み込みに失敗した場合は、plugin に名前の代わりに inline[0] のような位置のタグが入ります。

3-8. 圧縮したその他の節

残りの大きな節は、次のように使い分けます。

節何が載っているかいつ引くか
フック型HookEvent の33種と、各イベントの入力型(PreToolUseHookInput など)、出力型 HookJSONOutputフックのコールバックの引数と戻り値を型で書くとき(第82回)
ツール入力型・ツール出力タイプ組み込みツールごとの入力と出力。@anthropic-ai/claude-agent-sdk/sdk-tools から exporttool_use の入力や tool_use_result を型で読むとき(第102回の TaskCreateOutput など)
パーミッション型PermissionUpdate(addRules・replaceRules・removeRules・setMode・addDirectories・removeDirectories)、保存先(userSettings・projectSettings・localSettings・session・cliArg)canUseTool で「承認して記憶」を返すとき(第81回)
AgentDefinition・McpServerConfig・SdkPluginConfigサブエージェント・MCP サーバー・プラグインの設定の型第89回・第84回・第99回の設定を型で書くとき
進捗・状態のメッセージフックの開始/進行/応答、ツールの進捗、タスクの開始/進捗/更新、レート制限、思考トークンなどincludeHookEvents などを有効にして UI を作るとき

ツール入力型の節には1つ実務上の注意があります。Agent ツールの以前の名前 Task は今も別名として受け付けられ、初期化メッセージの tools 配列は後方互換のためこのツールを Task として載せています。第89回の「tool_use では Agent、init の一覧では Task」の理由がここで明示されています。

SdkPluginConfig には、第99回で出てこなかった skipMcpDiscovery があります。true にすると、プラグインのスキル・フック・エージェント・コマンドは読むが、.mcp.json やマニフェストの mcpServers は読みません。アプリが MCP の接続を自分で管理する場合のためのもので、第99回で筆者が指摘した「プラグインの読み込みが MCP サーバーの起動につながる」点を、プラグイン単位で切る手段になります(筆者の対応づけ)。


4. まとめ

  • このページは TypeScript SDK の全関数・全型の辞書。239本のコードの大半は型定義で、ガイドの回(第77〜103回)を読んだ後に「正確な名前と既定値」を引くために使う。
  • SDK のバージョンは同梱の Claude Code を追う(v0.3.191 ↔ v2.1.191)。「Claude Code v2.1.X 以降」の機能には同じパッチ番号以降の SDK が要る。
  • 配布:任意依存のバイナリ、Yarn 1.x の libc 二重取得、bun build --compile には extractFromBunfs()、自前バンドルには /core(ルートと混ぜない)。
  • 関数:startup()(事前起動)、prewarm()(アルファ、cwd 未定で温める、約230〜260MB)、resolveSettings()(アルファ、設定を事前に解決。policyHelper・サーバー管理設定・defaultMode でずれる)。
  • Options の新顔:projectConfigRoot、toolAliases、forwardSubagentText、onElicitation、taskBudget など。permissionMode を省略すると auto で始まる可能性があるので明示する。
  • Query:reinitialize() 後の canUseTool は冪等に。readFile() は Read ツールより狭い。applyFlagSettings() は次のターン/現ターン/効果なしの3区分。
  • CanUseTool:null を返すと無期限に止まる(自分で応答を送った場合以外は返さない)。defaultToNo・suppressAlwaysAllowRule は承認画面への指示。
  • サンドボックス:autoAllowBashIfSandboxed と allowUnsandboxedCommands は既定で true。bypassPermissions と組み合わせると静かに抜け出せるので、守りとして使うなら明示的に閉じる。Unix ソケットとドメインフロンティングに注意。
  • 結果メッセージ:terminal_reason、deferred_tool_use、result_index(欠番=消失)、startup_failure_reason(全部出すには CLAUDE_CODE_STARTUP_FAILURE_RESULTS を 1 に)。初期化メッセージの capabilities で機能を判定する。

次回予告

次回は 「Python SDK リファレンス」(agent-sdk/python) を取り上げる予定です。

今回、TypeScript SDK のリファレンスを地図として見ました。これまでの回では、ClaudeSDKClient や StreamEvent、TaskNotificationMessage、ストア対応の関数など、Python 側の詳細も「Python リファレンスを参照」として残してきました。次回は Python SDK の関数と型の全体像を、TypeScript との違いに注目しながら見ていきます。


よっしー
よっしー

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

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました