Simplify file tool interfaces
This commit is contained in:
parent
9bd9539b6a
commit
35c6ee6b44
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"description": "Replace text in a file. Has fuzzy matching (whitespace/indent flexible).",
|
||||
"outputFormat": "diff",
|
||||
"prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional)\n\n```\nfile_edit(path=\"<ABSOLUTE_PATH_FROM_PWD>\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"<ABSOLUTE_PATH_FROM_PWD>\", old_string=\"old text\", new_string=\"new text\", replace_all=\"true\")\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations \u2014 add surrounding context to disambiguate, or use `replace_all=true`.",
|
||||
"prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional boolean)\n\n```\nfile_edit(path=\"<ABSOLUTE_PATH_FROM_PWD>\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"<ABSOLUTE_PATH_FROM_PWD>\", old_string=\"old text\", new_string=\"new text\", replace_all=true)\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations \u2014 add surrounding context to disambiguate, or use `replace_all=true`.",
|
||||
"args": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -23,8 +23,8 @@
|
|||
"description": "Replacement text"
|
||||
},
|
||||
"replace_all": {
|
||||
"type": "string",
|
||||
"description": "Set to true/1/yes to replace all occurrences"
|
||||
"type": "boolean",
|
||||
"description": "Replace all occurrences (default: false)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"description": "Find files by glob pattern, sorted by mtime (newest first).",
|
||||
"prompt": "## file_glob\n\nFind files by glob pattern, sorted by mtime (newest first).\n\n**Args**: `[pattern]` or `[pattern, search_dir]`\n\n- First arg: glob pattern (e.g. `\"*.go\"`, `\"**/*.ts\"`).\n- Second arg (optional): absolute search directory. Defaults to cwd.\n\n```\nfile_glob(pattern=\"*.go\", search_dir=\"<ABSOLUTE_SEARCH_DIR>\")\nfile_glob(pattern=\"**/*.go\")\n```",
|
||||
"description": "Find files by Go filepath pattern, sorted by mtime (newest first).",
|
||||
"prompt": "## file_glob\n\nFind files by Go filepath pattern, sorted by mtime (newest first).\n\n**Args**: `pattern` (required), optional `search_dir`\n\n- `pattern`: Go filepath matching syntax, such as `*.go` or `**/*.ts`. Shell brace expansion is not supported.\n- `search_dir`: absolute search directory. Defaults to cwd.\n\n```\nfile_glob(pattern=\"*.go\", search_dir=\"<ABSOLUTE_SEARCH_DIR>\")\nfile_glob(pattern=\"**/*.go\")\n```",
|
||||
"args": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"description": "Search file contents with ripgrep. Capped at 50 matches by default.",
|
||||
"prompt": "## file_grep\n\nSearch file contents with ripgrep. Capped at 50 matches by default.\n\n**Args**: `pattern` (required), plus optional named params.\n\n```\nfile_grep(pattern=\"pattern\", path=\"<ABSOLUTE_SEARCH_DIR>\")\nfile_grep(pattern=\"TODO\", path=\"src/\", glob=\"*.go\", case_insensitive=true)\nfile_grep(pattern=\"func main\", path=\"<ABSOLUTE_SEARCH_DIR>\")\n```\n\n- `path`: search directory (not a positional arg)\n- `glob`: file glob filter\n- `case_insensitive`: boolean\n\n**Params**: `path`, `mode` (content|files_with_matches|count), `glob`, `type`, `case_insensitive`, `before`, `after`, `context`, `multiline`, `head`, `offset`.",
|
||||
"description": "Search file contents with a regular expression.",
|
||||
"prompt": "## file_grep\n\nSearch file contents with a regular expression.\n\n**Args**: `pattern` (required), plus optional named params.\n\n```\nfile_grep(pattern=\"pattern\", path=\"<ABSOLUTE_SEARCH_DIR>\")\nfile_grep(pattern=\"TODO\", path=\"<ABSOLUTE_SEARCH_DIR>\", glob=\"*.go\", case_insensitive=true)\n```\n\n- `path`: absolute search directory. Defaults to cwd.\n- `glob`: file glob filter.\n- `case_insensitive`: boolean.\n- `multiline`: boolean. When true, the regex can match across line breaks; content results show the match and its starting line.\n- `mode`: `content` (default), `files_with_matches`, or `count`.\n- `head`: maximum results to return (default: 50).\n- `offset`: number of results to skip.",
|
||||
"args": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
@ -31,21 +31,9 @@
|
|||
"type": "boolean",
|
||||
"description": "Case-insensitive search"
|
||||
},
|
||||
"after": {
|
||||
"type": "integer",
|
||||
"description": "Lines after match (-A)"
|
||||
},
|
||||
"before": {
|
||||
"type": "integer",
|
||||
"description": "Lines before match (-B)"
|
||||
},
|
||||
"context": {
|
||||
"type": "integer",
|
||||
"description": "Lines around match (-C)"
|
||||
},
|
||||
"multiline": {
|
||||
"type": "boolean",
|
||||
"description": "Enable multiline matching"
|
||||
"description": "Allow matches to span multiple lines"
|
||||
},
|
||||
"head": {
|
||||
"type": "integer",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"description": "Create or overwrite a file. Produces a unified diff.",
|
||||
"description": "Create or overwrite a file. Use for new files or intentional full-file replacement; use file_edit for targeted changes.",
|
||||
"outputFormat": "diff",
|
||||
"prompt": "## file_write\n\nCreate or overwrite a file. Produces a unified diff.\n\n**Args**: `[path, content]`\n\n```\nfile_write(path=\"<ABSOLUTE_PATH_FROM_PWD>\", content=\"file content here\")\n```\n\n**Constraints**: Absolute paths only. Parent directory must exist.",
|
||||
"prompt": "## file_write\n\nCreate or overwrite a file. Use for new files or intentional full-file replacement. Use `file_edit` for targeted changes.\n\n**Args**: `path`, `content` (required)\n\n```\nfile_write(path=\"<ABSOLUTE_PATH_FROM_PWD>\", content=\"file content here\")\n```\n\n**Constraints**: Absolute paths only. Parent directory must exist.",
|
||||
"args": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -522,13 +522,28 @@ func Grep(m map[string]any) (string, error) {
|
|||
if er != nil {
|
||||
return nil
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
matches := 0
|
||||
for i, line := range lines {
|
||||
if re.MatchString(line) {
|
||||
multiline, er := Bool(m, "multiline")
|
||||
if er != nil {
|
||||
return er
|
||||
}
|
||||
if multiline {
|
||||
for _, match := range re.FindAllStringIndex(string(data), -1) {
|
||||
matches++
|
||||
if mode == "content" {
|
||||
results = append(results, fmt.Sprintf("%s:%d:%s", p, i+1, line))
|
||||
text := string(data[match[0]:match[1]])
|
||||
line := 1 + strings.Count(string(data[:match[0]]), "\n")
|
||||
results = append(results, fmt.Sprintf("%s:%d:%s", p, line, text))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i, line := range lines {
|
||||
if re.MatchString(line) {
|
||||
matches++
|
||||
if mode == "content" {
|
||||
results = append(results, fmt.Sprintf("%s:%d:%s", p, i+1, line))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func TestDiffOmitsUnchangedFileContent(t *testing.T) {
|
|||
func TestGlobAndGrep(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
os.MkdirAll(filepath.Join(d, "sub"), 0755)
|
||||
os.WriteFile(filepath.Join(d, "a.go"), []byte("TODO: yes\n"), 0644)
|
||||
os.WriteFile(filepath.Join(d, "a.go"), []byte("TODO: yes\nnext line\n"), 0644)
|
||||
os.WriteFile(filepath.Join(d, "sub", "b.go"), []byte("todo: no\n"), 0644)
|
||||
out, err := Glob(map[string]any{"pattern": "**/*.go", "search_dir": d})
|
||||
if err != nil || !strings.Contains(out, "b.go") {
|
||||
|
|
@ -79,6 +79,10 @@ func TestGlobAndGrep(t *testing.T) {
|
|||
if err != nil || !strings.Contains(out, "a.go") || !strings.Contains(out, "b.go") {
|
||||
t.Fatal(out, err)
|
||||
}
|
||||
out, err = Grep(map[string]any{"pattern": "TODO: yes\\nnext line", "path": d, "glob": "a.go", "multiline": true})
|
||||
if err != nil || !strings.Contains(out, ":1:TODO: yes\nnext line") {
|
||||
t.Fatalf("multiline grep=%q err=%v", out, err)
|
||||
}
|
||||
_, err = Grep(map[string]any{"pattern": "[", "path": d})
|
||||
if err == nil || !strings.Contains(err.Error(), "regular expression") {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
Loading…
Reference in New Issue