mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-18 03:57:06 +08:00
v0.3.8
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package modeladapter
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
maxProviderToolCallIDLen = 64
|
||||
toolCallNamespaceHashLen = 12
|
||||
toolCallValueHashLen = 12
|
||||
)
|
||||
|
||||
// namespaceToolCallID 为 provider 原始 tool call id 增加 model-call 级别命名空间,
|
||||
// 避免像 functions.Shell:0 这类跨轮复用的 id 在客户端被误判为同一个 bubble。
|
||||
//
|
||||
// OpenAI 等 provider 对 tool_call_id 长度有限制,因此这里使用 model_call_id 的短哈希
|
||||
// 而不是完整 UUID,保证内部存储的 tool_call_id 既稳定又能安全回放给 provider。
|
||||
func namespaceToolCallID(modelCallID string, rawToolCallID string) string {
|
||||
raw := strings.TrimSpace(rawToolCallID)
|
||||
if raw == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.Contains(raw, "::") {
|
||||
return providerToolCallID(raw)
|
||||
}
|
||||
model := strings.TrimSpace(modelCallID)
|
||||
if model == "" {
|
||||
return providerToolCallID(raw)
|
||||
}
|
||||
return buildProviderSafeToolCallID(shortToolCallHash(model, toolCallNamespaceHashLen), raw)
|
||||
}
|
||||
|
||||
// providerToolCallID 把内部持久化的 tool_call_id 规整成 provider 可接受的安全长度。
|
||||
// 这样旧会话里已经落盘的 legacy "<modelCallID>::<rawID>" 也能继续回放。
|
||||
func providerToolCallID(toolCallID string) string {
|
||||
trimmed := strings.TrimSpace(toolCallID)
|
||||
if trimmed == "" {
|
||||
return ""
|
||||
}
|
||||
namespace, raw, ok := splitLegacyToolCallID(trimmed)
|
||||
if ok {
|
||||
return buildProviderSafeToolCallID(shortToolCallHash(namespace, toolCallNamespaceHashLen), raw)
|
||||
}
|
||||
if len(trimmed) <= maxProviderToolCallIDLen {
|
||||
return trimmed
|
||||
}
|
||||
return buildProviderSafeToolCallID("", trimmed)
|
||||
}
|
||||
|
||||
type providerToolCallDescriptor struct {
|
||||
ID string `json:"id"`
|
||||
Index int `json:"index,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Function ToolCallFunctionShape `json:"function"`
|
||||
}
|
||||
|
||||
func normalizeToolCallDescriptors(toolCalls []ToolCallDescriptor) []providerToolCallDescriptor {
|
||||
if len(toolCalls) == 0 {
|
||||
return nil
|
||||
}
|
||||
normalized := make([]providerToolCallDescriptor, 0, len(toolCalls))
|
||||
for _, toolCall := range toolCalls {
|
||||
item := providerToolCallDescriptor{
|
||||
ID: providerToolCallID(toolCall.ID),
|
||||
Index: toolCall.Index,
|
||||
Type: toolCall.Type,
|
||||
Function: toolCall.Function,
|
||||
}
|
||||
normalized = append(normalized, item)
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
func buildProviderSafeToolCallID(namespace string, raw string) string {
|
||||
trimmedRaw := strings.TrimSpace(raw)
|
||||
if trimmedRaw == "" {
|
||||
return ""
|
||||
}
|
||||
if namespace == "" && len(trimmedRaw) <= maxProviderToolCallIDLen && !strings.Contains(trimmedRaw, "::") {
|
||||
return trimmedRaw
|
||||
}
|
||||
|
||||
prefix := "tc"
|
||||
if namespace != "" {
|
||||
prefix += "_" + namespace
|
||||
}
|
||||
candidate := prefix + "_" + trimmedRaw
|
||||
if len(candidate) <= maxProviderToolCallIDLen {
|
||||
return candidate
|
||||
}
|
||||
|
||||
rawHash := shortToolCallHash(trimmedRaw, toolCallValueHashLen)
|
||||
remaining := maxProviderToolCallIDLen - len(prefix) - len(rawHash) - 2
|
||||
if remaining <= 0 {
|
||||
return prefix + "_" + rawHash
|
||||
}
|
||||
suffix := trimmedRaw
|
||||
if len(suffix) > remaining {
|
||||
suffix = suffix[len(suffix)-remaining:]
|
||||
}
|
||||
return prefix + "_" + rawHash + "_" + suffix
|
||||
}
|
||||
|
||||
func splitLegacyToolCallID(value string) (namespace string, raw string, ok bool) {
|
||||
namespace, raw, ok = strings.Cut(strings.TrimSpace(value), "::")
|
||||
if !ok {
|
||||
return "", "", false
|
||||
}
|
||||
namespace = strings.TrimSpace(namespace)
|
||||
raw = strings.TrimSpace(raw)
|
||||
if namespace == "" || raw == "" {
|
||||
return "", "", false
|
||||
}
|
||||
return namespace, raw, true
|
||||
}
|
||||
|
||||
func shortToolCallHash(value string, size int) string {
|
||||
sum := sha256.Sum256([]byte(strings.TrimSpace(value)))
|
||||
encoded := hex.EncodeToString(sum[:])
|
||||
if size <= 0 || size > len(encoded) {
|
||||
return encoded
|
||||
}
|
||||
return encoded[:size]
|
||||
}
|
||||
Reference in New Issue
Block a user