【Claude Code 連載 第79回】エージェントを設定する — options オブジェクトの全体像

スポンサーリンク
【Claude Code 連載 第79回】エージェントを設定する — options オブジェクトの全体像 用語解説
【Claude Code 連載 第79回】エージェントを設定する — options オブジェクトの全体像
この記事は約19分で読めます。
よっしー
よっしー

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

スポンサーリンク

背景

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

1. 一言でいうと何か

このページは、Agent SDK セッションの設定がどこから来て、どう書くかを整理した索引です。

第78回のクイックスタートが「動かす」回なら、今回は「調整する」回。原文の定義から入ります。

Agent SDK セッションは、設定ファイル、環境変数、およびセッション開始時に渡す options オブジェクトから設定を読み込みます。

つまり設定の入口は3つ——ファイル、環境変数、options。このページは主に3つ目の書き方と、どのオプションがどの機能ページに対応するかの対応表を提供します。

構造も明快です。すべての query() 呼び出しは options オブジェクトを受け入れます:TypeScript では Options、Python では ClaudeAgentOptions です。各フィールドはオプションであり、オプションなしで開始されたセッションは SDK のデフォルトで実行されます。

**全部省略できる。**必要なものだけ書けばよい設計です。

そして本ページで最も実用的なのは、末尾の19行の対応表です。「やりたいこと → どのオプション → どのページ」が一覧になっており、Agent SDK クラスタ全体の目次として機能します。

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

シーン1:最初の1本を実用レベルに調整する

モデル、使わせるツール、ターン上限、作業ディレクトリ——最小限の4つを指定する例が冒頭に置かれています。クイックスタートの次に読む位置づけです。

シーン2:セッション途中で方針を変える

ストリーミング入力でセッションを開始する場合、実行中にモデルと権限モードを切り替えることができます。「探索は安いモデル、実装は強いモデル」といった切り替えが可能です。

シーン3:ゲートウェイや独自環境に通す

env オプションは、セッションを実行する Claude Code プロセスの環境変数を設定します。ANTHROPIC_BASE_URL を差し替える例が示されています。

シーン4:目的からオプションを逆引きする

対応表がそのまま逆引き辞書になります。目標は知っているが、どのオプションがそれを提供するかわからない場合の入口も案内されています。

不要・向かないケース

  • **temperature や top_p を触りたい。**フィールドがありません(後述)。
  • **セッション途中で作業ディレクトリを変えたい。**どちらの SDK にも cwd のセッターはありません。別のディレクトリで実行するには、その cwd で別のセッションを開始します。
  • Python の query() から設定を変えたい。できません。query() は制御メソッドのないプレーンイテレータを返すため、ClaudeSDKClient が必要です。
  • **単発の query() でターン上限を超えても処理を続けたい。**SDK はキャップ結果を生成してから発生するため、ループを try ブロックでラップしてエラーを超えて続行します。
  • **予算上限に 0 を入れて「無制限」にしたい。**逆です。CLI はスタートアップで 0 を無効な金額として拒否し、セッションは実行されません。

3. 設定の書き方と落とし穴

fenced ブロックは8本(Python 4・TypeScript 4)。**4組の対訳なので、すべて原文どおり引用します。**19行の対応表も保持します。

前提:このページ自体にバージョン要件の記載はありません。個別オプションのバージョン要件は各リファレンスに委ねられています。

基本の4オプション

以下の例は、プロジェクトのオープン TODO を要約する読み取り専用セッションを設定します。

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

for await (const message of query({
  prompt: "Summarize the open TODOs in this repo",
  options: {
    model: "claude-sonnet-5",
    allowedTools: ["Read", "Glob", "Grep"],
    maxTurns: 8,
    cwd: "/path/to/repo",
  },
})) {
  if (message.type === "result" && message.subtype === "success" && !message.is_error) {
    console.log(message.result);
  }
}
import asyncio

from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, query

async def main():
    options = ClaudeAgentOptions(
        model="claude-sonnet-5",
        allowed_tools=["Read", "Glob", "Grep"],
        max_turns=8,
        cwd="/path/to/repo",
    )

    async for message in query(
        prompt="Summarize the open TODOs in this repo",
        options=options,
    ):
        if isinstance(message, ResultMessage) and not message.is_error:
            print(message.result)

asyncio.run(main())

allowedTools の意味が、ここで正確に定義されています。リストされたツールを事前承認するため、それらへの呼び出しは承認を待たずに実行されます。リストの外側のツールは利用可能なままです。Claude が未リストのツールを呼び出すと、権限モードが呼び出しを実行するかどうかを決定します。

