Skip to content

Commit e869d72

Browse files
authored
Merge pull request #13 from rusiaaman/hotfix/searchreplace
Hotfix: context issue in edit distance based editing
2 parents 7e8a647 + f7f77d5 commit e869d72

File tree

7 files changed

+24
-15
lines changed

7 files changed

+24
-15
lines changed

gpt_instructions.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Instructions for `BashCommand`:
1616
- Do not use interactive commands like nano. Prefer writing simpler commands.
1717
- Status of the command and the current working directory will always be returned at the end.
1818
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
19-
- The first line might be `(...truncated)` if the output is too long.
19+
- The first or the last line might be `(...truncated)` if the output is too long.
2020
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
2121
- Run long running commands in background using screen instead of "&".
2222

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
authors = [{ name = "Aman Rusia", email = "[email protected]" }]
33
name = "wcgw"
4-
version = "2.2.1"
4+
version = "2.2.2"
55
description = "Shell and coding agent on claude and chatgpt"
66
readme = "README.md"
77
requires-python = ">=3.11, <3.13"

src/wcgw/client/anthropic_client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def loop(
169169
- Do not use interactive commands like nano. Prefer writing simpler commands.
170170
- Status of the command and the current working directory will always be returned at the end.
171171
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
172-
- The first line might be `(...truncated)` if the output is too long.
172+
- The first or the last line might be `(...truncated)` if the output is too long.
173173
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
174174
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
175175
- Run long running commands in background using screen instead of "&".

src/wcgw/client/mcp_server/server.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ async def handle_list_tools() -> list[types.Tool]:
8989
- Do not use interactive commands like nano. Prefer writing simpler commands.
9090
- Status of the command and the current working directory will always be returned at the end.
9191
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
92-
- The first line might be `(...truncated)` if the output is too long.
92+
- The first or the last line might be `(...truncated)` if the output is too long.
9393
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
9494
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
9595
- Run long running commands in background using screen instead of "&".

src/wcgw/client/openai_client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def loop(
172172
- Do not use interactive commands like nano. Prefer writing simpler commands.
173173
- Status of the command and the current working directory will always be returned at the end.
174174
- Optionally `exit shell has restarted` is the output, in which case environment resets, you can run fresh commands.
175-
- The first line might be `(...truncated)` if the output is too long.
175+
- The first or the last line might be `(...truncated)` if the output is too long.
176176
- Always run `pwd` if you get any file or directory not found error to make sure you're not lost.
177177
- The control will return to you in 5 seconds regardless of the status. For heavy commands, keep checking status using BashInteraction till they are finished.
178178
- Run long running commands in background using screen instead of "&".

src/wcgw/client/tools.py

+18-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import importlib.metadata
1414
import time
1515
import traceback
16-
from tempfile import TemporaryDirectory
16+
from tempfile import NamedTemporaryFile, TemporaryDirectory
1717
from typing import (
1818
Callable,
1919
Literal,
@@ -412,7 +412,7 @@ def execute_bash(
412412
tokens = enc.encode(text)
413413

414414
if max_tokens and len(tokens) >= max_tokens:
415-
text = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
415+
text = "(...truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
416416

417417
if is_interrupt:
418418
text = (
@@ -441,7 +441,7 @@ def execute_bash(
441441

442442
tokens = enc.encode(output)
443443
if max_tokens and len(tokens) >= max_tokens:
444-
output = "...(truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
444+
output = "(...truncated)\n" + enc.decode(tokens[-(max_tokens - 1) :])
445445

446446
try:
447447
exit_status = get_status()
@@ -592,7 +592,7 @@ def write_file(writefile: WriteIfEmpty, error_on_exist: bool) -> str:
592592

593593
def find_least_edit_distance_substring(
594594
content: str, find_str: str
595-
) -> tuple[str, float]:
595+
) -> tuple[str, str, float]:
596596
orig_content_lines = content.split("\n")
597597
content_lines = [
598598
line.strip() for line in orig_content_lines
@@ -612,6 +612,7 @@ def find_least_edit_distance_substring(
612612
# Slide window and find one with sum of edit distance least
613613
min_edit_distance = float("inf")
614614
min_edit_distance_lines = []
615+
context_lines = []
615616
for i in range(max(1, len(content_lines) - len(find_lines) + 1)):
616617
edit_distance_sum = 0
617618
for j in range(len(find_lines)):
@@ -629,27 +630,35 @@ def find_least_edit_distance_substring(
629630
+ 1
630631
)
631632
min_edit_distance_lines = orig_content_lines[
633+
orig_start_index:orig_end_index
634+
]
635+
636+
context_lines = orig_content_lines[
632637
max(0, orig_start_index - 10) : (orig_end_index + 10)
633638
]
634-
return "\n".join(min_edit_distance_lines), min_edit_distance
639+
return (
640+
"\n".join(min_edit_distance_lines),
641+
"\n".join(context_lines),
642+
min_edit_distance,
643+
)
635644

636645

637646
def edit_content(content: str, find_lines: str, replace_with_lines: str) -> str:
638647
count = content.count(find_lines)
639648
if count == 0:
640-
closest_match, min_edit_distance = find_least_edit_distance_substring(
641-
content, find_lines
649+
closest_match, context_lines, min_edit_distance = (
650+
find_least_edit_distance_substring(content, find_lines)
642651
)
643652
if min_edit_distance == 0:
644-
return edit_content(content, closest_match, replace_with_lines)
653+
return content.replace(closest_match, replace_with_lines, 1)
645654
else:
646655
print(
647656
f"Exact match not found, found with whitespace removed edit distance: {min_edit_distance}"
648657
)
649658
raise Exception(
650659
f"""Error: no match found for the provided search block.
651660
Requested search block: \n```\n{find_lines}\n```
652-
Possible relevant section in the file:\n---\n```\n{closest_match}\n```\n---\nFile not edited
661+
Possible relevant section in the file:\n---\n```\n{context_lines}\n```\n---\nFile not edited
653662
\nPlease retry with exact search. Re-read the file if unsure.
654663
"""
655664
)

uv.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)