diff --git a/.jules/bolt.md b/.jules/bolt.md index 7416f0a69..c2a5a7461 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -8,3 +8,6 @@ ## 2024-05-26 - Avoid Unnecessary `strings.ToLower` **Learning:** Calling `strings.ToLower` on the entire message content allocates a new string and iterates over all runes. This causes measurable GC pressure and latency on hot paths like feature extraction during routing. **Action:** Use fast paths to bypass `strings.ToLower`. For instance, check if a requisite character (like a dot `.`) exists, or check common casings directly (`DATA:IMAGE` vs `data:image`) before falling back to full case-normalization. +## 2025-03-20 - String Operations Fast Paths and Avoiding Double Searches +**Learning:** When trying to optimize `strings.ToLower`, ensure you don't introduce regressions with byte-to-rune casting on UTF-8 strings. Also, `strings.Contains(s, sub)` literally calls `strings.Index(s, sub)` under the hood. Using `strings.Contains` followed immediately by `strings.Index` to extract the position is an anti-pattern that searches the string twice, undermining the intended performance optimization. +**Action:** Always prefer a single `strings.Index` call over `Contains`+`Index`. Stick to one single optimization per PR to reduce risk and review burden. diff --git a/pkg/agent/loop_utils.go b/pkg/agent/loop_utils.go index 17fc2914a..f6e4e8d77 100644 --- a/pkg/agent/loop_utils.go +++ b/pkg/agent/loop_utils.go @@ -102,28 +102,44 @@ func formatToolsForLog(toolDefs []providers.ToolDefinition) string { // inferMediaType determines the media type ("image", "audio", "video", "file") // from a filename and MIME content type. func inferMediaType(filename, contentType string) string { - ct := strings.ToLower(contentType) - fn := strings.ToLower(filename) - - if strings.HasPrefix(ct, "image/") { + // Fast path for common, correctly cased content types + if strings.HasPrefix(contentType, "image/") { return "image" } - if strings.HasPrefix(ct, "audio/") || ct == "application/ogg" { + if strings.HasPrefix(contentType, "audio/") || contentType == "application/ogg" { return "audio" } - if strings.HasPrefix(ct, "video/") { + if strings.HasPrefix(contentType, "video/") { return "video" } + // Slower path for uppercase or mixed case + if contentType != "" { + ct := strings.ToLower(contentType) + if strings.HasPrefix(ct, "image/") { + return "image" + } + if strings.HasPrefix(ct, "audio/") || ct == "application/ogg" { + return "audio" + } + if strings.HasPrefix(ct, "video/") { + return "video" + } + } + // Fallback: infer from extension - ext := filepath.Ext(fn) - switch ext { - case ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg": - return "image" - case ".mp3", ".wav", ".ogg", ".m4a", ".flac", ".aac", ".wma", ".opus": - return "audio" - case ".mp4", ".avi", ".mov", ".webm", ".mkv": - return "video" + ext := filepath.Ext(filename) + if ext != "" { + // Only lower case the extension, which is usually just a few characters + ext = strings.ToLower(ext) + switch ext { + case ".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".svg": + return "image" + case ".mp3", ".wav", ".ogg", ".m4a", ".flac", ".aac", ".wma", ".opus": + return "audio" + case ".mp4", ".avi", ".mov", ".webm", ".mkv": + return "video" + } } return "file"