v0.0.3: add built-in web tools
Add no-key web_search and web_fetch tools. Fetch pages with net/http and parse HTML content. Document built-in web capabilities.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuiltinSearchTool(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
t.Fatalf("method = %s", r.Method)
|
||||
}
|
||||
if got := r.URL.Query().Get("q"); got != "agentu" {
|
||||
t.Fatalf("query = %q", got)
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
_, _ = w.Write([]byte(`
|
||||
<html><body>
|
||||
<div class="result">
|
||||
<a class="result__a" href="/l/?uddg=https%3A%2F%2Fexample.com%2Fagentu">Agentu release</a>
|
||||
<a class="result__snippet">Agentu adds built-in web tools.</a>
|
||||
</div>
|
||||
</body></html>`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
tool := NewBuiltinSearchToolWithBaseURL(server.URL, 5, server.Client())
|
||||
out, err := tool.Execute(context.Background(), json.RawMessage(`{"query":"agentu"}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{"Web search results", "Agentu release", "https://example.com/agentu", "Agentu adds built-in web tools"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("output missing %q:\n%s", want, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinFetchTool(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
t.Fatalf("method = %s", r.Method)
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = w.Write([]byte(`
|
||||
<html>
|
||||
<head><title>Agentu</title><script>hidden()</script></head>
|
||||
<body>
|
||||
<h1>Agentu</h1>
|
||||
<p>Built-in fetch reads HTML.</p>
|
||||
<ul><li>Search</li><li>Fetch</li></ul>
|
||||
</body>
|
||||
</html>`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
tool := NewBuiltinFetchTool(server.Client())
|
||||
out, err := tool.Execute(context.Background(), json.RawMessage(`{"url":"`+server.URL+`"}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{"Fetched web content", server.URL, "# Agentu", "Built-in fetch reads HTML", "- Search", "- Fetch"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("output missing %q:\n%s", want, out)
|
||||
}
|
||||
}
|
||||
if strings.Contains(out, "hidden") {
|
||||
t.Fatalf("script content should be ignored:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinFetchToolAcceptsURLsWithoutScheme(t *testing.T) {
|
||||
args, err := parseWebFetchArgs(json.RawMessage(`{"url":"example.com/page"}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if args.URL != "https://example.com/page" {
|
||||
t.Fatalf("url = %q", args.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinFetchToolFormatsFailedResults(t *testing.T) {
|
||||
response := webFetchResponse{
|
||||
FailedResults: []webFetchFailed{{URL: "https://example.com", Error: "blocked"}},
|
||||
}
|
||||
out := formatWebFetchResults("https://example.com", response)
|
||||
for _, want := range []string{"No readable web content", "Fetch failed", "blocked"} {
|
||||
if !strings.Contains(out, want) {
|
||||
t.Fatalf("output missing %q:\n%s", want, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user