Repository navigation
feat(harness): edit built-in tool - #63
Merged
Merged
Conversation
…ion handling in read tool
Rewrite `read` to match Pi's read tool: Pi's parameters, description, prompt snippet and continuation notices; text read through `scanLines` so only the shown window leaves the sandbox; images detected by magic bytes (animated PNGs excluded), converted and resized with Photon on a worker thread with EXIF orientation applied; binary files reported as unsupported; macOS path spellings resolved. Add `readBytes` to the sandbox filesystem contract, with a base64 shell form for remote backends, and an optional `encodeDetails` on tool definitions so a payload carried in content is not stored twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `write` matching Pi's write tool: Pi's parameters, description and prompt text, `Successfully wrote to <path>`, parent directories created, and the whole write held under the file's mutation lock. Make `SandboxFileSystem.writeFile` uninterruptible: a started write cannot be called back, so interrupting it only released the file's lock while its bytes still landed over the next writer's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `edit` ported from Pi's edit tool: exact-text replacements matched against the original file, exact first then fuzzy (NFKC, trailing whitespace, smart quotes, dashes, special spaces) with untouched lines kept byte for byte, CRLF and BOM preserved, Pi's error messages, and a numbered display diff plus unified patch in `details`. The whole read-match-write holds the file's mutation lock. Add `prepareArguments` to tool definitions, run by the executor before the arguments are validated, so `edit` repairs `edits` sent as a JSON string, a single object, or a top-level oldText/newText pair. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # packages/harness/src/tool/executor.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # packages/harness/src/plugin/builtin.ts # packages/harness/test/plugin.external.test.ts # packages/harness/test/plugin.git.live.test.ts # packages/plugin/src/sandbox/filesystem.ts
# Conflicts: # packages/harness/src/plugin/builtin.ts # packages/harness/test/plugin.external.test.ts # packages/harness/test/tools.write.test.ts
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.
Builds on
read(#45) andwrite(#62), both merged.editA port of Pi's edit tool (
edit.ts+edit-diff.ts), behaviour and messages unchanged:pathandedits: [{oldText, newText}]. Pi's description, prompt snippet and the four guidelines.oldTextwritten with LF matches a CRLF file.oldText, not found, multiple occurrences, overlapping edits, no change. When any edit fails, nothing is written. Access errors readCould not edit file: <path>. Error code: <code>., and a path that isn't a file getsPath is not a file.Successfully replaced N block(s) in <path>.detailscarries{ diff, patch, firstChangedLine? }: a numbered diff with 4 context lines and long unchanged gaps collapsed, plus a unified patch.Uses
diff@9.0.0, the latest. Pi pins 8.0.4; the APIs used here are unchanged in 9.prepareArgumentsA new optional tool-definition hook, as in Pi. The executor runs it before validating arguments; if it throws, the call fails as invalid arguments.
edituses it to repaireditssent as a JSON string, as a single object, or as a top-leveloldText/newTextpair. The arguments stored with the call stay exactly as the model sent them. It runs before the decoder from #61, so repaired arguments still get strict mode's null normalisation.Tests
tools.edit.test.ts: an E2E turn through the harness with 41 of Pi's cases, each on its own file. It covers multi-edit, collapsed gaps, matching against the original, every rejection, ENOENT, EACCES, not a file, symlinks, all of Pi's fuzzy cases (including line preservation), CRLF/LF/BOM, and every argument repair. Like Pi's tests, each success checks that the patch applied to the old file gives the new file. Snapshotted to__artifacts__/tools.edit.json.writetest.Known Pi behaviour, kept on purpose: overlapping occurrences (
"aa"in"aaa") count as unique, and a whitespace-only final line the edit doesn't touch makes a fuzzy edit fail with "Cannot preserve unchanged lines…".🤖 Generated with Claude Code