145 lines · 3.6 KB · Go
RawDownload
package helps import (	"crypto/sha256"	"encoding/hex"	"strconv"	"strings" 	"github.com/router-for-me/CLIProxyAPI/v7/internal/util"	"github.com/tidwall/gjson"	"github.com/tidwall/sjson") const (	codexInputItemIDLimit         = 64	codexMessageItemIDPrefix      = "msg"	codexReasoningItemIDPrefix    = "rs"	codexFunctionCallItemIDPrefix = "fc") // SanitizeCodexInputItemIDs normalizes supported input item IDs for Codex, removes encrypted// reasoning items whose IDs exceed the Codex limit, and deterministically shortens// other overlong input item IDs.func SanitizeCodexInputItemIDs(body []byte) []byte {	input := util.GetGJSONBytesNoCopy(body, "input")	if !input.IsArray() {		return body	} 	items := input.Array()	occupied := make(map[string]struct{}, len(items))	for _, item := range items {		if shouldDropCodexEncryptedReasoningItem(item) {			continue		}		itemID := item.Get("id")		if itemID.Type != gjson.String {			continue		}		id := normalizeCodexInputItemID(item, itemID.String())		if len([]rune(id)) <= codexInputItemIDLimit {			occupied[id] = struct{}{}		}	} 	mapped := make(map[string]string, len(items))	rebuilt := make([]string, 0, len(items))	changed := false	for _, item := range items {		if shouldDropCodexEncryptedReasoningItem(item) {			changed = true			continue		} 		raw := item.Raw		itemID := item.Get("id")		if itemID.Type == gjson.String {			originalID := itemID.String()			id := normalizeCodexInputItemID(item, originalID)			if len([]rune(id)) > codexInputItemIDLimit {				shortened, ok := mapped[id]				if !ok {					shortened = shortenCodexInputItemID(id)					for attempt := 1; ; attempt++ {						if _, exists := occupied[shortened]; !exists {							break						}						shortened = shortenCodexInputItemIDWithAttempt(id, attempt)					}					mapped[id] = shortened					occupied[shortened] = struct{}{}				}				id = shortened			} 			if id != originalID {				next, errSet := sjson.SetBytes([]byte(raw), "id", id)				if errSet == nil {					raw = string(next)					changed = true				}			}		}		rebuilt = append(rebuilt, raw)	}	if !changed {		return body	} 	updated, errSet := sjson.SetRawBytes(body, "input", []byte("["+strings.Join(rebuilt, ",")+"]"))	if errSet != nil {		return body	}	return updated} func normalizeCodexInputItemID(item gjson.Result, id string) string {	var prefix string	switch item.Get("type").String() {	case "message":		prefix = codexMessageItemIDPrefix	case "reasoning":		prefix = codexReasoningItemIDPrefix	case "function_call":		prefix = codexFunctionCallItemIDPrefix	default:		return id	}	if id == "" || strings.HasPrefix(id, prefix) {		return id	}	return prefix + "_" + id} func shouldDropCodexEncryptedReasoningItem(item gjson.Result) bool {	if item.Get("type").String() != "reasoning" {		return false	}	itemID := item.Get("id")	if itemID.Type != gjson.String || len([]rune(itemID.String())) <= codexInputItemIDLimit {		return false	}	encryptedContent := item.Get("encrypted_content")	return encryptedContent.Type == gjson.String && encryptedContent.String() != ""} func shortenCodexInputItemID(id string) string {	return shortenCodexInputItemIDWithAttempt(id, 0)} func shortenCodexInputItemIDWithAttempt(id string, attempt int) string {	runes := []rune(id)	if len(runes) <= codexInputItemIDLimit {		return id	} 	hashInput := id	if attempt > 0 {		hashInput += "\x00" + strconv.Itoa(attempt)	}	sum := sha256.Sum256([]byte(hashInput))	suffix := "_" + hex.EncodeToString(sum[:8])	prefixLength := codexInputItemIDLimit - len(suffix)	return string(runes[:prefixLength]) + suffix}