- windsurf: client/pool/local_ls/tool_emulation/tool_names/models 调整 - handler: admin account_data / failover_loop / gateway_handler - repository: scheduler_cache 及测试 - service: windsurf_chat_service / windsurf_gateway_service - deploy: compose 合并为单文件(含 windsurf-ls profile),Dockerfile.ls - cmd: 新增 dump_ls_models / dump_preamble / test_windsurf_tools 辅助工具
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
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
|
|
}
|