diff --git a/data/tools/file_read.meta b/data/tools/file_read.meta index 9157828..dc68ace 100644 --- a/data/tools/file_read.meta +++ b/data/tools/file_read.meta @@ -1,6 +1,6 @@ { "description": "Read a file with line numbers. Prefer segments over full reads.", - "prompt": "## file_read\n\nRead a file with line numbers. Prefer segments over full reads.\n\n**Args**: `path` (required), `start`, `end`, or `head`\n\n- `start`/`end`: 1-indexed line numbers, inclusive. Must be strings. Max segment: 2000 lines.\n- No start/end: reads up to 500 lines from line 1.\n- `head`: read first N lines (alternative to start/end).\n\n```\nfile_read(path=\"\")\nfile_read(path=\"\", start=\"100\", end=\"200\")\nfile_read(path=\"\", head=\"50\")\n```\n\n- `start`/`end` are strings even though they represent numbers.\n- Use `head` as alternative to `start`/`end`.\n\n**Constraints**: Absolute paths only.", + "prompt": "## file_read\n\nRead a file with line numbers. Prefer segments over full reads.\n\n**Args**: `path` (required), `start`, `end`, or `head`\n\n- `start`/`end`: 1-indexed line numbers, inclusive. Use integers. Max segment: 2000 lines.\n- No start/end: reads up to 500 lines from line 1.\n- `head`: read first N lines (alternative to start/end).\n\n```\nfile_read(path=\"\")\nfile_read(path=\"\", start=100, end=200)\nfile_read(path=\"\", head=50)\n```\n\n- Use `start`/`end` as integers even though they represent line numbers.\n- Use `head` as an integer alternative to `start`/`end`.\n\n**Constraints**: Absolute paths only.", "args": { "type": "object", "required": [ @@ -12,16 +12,16 @@ "description": "Absolute path to file" }, "start": { - "type": "string", - "description": "1-indexed start line (default: 1)" + "type": "integer", + "description": "1-indexed start line (default: 1). Use an integer." }, "end": { - "type": "string", - "description": "1-indexed end line, inclusive (max 2000 line segment)" + "type": "integer", + "description": "1-indexed end line, inclusive (max 2000 line segment). Use an integer." }, "head": { - "type": "string", - "description": "Read first N lines (alternative to start/end)" + "type": "integer", + "description": "Read first N lines (alternative to start/end). Use an integer." } } }, diff --git a/tools/filetools/internal/filetools/filetools.go b/tools/filetools/internal/filetools/filetools.go index 5809b99..3d95522 100644 --- a/tools/filetools/internal/filetools/filetools.go +++ b/tools/filetools/internal/filetools/filetools.go @@ -2,6 +2,7 @@ package filetools import ( "bytes" + "encoding/json" "errors" "fmt" "io/fs" @@ -35,19 +36,31 @@ func Int(m map[string]any, key string, def *int) (*int, error) { if !ok || v == nil { return def, nil } - var s string + var n int switch x := v.(type) { case string: - s = x + s := strings.TrimSpace(x) + parsed, e := strconv.Atoi(s) + if e != nil { + return nil, fmt.Errorf("argument %q must be a valid integer, got %q", key, s) + } + n = parsed case float64: - s = strconv.Itoa(int(x)) + if x != float64(int(x)) { + return nil, fmt.Errorf("argument %q must be an integer, got %v", key, x) + } + n = int(x) + case json.Number: + parsed, e := strconv.Atoi(string(x)) + if e != nil { + return nil, fmt.Errorf("argument %q must be a valid integer, got %q", key, x) + } + n = parsed + case int: + n = x default: return nil, fmt.Errorf("argument %q must be an integer, got %T", key, v) } - n, e := strconv.Atoi(s) - if e != nil { - return nil, fmt.Errorf("argument %q must be a valid integer, got %q", key, s) - } return &n, nil } func Bool(m map[string]any, key string) (bool, error) {