on main help sign in
fix: remove pool logic
commit5056d443ec70303de4b1ee5d92c9eb02ceb158ee authorRaphael Amorim <rapha850@gmail.com> dateMon 16 Jun 2025, 16:53 (1 year ago) parent6261a57
3 files changed+40−106
internal/llm/tools/fetch.go+15−49 internal/llm/tools/grep.go+10−9 internal/llm/tools/sourcegraph.go+15−48
internal/llm/tools/fetch.go+15−49
@@ -7,7 +7,6 @@ import (
77 "io"
88 "net/http"
99 "strings"
10− "sync"
1110 "time"
1211
1312 md "github.com/JohannesKaufmann/html-to-markdown"
@@ -29,10 +28,8 @@ type FetchPermissionsParams struct {
2928}
3029
3130type fetchTool struct {
32− client *http.Client
33− clientPool map[int]*http.Client
34− clientPoolMu sync.RWMutex
35− permissions permission.Service
31+ client *http.Client
32+ permissions permission.Service
3633}
3734
3835const (
@@ -78,51 +75,10 @@ func NewFetchTool(permissions permission.Service) BaseTool {
7875 IdleConnTimeout: 90 * time.Second,
7976 },
8077 },
81− clientPool: make(map[int]*http.Client),
8278 permissions: permissions,
8379 }
8480}
8581
86−// getClientForTimeout returns a cached client for the given timeout or the default client
87−func (t *fetchTool) getClientForTimeout(timeout int) *http.Client {
88− if timeout <= 0 {
89− return t.client
90− }
91−
92− maxTimeout := 120 // 2 minutes
93− if timeout > maxTimeout {
94− timeout = maxTimeout
95− }
96−
97− // Check if we have a cached client for this timeout
98− t.clientPoolMu.RLock()
99− if client, exists := t.clientPool[timeout]; exists {
100− t.clientPoolMu.RUnlock()
101− return client
102− }
103− t.clientPoolMu.RUnlock()
104−
105− // Create and cache a new client
106− t.clientPoolMu.Lock()
107− defer t.clientPoolMu.Unlock()
108−
109− // Double-check in case another goroutine created it
110− if client, exists := t.clientPool[timeout]; exists {
111− return client
112− }
113−
114− client := &http.Client{
115− Timeout: time.Duration(timeout) * time.Second,
116− Transport: &http.Transport{
117− MaxIdleConns: 100,
118− MaxIdleConnsPerHost: 10,
119− IdleConnTimeout: 90 * time.Second,
120− },
121− }
122− t.clientPool[timeout] = client
123− return client
124−}
125−
12682func (t *fetchTool) Info() ToolInfo {
12783 return ToolInfo{
12884 Name: FetchToolName,
@@ -185,16 +141,26 @@ func (t *fetchTool) Run(ctx context.Context, call ToolCall) (ToolResponse, error
185141 return ToolResponse{}, permission.ErrorPermissionDenied
186142 }
187143
188− client := t.getClientForTimeout(params.Timeout)
144+ // Handle timeout with context
145+ requestCtx := ctx
146+ if params.Timeout > 0 {
147+ maxTimeout := 120 // 2 minutes
148+ if params.Timeout > maxTimeout {
149+ params.Timeout = maxTimeout
150+ }
151+ var cancel context.CancelFunc
152+ requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
153+ defer cancel()
154+ }
189155
190− req, err := http.NewRequestWithContext(ctx, "GET", params.URL, nil)
156+ req, err := http.NewRequestWithContext(requestCtx, "GET", params.URL, nil)
191157 if err != nil {
192158 return ToolResponse{}, fmt.Errorf("failed to create request: %w", err)
193159 }
194160
195161 req.Header.Set("User-Agent", "crush/1.0")
196162
197− resp, err := client.Do(req)
163+ resp, err := t.client.Do(req)
198164 if err != nil {
199165 return ToolResponse{}, fmt.Errorf("failed to fetch URL: %w", err)
200166 }
internal/llm/tools/grep.go+10−9
@@ -402,19 +402,20 @@ func fileContainsPattern(filePath string, pattern *regexp.Regexp) (bool, int, st
402402 return false, 0, "", scanner.Err()
403403}
404404
405+var binaryExts = map[string]struct{}{
406+ ".exe": {}, ".dll": {}, ".so": {}, ".dylib": {},
407+ ".bin": {}, ".obj": {}, ".o": {}, ".a": {},
408+ ".zip": {}, ".tar": {}, ".gz": {}, ".bz2": {},
409+ ".jpg": {}, ".jpeg": {}, ".png": {}, ".gif": {},
410+ ".pdf": {}, ".doc": {}, ".docx": {}, ".xls": {},
411+ ".mp3": {}, ".mp4": {}, ".avi": {}, ".mov": {},
412+}
413+
405414// isBinaryFile performs a quick check to determine if a file is binary
406415func isBinaryFile(filePath string) bool {
407416 // Check file extension first (fastest)
408417 ext := strings.ToLower(filepath.Ext(filePath))
409− binaryExts := map[string]bool{
410− ".exe": true, ".dll": true, ".so": true, ".dylib": true,
411− ".bin": true, ".obj": true, ".o": true, ".a": true,
412− ".zip": true, ".tar": true, ".gz": true, ".bz2": true,
413− ".jpg": true, ".jpeg": true, ".png": true, ".gif": true,
414− ".pdf": true, ".doc": true, ".docx": true, ".xls": true,
415− ".mp3": true, ".mp4": true, ".avi": true, ".mov": true,
416− }
417− if binaryExts[ext] {
418+ if _, isBinary := binaryExts[ext]; isBinary {
418419 return true
419420 }
420421
internal/llm/tools/sourcegraph.go+15−48
@@ -8,7 +8,6 @@ import (
88 "io"
99 "net/http"
1010 "strings"
11− "sync"
1211 "time"
1312)
1413
@@ -25,9 +24,7 @@ type SourcegraphResponseMetadata struct {
2524}
2625
2726type sourcegraphTool struct {
28− client *http.Client
29− clientPool map[int]*http.Client
30− clientPoolMu sync.RWMutex
27+ client *http.Client
3128}
3229
3330const (
@@ -138,50 +135,9 @@ func NewSourcegraphTool() BaseTool {
138135 IdleConnTimeout: 90 * time.Second,
139136 },
140137 },
141− clientPool: make(map[int]*http.Client),
142138 }
143139}
144140
145−// getClientForTimeout returns a cached client for the given timeout or the default client
146−func (t *sourcegraphTool) getClientForTimeout(timeout int) *http.Client {
147− if timeout <= 0 {
148− return t.client
149− }
150−
151− maxTimeout := 120 // 2 minutes
152− if timeout > maxTimeout {
153− timeout = maxTimeout
154− }
155−
156− // Check if we have a cached client for this timeout
157− t.clientPoolMu.RLock()
158− if client, exists := t.clientPool[timeout]; exists {
159− t.clientPoolMu.RUnlock()
160− return client
161− }
162− t.clientPoolMu.RUnlock()
163−
164− // Create and cache a new client
165− t.clientPoolMu.Lock()
166− defer t.clientPoolMu.Unlock()
167−
168− // Double-check in case another goroutine created it
169− if client, exists := t.clientPool[timeout]; exists {
170− return client
171− }
172−
173− client := &http.Client{
174− Timeout: time.Duration(timeout) * time.Second,
175− Transport: &http.Transport{
176− MaxIdleConns: 100,
177− MaxIdleConnsPerHost: 10,
178− IdleConnTimeout: 90 * time.Second,
179− },
180− }
181− t.clientPool[timeout] = client
182− return client
183−}
184−
185141func (t *sourcegraphTool) Info() ToolInfo {
186142 return ToolInfo{
187143 Name: SourcegraphToolName,
@@ -227,7 +183,18 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
227183 if params.ContextWindow <= 0 {
228184 params.ContextWindow = 10 // Default context window
229185 }
230− client := t.getClientForTimeout(params.Timeout)
186+
187+ // Handle timeout with context
188+ requestCtx := ctx
189+ if params.Timeout > 0 {
190+ maxTimeout := 120 // 2 minutes
191+ if params.Timeout > maxTimeout {
192+ params.Timeout = maxTimeout
193+ }
194+ var cancel context.CancelFunc
195+ requestCtx, cancel = context.WithTimeout(ctx, time.Duration(params.Timeout)*time.Second)
196+ defer cancel()
197+ }
231198
232199 type graphqlRequest struct {
233200 Query string `json:"query"`
@@ -248,7 +215,7 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
248215 graphqlQuery := string(graphqlQueryBytes)
249216
250217 req, err := http.NewRequestWithContext(
251− ctx,
218+ requestCtx,
252219 "POST",
253220 "https://sourcegraph.com/.api/graphql",
254221 bytes.NewBuffer([]byte(graphqlQuery)),
@@ -260,7 +227,7 @@ func (t *sourcegraphTool) Run(ctx context.Context, call ToolCall) (ToolResponse,
260227 req.Header.Set("Content-Type", "application/json")
261228 req.Header.Set("User-Agent", "crush/1.0")
262229
263− resp, err := client.Do(req)
230+ resp, err := t.client.Do(req)
264231 if err != nil {
265232 return ToolResponse{}, fmt.Errorf("failed to fetch URL: %w", err)
266233 }