feat(tools/io): 内置 IO/网络工具(file(路径安全)/http(SSRF防护)/web-search/web-fetch/knowledge)+ 大小截断
This commit is contained in:
1 parent
488cf9c79c
commit
3ce9489f8e
17 files changed
+2223
No files matched your search
@@ -0,0 +1,109 @@
|
||||
package io
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
|
||||
)
|
||||
|
||||
// webSearchToolForTest builds a tools set with opts and returns the web-search
|
||||
// tool.
|
||||
func webSearchToolForTest(t *testing.T, opts ...Option) *webSearchTool {
|
||||
t.Helper()
|
||||
return findTool(t, buildTools(t, &config.Config{}, opts...), "web-search").(*webSearchTool)
|
||||
}
|
||||
|
||||
func TestWebSearch_NoEndpoint(t *testing.T) {
|
||||
t.Parallel()
|
||||
ws := webSearchToolForTest(t) // no endpoint configured
|
||||
_, err := ws.Execute(context.Background(), map[string]any{"query": "cyrene"})
|
||||
if err == nil || !strings.Contains(err.Error(), "no search endpoint") {
|
||||
t.Fatalf("expected no-endpoint error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSearch_Query(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Query().Get("q") != "cyrene" {
|
||||
t.Errorf("query param q = %q", r.URL.Query().Get("q"))
|
||||
}
|
||||
if r.URL.Query().Get("format") != "json" {
|
||||
t.Errorf("format = %q", r.URL.Query().Get("format"))
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = io.WriteString(w, `{"results":[
|
||||
{"title":"A","url":"http://a.example","content":"alpha"},
|
||||
{"title":"B","url":"http://b.example","snippet":"beta"}
|
||||
]}`)
|
||||
}))
|
||||
defer srv.Close()
|
||||
ws := webSearchToolForTest(t,
|
||||
WithSearchEndpoint(srv.URL),
|
||||
WithAllowedHosts(serverHost(srv)),
|
||||
WithHTTPClient(srv.Client()),
|
||||
)
|
||||
|
||||
got, err := ws.Execute(context.Background(), map[string]any{"query": "cyrene", "count": 2})
|
||||
if err != nil {
|
||||
t.Fatalf("Execute: %v", err)
|
||||
}
|
||||
m := got.(map[string]any)
|
||||
if m["count"].(int) != 2 {
|
||||
t.Fatalf("count = %v", m["count"])
|
||||
}
|
||||
results := m["results"].([]searchResult)
|
||||
if results[0].Title != "A" || results[0].Content != "alpha" {
|
||||
t.Fatalf("result[0] = %+v", results[0])
|
||||
}
|
||||
if results[1].Content != "beta" {
|
||||
t.Fatalf("result[1] snippet fallback = %+v", results[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSearch_SizeLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
big := strings.Repeat("a", 64)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = io.WriteString(w, big)
|
||||
}))
|
||||
defer srv.Close()
|
||||
ws := webSearchToolForTest(t,
|
||||
WithSearchEndpoint(srv.URL),
|
||||
WithAllowedHosts(serverHost(srv)),
|
||||
WithHTTPClient(srv.Client()),
|
||||
WithHTTPResponseLimit(16),
|
||||
)
|
||||
_, err := ws.Execute(context.Background(), map[string]any{"query": "cyrene"})
|
||||
if err == nil || !strings.Contains(err.Error(), "exceeds the 16-byte limit") {
|
||||
t.Fatalf("expected size-limit error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebSearch_CountCapped(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = io.WriteString(w, `{"results":[{"title":"A","url":"http://a","content":"x"}]}`)
|
||||
}))
|
||||
defer srv.Close()
|
||||
ws := webSearchToolForTest(t,
|
||||
WithSearchEndpoint(srv.URL),
|
||||
WithAllowedHosts(serverHost(srv)),
|
||||
WithHTTPClient(srv.Client()),
|
||||
WithMaxResults(0), // ignored; default 10
|
||||
WithMaxResults(1),
|
||||
)
|
||||
got, err := ws.Execute(context.Background(), map[string]any{"query": "cyrene"})
|
||||
if err != nil {
|
||||
t.Fatalf("Execute: %v", err)
|
||||
}
|
||||
if m := got.(map[string]any); m["count"].(int) != 1 {
|
||||
t.Fatalf("count = %v", m["count"])
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user