feat: Add hashline-based file read and edit tools#167
Merged
Conversation
Add hashline() and format_hashlines() helpers that annotate file content with line_number:hash| prefixes. Modify btw_tool_files_read to return hashline-annotated output in @value for the model while keeping clean code blocks in display.markdown for users.
Update existing tests that checked @value for code-fenced output to use expect_match with hashline regex patterns. Add new tests verifying hashline-annotated output format and correct line numbering in ranges.
Implement the edit tool with replace, insert_after, and replace_range actions. Edits are validated against hashline references from the read tool to detect concurrent modifications. Includes S7 class with diffviewer integration and full tool registration.
Cover replace, delete, insert_after, insert at top, replace_range, stale hash rejection, overlapping edit detection, multiple edits, line expansion, range deletion, and path security validation.
Run devtools::document() to create Rd file for the new edit tool and update NAMESPACE with the new export.
Add include_hashline parameter to btw_tool_files_read_impl() that defaults to TRUE. btw_this() passes include_hashline = FALSE so it returns the original code-block format instead of hashline annotations.
Invert the default so only the model-facing tool wrapper opts in to hashlines. Internal callers like btw_this() get clean output without needing to explicitly pass include_hashline = FALSE.
The edit tool response now includes hashline-annotated context around each edited region, so the model can make follow-up edits without re-reading the entire file. Nearby edits (within 10 lines) are merged into a single region. When edits change the line count, a shift hint tells the model how to adjust its cached line numbers.
- Extract validate_one_hash() to deduplicate hash validation logic - Extract splice_lines() to DRY before/after slicing in apply_edits - Extract sort_edits_ascending/descending shared sort helpers - Pre-filter insert_after edits in check_edit_overlaps - Add diffviewer warning to edit tool's contents_shinychat method - Fix sprintf no-op in edit tool shinychat path construction - Rename duplicate test name for multi-edit response test - Add tests for last-line edit and parser error paths
The edit response now returns hashlines and shift hints, so the model can chain follow-up edits without re-reading the file. Update the tool description, argument docs, and guidance to teach this workflow.
- btw_tool_files_read: Add R code examples, USAGE NOTES section, clarify argument descriptions with concrete examples - btw_tool_files_edit: Reorganize into WHEN TO USE, EDIT ACTIONS, RESPONSE FORMAT, WORKFLOW, and NOTES sections; add hashline reference example; clarify atomic behavior - btw_tool_files_replace: Add HOW IT WORKS section, use case examples, TIPS FOR SUCCESS guidance; improve argument clarity
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.
Implements the hashline approach described in The Harness Problem — content-hash line annotations for reliable, validated file editing.
Summary
btw_tool_files_read: Each line returned to the model is now prefixed withline_number:hash|(e.g.2:f1a| return("world")). The 3-character hash is derived fromrlang::hash()over trimmed, 80-char-truncated content. Thedisplay.markdownshown to users remains a clean code block.btw_tool_files_edittool: Uses hashline references from the read output to make targeted edits —replace,insert_after, andreplace_rangeactions. Hashes are validated against the current file state, so stale edits are rejected atomically. Multiple edits in a single call are applied bottom-to-top to preserve line numbering.include_hashlineparameter: Defaults toFALSEin the_impl()function so internal callers likebtw_this()get clean output. Only the model-facing tool wrapper passesTRUE.Edit response format
The response is tiered by complexity:
Example tier 2 response (insert 2 lines after line 2):
Verification