plan / act モード:同一アーキテクチャの下の二つの役割
役割
Cline は「ユーザーと対話する」と「実際にファイルを変更する」の二つを plan と act の二つのモード (mode) に分け、Mode = "plan" | "act" 型で明示的に标注する(Mode type:14)。一つの Task インスタンスは一つの mode にしか属さず、モード切り替えは Task を再構築する。だから単一タスク内では mode は不変である。この mode パラメータは buildApiHandler から ApiHandler まで伝わり、さらに attemptApiRequest から getSystemPrompt の context に伝わって、最後まで貫く。
二つの中核的な役割がある:第一に ApiHandler の選択に影響する —— buildApiHandler が mode に従って planModeApiProvider または actModeApiProvider から provider を選ぶ(mode provider:520)。plan と act には異なるモデル、異なる thinkingBudget を掛けられる。第二にシステム提示の中の ACT_VS_PLAN コンポーネントの内容と、一部ツールの利用可否ヒントに影響する(act_vs_plan template:5).
設計動機
- plan / act 二套の ApiConfiguration:
planModeApiProvider / actModeApiProviderは二つの独立したフィールドで、デフォルト値はともにDEFAULT_API_PROVIDER(planModeApiProvider:243)。ユーザーは plan で安いモデルを使って素早く方針を議論し、act でより強いモデルで実際にコードを変える、ということができる。 - mode を handler 構築まで貫通:
createHandlerForProviderは mode を受け取ると、planModeApiModelId / actModeApiModelId、planModeReasoningEffort / actModeReasoningEffort、planModeThinkingBudgetTokens / actModeThinkingBudgetTokensなどのペアフィールドから対応するものを取得する(mode-aware options:94)。「思考予算」「reasoning effort」「model id」はすべて mode 単位で隔離される。 - plan_mode_respond ツールは plan 専属:
plan_mode_respondツールの description はThis tool is only available in PLAN MODEと明記する。act モードには実行時の呼び出し阻止はないが、システム提示のACT_VS_PLANセクションが「ACT MODE では plan_mode_respond を使えない」とモデルに伝える(ACT MODE exclusion:9). - ACT MODE の主要ツールセット:generic variant が宣言する 18 個のツールのうち、
PLAN_MODE = "plan_mode_respond"だけが plan 専属で、それ以外のexecute_command / read_file / write_to_file / replace_in_file / search_files / list_files / attempt_completionなどは両モードで利用可能(generic tools:58)。act モードはこのセットでファイルを変え、コマンドを走らせ、完了時にattempt_completionで締める。 - yoloMode が plan ヒントに影響:
getActVsPlanModeTemplateTextはcontext.yoloModeToggled !== trueをチェックし、非 yolo モードの時だけ plan の説明に「ask_followup_question で確認質問をできる」という一文を加える(yolo guard:18)。yolo モードはデフォルトで自発的に問わない。 - needs_more_exploration パラメータ:plan_mode_respond は
needs_more_explorationというオプションの真偽値パラメータを持つ(needs_more_exploration:38)。モデルが応答を書き終えた後に「まだあと数個ファイルを読む必要がある」と戻ることができ、自分の初期 plan に縛られないようにする。
主要ファイル
Mode type:14—type Mode = "plan" | "act"。この二値しかない。buildApiHandler:517— 入口。planModeApiProvider / actModeApiProviderから provider を選び、mode をcreateHandlerForProviderにそのまま渡す。anthropic case mode-aware:94—case "anthropic"分岐は mode に従ってペアフィールドからapiModelId / reasoningEffort / thinkingBudgetTokensを取得する。mode provider pick:520—const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider。planModeApiProvider default:243— 二つのフィールドのデフォルトはともにDEFAULT_API_PROVIDER。ユーザーが明示的に設定しない時は plan/act は同じ provider で動く。act_vs_plan template:5— システム提示の ACT_VS_PLAN セクションのテンプレート。二つのモードそれぞれのツール利用可否と期待される振る舞いを定義する。ACT MODE description:9— ACT MODE は plan_mode_respond 以外のすべてのツールを使える。完了時に attempt_completion を使う。PLAN MODE description:11— PLAN MODE は plan_mode_respond だけで応答する。目標はまず情報を集めてから計画を出すこと。yolo mode guard:18— yolo モードでは「確認質問できる」ヒントを削る。plan_mode_respond generic:25— plan モード専属ツールの仕様。response / needs_more_exploration / task_progressの三つのパラメータを持つ。PLAN MODE only constraint:7— description にThis tool is only available in PLAN MODEと明記。モデルはプロンプトで自己制約する。act_mode_respond description:29— act モード専属ツール。実行の流れを止めずに進捗を報告するために使う。連続呼び出しはできない。generic tools list:58— generic variant が宣言する 18 個のツール id。plan と act のツールを同時にカバーする。Task mode field:585— Task は構築時にmodeパラメータでbuildApiHandlerを呼ぶ。この mode は TaskParams から来る。
データフロー
mode の伝播は一方向の直線である:Task が構築時に一つの mode を受け取り、その mode が buildApiHandler の分岐を決める。その後 attemptApiRequest が同じ mode を SystemPromptContext.providerInfo.mode を通じてシステム提示層に渡す:
// apps/vscode/src/core/api/index.ts
export function buildApiHandler(configuration: ApiConfiguration, mode: Mode): ApiHandler {
const { planModeApiProvider, actModeApiProvider, ...options } = configuration
const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider
// ... thinkingBudget clip ...
return createHandlerForProvider(apiProvider, options, mode)
}createHandlerForProvider の各 case は mode でフィールドを選ぶ。Anthropic 分岐が典型的である:
// apps/vscode/src/core/api/index.ts
case "anthropic":
return new AnthropicHandler({
onRetryAttempt: options.onRetryAttempt,
apiKey: options.apiKey,
anthropicBaseUrl: options.anthropicBaseUrl,
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
thinkingBudgetTokens:
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
})mode === "plan" という判定は 30 以上の case で繰り返し現れる。冗長に見えるが、利点は各分岐が「ここには plan/act 二套の設定がある」と読者に明示する点で、フィールド名の慣習を覚える必要がない。システム提示層の ACT_VS_PLAN セクションは context に従ってレンダリングする:
// apps/vscode/src/core/prompts/system-prompt/components/act_vs_plan_mode.ts
const getActVsPlanModeTemplateText = (context: SystemPromptContext) => `ACT MODE V.S. PLAN MODE
In each user message, the environment_details will specify the current mode. There are two modes:
- ACT MODE: In this mode, you have access to all tools EXCEPT the plan_mode_respond tool.
- In ACT MODE, you use tools to accomplish the user's task. Once you've completed the user's task, you use the attempt_completion tool to present the result of the task to the user.
- PLAN MODE: In this special mode, you have access to the plan_mode_respond tool.
- In PLAN MODE, the goal is to gather information and get context to create a detailed plan for accomplishing the task, which the user will review and approve before they switch you to ACT MODE to implement the solution.
// ...`mode ごとに異なるテンプレートをレンダリングするのではなく、両モードのルールを同じセクションに書き込み、モデル自身に environment_details.mode フィールドでどちらの道を進むか判断させる(environment_details mode:7). 本当の「mode でツールを選ぶ」は ClineToolSet.getEnabledTools が context.providerInfo.mode に基づいてツールリストをフィルタすることで実現する(ApiProviderInfo.mode:75).
境界と失敗
- plan が act 専属ツールを使っても実行時阻止なし:
getEnabledToolsは variant.tools リストでフィルタするだけで、実行時に mode を別途チェックしてplan_mode_respondを排除しない(getEnabledTools:87)。generic variant はPLAN_MODEとATTEMPTを同時に宣言するため、モデルは主にシステム提示で自己制約する。 - mode 切替は Task を再構築:Task は構築時に mode を保存する。実行中に mode を切替ると新しい Task の構築がトリガーされ、フィールド書き換えではない。
buildApiHandlerは Task 構築時に一度だけ呼ばれる(buildApiHandler call:585). - planModeApiProvider のデフォルト値:
DEFAULT_API_PROVIDERは plan/act 共通のデフォルト(planModeApiProvider default:243)。だから新規ユーザーが初めて Cline を起動した時は plan と act が同じ provider で動き、挙動は一致する。 - thinkingBudget は plan / act それぞれで上限クリップ:
buildApiHandlerはmode === "plan" ? planModeThinkingBudgetTokens : actModeThinkingBudgetTokensを取得し、個別に maxTokens 上限クリップを行う(mode budget:525)。plan の budget が act に影響することやその逆はない。 - yoloMode と plan の衝突:
yoloModeToggled === trueの時、plan セクションは「ask_followup_question できる」ヒントを削る(yolo guard:18)。ただし yolo モードは本質的にユーザー確認をスキップして自動実行するもので、plan の「先に議論してから実行」という理念とは張力がある。実際、yolo ユーザーは基本的に plan を使わない。 - act_mode_respond 連続呼び出しの阻止:
act_mode_respondツールの description に「連続呼び出しはできない、さもなくば失敗する」と明記する(CRITICAL CONSTRAINT:43)。実行時の阻止に頼る。 - needs_more_exploration の自己修正:plan_mode_respond は plan を書き終えた後に「もっと探索が必要」と戻ることができる。
needs_more_exploration=trueで次ラウンドを探索ツールに進ませ、締めのステップに進ませない(needs_more_exploration:38)。モデルに自己修正の出口を与える。
まとめ
plan / act モードは Cline が「方針を議論する」と「実際にコードを変える」の間に引いた一本の線である。工学的には Mode = "plan" | "act" という型とペアになった設定フィールド一式に過ぎない。その設計上のトレードオフは:実行時に動的に mode を切り替えるのではなく、mode を切り替えるたびに Task を再構築することで、handler / プロンプト / ツールセットがすべて mode 単位で全体再構築され、状態の隔離が綺麗になる点である。モデルは実際にはシステム提示の ACT_VS_PLAN セクションで自己制約し、どちらのツールを使うかを決める。実行時の阻止はほとんど無い。
- ツールセットがどう context でフィルタされるか:
/prompts/toolset - システム提示がどう組み立てられるか:
/prompts/prompt-builder - mode が handler 選択にどう影響するか:
/providers/api-handler