Mining file paths from free-form text
How a small regex loop turns prose into path-like strings — with dedupe, length gates, and a hard cap of ten.
Mining file paths from free-form text
Failure notes and agent memories often mention files in passing (src/foo.go, app/handlers/…). Correlating memories by shared file refs starts with extracting those strings from unstructured text.
Credit: extractFileRefs in Agent-Observer (internal/patterns/correlator.go). Package-level fileRefPatterns is a []*regexp.Regexp of path-like matchers (not shown here) — this post focuses on the extraction loop only.
The function
func extractFileRefs(text string) []string {
seen := map[string]bool{}
var refs []string
for _, pattern := range fileRefPatterns {
for _, match := range pattern.FindAllString(text, -1) {
if len(match) > 5 && !seen[match] && len(match) < 200 {
seen[match] = true
refs = append(refs, match)
}
}
}
if len(refs) > 10 {
refs = refs[:10]
}
return refs
}
What it does
- Runs each compiled path-ish pattern over
text. - Keeps matches that are longer than 5 and shorter than 200 characters.
- Dedupes with a
seenmap (first occurrence wins). - Truncates the result to at most 10 refs.
Those refs later drive search for related memories that mention the same paths.
Why this shape
- Regex over free text beats brittle NLP for “looks like a path.”
- Length floors drop junk like
a.go-style noise; a 200-char ceiling avoids swallowing paragraphs. - A hard cap of 10 bounds downstream search fan-out — correlation stays cheap.
Gotcha
Order is pattern order, then left-to-right match order, not importance. After the tenth unique match, later (possibly better) paths are dropped. Patterns also false-positive on version strings, URLs fragments, or word.ext that are not filesystem paths — treat refs as soft hints for search, not as validated file identities.
Takeaway
Mining structure from prose is mostly gates: dedupe, length, and cardinality. The clever part is knowing what not to feed the correlator.