Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions apps/kilocode-docs/docs/features/tools/file-edit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: file_edit
---

# file_edit

The `file_edit` tool performs targeted string replacements inside an existing file without requiring full diff blocks or a Fast Apply model. It combines deterministic matching with fuzzy fallbacks so you can provide an `old_string` and `new_string`, and the tool will locate and replace the intended section while still showing a diff for review.

## Parameters

- `target_file` (required): Path to the file to modify, relative to the workspace root.
- `old_string` (required): The text you expect to replace. Provide enough context for a unique match. Use an empty string to replace the entire file.
- `new_string` (required): Replacement text. This can be empty when you want to delete the matched block.
- `replace_all` (optional, default `false`): When `true`, every occurrence of the matched text is replaced. When `false`, the tool refuses to apply the change if the match is ambiguous.

## How It Works

1. **Validation** – Ensures required parameters are provided and that `old_string` differs from `new_string`.
2. **Access Checks** – Respects `.rooignore` and write-protection rules before modifying files.
3. **Content Matching** – Searches for `old_string` using multiple strategies:
- Exact substring matches
- Trimmed and indentation-insensitive comparisons
- Context-aware block matching with anchor lines
- Escaped character normalization and whitespace normalization
4. **Replacement** – Applies the update (single occurrence by default, or all occurrences when `replace_all` is `true`).
5. **Review** – Opens a diff preview for approval before writing changes to disk.

Because the tool still previews differences, you maintain full control over the edit before it is applied.

## When to Use

- You want a precise, deterministic edit without crafting manual `apply_diff` blocks.
- The change is localized and can be described as “replace this text with that text.”
- You need to remove or rewrite a block of code using string-based matching.
- Fast Apply is disabled or unavailable, and you want an alternative to `apply_diff`.

## Tips

- Prefer multi-line `old_string` values for more reliable matching.
- Include surrounding context (such as function signatures and closing braces) when multiple similar blocks exist.
- Set `replace_all` to `true` only when you intentionally want to update each occurrence of the match.
- Use the tool in combination with `read_file` or `search_files` to confirm the exact text you need to replace.

## Comparison to Other Editing Tools

| Tool | Best For | Notes |
| --------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------- |
| `apply_diff` | Structured changes with explicit SEARCH/REPLACE blocks | Supports multi-file edits and precise line control via `:start_line:` metadata. |
| `file_edit` | String-based replacements with fuzzy matching | Great when you know the before/after text but want deterministic, model-free edits. |
| `edit_file` | Morph Fast Apply powered edits | Delegates the change to an external model; ideal for large or semantic refactors. |
| `write_to_file` | Creating or completely replacing files | Overwrites entire files or creates new files from scratch. |

Choose the tool that best matches your workflow and the level of control you need over the edit.
3 changes: 2 additions & 1 deletion apps/kilocode-docs/docs/features/tools/tool-use-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Tools are organized into logical groups based on their functionality:
| Category | Purpose | Tools | Common Use |
| ------------------ | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| **Read Group** | File system reading and searching | [read_file](/features/tools/read-file), [search_files](/features/tools/search-files), [list_files](/features/tools/list-files), [list_code_definition_names](/features/tools/list-code-definition-names) | Code exploration and analysis |
| **Edit Group** | File system modifications | [apply_diff](/features/tools/apply-diff), [write_to_file](/features/tools/write-to-file) | Code changes and file manipulation |
| **Edit Group** | File system modifications | [apply_diff](/features/tools/apply-diff), [file_edit](/features/tools/file-edit), [write_to_file](/features/tools/write-to-file) | Code changes and file manipulation |
| **Browser Group** | Web automation | [browser_action](/features/tools/browser-action) | Web testing and interaction |
| **Command Group** | System command execution | [execute_command](/features/tools/execute-command) | Running scripts, building projects |
| **MCP Group** | External tool integration | [use_mcp_tool](/features/tools/use-mcp-tool), [access_mcp_resource](/features/tools/access-mcp-resource) | Specialized functionality through external servers |
Expand Down Expand Up @@ -43,6 +43,7 @@ These tools help Axon Code understand your code and project:
These tools help Axon Code make changes to your code:

- [apply_diff](/features/tools/apply-diff) - Makes precise, surgical changes to your code
- [file_edit](/features/tools/file-edit) - Performs string-based replacements with fuzzy matching
- [write_to_file](/features/tools/write-to-file) - Creates new files or completely rewrites existing ones

