( opts: BuildPlanInstructionsOptions )
| 101 | * used a plan-like agent |
| 102 | */ |
| 103 | export async function buildPlanInstructions( |
| 104 | opts: BuildPlanInstructionsOptions |
| 105 | ): Promise<PlanInstructionsResult> { |
| 106 | const { |
| 107 | runtime, |
| 108 | metadata, |
| 109 | workspaceId, |
| 110 | effectiveMode, |
| 111 | effectiveAgentId, |
| 112 | agentIsPlanLike, |
| 113 | agentDiscoveryRuntime, |
| 114 | agentDiscoveryPath, |
| 115 | additionalSystemInstructions, |
| 116 | shouldDisableTaskToolsForDepth, |
| 117 | taskDepth, |
| 118 | taskSettings, |
| 119 | requestPayloadMessages, |
| 120 | } = opts; |
| 121 | |
| 122 | const workspaceLog = log.withFields({ workspaceId, workspaceName: metadata.name }); |
| 123 | |
| 124 | // Construct plan mode instruction if in plan mode |
| 125 | // This is done backend-side because we have access to the plan file path |
| 126 | let effectiveAdditionalInstructions = additionalSystemInstructions; |
| 127 | const muxHome = runtime.getMuxHome(); |
| 128 | const planFilePath = getPlanFilePath(metadata.name, metadata.projectName, muxHome); |
| 129 | |
| 130 | // Read plan file (handles legacy migration transparently) |
| 131 | const planResult = await readPlanFile(runtime, metadata.name, metadata.projectName, workspaceId); |
| 132 | |
| 133 | const chatHasStartHerePlanSummary = hasStartHerePlanSummary(requestPayloadMessages); |
| 134 | |
| 135 | if (effectiveMode === "plan") { |
| 136 | const planModeInstruction = getPlanModeInstruction(planFilePath, planResult.exists); |
| 137 | effectiveAdditionalInstructions = additionalSystemInstructions |
| 138 | ? `${planModeInstruction}\n\n${additionalSystemInstructions}` |
| 139 | : planModeInstruction; |
| 140 | } else if (planResult.exists && planResult.content.trim()) { |
| 141 | // Users often use "Replace all chat history" after plan mode. In exec (or other non-plan) |
| 142 | // modes, the model can lose the plan file location because plan path injection only |
| 143 | // happens in plan mode. |
| 144 | // |
| 145 | // Exception: the ProposePlanToolCall "Start Here" flow already stores the full plan |
| 146 | // (and plan path) directly in chat history. In that case, prompting the model to |
| 147 | // re-open the plan file is redundant and often results in an extra "read …KB" step. |
| 148 | if (!chatHasStartHerePlanSummary) { |
| 149 | const planFileHint = getPlanFileHint(planFilePath, planResult.exists); |
| 150 | if (planFileHint) { |
| 151 | effectiveAdditionalInstructions = effectiveAdditionalInstructions |
| 152 | ? `${planFileHint}\n\n${effectiveAdditionalInstructions}` |
| 153 | : planFileHint; |
| 154 | } |
| 155 | } else { |
| 156 | workspaceLog.debug( |
| 157 | "Skipping plan file hint: Start Here already includes the plan in chat history." |
| 158 | ); |
| 159 | } |
| 160 | } |
no test coverage detected