|
27 | 27 | ([path visited] |
28 | 28 | (if (contains? visited path) |
29 | 29 | [] |
30 | | - (let [root-content (llm-api/refine-file-context path nil) |
31 | | - visited' (conj visited path) |
32 | | - at-mentions (extract-at-mentions root-content) |
33 | | - parent-dir (str (fs/parent path)) |
34 | | - resolved-paths (map (fn [mention] |
35 | | - (cond |
36 | | - ;; Absolute path |
37 | | - (string/starts-with? mention "/") |
38 | | - (str (fs/canonicalize (fs/file mention))) |
| 30 | + (if-let [root-content (llm-api/refine-file-context path nil)] |
| 31 | + (let [visited' (conj visited path) |
| 32 | + at-mentions (extract-at-mentions root-content) |
| 33 | + parent-dir (str (fs/parent path)) |
| 34 | + resolved-paths (map (fn [mention] |
| 35 | + (cond |
| 36 | + ;; Absolute path |
| 37 | + (string/starts-with? mention "/") |
| 38 | + (str (fs/canonicalize (fs/file mention))) |
39 | 39 |
|
40 | | - ;; Relative path (./... or ../...) |
41 | | - (or (string/starts-with? mention "./") |
42 | | - (string/starts-with? mention "../")) |
43 | | - (str (fs/canonicalize (fs/file parent-dir mention))) |
| 40 | + ;; Relative path (./... or ../...) |
| 41 | + (or (string/starts-with? mention "./") |
| 42 | + (string/starts-with? mention "../")) |
| 43 | + (str (fs/canonicalize (fs/file parent-dir mention))) |
44 | 44 |
|
45 | | - ;; Simple filename, relative to current file's directory |
46 | | - :else |
47 | | - (str (fs/canonicalize (fs/file parent-dir mention))))) |
48 | | - at-mentions) |
49 | | - ;; Deduplicate resolved paths |
50 | | - unique-paths (distinct resolved-paths) |
51 | | - ;; Recursively parse all mentioned files |
52 | | - nested-results (mapcat #(parse-agents-file % visited') unique-paths)] |
53 | | - (concat [{:type :agents-file |
54 | | - :path path |
55 | | - :content root-content}] |
56 | | - nested-results))))) |
| 45 | + ;; Simple filename, relative to current file's directory |
| 46 | + :else |
| 47 | + (str (fs/canonicalize (fs/file parent-dir mention))))) |
| 48 | + at-mentions) |
| 49 | + ;; Deduplicate resolved paths |
| 50 | + unique-paths (distinct resolved-paths) |
| 51 | + ;; Recursively parse all mentioned files |
| 52 | + nested-results (mapcat #(parse-agents-file % visited') unique-paths)] |
| 53 | + (concat [{:type :agents-file |
| 54 | + :path path |
| 55 | + :content root-content}] |
| 56 | + nested-results)) |
| 57 | + [])))) |
57 | 58 |
|
58 | 59 | (defn agents-file-contexts |
59 | 60 | "Search for AGENTS.md file both in workspaceRoot and global config dir. |
|
75 | 76 | (mapcat #(parse-agents-file (str %)))))) |
76 | 77 |
|
77 | 78 | (defn ^:private file->refined-context [path lines-range] |
78 | | - (let [ext (string/lower-case (or (fs/extension path) ""))] |
79 | | - (if (contains? #{"png" "jpg" "jpeg" "gif" "webp"} ext) |
80 | | - {:type :image |
81 | | - :media-type (case ext |
82 | | - "jpg" "image/jpeg" |
83 | | - (str "image/" ext)) |
84 | | - :base64 (.encodeToString (Base64/getEncoder) |
85 | | - (fs/read-all-bytes (fs/file path))) |
86 | | - :path path} |
87 | | - (assoc-some |
88 | | - {:type :file |
89 | | - :path path |
90 | | - :content (llm-api/refine-file-context path lines-range)} |
91 | | - :lines-range lines-range)))) |
| 79 | + (if (fs/readable? path) |
| 80 | + (let [ext (string/lower-case (or (fs/extension path) ""))] |
| 81 | + (if (contains? #{"png" "jpg" "jpeg" "gif" "webp"} ext) |
| 82 | + {:type :image |
| 83 | + :media-type (case ext |
| 84 | + "jpg" "image/jpeg" |
| 85 | + (str "image/" ext)) |
| 86 | + :base64 (.encodeToString (Base64/getEncoder) |
| 87 | + (fs/read-all-bytes (fs/file path))) |
| 88 | + :path path} |
| 89 | + (when-let [content (llm-api/refine-file-context path lines-range)] |
| 90 | + (assoc-some |
| 91 | + {:type :file |
| 92 | + :path path |
| 93 | + :content content} |
| 94 | + :lines-range lines-range)))) |
| 95 | + (logger/warn logger-tag "File not found or unreadable at" path))) |
92 | 96 |
|
93 | 97 | (defn raw-contexts->refined [contexts db] |
94 | 98 | (mapcat (fn [{:keys [type path lines-range position uri]}] |
95 | 99 | (case (name type) |
96 | | - "file" [(file->refined-context path lines-range)] |
| 100 | + "file" (if-let [ctx (file->refined-context path lines-range)] |
| 101 | + [ctx] |
| 102 | + []) |
97 | 103 | "directory" (->> (fs/glob path "**") |
98 | 104 | (remove fs/directory?) |
99 | | - (map (fn [path] |
100 | | - (let [filename (str (fs/canonicalize path))] |
101 | | - (file->refined-context filename nil))))) |
| 105 | + (keep (fn [path] |
| 106 | + (let [filename (str (fs/canonicalize path))] |
| 107 | + (file->refined-context filename nil))))) |
102 | 108 | "repoMap" [{:type :repoMap}] |
103 | 109 | "cursor" [{:type :cursor |
104 | 110 | :path path |
|
122 | 128 | [prompt db] |
123 | 129 | (let [;; Capture @<path> with optional :L<start>-L<end> |
124 | 130 | context-pattern #"@([^\s:]+)(?::L(\d+)-L(\d+))?" |
125 | | - matches (re-seq context-pattern prompt)] |
126 | | - (when (seq matches) |
127 | | - (let [raw-contexts (mapv (fn [[_ path s e]] |
128 | | - (assoc-some {:type "file" |
129 | | - :path path} |
130 | | - :lines-range (when (and s e) |
131 | | - {:start (Integer/parseInt s) |
132 | | - :end (Integer/parseInt e)}))) |
133 | | - matches)] |
134 | | - (raw-contexts->refined raw-contexts db))))) |
| 131 | + matches (re-seq context-pattern prompt) |
| 132 | + raw-contexts (mapv (fn [[_ path s e]] |
| 133 | + (assoc-some {:type "file" |
| 134 | + :path path} |
| 135 | + :lines-range (when (and s e) |
| 136 | + {:start (Integer/parseInt s) |
| 137 | + :end (Integer/parseInt e)}))) |
| 138 | + matches)] |
| 139 | + (when (seq raw-contexts) |
| 140 | + (raw-contexts->refined raw-contexts db)))) |
135 | 141 |
|
136 | 142 | (defn ^:private all-files-from* [root-filename] (fs/glob root-filename "**")) |
137 | 143 | (def ^:private all-files-from (memoize all-files-from*)) |
|
0 commit comments