package agent import ( "context" "strings" "testing" "git.gopher.ink/mirrors2/AutoZero/llm" "git.gopher.ink/mirrors2/AutoZero/skills" ) // TestLoadSkillTool:load_skill 返回正文;allowed-tools 白名单过滤生效, // 白名单外工具被拒。 func TestLoadSkillTool(t *testing.T) { prov := &scriptedProvider{fn: func(call int, _ string, _ []llm.Message, tools []llm.ToolDef) (llm.Message, error) { switch call { case 1: // 模型加载 skill(工具全量可见) if !hasName(tools, "grep") || !hasName(tools, "load_skill") { t.Errorf("call 1: expected full toolset, got %v", toolNames(tools)) } return llm.Message{Role: llm.RoleAssistant, ToolCalls: []llm.ToolCall{ {ID: "sk1", Name: "load_skill", Input: `{"name":"review"}`}, }}, nil case 2: // 白名单生效:只剩 load_skill + read if hasName(tools, "grep") || !hasName(tools, "read") || !hasName(tools, "load_skill") { t.Errorf("call 2: expected filtered toolset [load_skill read], got %v", toolNames(tools)) } return llm.Message{Role: llm.RoleAssistant, ToolCalls: []llm.ToolCall{ {ID: "t1", Name: "grep", Input: `{"pattern":"x"}`}, // 白名单外 → 应得到错误结果 }}, nil case 3: return llm.Message{Role: llm.RoleAssistant, Content: "done"}, nil } t.Errorf("unexpected call %d", call) return llm.Message{}, nil }} a, sess := newTestAgent(t) a.Provider = prov a.Skills = []skills.Skill{{ Name: "review", Description: "code review", AllowedTools: []string{"read"}, Body: "Read the diff and comment.", }} if err := a.Tools.Register(a.SkillTool()); err != nil { t.Fatal(err) } if err := a.Run(context.Background(), "review the code"); err != nil { t.Fatal(err) } // skill 正文作为工具结果回填 var gotBody bool for _, m := range sess.Messages { if m.Role == llm.RoleTool && strings.Contains(m.Content, "Read the diff") { gotBody = true } // grep 调用应被白名单拒绝 if m.ToolCallID == "t1" && !strings.Contains(m.Content, "not allowed") { t.Fatalf("grep should be denied by skill filter, got %q", m.Content) } } if !gotBody { t.Fatal("skill body not fed back as tool result") } }