| package builtin |
|
|
| import ( |
| "crypto/sha1" |
| "encoding/hex" |
| "strings" |
|
|
| "ccLoad/internal/protocol" |
|
|
| "github.com/bytedance/sonic" |
| ) |
|
|
| const codexToolNameLimit = 64 |
|
|
| type codexToolAliases struct { |
| OriginalToShort map[string]string |
| ShortToOriginal map[string]string |
| } |
|
|
| func buildCodexToolAliases(names []string) codexToolAliases { |
| aliases := codexToolAliases{ |
| OriginalToShort: make(map[string]string), |
| ShortToOriginal: make(map[string]string), |
| } |
| used := make(map[string]string) |
| for _, rawName := range names { |
| name := strings.TrimSpace(rawName) |
| if name == "" { |
| continue |
| } |
| if short, ok := aliases.OriginalToShort[name]; ok { |
| aliases.ShortToOriginal[short] = name |
| continue |
| } |
| short := codexShortToolName(name, used) |
| used[short] = name |
| aliases.OriginalToShort[name] = short |
| aliases.ShortToOriginal[short] = name |
| } |
| return aliases |
| } |
|
|
| func codexShortToolName(name string, used map[string]string) string { |
| if len(name) <= codexToolNameLimit { |
| if existing := used[name]; existing == "" || existing == name { |
| return name |
| } |
| } |
| sum := sha1.Sum([]byte(name)) |
| hash := hex.EncodeToString(sum[:]) |
| for n := 12; n <= len(hash); n += 4 { |
| suffix := hash[:n] |
| prefixLen := codexToolNameLimit - len(suffix) - 1 |
| if prefixLen < 1 { |
| prefixLen = 1 |
| } |
| prefix := name |
| if len(prefix) > prefixLen { |
| prefix = prefix[:prefixLen] |
| } |
| alias := prefix + "_" + suffix |
| if existing := used[alias]; existing == "" || existing == name { |
| return alias |
| } |
| } |
| return hash[:codexToolNameLimit] |
| } |
|
|
| func (a codexToolAliases) shorten(name string) string { |
| name = strings.TrimSpace(name) |
| if name == "" { |
| return "" |
| } |
| if short := a.OriginalToShort[name]; short != "" { |
| return short |
| } |
| return name |
| } |
|
|
| func (a codexToolAliases) restore(name string) string { |
| name = strings.TrimSpace(name) |
| if name == "" { |
| return "" |
| } |
| if original := a.ShortToOriginal[name]; original != "" { |
| return original |
| } |
| return name |
| } |
|
|
| func collectCodexAliasNames(conv conversation) []string { |
| names := make([]string, 0) |
| seen := make(map[string]struct{}) |
| add := func(name string) { |
| name = strings.TrimSpace(name) |
| if name == "" { |
| return |
| } |
| if _, ok := seen[name]; ok { |
| return |
| } |
| seen[name] = struct{}{} |
| names = append(names, name) |
| } |
|
|
| for _, tool := range conv.Tools { |
| if tool.toolType() == "function" { |
| add(tool.Name) |
| } |
| } |
| if conv.ToolChoice.Mode == "named" && conv.ToolChoice.toolType() == "function" { |
| add(conv.ToolChoice.Name) |
| } |
| for _, turn := range conv.Turns { |
| for _, part := range turn.Parts { |
| switch part.Kind { |
| case partKindToolCall: |
| if part.ToolCall != nil { |
| add(part.ToolCall.Name) |
| } |
| case partKindToolResult: |
| if part.ToolResult != nil { |
| add(part.ToolResult.Name) |
| } |
| } |
| } |
| } |
| return names |
| } |
|
|
| func codexToolAliasesFromConversations(original, translated conversation) codexToolAliases { |
| aliases := buildCodexToolAliases(collectCodexAliasNames(original)) |
| translatedNames := collectCodexAliasNames(translated) |
| if len(translatedNames) == 0 { |
| return aliases |
| } |
| originalNames := collectCodexAliasNames(original) |
| for i, originalName := range originalNames { |
| if i >= len(translatedNames) { |
| break |
| } |
| shortName := strings.TrimSpace(translatedNames[i]) |
| if originalName == "" || shortName == "" { |
| continue |
| } |
| aliases.OriginalToShort[originalName] = shortName |
| aliases.ShortToOriginal[shortName] = originalName |
| } |
| return aliases |
| } |
|
|
| func codexToolAliasesFromRequests(source protocol.Protocol, rawReq, translatedReq []byte) codexToolAliases { |
| original, ok := normalizeConversationFromRequest(source, rawReq) |
| if !ok { |
| return codexToolAliases{} |
| } |
| translated, ok := normalizeConversationFromRequest(protocol.Codex, translatedReq) |
| if !ok { |
| return buildCodexToolAliases(collectCodexAliasNames(original)) |
| } |
| return codexToolAliasesFromConversations(original, translated) |
| } |
|
|
| func normalizeConversationFromRequest(source protocol.Protocol, rawReq []byte) (conversation, bool) { |
| if len(rawReq) == 0 { |
| return conversation{}, false |
| } |
| switch source { |
| case protocol.OpenAI: |
| var req openAIChatRequest |
| if err := sonic.Unmarshal(rawReq, &req); err != nil { |
| return conversation{}, false |
| } |
| conv, err := normalizeOpenAIConversation(req) |
| return conv, err == nil |
| case protocol.Gemini: |
| var req geminiRequestPayload |
| if err := sonic.Unmarshal(rawReq, &req); err != nil { |
| return conversation{}, false |
| } |
| conv, err := normalizeGeminiConversation(req) |
| return conv, err == nil |
| case protocol.Anthropic: |
| var req anthropicMessagesRequest |
| if err := sonic.Unmarshal(rawReq, &req); err != nil { |
| return conversation{}, false |
| } |
| conv, err := normalizeAnthropicConversation(req) |
| return conv, err == nil |
| case protocol.Codex: |
| var req codexRequest |
| if err := sonic.Unmarshal(rawReq, &req); err != nil { |
| return conversation{}, false |
| } |
| conv, err := normalizeCodexConversation(req) |
| return conv, err == nil |
| default: |
| return conversation{}, false |
| } |
| } |
|
|