Skip to content

plan / act モード:同一アーキテクチャの下の二つの役割

源码版本v4.0.10

役割

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 / actModeApiModelIdplanModeReasoningEffort / actModeReasoningEffortplanModeThinkingBudgetTokens / 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 ヒントに影響:getActVsPlanModeTemplateTextcontext.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:14type Mode = "plan" | "act"。この二値しかない。
  • buildApiHandler:517 — 入口。planModeApiProvider / actModeApiProvider から provider を選び、mode を createHandlerForProvider にそのまま渡す。
  • anthropic case mode-aware:94case "anthropic" 分岐は mode に従ってペアフィールドから apiModelId / reasoningEffort / thinkingBudgetTokens を取得する。
  • mode provider pick:520const 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 を通じてシステム提示層に渡す:

typescript
// 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 分岐が典型的である:

typescript
// 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 に従ってレンダリングする:

typescript
// 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.getEnabledToolscontext.providerInfo.mode に基づいてツールリストをフィルタすることで実現する(ApiProviderInfo.mode:75).

境界と失敗

  • plan が act 専属ツールを使っても実行時阻止なし:getEnabledTools は variant.tools リストでフィルタするだけで、実行時に mode を別途チェックして plan_mode_respond を排除しない(getEnabledTools:87)。generic variant は PLAN_MODEATTEMPT を同時に宣言するため、モデルは主にシステム提示で自己制約する。
  • 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 それぞれで上限クリップ:buildApiHandlermode === "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

公式資料:Cline 文档 · README