mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-15 23:22:59 +08:00
87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
package service
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
const openAIResponsesInputTextMaxChars = 10000000
|
|
|
|
// sanitizeOpenAIResponsesOrphanToolOutputs removes tool-output items that have
|
|
// no matching call or item reference anywhere in the current input. Named
|
|
// function outputs without a call ID are standalone inputs, not orphan results.
|
|
func sanitizeOpenAIResponsesOrphanToolOutputs(reqBody map[string]any, input []any, hasPreviousResponseID bool) bool {
|
|
if len(input) == 0 || hasPreviousResponseID {
|
|
return false
|
|
}
|
|
|
|
toolCallIDs := make(map[string]struct{}, len(input))
|
|
referenceIDs := make(map[string]struct{}, len(input))
|
|
for _, rawItem := range input {
|
|
item, ok := rawItem.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
itemType := strings.TrimSpace(firstNonEmptyString(item["type"]))
|
|
if itemType == "item_reference" {
|
|
if id := strings.TrimSpace(firstNonEmptyString(item["id"])); id != "" {
|
|
referenceIDs[id] = struct{}{}
|
|
}
|
|
continue
|
|
}
|
|
if !isCodexToolCallContextItemType(itemType) {
|
|
continue
|
|
}
|
|
if id := strings.TrimSpace(firstNonEmptyString(item["call_id"], item["id"])); id != "" {
|
|
toolCallIDs[id] = struct{}{}
|
|
}
|
|
}
|
|
|
|
modified := false
|
|
normalized := make([]any, 0, len(input))
|
|
for _, rawItem := range input {
|
|
item, ok := rawItem.(map[string]any)
|
|
if !ok || !isCodexToolCallOutputItemType(strings.TrimSpace(firstNonEmptyString(item["type"]))) {
|
|
normalized = append(normalized, rawItem)
|
|
continue
|
|
}
|
|
|
|
callID := strings.TrimSpace(firstNonEmptyString(item["call_id"]))
|
|
// Codex sends externally supplied inputs (such as task delegation) as
|
|
// named function outputs without a preceding function call. Preserve
|
|
// their native type, namespace and output instead of silently dropping
|
|
// the request that started the turn.
|
|
if callID == "" && strings.TrimSpace(firstNonEmptyString(item["type"])) == "function_call_output" &&
|
|
strings.TrimSpace(firstNonEmptyString(item["name"])) != "" {
|
|
normalized = append(normalized, rawItem)
|
|
continue
|
|
}
|
|
_, hasToolCall := toolCallIDs[callID]
|
|
_, hasReference := referenceIDs[callID]
|
|
if callID != "" && (hasToolCall || hasReference) {
|
|
normalized = append(normalized, rawItem)
|
|
continue
|
|
}
|
|
|
|
modified = true
|
|
}
|
|
if !modified {
|
|
return false
|
|
}
|
|
reqBody["input"] = normalized
|
|
return true
|
|
}
|
|
|
|
func truncateOpenAIResponsesInputText(_ map[string]any) bool {
|
|
// Do not silently rewrite client or tool output. If an upstream enforces a
|
|
// text limit, forwarding the original value preserves its explicit error for
|
|
// the client and the normal Ops error pipeline. This compatibility shim is
|
|
// retained until the two callers can remove the old mutation hook together.
|
|
return false
|
|
}
|
|
|
|
func openAIResponsesInputMayNeedTruncation(_ []byte) bool {
|
|
// See truncateOpenAIResponsesInputText. Returning false also avoids decoding
|
|
// very large bodies solely for a mutation that must not happen.
|
|
return false
|
|
}
|