package tool import ( "context" "encoding/json" "testing" ) type stubTool struct{ name string } func (s stubTool) Name() string { return s.name } func (s stubTool) Description() string { return "" } func (s stubTool) Schema() json.RawMessage { return json.RawMessage(`{}`) } func (s stubTool) Run(ctx context.Context, input json.RawMessage, env Env) (Result, error) { return Result{}, nil } // TestRegistry_Defs_StableOrder sichert einen konkreten Bug ab: Defs() // iterierte früher direkt über die interne Map, deren Reihenfolge Go pro // Aufruf zufällig mischt. Da tools im Request vor messages steht und Teil // des gecachten Prefix ist (E-06), hat das Prompt-Caching bei jedem Turn // neu gebrochen. Defs() muss deterministisch (nach Name) sortiert sein. func TestRegistry_Defs_StableOrder(t *testing.T) { r := NewRegistry() names := []string{"read", "write", "edit", "bash", "glob", "grep", "todo", "read_skill"} for _, n := range names { r.Register(stubTool{name: n}) } first := r.Defs() for i := 0; i < 20; i++ { got := r.Defs() if len(got) != len(first) { t.Fatalf("Defs() length changed between calls: %d vs %d", len(got), len(first)) } for j := range got { if got[j].Name != first[j].Name { t.Fatalf("Defs() order not stable across calls (iteration %d): %+v vs %+v", i, got, first) } } } for i := 1; i < len(first); i++ { if first[i-1].Name > first[i].Name { t.Errorf("Defs() not sorted by name: %q before %q", first[i-1].Name, first[i].Name) } } }