mirror of
https://gh-proxy.org/https://github.com/klinsmaya/CLIProxyAPI.git
synced 2026-11-08 01:16:47 +08:00
perf(translator): build claude system and messages arrays in a single pass
- Replaced per-item `sjson.SetRawBytes(out, "system.-1"/"messages.-1", ...)` appends, which reparsed and rewrote the growing output document on every conversation item, causing O(n^2) work on long histories. - Collected system and message blocks into slices and wrote each array once via `common.JoinRawArray`, moving the cache_control post-processing and system-only fallback turn onto the collected slices.
This commit is contained in:
@@ -163,39 +163,36 @@ func ConvertOpenAIRequestToClaude(modelName string, inputRawJSON []byte, stream
|
||||
|
||||
// Process messages and transform them to Claude Code format
|
||||
if messages := root.Get("messages"); messages.Exists() && messages.IsArray() {
|
||||
messageIndex := 0
|
||||
systemBlocks := make([][]byte, 0)
|
||||
messageBlocks := make([][]byte, 0)
|
||||
messages.ForEach(func(_, message gjson.Result) bool {
|
||||
role := message.Get("role").String()
|
||||
contentResult := message.Get("content")
|
||||
|
||||
switch role {
|
||||
case "system":
|
||||
systemStart := len(gjson.GetBytes(out, "system").Array())
|
||||
systemStart := len(systemBlocks)
|
||||
if contentResult.Exists() && contentResult.Type == gjson.String && contentResult.String() != "" {
|
||||
textPart := []byte(`{"type":"text","text":""}`)
|
||||
textPart, _ = sjson.SetBytes(textPart, "text", contentResult.String())
|
||||
textPart = common.AttachCacheControl(textPart, message)
|
||||
out, _ = sjson.SetRawBytes(out, "system.-1", textPart)
|
||||
systemBlocks = append(systemBlocks, textPart)
|
||||
} else if contentResult.Exists() && contentResult.IsArray() {
|
||||
contentResult.ForEach(func(_, part gjson.Result) bool {
|
||||
if part.Get("type").String() == "text" {
|
||||
textPart := []byte(`{"type":"text","text":""}`)
|
||||
textPart, _ = sjson.SetBytes(textPart, "text", part.Get("text").String())
|
||||
textPart = common.AttachCacheControl(textPart, part)
|
||||
out, _ = sjson.SetRawBytes(out, "system.-1", textPart)
|
||||
systemBlocks = append(systemBlocks, textPart)
|
||||
}
|
||||
return true
|
||||
})
|
||||
// Message-level cache_control applies to the last system block from this message.
|
||||
if message.Get("cache_control").Exists() {
|
||||
systemArr := gjson.GetBytes(out, "system").Array()
|
||||
if len(systemArr) > systemStart {
|
||||
lastIdx := len(systemArr) - 1
|
||||
if !systemArr[lastIdx].Get("cache_control").Exists() {
|
||||
path := fmt.Sprintf("system.%d", lastIdx)
|
||||
block := []byte(systemArr[lastIdx].Raw)
|
||||
block = common.AttachCacheControl(block, message)
|
||||
out, _ = sjson.SetRawBytes(out, path, block)
|
||||
if len(systemBlocks) > systemStart {
|
||||
lastIdx := len(systemBlocks) - 1
|
||||
if !gjson.GetBytes(systemBlocks[lastIdx], "cache_control").Exists() {
|
||||
systemBlocks[lastIdx] = common.AttachCacheControl(systemBlocks[lastIdx], message)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,8 +255,7 @@ func ConvertOpenAIRequestToClaude(modelName string, inputRawJSON []byte, stream
|
||||
}
|
||||
|
||||
msg = common.AttachMessageCacheControl(msg, message)
|
||||
out, _ = sjson.SetRawBytes(out, "messages.-1", msg)
|
||||
messageIndex++
|
||||
messageBlocks = append(messageBlocks, msg)
|
||||
|
||||
case "tool":
|
||||
// Handle tool result messages conversion
|
||||
@@ -276,20 +272,22 @@ func ConvertOpenAIRequestToClaude(modelName string, inputRawJSON []byte, stream
|
||||
msg, _ = sjson.SetBytes(msg, "content.0.content", toolResultContent)
|
||||
}
|
||||
msg = common.AttachMessageCacheControl(msg, message)
|
||||
out, _ = sjson.SetRawBytes(out, "messages.-1", msg)
|
||||
messageIndex++
|
||||
messageBlocks = append(messageBlocks, msg)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// Preserve a minimal conversational turn for system-only inputs.
|
||||
// Claude payloads with top-level system instructions but no messages are risky for downstream validation.
|
||||
if messageIndex == 0 {
|
||||
system := gjson.GetBytes(out, "system")
|
||||
if system.Exists() && system.IsArray() && len(system.Array()) > 0 {
|
||||
fallbackMsg := []byte(`{"role":"user","content":[{"type":"text","text":""}]}`)
|
||||
out, _ = sjson.SetRawBytes(out, "messages.-1", fallbackMsg)
|
||||
}
|
||||
if len(messageBlocks) == 0 && len(systemBlocks) > 0 {
|
||||
messageBlocks = append(messageBlocks, []byte(`{"role":"user","content":[{"type":"text","text":""}]}`))
|
||||
}
|
||||
|
||||
if len(systemBlocks) > 0 {
|
||||
out, _ = sjson.SetRawBytes(out, "system", common.JoinRawArray(systemBlocks))
|
||||
}
|
||||
if len(messageBlocks) > 0 {
|
||||
out, _ = sjson.SetRawBytes(out, "messages", common.JoinRawArray(messageBlocks))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user