**「許可リスト」ではなく「事前承認リスト」。**載せなかったツールが使えなくなるわけではありません。第77回の権限モードの話と合わせて読むべき箇所です。

設定ファイルの読み込み

オプションは2つ。

  • settingSources / setting_sources:どのファイルシステムソースを読み込むかを制御します:ユーザー、プロジェクト、ローカル。設定ファイルと CLAUDE.md ファイルはこれらのソースを通じて到着します。
  • settings:設定ファイルパスまたはいずれかの言語のインライン JSON 文字列を読み込み、TypeScript は設定オブジェクトも受け入れます。

優先順位が明示されています。渡すフォームに関係なく、ユーザー、プロジェクト、ローカルファイルシステム設定をオーバーライドします。管理ポリシー設定のみがより高いランクです。

settings は管理ポリシー以外の全てに勝つ。そしてユーザー、プロジェクト、ローカル設定を無効にするには [] を渡します。

第76回で「.claude/ と ~/.claude/ から自動的に読み込み、Claude Code と同じ」とありましたが、その読み込みを切る手段がこれです。第75回のベアモード(--bare)に相当する働きをします。

モデルを選ぶ

**model オプション、設定、または環境がモデルを選択しない限り、新しいセッションは Claude Code のデフォルトモデルで開始されます。**値はモデルエイリアスまたは完全なモデル名を取ります。

フォールバックの挙動が丁寧です。プライマリがオーバーロードされているか利用できない場合、セッションはバックアップに切り替わります。プライマリは各ユーザーターンの開始時に再試行されるため、停止が解決されるとセッションはそれに戻ります。

**落ちっぱなしにならず、ターンごとに本命へ戻ろうとする。**良い設計だと思います(この評価は筆者のものです)。

**どちらの言語でも、オプションは単一のモデルまたはコンマ区切りのバックアップリストを受け入れます。**そして TypeScript には安全装置があります。TypeScript では、model に等しいフォールバックはスタートアップでエラーをスローします。

const options = {
  model: "claude-fable-5",
  fallbackModel: "claude-opus-5,claude-sonnet-5",
};
options = ClaudeAgentOptions(
    model="claude-fable-5",
    fallback_model="claude-opus-5",
)

サンプリングパラメータは無いという注記が重要です。

Messages API リクエストパラメータ temperature、top_p、および max_tokens には、どちらの言語でも options オブジェクトにフィールドがありません。

代替として努力レベルまたは支出キャップを設定するか、これらのパラメータが直接必要な場合は Messages API を呼び出します。

**Agent SDK は「エージェントを動かす」層であり、生成パラメータを触る層ではない。**この線引きは、第76回の4択比較(Agent SDK / CLI / Client SDK / Managed Agents)とも整合します。

環境変数 — 言語で挙動が違う

このページで最も事故りやすい箇所です。

  • TypeScript:env はサブプロセス環境を置き換えます
  • Python:SDK は値を継承された環境にマージし、値は継承されたものをオーバーライドします

TypeScript で素朴に書くと**PATH も HOME も ANTHROPIC_API_KEY も消えます。**だから原文はこう指示しています。TypeScript では、process.env を env に展開して、PATH、HOME、ANTHROPIC_API_KEY などの継承された変数を保持します。

const options = {
  env: { ...process.env, ANTHROPIC_BASE_URL: "https://gateway.example.com" },
};
options = ClaudeAgentOptions(
    env={"ANTHROPIC_BASE_URL": "https://gateway.example.com"},
)

同じことをしているのに、TypeScript だけ ...process.env が付いている。この差が言語間の仕様差そのものです。なおenv を設定しないままにすると、サブプロセスは両方の言語で環境を継承します。

渡せる変数は API 接続先だけではありません。渡す変数は Claude Code 自体を設定することもできます。

作業ディレクトリ

cwd を設定しないままにすると、セッションはプロセスの作業ディレクトリで実行されます。

cwd が決めるものが3つ挙げられています。

  • プロジェクト設定とフック:どのプロジェクトの設定とフックが読み込まれるか
  • スキル:セッションスキルが発見される場所
  • セッションストレージ:保存されたセッションが属するプロジェクト

**cwd は単なる相対パスの基準ではない。**何が読み込まれ、どこに記録されるかまで決めます。

外に出たい場合は**additionalDirectories(TypeScript)または add_dirs(Python)でパスを追加します。**ただし付与されるのはファイルアクセスだけで、設定ではない点が参照先で強調されています。

