package windsurf import "strings" var canonicalToolAliases = map[string]string{ "read": "read", "read_file": "read", "readfile": "read", "write": "write", "write_file": "write", "writefile": "write", "edit": "edit", "apply_patch": "edit", "applypatch": "edit", "bash": "bash", "execute_bash": "bash", "executebash": "bash", "exec_bash": "bash", "execbash": "bash", "glob": "glob", "list_files": "glob", "listfiles": "glob", "grep": "grep", "search_files": "grep", "searchfiles": "grep", "webfetch": "webfetch", "web_fetch": "webfetch", "fetch": "webfetch", } // NormalizeToolName canonicalizes known tool aliases while preserving unknown tool names. // // Callers use different conventions: // - OpenCode / Codex: lowercase or snake_case ("read_file", "search_files") // → canonicalize via aliases map. // - Claude Code: PascalCase ("Read", "Bash", "Glob", "Edit", "TodoWrite", …) // → must pass through untouched; lowercasing them breaks round-trip because // Claude Code only recognizes its exact PascalCase names. // // Heuristic: if the input starts with an uppercase letter, treat it as the // caller's authoritative name and do NOT canonicalize. func NormalizeToolName(name string) string { trimmed := strings.TrimSpace(name) if trimmed == "" { return "" } if c := trimmed[0]; c >= 'A' && c <= 'Z' { return trimmed } if canonical, ok := canonicalToolAliases[strings.ToLower(trimmed)]; ok { return canonical } return trimmed } func normalizeOpenAITool(tool OpenAITool) OpenAITool { if tool.Type != "function" { return tool } tool.Function.Name = NormalizeToolName(tool.Function.Name) return tool } func canonicalizeOpenAITools(tools []OpenAITool) []OpenAITool { if len(tools) == 0 { return nil } out := make([]OpenAITool, 0, len(tools)) seen := make(map[string]int, len(tools)) for _, tool := range tools { normalized := normalizeOpenAITool(tool) if normalized.Type != "function" { out = append(out, normalized) continue } name := strings.TrimSpace(normalized.Function.Name) if name == "" { continue } key := strings.ToLower(name) if idx, ok := seen[key]; ok { if out[idx].Function.Description == "" { out[idx].Function.Description = normalized.Function.Description } if len(out[idx].Function.Parameters) == 0 { out[idx].Function.Parameters = normalized.Function.Parameters } continue } seen[key] = len(out) out = append(out, normalized) } return out }