llm(三协议 Provider)/ session(JSONL 持久化)/ tools(Registry、围栏、 builtin、computer)/ cdp(browser)/ skills / mcp / agent(循环、两级压缩、 编排、审批门控)+ 底座 jsonl/textx/execx/diag/scratch/spill/imagecache。 产品装配代码(config 桥接、schedule 工具、memory/plan/retro/prompt) 留在 AutoGo,宿主接入方式见 MIGRATION.md。
106 lines
2.6 KiB
Go
106 lines
2.6 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func readIn(t *testing.T, input string, files map[string]string) (string, error) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
for name, content := range files {
|
|
p := filepath.Join(dir, name)
|
|
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(p, []byte(content), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
reg := NewRegistry()
|
|
for _, tl := range BuiltinIn(dir, NewFence(), nil) {
|
|
if err := reg.Register(tl); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
r, _ := reg.Get("read")
|
|
res, err := r.Run(context.Background(), input)
|
|
return res.Text, err
|
|
}
|
|
|
|
// TestReadSmallFileUnchanged:不分页的小文件保持原样,不加头尾。
|
|
func TestReadSmallFileUnchanged(t *testing.T) {
|
|
got, err := readIn(t, `{"path":"f.txt"}`, map[string]string{"f.txt": "a\nb\nc\n"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != "a\nb\nc\n" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestReadOffsetLimit(t *testing.T) {
|
|
got, err := readIn(t, `{"path":"f.txt","offset":2,"limit":2}`,
|
|
map[string]string{"f.txt": "l1\nl2\nl3\nl4\nl5\n"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(got, "lines 2-3 of 5") || !strings.Contains(got, "l2\nl3") {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
if !strings.Contains(got, "continue with offset: 4") {
|
|
t.Fatalf("missing continuation: %q", got)
|
|
}
|
|
if strings.Contains(got, "l1") || strings.Contains(got, "l4") {
|
|
t.Fatalf("paging leaked other lines: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestReadBeyondEOF(t *testing.T) {
|
|
got, err := readIn(t, `{"path":"f.txt","offset":99}`, map[string]string{"f.txt": "a\nb\n"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(got, "beyond EOF") {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestReadDirectoryListing(t *testing.T) {
|
|
got, err := readIn(t, `{"path":".","offset":2,"limit":1}`, map[string]string{
|
|
"a.txt": "x",
|
|
"sub/b.go": "y",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(got, "entries 2-2 of 2") || !strings.Contains(got, "sub/") {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
if strings.Contains(got, "a.txt") {
|
|
t.Fatalf("paging leaked other entries: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestReadRejectsBinary(t *testing.T) {
|
|
dir := t.TempDir()
|
|
p := filepath.Join(dir, "bin")
|
|
if err := os.WriteFile(p, []byte{'a', 0, 'b'}, 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
reg := NewRegistry()
|
|
for _, tl := range BuiltinIn(dir, NewFence(), nil) {
|
|
if err := reg.Register(tl); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
r, _ := reg.Get("read")
|
|
if _, err := r.Run(context.Background(), `{"path":"bin"}`); err == nil ||
|
|
!strings.Contains(err.Error(), "binary") {
|
|
t.Fatalf("want binary error, got %v", err)
|
|
}
|
|
}
|