package helps import ( "crypto/sha256" "encoding/hex" "strconv" "strings" "github.com/tidwall/gjson" "github.com/tidwall/sjson" ) const ( codexInputItemIDLimit = 64 codexMessageItemIDPrefix = "msg" ) // SanitizeCodexInputItemIDs normalizes message 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 := gjson.GetBytes(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 { if item.Get("type").String() != "message" || id == "" || strings.HasPrefix(id, codexMessageItemIDPrefix) { return id } return codexMessageItemIDPrefix + "_" + 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 }