/ tools / EnterPlanModeTool / EnterPlanModeTool.ts
EnterPlanModeTool.ts
  1  import { feature } from 'bun:bundle'
  2  import { z } from 'zod/v4'
  3  import {
  4    getAllowedChannels,
  5    handlePlanModeTransition,
  6  } from '../../bootstrap/state.js'
  7  import type { Tool } from '../../Tool.js'
  8  import { buildTool, type ToolDef } from '../../Tool.js'
  9  import { lazySchema } from '../../utils/lazySchema.js'
 10  import { applyPermissionUpdate } from '../../utils/permissions/PermissionUpdate.js'
 11  import { prepareContextForPlanMode } from '../../utils/permissions/permissionSetup.js'
 12  import { isPlanModeInterviewPhaseEnabled } from '../../utils/planModeV2.js'
 13  import { ENTER_PLAN_MODE_TOOL_NAME } from './constants.js'
 14  import { getEnterPlanModeToolPrompt } from './prompt.js'
 15  import {
 16    renderToolResultMessage,
 17    renderToolUseMessage,
 18    renderToolUseRejectedMessage,
 19  } from './UI.js'
 20  
 21  const inputSchema = lazySchema(() =>
 22    z.strictObject({
 23      // No parameters needed
 24    }),
 25  )
 26  type InputSchema = ReturnType<typeof inputSchema>
 27  
 28  const outputSchema = lazySchema(() =>
 29    z.object({
 30      message: z.string().describe('Confirmation that plan mode was entered'),
 31    }),
 32  )
 33  type OutputSchema = ReturnType<typeof outputSchema>
 34  export type Output = z.infer<OutputSchema>
 35  
 36  export const EnterPlanModeTool: Tool<InputSchema, Output> = buildTool({
 37    name: ENTER_PLAN_MODE_TOOL_NAME,
 38    searchHint: 'switch to plan mode to design an approach before coding',
 39    maxResultSizeChars: 100_000,
 40    async description() {
 41      return 'Requests permission to enter plan mode for complex tasks requiring exploration and design'
 42    },
 43    async prompt() {
 44      return getEnterPlanModeToolPrompt()
 45    },
 46    get inputSchema(): InputSchema {
 47      return inputSchema()
 48    },
 49    get outputSchema(): OutputSchema {
 50      return outputSchema()
 51    },
 52    userFacingName() {
 53      return ''
 54    },
 55    shouldDefer: true,
 56    isEnabled() {
 57      // When --channels is active, ExitPlanMode is disabled (its approval
 58      // dialog needs the terminal). Disable entry too so plan mode isn't a
 59      // trap the model can enter but never leave.
 60      if (
 61        (feature('KAIROS') || feature('KAIROS_CHANNELS')) &&
 62        getAllowedChannels().length > 0
 63      ) {
 64        return false
 65      }
 66      return true
 67    },
 68    isConcurrencySafe() {
 69      return true
 70    },
 71    isReadOnly() {
 72      return true
 73    },
 74    renderToolUseMessage,
 75    renderToolResultMessage,
 76    renderToolUseRejectedMessage,
 77    async call(_input, context) {
 78      if (context.agentId) {
 79        throw new Error('EnterPlanMode tool cannot be used in agent contexts')
 80      }
 81  
 82      const appState = context.getAppState()
 83      handlePlanModeTransition(appState.toolPermissionContext.mode, 'plan')
 84  
 85      // Update the permission mode to 'plan'. prepareContextForPlanMode runs
 86      // the classifier activation side effects when the user's defaultMode is
 87      // 'auto' — see permissionSetup.ts for the full lifecycle.
 88      context.setAppState(prev => ({
 89        ...prev,
 90        toolPermissionContext: applyPermissionUpdate(
 91          prepareContextForPlanMode(prev.toolPermissionContext),
 92          { type: 'setMode', mode: 'plan', destination: 'session' },
 93        ),
 94      }))
 95  
 96      return {
 97        data: {
 98          message:
 99            'Entered plan mode. You should now focus on exploring the codebase and designing an implementation approach.',
100        },
101      }
102    },
103    mapToolResultToToolResultBlockParam({ message }, toolUseID) {
104      const instructions = isPlanModeInterviewPhaseEnabled()
105        ? `${message}
106  
107  DO NOT write or edit any files except the plan file. Detailed workflow instructions will follow.`
108        : `${message}
109  
110  In plan mode, you should:
111  1. Thoroughly explore the codebase to understand existing patterns
112  2. Identify similar features and architectural approaches
113  3. Consider multiple approaches and their trade-offs
114  4. Use AskUserQuestion if you need to clarify the approach
115  5. Design a concrete implementation strategy
116  6. When ready, use ExitPlanMode to present your plan for approval
117  
118  Remember: DO NOT write or edit any files yet. This is a read-only exploration and planning phase.`
119  
120      return {
121        type: 'tool_result',
122        content: instructions,
123        tool_use_id: toolUseID,
124      }
125    },
126  } satisfies ToolDef<InputSchema, Output>)