| 976 | } |
| 977 | |
| 978 | func (t *ToolSet) handleReadFile(ctx context.Context, args ReadFileArgs) (*tools.ToolCallResult, error) { |
| 979 | annotateFilesystemSpan(ctx, "read_file", args.Path) |
| 980 | resolvedPath, err := t.resolveAndCheckPath(args.Path) |
| 981 | if err != nil { |
| 982 | return &tools.ToolCallResult{ |
| 983 | Output: err.Error(), |
| 984 | IsError: true, |
| 985 | Meta: ReadFileMeta{Path: args.Path, Error: err.Error()}, |
| 986 | }, nil |
| 987 | } |
| 988 | |
| 989 | // Check if the file exists before any type detection. |
| 990 | info, err := t.stat(resolvedPath) |
| 991 | if err != nil { |
| 992 | var errMsg string |
| 993 | if errors.Is(err, fs.ErrNotExist) { |
| 994 | errMsg = "not found" |
| 995 | } else { |
| 996 | errMsg = err.Error() |
| 997 | } |
| 998 | |
| 999 | return &tools.ToolCallResult{ |
| 1000 | Output: errMsg, |
| 1001 | IsError: true, |
| 1002 | Meta: ReadFileMeta{ |
| 1003 | Error: errMsg, |
| 1004 | }, |
| 1005 | }, nil |
| 1006 | } |
| 1007 | |
| 1008 | // Only check for image files on regular files (not directories, etc.) |
| 1009 | if info.Mode().IsRegular() && chat.IsImageFile(resolvedPath) { |
| 1010 | return t.readImageFile(resolvedPath, args.Path) |
| 1011 | } |
| 1012 | |
| 1013 | content, err := t.readFile(resolvedPath) |
| 1014 | if err != nil { |
| 1015 | return &tools.ToolCallResult{ |
| 1016 | Output: err.Error(), |
| 1017 | IsError: true, |
| 1018 | Meta: ReadFileMeta{ |
| 1019 | Error: err.Error(), |
| 1020 | }, |
| 1021 | }, nil |
| 1022 | } |
| 1023 | |
| 1024 | text := string(content) |
| 1025 | |
| 1026 | return &tools.ToolCallResult{ |
| 1027 | Output: text, |
| 1028 | Meta: ReadFileMeta{ |
| 1029 | LineCount: strings.Count(text, "\n") + 1, |
| 1030 | }, |
| 1031 | }, nil |
| 1032 | } |
| 1033 | |
| 1034 | // readImageFile reads an image file and returns it as base64-encoded image content. |
| 1035 | // The caller must ensure the file exists (e.g. via os.Stat) before calling this method. |