package windsurf import ( "testing" ) func TestExtractToolCallsNLU(t *testing.T) { tools := []string{"edit_file", "read_file", "run_command"} tests := []struct { name string text string available []string wantCount int wantName string }{ { name: "marker form: function: edit_file with JSON", text: `I'll use function: edit_file with {"path": "/tmp/x", "content": "abc"}`, available: tools, wantCount: 1, wantName: "edit_file", }, { name: "marker form: tool_call read_file", text: `tool_call: read_file arguments: {"path": "/etc/hosts"}`, available: tools, wantCount: 1, wantName: "read_file", }, { name: "marker form: nested JSON object", text: `function: run_command with {"cmd": "ls", "opts": {"long": true}}`, available: tools, wantCount: 1, wantName: "run_command", }, { name: "bare name fallback when no marker", text: `Sure, I'll edit_file {"path": "/tmp/y"} for you.`, available: tools, wantCount: 1, wantName: "edit_file", }, { name: "unknown tool name rejected when available list is non-empty", text: `function: delete_universe {"target": "all"}`, available: tools, wantCount: 0, }, { name: "no JSON after marker yields no call", text: `function: edit_file but I'm not sure what arguments to use`, available: tools, wantCount: 0, }, { name: "empty text returns nil", text: "", available: tools, wantCount: 0, }, { name: "duplicate names deduplicated", text: `function: edit_file {"path": "/a"} then function: edit_file {"path": "/b"}`, available: tools, wantCount: 1, wantName: "edit_file", }, { name: "name not in available list is rejected even when JSON valid", text: `Calling foo with {"x": 1}`, available: []string{"bar"}, wantCount: 0, }, { name: "marker with no available list still extracts", text: `function: my_tool {"x": 1}`, available: nil, wantCount: 1, wantName: "my_tool", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := ExtractToolCallsNLU(tc.text, tc.available) if len(got) != tc.wantCount { t.Fatalf("expected %d call(s), got %d: %+v", tc.wantCount, len(got), got) } if tc.wantCount > 0 && got[0].Name != tc.wantName { t.Fatalf("expected name %q, got %q", tc.wantName, got[0].Name) } if tc.wantCount > 0 && got[0].ArgumentsJSON == "" { t.Fatalf("expected non-empty ArgumentsJSON, got %q", got[0].ArgumentsJSON) } }) } } func TestHasNLUSignal(t *testing.T) { tests := []struct { text string want bool }{ {"function: edit_file {}", true}, {"I'll call edit_file", true}, {"calling tool edit_file", true}, {"调用工具 edit_file", true}, {"Hello, just a chat reply.", false}, {"", false}, {"foo", false}, } for _, tc := range tests { t.Run(tc.text, func(t *testing.T) { if got := HasNLUSignal(tc.text); got != tc.want { t.Fatalf("HasNLUSignal(%q) = %v, want %v", tc.text, got, tc.want) } }) } } func TestResolveEmulationFlavor(t *testing.T) { tests := []struct { name string meta *ModelMeta want string }{ {"nil meta", nil, EmulationFlavorAuto}, {"explicit override wins", &ModelMeta{Provider: "anthropic", EmulationFlavor: "nlu"}, "nlu"}, {"anthropic default tool_use", &ModelMeta{Provider: "anthropic"}, EmulationFlavorToolUse}, {"zhipu default nlu", &ModelMeta{Provider: "zhipu"}, EmulationFlavorNLU}, {"moonshot default nlu", &ModelMeta{Provider: "moonshot"}, EmulationFlavorNLU}, {"openai default auto", &ModelMeta{Provider: "openai"}, EmulationFlavorAuto}, {"unknown provider auto", &ModelMeta{Provider: "xyz"}, EmulationFlavorAuto}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { if got := ResolveEmulationFlavor(tc.meta); got != tc.want { t.Fatalf("ResolveEmulationFlavor = %q, want %q", got, tc.want) } }) } }