Skip to content

Modos plan / act: dos roles bajo una misma arquitectura

源码版本v4.0.10

Responsabilidades

Cline separa «conversar con el usuario» y «modificar archivos de verdad» en dos modos (mode): plan y act, marcados explícitamente por el tipo Mode = "plan" | "act" (Mode type:14). Una misma instancia de Task pertenece a un único mode; cambiar de modo reconstruye el Task, de modo que dentro de una misma tarea el mode es fijo. Este parámetro se propaga desde buildApiHandler hasta ApiHandler, y desde attemptApiRequest hasta el context de getSystemPrompt, atravesando todo el stack.

Sus dos efectos centrales: primero, influye en la selección del ApiHandler —buildApiHandler elige provider según mode desde planModeApiProvider o actModeApiProvider (mode provider:520), de modo que plan y act pueden colgar distintos modelos y distintos thinkingBudget—; segundo, influye en el contenido del componente ACT_VS_PLAN del system prompt y en las notas de disponibilidad de ciertas herramientas (act_vs_plan template:5).

Motivación de diseño

  • Dos ApiConfiguration para plan / act: planModeApiProvider / actModeApiProvider son dos campos independientes; ambos tienen como valor por defecto DEFAULT_API_PROVIDER (planModeApiProvider:243). El usuario puede hacer que plan use un modelo barato para discutir enfoques con rapidez y act un modelo más capaz para cambiar código de verdad.
  • mode atravesando la construcción del handler: createHandlerForProvider recibe mode y escoge el campo correspondiente de los pares planModeApiModelId / actModeApiModelId, planModeReasoningEffort / actModeReasoningEffort, planModeThinkingBudgetTokens / actModeThinkingBudgetTokens (mode-aware options:94). Todo «presupuesto de pensamiento», «reasoning effort» y «model id» queda aislado por mode.
  • plan_mode_respond es exclusivo de plan: la descripción de plan_mode_respond dice This tool is only available in PLAN MODE; act mode no tiene bloqueo en runtime para esta herramienta, pero el segmento ACT_VS_PLAN del system prompt indica al modelo «en ACT MODE no se puede usar plan_mode_respond» (ACT MODE exclusion:9).
  • Conjunto de herramientas principal en ACT MODE: de las 18 herramientas del variant generic, solo PLAN_MODE = "plan_mode_respond" es exclusiva de plan; el resto (execute_command / read_file / write_to_file / replace_in_file / search_files / list_files / attempt_completion, etc.) está disponible en ambos modos (generic tools:58). Act mode se apoya en este conjunto para cambiar archivos, ejecutar comandos y cerrar con attempt_completion.
  • yoloMode afecta al prompt de plan: getActVsPlanModeTemplateText comprueba context.yoloModeToggled !== true; solo en modo no-yolo la descripción de plan añade «puedes usar ask_followup_question para preguntas de clarificación» (yolo guard:18); en yolo no se pregunta proactivamente.
  • Parámetro needs_more_exploration: plan_mode_respond incluye el booleano opcional needs_more_exploration (needs_more_exploration:38), permitiendo al modelo, tras redactar su respuesta, volver atrás y decir «necesito leer más archivos», evitando quedar atrapado por su plan inicial.

Archivos clave

  • Mode type:14type Mode = "plan" | "act", solo estos dos valores.
  • buildApiHandler:517 — entrada; elige provider desde planModeApiProvider / actModeApiProvider y propaga mode a createHandlerForProvider.
  • anthropic case mode-aware:94 — la rama case "anthropic" toma apiModelId / reasoningEffort / thinkingBudgetTokens según mode.
  • mode provider pick:520const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider.
  • planModeApiProvider default:243 — ambos campos tienen como default DEFAULT_API_PROVIDER; si el usuario no configura explícitamente, plan/act usan el mismo provider.
  • act_vs_plan template:5 — plantilla del segmento ACT_VS_PLAN del system prompt; define la disponibilidad de herramientas y el comportamiento esperado en cada modo.
  • ACT MODE description:9 — ACT MODE puede usar todas las herramientas excepto plan_mode_respond y cierra con attempt_completion.
  • PLAN MODE description:11 — PLAN MODE solo puede responder con plan_mode_respond; su objetivo es primero recopilar información y luego proponer un plan.
  • yolo mode guard:18 — en modo yolo se elimina la indicación «puedes hacer preguntas de clarificación».
  • plan_mode_respond generic:25 — especificación de la herramienta exclusiva de plan, con tres parámetros: response / needs_more_exploration / task_progress.
  • PLAN MODE only constraint:7 — la descripción dice This tool is only available in PLAN MODE; el modelo se autoconstriñe por la indicación.
  • act_mode_respond description:29 — herramienta exclusiva de act, sirve para reportar progreso sin interrumpir el flujo de ejecución y no puede llamarse de forma consecutiva.
  • generic tools list:58 — los 18 ids de herramientas declarados por el variant generic, cubriendo tanto herramientas de plan como de act.
  • Task mode field:585 — el constructor de Task llama a buildApiHandler con el parámetro mode, proveniente de TaskParams.

