Skip to content

Commit d875f22

Browse files
committed
feat: implement apply_code tool for two-stage code generation
- Add new apply_code tool that uses a two-stage approach: 1. Creative code generation based on instructions 2. Focused diff generation with clean context - Add applyEnabled configuration option to enable/disable the feature - Update tool descriptions and type definitions - Add comprehensive tests for the new tool - Integrate with existing diff application infrastructure This addresses issue #6159 by providing a more reliable alternative to apply_diff that separates creative code generation from technical diff creation, reducing errors from noisy conversational contexts.
1 parent 1e17b3b commit d875f22

File tree

9 files changed

+756
-1
lines changed

9 files changed

+756
-1
lines changed

packages/types/src/provider-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export const DEFAULT_CONSECUTIVE_MISTAKE_LIMIT = 3
6363
const baseProviderSettingsSchema = z.object({
6464
includeMaxTokens: z.boolean().optional(),
6565
diffEnabled: z.boolean().optional(),
66+
applyEnabled: z.boolean().optional(),
6667
todoListEnabled: z.boolean().optional(),
6768
fuzzyMatchThreshold: z.number().optional(),
6869
modelTemperature: z.number().nullish(),

packages/types/src/tool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const toolNames = [
1919
"read_file",
2020
"write_to_file",
2121
"apply_diff",
22+
"apply_code",
2223
"insert_content",
2324
"search_and_replace",
2425
"search_files",

src/core/assistant-message/presentAssistantMessage.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { Task } from "../task/Task"
3434
import { codebaseSearchTool } from "../tools/codebaseSearchTool"
3535
import { experiments, EXPERIMENT_IDS } from "../../shared/experiments"
3636
import { applyDiffToolLegacy } from "../tools/applyDiffTool"
37+
import { applyCodeTool } from "../tools/applyCodeTool"
3738

3839
/**
3940
* Processes and presents assistant message content to the user interface.
@@ -214,6 +215,8 @@ export async function presentAssistantMessage(cline: Task) {
214215
const modeName = getModeBySlug(mode, customModes)?.name ?? mode
215216
return `[${block.name} in ${modeName} mode: '${message}']`
216217
}
218+
case "apply_code":
219+
return `[${block.name} for '${block.params.path}' with instruction: '${block.params.instruction}']`
217220
}
218221
}
219222

@@ -522,6 +525,9 @@ export async function presentAssistantMessage(cline: Task) {
522525
askFinishSubTaskApproval,
523526
)
524527
break
528+
case "apply_code":
529+
await applyCodeTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
530+
break
525531
}
526532

527533
break
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ToolArgs } from "./types"
2+
3+
export function getApplyCodeDescription(args: ToolArgs): string {
4+
return `## apply_code
5+
Description: Request to apply code changes using a two-stage approach for improved reliability. This tool first generates code based on your instruction, then creates an accurate diff to integrate it into the existing file. This approach separates creative code generation from technical diff creation, resulting in more reliable code modifications.
6+
7+
Parameters:
8+
- path: (required) The path of the file to modify (relative to the current workspace directory ${args.cwd})
9+
- instruction: (required) Clear instruction describing what code changes to make
10+
11+
Usage:
12+
<apply_code>
13+
<path>File path here</path>
14+
<instruction>Your instruction for code changes</instruction>
15+
</apply_code>
16+
17+
Example: Adding a new function to an existing file
18+
<apply_code>
19+
<path>src/utils.ts</path>
20+
<instruction>Add a function called calculateAverage that takes an array of numbers and returns their average</instruction>
21+
</apply_code>
22+
23+
Example: Modifying existing code
24+
<apply_code>
25+
<path>src/api/handler.ts</path>
26+
<instruction>Update the error handling in the fetchData function to include retry logic with exponential backoff</instruction>
27+
</apply_code>
28+
29+
Benefits over apply_diff:
30+
- More reliable: Separates code generation from diff creation
31+
- Cleaner context: Each stage has focused, minimal context
32+
- Better success rate: Reduces failures due to inaccurate diffs
33+
- Natural instructions: Use plain language instead of crafting diffs`
34+
}

src/core/prompts/tools/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { getSwitchModeDescription } from "./switch-mode"
2323
import { getNewTaskDescription } from "./new-task"
2424
import { getCodebaseSearchDescription } from "./codebase-search"
2525
import { getUpdateTodoListDescription } from "./update-todo-list"
26+
import { getApplyCodeDescription } from "./apply-code"
2627
import { CodeIndexManager } from "../../../services/code-index/manager"
2728

2829
// Map of tool names to their description functions
@@ -46,6 +47,7 @@ const toolDescriptionMap: Record<string, (args: ToolArgs) => string | undefined>
4647
search_and_replace: (args) => getSearchAndReplaceDescription(args),
4748
apply_diff: (args) =>
4849
args.diffStrategy ? args.diffStrategy.getToolDescription({ cwd: args.cwd, toolOptions: args.toolOptions }) : "",
50+
apply_code: (args) => getApplyCodeDescription(args),
4951
update_todo_list: (args) => getUpdateTodoListDescription(args),
5052
}
5153

@@ -114,6 +116,11 @@ export function getToolDescriptionsForMode(
114116
tools.delete("update_todo_list")
115117
}
116118

119+
// Conditionally exclude apply_code if disabled in settings
120+
if (settings?.applyEnabled === false) {
121+
tools.delete("apply_code")
122+
}
123+
117124
// Map tool descriptions for allowed tools
118125
const descriptions = Array.from(tools).map((toolName) => {
119126
const descriptionFn = toolDescriptionMap[toolName]
@@ -148,4 +155,5 @@ export {
148155
getInsertContentDescription,
149156
getSearchAndReplaceDescription,
150157
getCodebaseSearchDescription,
158+
getApplyCodeDescription,
151159
}

0 commit comments

Comments
 (0)