ターンと予算 — 0 の扱いが逆

第77回で見た2つのキャップの、設定側からの記述です。両方のキャップは設定しないままにすると無効です。

入力モードによる差も再掲されています。シングルショット query() はキャップ結果の後にエラーが発生するので try で包む。ストリーミング入力はセッションはキャップ結果を超えて生きたままであり、max-turns カウントは各キューに入ったメッセージに対して開始されます。

そして**0 の意味が2つのキャップで逆**です。

オプション0 を渡すと
maxTurns / max_turnsセッションをターン制限なしで実行します。オプションを設定しないままにするのと同じです
maxBudgetUsd / max_budget_usdCLI はスタートアップで 0 を無効な金額として拒否し、セッションは実行されません

**片方は「無制限」、もう片方は「起動しない」。**設定値を変数で組み立てている場合、うっかり 0 が入ると挙動が全く違います。

セッション中に切り替える

ストリーミング入力が前提です。呼び出し口が言語で違います。

  • TypeScript:query() が返すオブジェクトのメソッド
  • Python:ClaudeSDKClient のメソッド。query() は制御メソッドのないプレーンイテレータを返すため

共通のセッターは2つ。setModel() / set_model() と setPermissionMode() / set_permission_mode()。

setModel() には隠れた使い方があります。モデルなしで呼び出して、渡した model ではなく Claude Code のデフォルトモデルに切り替えます。

TypeScript にはさらに2つあります。

applyFlagSettings():await session.applyFlagSettings({ effortLevel: "high" }) のように実行時に設定を適用します。注意点としてメソッドは options フィールドではなく設定ファイルキーを取ります。

updateSettings():**許可リストに登録されたキーを設定ファイルに書き込みます。**書き込み先で挙動が違います。

書き込み先受け付けるキー効き方
"localSettings"複数(例:outputStyle)書き込まれたキーはセッションの次のリクエストで有効になり、local 設定を読み込む後のセッションに対して永続化されます
"userSettings"effortLevel のみセッションの現在のモデルのデフォルト努力レベルとして保存し、実行中のセッションの努力は変わりません

**userSettings は「今」には効かない。**次回以降のためのデフォルト設定です。

以下が実例です。2ターンセッションを実行し、ターン間で設定を変更し、各ターンに答えたモデルを出力します。

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

function userMessage(text: string): SDKUserMessage {
  return { type: "user", message: { role: "user", content: text }, parent_tool_use_id: null };
}

// Hold the second prompt until the setters have run.
let startSecondTurn!: () => void;
const secondTurnReady = new Promise<void>((resolve) => {
  startSecondTurn = resolve;
});

async function* turnPrompts(): AsyncGenerator<SDKUserMessage, void> {
  yield userMessage("Reply with exactly: ready");
  await secondTurnReady;
  yield userMessage("Reply with exactly: done");
}

const session = query({
  prompt: turnPrompts(),
  options: {
    model: "claude-sonnet-5",
  },
});

let turnModel = "";
let completedTurns = 0;

for await (const message of session) {
  if (message.type === "assistant") {
    turnModel = message.message.model;
  } else if (message.type === "result") {
    completedTurns += 1;
    if (completedTurns === 1) {
      console.log(`First turn model: ${turnModel}`);
      await session.setModel("claude-opus-5");
      await session.setPermissionMode("acceptEdits");
      startSecondTurn();
    } else {
      console.log(`Second turn model: ${turnModel}`);
      break;
    }
  }
}
import asyncio

from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, ClaudeSDKClient

async def main():
    options = ClaudeAgentOptions(model="claude-sonnet-5")

    async with ClaudeSDKClient(options=options) as client:
        await client.query("Reply with exactly: ready")
        first_model = ""
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                first_model = message.model

        await client.set_model("claude-opus-5")
        await client.set_permission_mode("acceptEdits")

        await client.query("Reply with exactly: done")
        second_model = ""
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                second_model = message.model

    print(f"First turn model: {first_model}")
    print(f"Second turn model: {second_model}")

asyncio.run(main())

Claude API では、プログラムは First turn model: claude-sonnet-5 を出力してから、切り替え後に Second turn model: claude-opus-5 を出力します。

2つの実装の差が目立ちます。TypeScript 側はプロンプトストリームは2番目のメッセージをセッターが実行されるまで保持し、2番目のターンは新しいモデルで実行されます——つまり Promise で明示的に待たせる必要があります。Python 側は ClaudeSDKClient の async with と receive_response() で素直に順番が保証されます。同じことをするのに TypeScript のほうが手数が多い構図です。