Flujo de datos

La propagación de mode es lineal y en un solo sentido: el constructor de Task recibe un mode, este mode decide qué rama sigue buildApiHandler, y luego attemptApiRequest propaga ese mismo mode vía SystemPromptContext.providerInfo.mode a la capa de system prompt:

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

	// ... límite thinkingBudget ...
	return createHandlerForProvider(apiProvider, options, mode)
}

Cada case de createHandlerForProvider elige el campo según mode; la rama Anthropic es típica:

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,
	})

La comprobación mode === "plan" se repite en más de 30 cases; puede parecer verboso, pero la ventaja es que cada rama le deja claro al lector «aquí hay dos configuraciones, una para plan y otra para act», sin necesidad de recordar convenciones de nombres. El segmento ACT_VS_PLAN del system prompt se renderiza según el 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.
 // ...`

Observa que no renderiza plantillas distintas por mode, sino que escribe las reglas de ambos modos en el mismo segmento, dejando que el modelo decida el camino según el campo environment_details.mode (environment_details mode:7). La verdadera «selección de herramientas por mode» la realiza ClineToolSet.getEnabledTools filtrando la lista de herramientas según context.providerInfo.mode (ApiProviderInfo.mode:75).

Límites y fallos

  • plan usando herramienta exclusiva de act sin bloqueo duro: getEnabledTools filtra por la lista variant.tools y no chequea mode en runtime para excluir plan_mode_respond (getEnabledTools:87); el variant generic declara simultáneamente PLAN_MODE y ATTEMPT, de modo que el modelo se autoconstriñe principalmente por el system prompt.
  • Cambiar de mode reconstruye Task: el constructor de Task almacena mode; cambiar de mode durante la ejecución dispara un nuevo Task en lugar de modificar el campo, y buildApiHandler solo se llama una vez, al construir el Task (buildApiHandler call:585).
  • Valor por defecto de planModeApiProvider: DEFAULT_API_PROVIDER es el valor común para plan y act (planModeApiProvider default:243); así, al iniciar Cline por primera vez, plan y act usan el mismo provider y el comportamiento coincide.
  • thinkingBudget con límite separado en plan / act: buildApiHandler toma mode === "plan" ? planModeThinkingBudgetTokens : actModeThinkingBudgetTokens y aplica el límite maxTokens de forma independiente (mode budget:525), de modo que el budget de plan no afecta a act ni viceversa.
  • Conflicto entre yoloMode y plan: cuando yoloModeToggled === true, el segmento de plan elimina la indicación «puedes usar ask_followup_question» (yolo guard:18), pero yolo consiste en saltarse la confirmación del usuario y ejecutar automáticamente, lo cual entra en tensión con la filosofía de plan de «primero discutir, luego ejecutar»; en la práctica, los usuarios yolo casi no usan plan.
  • Bloqueo de llamadas consecutivas a act_mode_respond: la descripción de act_mode_respond indica explícitamente «no puede llamarse de forma consecutiva, fallará» (CRITICAL CONSTRAINT:43), respaldado por un bloqueo en runtime.
  • Autocorrección con needs_more_exploration: plan_mode_respond permite, tras redactar el plan, volver atrás y decir «necesita más exploración»; con needs_more_exploration=true la siguiente ronda usa herramientas de exploración en lugar de cerrar (needs_more_exploration:38), ofreciendo al modelo una vía de autocorrección.

Resumen

Los modos plan / act son la línea que Cline traza entre «discutir un enfoque» y «modificar código»; en términos de ingeniería, se reduce a un tipo Mode = "plan" | "act" más un conjunto de campos de configuración por pares. Su compromiso de diseño es: no cambiar mode dinámicamente en runtime, sino reconstruir el Task en cada cambio de mode, ganando que handler / prompt / toolset se reconstruyan como un bloque según mode y dejando el estado limpiamente aislado. En la práctica, el modelo se autoconstriñe a qué herramienta usar mediante el segmento ACT_VS_PLAN del system prompt; los bloqueos en runtime son mínimos.

  • Cómo se filtra el toolset por context: /prompts/toolset
  • Cómo se ensambla el system prompt: /prompts/prompt-builder
  • Cómo afecta mode a la selección de handler: /providers/api-handler

Véase la documentación oficial: Cline 文档 · README