@kennyfrc/pi-str-replace-editor
v0.1.1
Published
Model-facing str_replace_editor (view/create/str_replace/insert) for DeepSeek-family models on Pi; replaces read/edit/write for those models
Maintainers
Readme
pi-str-replace-editor
Model-facing str_replace_editor (view / create / str_replace / insert) for Pi,
enabled only for DeepSeek-family models, where it replaces the built-in read,
edit, and write tools.
Why
DeepSeek-family models are tuned on the canonical Claude Code str_replace_editor
surface (cat -n views, unique literal old_str, insert-after-line). Serving them
pi's edit/write JSON contract wastes tokens and turns. This extension gives
DeepSeek models the tool they were trained for and removes the three built-in
tools that become redundant (view covers read, create covers write,
str_replace/insert cover edit). bash, grep, find, ls stay active.
Semantics are a faithful port of the reference RL harness's
str_replace_editor tool; its benchmark suite
(tools.spec.ts) is re-characterized in test/engine.test.ts.
Gating
- A model is "deepseek" when its id, provider, or display name matches
/deepseek/i(case-insensitive, router-robust). session_start+model_selectswap the active tool set:- deepseek:
read/edit/writeremoved,str_replace_editoradded, andgrep/find/lsremoved by default — leavingbash+str_replace_editor, the harness minimal-preset shape those models were tuned on. Search goes throughbash grep -rn/find/lsorstr_replace_editor viewon a directory. - everyone else:
str_replace_editorremoved,read/edit/writeandgrep/find/lsrestored. GPT-family models keepedit/writeexactly as-is (pi-apply-patch owns them there), so the two extensions never fight.
- deepseek:
- Defense in depth:
tool_callblocks a deepseek model that somehow callsread/edit/write(pointer atstr_replace_editor) and any other model that callsstr_replace_editor(pointer atread/edit/write). No ordering race between extensions can produce a wrong write.
Config file ~/.pi/agent/pi-str-replace-editor.json (optional):
{
"mode": "auto",
"deepseekPatterns": ["deepseek"],
"extraDisabledTools": ["grep", "find", "ls"]
}mode:auto(default) |on(editor for every model) |off.deepseekPatterns: regex list tested against id/provider/name.extraDisabledTools: additional tool names hidden for deepseek models (default["grep", "find", "ls"]; set to[]to keep those three).
Improvements over the harness
- Syntax highlighting in the TUI for
viewresults (pi's highlighter), plus a display diff forstr_replaceresults. - Better errors / fallbacks:
- old_str not found → closest lines with their line numbers + CRLF hint.
- relative paths → the cwd-resolved absolute suggestion (
Maybe you meant /abs/path?). - missing parent directory →
mkdir -phint; vanished files → FS_NOT_FOUND. - binary files → refused with a bash/xxd fallback hint.
viewon an image returns the image as an attachment.prepareArgumentsaccepts legacy shapes (unadvertised):file_path,file://prefixes, backtick-wrapped paths,replace_all: true.
- Concurrency: every mutation runs inside pi's
withFileMutationQueue, so parallel tool calls on the same file serialize instead of losing updates. - Error codes (
FS_NOT_FOUND,FS_EDIT_NOT_FOUND,FS_AMBIGUOUS_EDIT, …) mirror the harness vocabulary.
Development
npm run check:str-replace-editor # typecheck
npm run test:str-replace-editor # benchmark port + adversarial battery