// tool_safety_description_test.go — Agent Tool Safety Protocol 在 buildToolDefs // 层对 MinConfidence>0 工具的 Description 注入回归保证. // // 锁一个 sub-claim: MinConfidence>0 工具的 Description 被追加 _flyto_confidence // 提示 + 阈值; MinConfidence=0 工具 Description 不变. 功能性 gate 拦截 / // 放行行为在 pkg/tools/orchestrator_test.go 锁. package engine import ( "context" "encoding/json" "strings" "testing" "git.flytoex.net/yuanwei/flyto-agent/pkg/tools" ) type gatedDescTool struct { name string baseDesc string threshold int } func (g *gatedDescTool) Name() string { return g.name } func (g *gatedDescTool) Description(ctx context.Context) string { return g.baseDesc } func (g *gatedDescTool) InputSchema() json.RawMessage { return json.RawMessage(`{}`) } func (g *gatedDescTool) Execute(ctx context.Context, input json.RawMessage, progress tools.ProgressFunc) (*tools.Result, error) { return &tools.Result{Output: "ok"}, nil } func (g *gatedDescTool) Capability() tools.ToolCapability { return tools.ToolCapability{MinConfidence: g.threshold} } func TestBuildToolDefs_SafetyHintAppended_OnlyForGatedTool(t *testing.T) { reg := tools.NewRegistry() gated := &gatedDescTool{name: "Gated", baseDesc: "edit the thing", threshold: 75} free := &gatedDescTool{name: "Free", baseDesc: "read the thing", threshold: 0} if err := reg.Register(gated); err != nil { t.Fatalf("register gated: %v", err) } if err := reg.Register(free); err != nil { t.Fatalf("register free: %v", err) } e := &Engine{tools: reg} defs := e.buildToolDefs(context.Background()) var gatedDesc, freeDesc string for _, d := range defs { switch d.Name { case "Gated": gatedDesc = d.Description case "Free": freeDesc = d.Description } } if !strings.Contains(gatedDesc, "_flyto_confidence") { t.Errorf("gated tool Description 应追加 _flyto_confidence 提示, 实际: %q", gatedDesc) } if !strings.Contains(gatedDesc, "75") { t.Errorf("gated tool Description 应含阈值 75, 实际: %q", gatedDesc) } if !strings.HasPrefix(gatedDesc, "edit the thing") { t.Errorf("gated tool Description 应保留原始描述在前, 实际: %q", gatedDesc) } if strings.Contains(freeDesc, "_flyto_confidence") { t.Errorf("MinConfidence=0 工具 Description 不应被污染, 实际: %q", freeDesc) } if freeDesc != "read the thing" { t.Errorf("MinConfidence=0 工具 Description 应原样, 实际: %q", freeDesc) } }