### Browser Tools
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const toolNames = [
"read_file",
"write_to_file",
"apply_diff",
"file_edit",
"insert_content",
"search_and_replace",
"search_files",
Expand Down
6 changes: 3 additions & 3 deletions src/api/providers/kilocode/nativeToolCallHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ import type { ApiStreamNativeToolCallsChunk } from "../../transform/kilocode/api
*/
export function addNativeToolCallsToParams<T extends OpenAI.Chat.ChatCompletionCreateParams>(
params: T,
options: ProviderSettings,
metadata?: ApiHandlerCreateMessageMetadata,
_options: ProviderSettings,
_metadata?: ApiHandlerCreateMessageMetadata,
): T {
// When toolStyle is "json", always add all native tools

// Use allowedTools if provided, otherwise use all native tools
const tools = metadata?.allowedTools || nativeTools
const tools = nativeTools
if (tools && tools.length > 0) {
params.tools = tools
//optimally we'd have tool_choice as 'required', but many providers, especially
Expand Down
50 changes: 10 additions & 40 deletions src/api/providers/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,19 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
const baseURL = this.options.openRouterBaseUrl || "https://api.matterai.so/v1/web"
const apiKey = this.options.openRouterApiKey ?? "not-provided"

console.log("baseURL", baseURL)
console.log("apiKey", apiKey)

this.client = new OpenAI({ baseURL, apiKey, defaultHeaders: DEFAULT_HEADERS })
// this.client = new OpenAI({ baseURL: "http://localhost:4064/v1/web", apiKey, defaultHeaders: DEFAULT_HEADERS })
}

// kilocode_change start
customRequestOptions(_metadata?: ApiHandlerCreateMessageMetadata): { headers: Record<string, string> } | undefined {
return undefined
customRequestOptions(metadata?: ApiHandlerCreateMessageMetadata): { headers: Record<string, string> } | undefined {
const headers: Record<string, string> = {}

if (metadata?.taskId) {
headers["X-AXON-TASK-ID"] = metadata.taskId
}

return Object.keys(headers).length > 0 ? { headers } : undefined
}

getCustomRequestHeaders(taskId?: string) {
Expand Down Expand Up @@ -208,40 +212,6 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
let { id: modelId, maxTokens, temperature, topP, reasoning } = model
const convertedMessages = [systemMessage, ...convertToOpenAiMessages(messages)]

// openAiMessages = openAiMessages
// .map((msg: any) => {
// let content = flattenMessageContent(msg.content)

// // Strip thinking tokens from assistant messages to prevent confusion
// if (msg.role === "assistant") {
// content = stripThinkingTokens(content)
// }

// return {
// role: msg.role,
// content,
// }
// })
// .filter((msg: any) => msg.content.trim() !== "")

// const transforms = (this.options.openRouterUseMiddleOutTransform ?? true) ? ["middle-out"] : undefined

console.log("convertedMessages", convertedMessages)

// https://openrouter.ai/docs/transforms
// const completionParams: OpenRouterChatCompletionParams = {
// model: modelId,
// ...(maxTokens && maxTokens > 0 && { max_tokens: maxTokens }),
// temperature,
// top_p: topP,
// messages: convertedMessages,
// stream: true,
// stream_options: { include_usage: true },
// ...this.getProviderParams(), // kilocode_change: original expression was moved into function
// ...(transforms && { transforms }),
// ...(reasoning && { reasoning }),
// }

const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
model: modelId,
temperature: 0,
Expand All @@ -256,7 +226,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
let stream
try {
console.log("requestOptions", requestOptions)
// console.log("customRequestOptions", this.customRequestOptions(metadata))
console.log("metadata", metadata)
stream = await this.client.chat.completions.create(
requestOptions,
this.customRequestOptions(metadata), // kilocode_change
Expand Down
6 changes: 6 additions & 0 deletions src/core/assistant-message/presentAssistantMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { writeToFileTool } from "../tools/writeToFileTool"
import { applyDiffTool } from "../tools/multiApplyDiffTool"
import { insertContentTool } from "../tools/insertContentTool"
import { searchAndReplaceTool } from "../tools/searchAndReplaceTool"
import { fileEditTool } from "../tools/fileEditTool"
import { editFileTool } from "../tools/editFileTool" // kilocode_change: Morph fast apply
import { listCodeDefinitionNamesTool } from "../tools/listCodeDefinitionNamesTool"
import { searchFilesTool } from "../tools/searchFilesTool"
Expand Down Expand Up @@ -201,6 +202,8 @@ export async function presentAssistantMessage(cline: Task) {
}]`
case "insert_content":
return `[${block.name} for '${block.params.path}']`
case "file_edit":
return `[${block.name} for '${block.params.target_file}']`
case "search_and_replace":
return `[${block.name} for '${block.params.path}']`
// kilocode_change start: Morph fast apply
Expand Down Expand Up @@ -508,6 +511,9 @@ export async function presentAssistantMessage(cline: Task) {
// await checkpointSaveAndMark(cline) // kilocode_change
await searchAndReplaceTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
case "file_edit":
await fileEditTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
break
// kilocode_change start: Morph fast apply
case "edit_file":
await editFileTool(cline, block, askApproval, handleError, pushToolResult, removeClosingTag)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading