Class: Tools::Edit

Inherits:
Base
  • Object
show all
Defined in:
lib/tools/edit.rb

Overview

Performs surgical text replacement with uniqueness constraint. Finds old_text in the file (must match exactly one location), replaces with new_text, and returns a unified diff. Falls back to whitespace-normalized fuzzy matching when exact match fails.

Normalizes BOM and CRLF line endings for matching, restoring them after the edit. Rejects ambiguous edits where old_text matches zero or multiple locations.

Examples:

Replacing a method body

tool.execute("path" => "app.rb",
             "old_text" => "def greet\n  'hi'\nend",
             "new_text" => "def greet\n  'hello'\nend")
# => "--- app.rb\n+++ app.rb\n@@ -1,3 +1,3 @@\n ..."

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

schema

Constructor Details

#initialize(shell_session: nil) ⇒ Edit

Returns a new instance of Edit.

Parameters:

  • shell_session (ShellSession, nil) (defaults to: nil)

    provides working directory for resolving relative paths



38
39
40
# File 'lib/tools/edit.rb', line 38

def initialize(shell_session: nil, **)
  @working_directory = shell_session&.pwd
end

Class Method Details

.descriptionObject



21
22
23
# File 'lib/tools/edit.rb', line 21

def self.description = "Replace exact text in a file. old_text must match exactly one location; " \
"include surrounding lines for uniqueness. Use for surgical edits; " \
"use write for new files or full replacement."

.input_schemaObject



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/tools/edit.rb', line 25

def self.input_schema
  {
    type: "object",
    properties: {
      path: {type: "string", description: "Absolute or relative file path (relative resolved against working directory)"},
      old_text: {type: "string", description: "Exact text to find (must match exactly one location — include surrounding context if needed)"},
      new_text: {type: "string", description: "Replacement text (empty string to delete)"}
    },
    required: %w[path old_text new_text]
  }
end

.tool_nameObject



19
# File 'lib/tools/edit.rb', line 19

def self.tool_name = "edit"

Instance Method Details

#execute(input) ⇒ String, Hash

Parameters:

  • input (Hash<String, Object>)

    string-keyed hash from the Anthropic API

Returns:

  • (String)

    unified diff showing the change

  • (Hash)

    with :error key on failure



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/tools/edit.rb', line 45

def execute(input)
  path, old_text, new_text = extract_params(input)
  return {error: "Path cannot be blank"} if path.empty?
  return {error: "old_text cannot be blank"} if old_text.empty?

  path = resolve_path(path)

  error = validate_file(path)
  return error if error

  edit_file(path, old_text, new_text)
end