Repository navigation
Conversation
yaoyi1222
force-pushed
the
fix/edit-fuzzy-match-strategy
branch
from
August 27, 2026 06:10
aeb843f to
e3c04a0
Compare
edit.txt tells the model the tool "Performs exact string replacements in
files", that it must "preserve the exact indentation (tabs/spaces)", and that
the edit "will FAIL if oldString is not found in the file". The not-found
error repeats it: "It must match exactly, including whitespace, indentation,
and line endings."
That is not what happens. replace() tries SimpleReplacer (byte-exact) first,
then eight tolerant fallbacks. When a fallback wins, the tool returns the same
plain "Edit applied successfully." as an exact match, so the only thing the
caller can conclude from the documented contract is that oldString matched
exactly, indentation included - and that is wrong. A wrong oldString, e.g.
4-space indentation where the file has 3, is silently absorbed and the line is
rewritten with the wrong indentation.
The winning strategy was already known inside the loop; it was just dropped at
return. replace() now returns { content, strategy } and the chain is a list of
[name, replacer] pairs. On a non-exact hit the tool appends a note naming the
strategy and echoes the diff. matchStrategy is added to the tool metadata.
Fuzzy tolerance itself is unchanged - only the reporting.
yaoyi1222
force-pushed
the
fix/edit-fuzzy-match-strategy
branch
from
August 27, 2026 06:18
e3c04a0 to
f7956a0
Compare
yaoyi1222
marked this pull request as ready for review
August 27, 2026 06:20
Contributor
|
Automated PR Cleanup Thank you for contributing to opencode. Due to the high volume of PRs from users and AI agents, we periodically close older PRs using automated criteria so maintainers can focus review time on the most active and community-supported contributions. This PR was closed because it matched the following cleanup criteria:
PRs created within the last month are not affected by this cleanup. If you believe this PR was closed incorrectly, or if you are still actively working on it, please leave a comment explaining why it should be reopened. A maintainer can review and reopen it if appropriate. Thanks again for taking the time to contribute. |
1 task done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue for this PR
Closes #34424
This covers points 2 and 3 of that issue. Points 1, 4 and 5 are out of scope here and can be tracked separately.
Type of change
What does this PR do?
edit.txttells the model the tool "Performs exact string replacements in files", that it must "preserve the exact indentation (tabs/spaces)", and that "the edit will FAIL ifoldStringis not found in the file". The not-found error says the same thing: "It must match exactly, including whitespace, indentation, and line endings."That is not what happens.
replace()triesSimpleReplacer(byte-exact) first, then eight tolerant fallbacks. When a fallback wins, the tool returns the same plain"Edit applied successfully."as an exact match. Given the contract above, the only thing the model can conclude from that is "myoldStringmatched exactly, indentation included" — and it is wrong. A wrongoldString, e.g. 4-space indentation where the file has 3, is silently absorbed and the line gets rewritten with the wrong indentation.The strategy that won was already known inside the loop; it was just being dropped at
return.replace()returns{ content, strategy }instead of a bare string, and the chain is a list of[name, replacer]pairs so the winning matcher comes back with the result.matchStrategyis added to the tool metadata.Three things I deliberately did not do:
edit.txtinstead. That is the other way to resolve a docs-vs-behaviour mismatch, but a static "sometimes it matches loosely" cannot tell the model whether this particular call was loose. The per-call signal is the part that is missing.contentOld.includes(oldString). Looks cheaper, but it reportsexactincorrectly whenSimpleReplacermatches in more than one place: the loopcontinues past it (index !== lastIndex), a fuzzy replacer wins, andincludesis still true. Changing the signature costs the same and does not lie —replace()has exactly one caller in the repo (edit.ts:133), and the tests go throughEditTool, notreplacedirectly.Related: #44996 is the same mismatch on the failure path (the not-found error text). Left alone to keep this focused.
How did you verify your code works?
beta_line(3 spaces),oldStringhas 4. AssertsmatchStrategy === "line-trimmed", that the note names the strategy, and that the diff is echoed.matchStrategy === "exact"and that no note is emitted, so the exact path stays byte-identical to before.bun test test/tool/edit.test.ts— 30/30 pass. (rejects empty oldString on existing filesintermittently hits the 5s timeout on my machine, but it does that on a cleandevcheckout too, with my changes stashed.)bun test test/acp/tool.test.ts— 9/9 pass. These assert the exact"Edit applied successfully."string, so they confirm the exact path is untouched.bun run typecheckinpackages/opencode— clean.To see the original behaviour on
dev: create a file with a 3-space-indented line, calleditwith a 4-space-indentedoldString, and note the output is indistinguishable from an exact match.Screenshots / recordings
n/a — not a UI change.
Checklist