package tools import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" llm "gitea.stevedudenhoeffer.com/steve/go-llm/v2" ) // HTTPParams defines parameters for the HTTP request tool. type HTTPParams struct { Method string `json:"method" description:"HTTP method" enum:"GET,POST,PUT,DELETE,PATCH,HEAD"` URL string `json:"url" description:"Request URL"` Headers map[string]string `json:"headers,omitempty" description:"Request headers"` Body *string `json:"body,omitempty" description:"Request body"` } // HTTP creates an HTTP request tool. // // Example: // // tools := llm.NewToolBox(tools.HTTP()) func HTTP() llm.Tool { return llm.Define[HTTPParams]("http_request", "Make an HTTP request and return the response", func(ctx context.Context, p HTTPParams) (string, error) { var bodyReader io.Reader if p.Body != nil { bodyReader = bytes.NewBufferString(*p.Body) } req, err := http.NewRequestWithContext(ctx, p.Method, p.URL, bodyReader) if err != nil { return "", fmt.Errorf("creating request: %w", err) } for k, v := range p.Headers { req.Header.Set(k, v) } resp, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("request failed: %w", err) } defer resp.Body.Close() // Limit to 1MB limited := io.LimitReader(resp.Body, 1<<20) body, err := io.ReadAll(limited) if err != nil { return "", fmt.Errorf("reading response: %w", err) } headers := map[string]string{} for k, v := range resp.Header { if len(v) > 0 { headers[k] = v[0] } } result := map[string]any{ "status": resp.StatusCode, "status_text": resp.Status, "headers": headers, "body": string(body), } out, _ := json.MarshalIndent(result, "", " ") return string(out), nil }, ) }