コスト面の注意も添えられています。各モデルは独自のプロンプトキャッシュを持つため、セッション中の切り替え後、次のリクエストは新しいモデルのレートでキャッシュされていない完全な会話を再計算します。

**モデル切り替えはタダではない。**会話が長いほど、切り替えの代償は大きくなります。

機能とオプションの対応表

Agent SDK クラスタの目次として使える表です。

TypeScriptPython制御カバー対象
permissionModepermission_modeエージェントが承認なしでできることは何か権限を設定する
allowedToolsallowed_toolsどのツール呼び出しが事前承認されるか権限を設定する
canUseToolcan_use_toolツール呼び出しの承認コールバックツール承認リクエストを処理する
systemPromptsystem_promptエージェントの指示システムプロンプトを変更する
settingSourcessetting_sourcesどのファイルシステム設定が読み込まれるかSDK で Claude Code 機能を使用する
mcpServersmcp_servers外部ツールサーバーMCP で外部ツールに接続する
agentsagentsサブエージェント定義サブエージェント
hookshooksライフサイクルポイントでのコールバックフック
skillsskillsどのスキルが読み込まれるかスキルでエージェントを拡張する
pluginspluginsどのプラグインが読み込まれるかプラグイン
outputFormatoutput_format構造化出力スキーマ構造化出力
resumeresume保存されたセッションを続行するセッション
forkSessionfork_sessionセッションをブランチするセッション
sessionStoresession_store外部セッション永続化セッションストレージ
enableFileCheckpointingenable_file_checkpointing巻き戻し可能なファイル編集ファイルチェックポイント
efforteffortClaude がレスポンスにどれだけの作業を入れるか努力レベル
sandboxsandboxツール実行のサンドボックス動作各言語リファレンス/安全なデプロイ

この表から、連載でまだ扱っていない SDK ページが分かります。structured-outputs・file-checkpointing・secure-deployment・examples・user-input は、ここで初めて存在が明示されました。

最後にマルチテナントへの言及があります。settingSources / setting_sources、env、および cwd で各テナントの設定とメモリを分離します。——この3つがテナント分離の道具である、という設計指針です。

4. まとめ + 次回予告

  • 設定の入口は3つ——設定ファイル・環境変数・options オブジェクト。
  • options は**全フィールドが省略可能。**何も渡さなければ SDK のデフォルト。
  • **allowedTools は「許可リスト」ではなく「事前承認リスト」。**載せなかったツールも使え、その可否は権限モードが決める。
  • settings はユーザー・プロジェクト・ローカルを上書きし、管理ポリシーだけがそれより上。****settingSources に [] を渡すとファイルシステム設定を全部切れる。
  • フォールバックモデルはコンマ区切りで複数指定でき、各ユーザーターンの開始時に本命へ戻ろうとする。TypeScript はmodel と同じフォールバックを起動時にエラーにする。
  • **temperature / top_p / max_tokens のフィールドは無い。**必要なら Messages API を直接呼ぶ。
  • **env は TypeScript が「置換」、Python が「マージ」。**TypeScript は ...process.env を展開しないと PATH も ANTHROPIC_API_KEY も消える。
  • **cwd は設定・フック・スキル発見・セッション保存先まで決める。**セッション途中では変えられない。外部ディレクトリは additionalDirectories / add_dirs。
  • 0 の意味が逆。maxTurns の 0 は無制限、maxBudgetUsd の 0 は起動拒否。
  • セッション中に変えられるのは**モデルと権限モード。**ストリーミング入力が前提で、Python は ClaudeSDKClient が必要(query() には制御メソッドが無い)。
  • setModel() を引数なしで呼ぶと Claude Code のデフォルトモデルに戻る。
  • TypeScript 限定で applyFlagSettings()(設定ファイルキーを取る)と updateSettings()。後者は**"localSettings" が次リクエストから有効かつ永続化、"userSettings" は effortLevel のみで実行中のセッションには効かない。**
  • **モデルを切り替えると、新しいモデルのレートで会話全体が再計算される。**プロンプトキャッシュはモデルごと。
  • マルチテナント分離の道具は settingSources・env・cwd の3つ。

次回予告(暫定):対応表の筆頭に置かれ、第77回でもモード一覧だけ扱った**権限(agent-sdk/permissions)**を取り上げ、許可・拒否ルールの構文と評価順序、canUseTool コールバックを扱う予定です。


よっしー
よっしー

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

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

コメント

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