[PR #1550] [CLOSED] fix: address "oldString not found in content" and more #9971

Closed
opened 2026-02-16 18:14:29 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/anomalyco/opencode/pull/1550
Author: @rstacruz
Created: 8/2/2025
Status: Closed

Base: devHead: feat-enable-replacers


📝 Commits (2)

  • 0c954a6 feat(edit): enable advanced replacers for string replacement
  • 2a00354 Merge branch 'dev' into feat-enable-replacers

📊 Changes

1 file changed (+3 additions, -3 deletions)

View changed files

📝 packages/opencode/src/tool/edit.ts (+3 -3)

📄 Description

Context

  • EscapeNormalizedReplacer, TrimmedBoundaryReplacer, ContextAwareReplacer, and MultiOccurrenceReplacer were disabled in cf83e31f ("add elixir lsp support") on 3 July 2025
  • This seems unrelated to Elixir LSP work

Solution

  • This enables these replacers.
  • This should help alleviate "oldString not found in content or was found multiple times" errors.
  • This also makes tests pass.

What tests?

cd packages/opencode && bun test test/tool/edit.test.ts

✓ EditTool Replacers > case 18
471 |       const lastIndex = content.lastIndexOf(search)
472 |       if (index !== lastIndex) continue
473 |       return content.substring(0, index) + newString + content.substring(index + search.length)
474 |     }
475 |   }
476 |   throw new Error("oldString not found in content or was found multiple times")
                                                                                    ^
error: oldString not found in content or was found multiple times
      at replace (/home/rsc/Dev/@github/opencode/packages/opencode/src/tool/edit.ts:476:79)
      at <anonymous> (/home/rsc/Dev/@github/opencode/packages/opencode/test/tool/edit.test.ts:338:22)
✗ EditTool Replacers > case 19 [1.00ms]
471 |       const lastIndex = content.lastIndexOf(search)
472 |       if (index !== lastIndex) continue
473 |       return content.substring(0, index) + newString + content.substring(index + search.length)
474 |     }
475 |   }
476 |   throw new Error("oldString not found in content or was found multiple times")

What do they do?

Disclaimer: These examples were made with the help of OpenCode and Sonnet 4.

  • TrimmedBoundaryReplacer matches by trimming whitespace boundaries @ src/tool/edit.ts:329-353

    # Content has:
    def calculate():
        return 42
    
    # LLM searches for (with extra whitespace):
        def calculate():
            return 42
    
    # Matches by trimming boundaries
    
  • ContextAwareReplacer uses first/last line anchors with fuzzy middle matching @ src/tool/edit.ts:355-411

    // Content has:
    function processUser(LLM) {
      const validated = validateUser(LLM)
      const processed = transformUser(validated)
      return processed
    }
    
    // LLM searches for (different middle):
    function processUser(LLM) {
      const valid = validateUser(LLM)
      const result = transformUser(valid)
      return processed
    }
    
    // Matches: same first/last lines + >50% middle similarity
    
  • MultiOccurrenceReplacer handles multiple identical occurrences @ src/tool/edit.ts:315-327

    /* Content has: */
    .button { color: red; }
    .link { color: red; }
    .text { color: red; }
    
    /* Finds all "red" occurrences for replaceAll=true */
    

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/anomalyco/opencode/pull/1550 **Author:** [@rstacruz](https://github.com/rstacruz) **Created:** 8/2/2025 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `feat-enable-replacers` --- ### 📝 Commits (2) - [`0c954a6`](https://github.com/anomalyco/opencode/commit/0c954a662be8c41b99c7629b1f1864ef0e05e2fb) feat(edit): enable advanced replacers for string replacement - [`2a00354`](https://github.com/anomalyco/opencode/commit/2a00354126f8f59d66cadae1871dc72e46459e5b) Merge branch 'dev' into feat-enable-replacers ### 📊 Changes **1 file changed** (+3 additions, -3 deletions) <details> <summary>View changed files</summary> 📝 `packages/opencode/src/tool/edit.ts` (+3 -3) </details> ### 📄 Description ### Context - EscapeNormalizedReplacer, TrimmedBoundaryReplacer, ContextAwareReplacer, and MultiOccurrenceReplacer were disabled in cf83e31f ("add elixir lsp support") on 3 July 2025 - This seems unrelated to Elixir LSP work ### Solution - This enables these replacers. - This should help alleviate "oldString not found in content or was found multiple times" errors. - This also makes tests pass. ### What tests? ``` cd packages/opencode && bun test test/tool/edit.test.ts ✓ EditTool Replacers > case 18 471 | const lastIndex = content.lastIndexOf(search) 472 | if (index !== lastIndex) continue 473 | return content.substring(0, index) + newString + content.substring(index + search.length) 474 | } 475 | } 476 | throw new Error("oldString not found in content or was found multiple times") ^ error: oldString not found in content or was found multiple times at replace (/home/rsc/Dev/@github/opencode/packages/opencode/src/tool/edit.ts:476:79) at <anonymous> (/home/rsc/Dev/@github/opencode/packages/opencode/test/tool/edit.test.ts:338:22) ✗ EditTool Replacers > case 19 [1.00ms] 471 | const lastIndex = content.lastIndexOf(search) 472 | if (index !== lastIndex) continue 473 | return content.substring(0, index) + newString + content.substring(index + search.length) 474 | } 475 | } 476 | throw new Error("oldString not found in content or was found multiple times") ``` ### What do they do? > Disclaimer: These examples were made with the help of OpenCode and Sonnet 4. <!-- - `EscapeNormalizedReplacer` handles escaped characters in strings @ `src/tool/edit.ts:266-313` ```javascript // Content has: console.log("Hello\nWorld") // LLM searches for: console.log("Hello\\nWorld") // Matches by unescaping both to find same logical content ``` --> - `TrimmedBoundaryReplacer` matches by trimming whitespace boundaries @ `src/tool/edit.ts:329-353` ```python # Content has: def calculate(): return 42 # LLM searches for (with extra whitespace): def calculate(): return 42 # Matches by trimming boundaries ``` - `ContextAwareReplacer` uses first/last line anchors with fuzzy middle matching @ `src/tool/edit.ts:355-411` ```typescript // Content has: function processUser(LLM) { const validated = validateUser(LLM) const processed = transformUser(validated) return processed } // LLM searches for (different middle): function processUser(LLM) { const valid = validateUser(LLM) const result = transformUser(valid) return processed } // Matches: same first/last lines + >50% middle similarity ``` - `MultiOccurrenceReplacer` handles multiple identical occurrences @ `src/tool/edit.ts:315-327` ```css /* Content has: */ .button { color: red; } .link { color: red; } .text { color: red; } /* Finds all "red" occurrences for replaceAll=true */ ``` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-16 18:14:29 -05:00
yindo closed this issue 2026-02-16 18:14:29 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#9971