Files
Agent-Native/runtime/skills/skills_test.go
T
weichen 6ddd3da8df Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:36:10 +00:00

123 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package skills
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/tools"
)
// writeSkill 写一份符合开放规范的 SKILL.md(name/description 齐备)。
func writeSkill(t *testing.T, root, name, body string) {
t.Helper()
writeRawSkill(t, root, name, "---\nname: "+name+"\ndescription: 测试技能 "+name+"\n---\n\n"+body)
}
func writeRawSkill(t *testing.T, root, name, text string) {
t.Helper()
dir := filepath.Join(root, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "SKILL.md"), []byte(text), 0o644); err != nil {
t.Fatal(err)
}
}
func TestStoreListAndLoad(t *testing.T) {
root := t.TempDir()
writeSkill(t, root, "docx-author", "## 步骤\n1. 用 run_python")
writeSkill(t, root, "xlsx-author", "没有 frontmatter 的技能正文")
writeSkill(t, root, "bad name", "目录名不合法") //nolint
// 无 frontmatter(缺 name/description):开放规范下不合规,进诊断不进索引。
writeRawSkill(t, root, "nofm", "没有任何头部")
store := NewStore(root)
list := store.List()
if len(list) != 2 {
t.Fatalf("want 2 valid skills (bad dir + nofm skipped), got %d: %+v", len(list), list)
}
byName := map[string]Skill{}
for _, s := range list {
byName[s.Name] = s
}
if byName["docx-author"].Description != "测试技能 docx-author" {
t.Fatalf("frontmatter description wrong: %+v", byName["docx-author"])
}
if !strings.Contains(byName["docx-author"].Body, "run_python") {
t.Fatalf("body must exclude frontmatter, got %q", byName["docx-author"].Body)
}
skill, err := store.Load("docx-author")
if err != nil || !strings.Contains(skill.Body, "步骤") {
t.Fatalf("load failed: %v %+v", err, skill)
}
// 同名不合规:Load 返回带字段定位的校验错误(不是笼统 unknown)。
_, err = store.Load("nofm")
if err == nil || !strings.Contains(err.Error(), "name") {
t.Fatalf("invalid skill must surface its validation error, got %v", err)
}
_, err = store.Load("nope")
if err == nil || !strings.Contains(err.Error(), "unknown skill") {
t.Fatalf("unknown skill must fail-closed, got %v", err)
}
}
func TestStoreRootPriorityAndMissingRoot(t *testing.T) {
r1, r2 := t.TempDir(), t.TempDir()
writeSkill(t, r1, "dup", "from r1")
writeSkill(t, r2, "dup", "from r2")
writeSkill(t, r2, "only-r2", "x")
store := NewStore(r1, r2, "/nonexistent/root")
list := store.List()
if len(list) != 2 {
t.Fatalf("want 2 skills, got %d", len(list))
}
skill, _ := store.Load("dup")
if !strings.Contains(skill.Body, "from r1") {
t.Fatalf("earlier root must win, got %q", skill.Body)
}
}
func TestRegisterLoaderTool(t *testing.T) {
root := t.TempDir()
writeSkill(t, root, "docx-author", "正文指令")
reg := tools.NewRegistry(t.TempDir())
RegisterLoader(reg, NewStore(root))
var found bool
for _, d := range reg.Decls() {
if d.Name == "load_skill" {
found = true
}
}
if !found {
t.Fatal("load_skill must be registered when skills exist")
}
res := reg.Execute(context.Background(), "load_skill", json.RawMessage(`{"name":"docx-author"}`))
if res.IsError || !strings.Contains(res.Content, "正文指令") {
t.Fatalf("load failed: %+v", res)
}
res = reg.Execute(context.Background(), "load_skill", json.RawMessage(`{"name":"ghost"}`))
if !res.IsError || !strings.Contains(res.Content, "unknown skill") {
t.Fatalf("ghost skill must error, got %+v", res)
}
}
func TestRegisterLoaderSkipsEmptyStore(t *testing.T) {
reg := tools.NewRegistry(t.TempDir())
RegisterLoader(reg, NewStore(t.TempDir()))
for _, d := range reg.Decls() {
if d.Name == "load_skill" {
t.Fatal("no skills = no loader tool")
}
}
RegisterLoader(reg, nil)
if len(reg.Decls()) != 0 {
t.Fatal("nil store must not register")
}
}