Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit 8e2ffae

Browse files
committed
WIP: smarter edit algorithm
1 parent 02f0908 commit 8e2ffae

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

lib/ai_bot/artifact_update_strategies/diff.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,18 @@ def system_prompt
9898
9999
1. Use EXACTLY this format for changes:
100100
<<<<<<< SEARCH
101-
(exact code to find)
101+
(first line of code to replace)
102+
(other lines of code to avoid ambiguity)
103+
(last line of code to replace)
102104
=======
103105
(replacement code)
104106
>>>>>>> REPLACE
105107
2. DO NOT modify the markers or add spaces around them
106108
3. DO NOT add explanations or comments within sections
107109
4. ONLY include [HTML], [CSS], and [JavaScript] sections if they have changes
108-
5. Ensure search text matches EXACTLY - partial matches will fail
109-
6. Keep changes minimal and focused
110-
7. HTML should not include <html>, <head>, or <body> tags, it is injected into a template
110+
5. Keep changes minimal and focused
111+
6. HTML should not include <html>, <head>, or <body> tags, it is injected into a template
112+
7. When specifying a SEARCH block, ALWAYS keep it 8 lines or less, you will be interrupted and a retry will be required if you exceed this limit
111113
112114
JavaScript libraries must be sourced from the following CDNs, otherwise CSP will reject it:
113115
#{AiArtifact::ALLOWED_CDN_SOURCES.join("\n")}

lib/utils/diff_utils/simple_diff.rb

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def apply(content, search, replace)
2626
lines = content.split("\n")
2727
search_lines = search.split("\n")
2828

29+
### TODO implement me
30+
2931
# 1. Try exact matching
3032
match_positions =
3133
find_matches(lines, search_lines) { |line, search_line| line == search_line }
@@ -38,15 +40,25 @@ def apply(content, search, replace)
3840
end
3941
end
4042

41-
# 3. Try fuzzy matching
43+
# 3. Try non-contiguous line based stripped matching
44+
if match_positions.empty?
45+
if range = non_contiguous_match_range(lines, search_lines)
46+
first_match, last_match = range
47+
lines.slice!(first_match, last_match - first_match + 1)
48+
lines.insert(first_match, *replace.split("\n"))
49+
return lines.join("\n")
50+
end
51+
end
52+
53+
# 4. Try fuzzy matching
4254
if match_positions.empty?
4355
match_positions =
4456
find_matches(lines, search_lines) do |line, search_line|
4557
fuzzy_match?(line, search_line)
4658
end
4759
end
4860

49-
# 4. Try block matching as last resort
61+
# 5. Try block matching as last resort
5062
if match_positions.empty?
5163
if block_matches = find_block_matches(content, search)
5264
return replace_blocks(content, block_matches, replace)
@@ -68,6 +80,23 @@ def apply(content, search, replace)
6880

6981
private
7082

83+
def non_contiguous_match_range(lines, search_lines)
84+
first_idx = nil
85+
last_idx = nil
86+
search_index = 0
87+
88+
lines.each_with_index do |line, idx|
89+
if line.strip == search_lines[search_index].strip
90+
first_idx ||= idx
91+
last_idx = idx
92+
search_index += 1
93+
return first_idx, last_idx if search_index == search_lines.length
94+
end
95+
end
96+
97+
nil
98+
end
99+
71100
def find_matches(lines, search_lines)
72101
matches = []
73102
max_index = lines.length - search_lines.length

spec/lib/utils/diff_utils/simple_diff_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,31 @@
171171

172172
expect(subject.apply(content, search, replace).strip).to eq(expected.strip)
173173
end
174+
175+
it "handles missing lines in search" do
176+
original = <<~TEXT
177+
line1
178+
line2
179+
line3
180+
line4
181+
line5
182+
line1
183+
line2
184+
TEXT
185+
186+
search = <<~TEXT
187+
line1
188+
line3
189+
line1
190+
TEXT
191+
192+
replace = ""
193+
194+
expected = <<~TEXT
195+
line2
196+
TEXT
197+
198+
expect(subject.apply(original, search, replace).strip).to eq(expected.strip)
199+
end
174200
end
175201
end

0 commit comments

Comments
 (0)