Skip to content

Commit a86d501

Browse files
committed
refactor: replace json.Marshal and json.Unmarshal with sjson and gjson
Optimized the handling of JSON serialization and deserialization by replacing redundant `json.Marshal` and `json.Unmarshal` calls with `sjson` and `gjson`. Introduced a `marshalJSONValue` utility for compact JSON encoding, improving performance and code simplicity. Removed unused `encoding/json` imports.
1 parent dbcbe48 commit a86d501

27 files changed

+864
-1615
lines changed

internal/translator/antigravity/claude/antigravity_claude_response.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ func ConvertAntigravityResponseToClaudeNonStream(_ context.Context, _ string, or
452452
toolBlock, _ = sjson.Set(toolBlock, "id", fmt.Sprintf("tool_%d", toolIDCounter))
453453
toolBlock, _ = sjson.Set(toolBlock, "name", name)
454454

455-
if args := functionCall.Get("args"); args.Exists() && args.Raw != "" && gjson.Valid(args.Raw) {
455+
if args := functionCall.Get("args"); args.Exists() && args.Raw != "" && gjson.Valid(args.Raw) && args.IsObject() {
456456
toolBlock, _ = sjson.SetRaw(toolBlock, "input", args.Raw)
457457
}
458458

internal/translator/antigravity/gemini/antigravity_gemini_request.go

Lines changed: 43 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package gemini
77

88
import (
99
"bytes"
10-
"encoding/json"
1110
"fmt"
1211

1312
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
@@ -135,41 +134,31 @@ func ConvertGeminiRequestToAntigravity(_ string, inputRawJSON []byte, _ bool) []
135134

136135
// FunctionCallGroup represents a group of function calls and their responses
137136
type FunctionCallGroup struct {
138-
ModelContent map[string]interface{}
139-
FunctionCalls []gjson.Result
140137
ResponsesNeeded int
141138
}
142139

143-
// parseFunctionResponse attempts to unmarshal a function response part.
144-
// Falls back to gjson extraction if standard json.Unmarshal fails.
145-
func parseFunctionResponse(response gjson.Result) map[string]interface{} {
146-
var responseMap map[string]interface{}
147-
err := json.Unmarshal([]byte(response.Raw), &responseMap)
148-
if err == nil {
149-
return responseMap
140+
// parseFunctionResponseRaw attempts to normalize a function response part into a JSON object string.
141+
// Falls back to a minimal "functionResponse" object when parsing fails.
142+
func parseFunctionResponseRaw(response gjson.Result) string {
143+
if response.IsObject() && gjson.Valid(response.Raw) {
144+
return response.Raw
150145
}
151146

152-
log.Debugf("unmarshal function response failed, using fallback: %v", err)
147+
log.Debugf("parse function response failed, using fallback")
153148
funcResp := response.Get("functionResponse")
154149
if funcResp.Exists() {
155-
fr := map[string]interface{}{
156-
"name": funcResp.Get("name").String(),
157-
"response": map[string]interface{}{
158-
"result": funcResp.Get("response").String(),
159-
},
160-
}
150+
fr := `{"functionResponse":{"name":"","response":{"result":""}}}`
151+
fr, _ = sjson.Set(fr, "functionResponse.name", funcResp.Get("name").String())
152+
fr, _ = sjson.Set(fr, "functionResponse.response.result", funcResp.Get("response").String())
161153
if id := funcResp.Get("id").String(); id != "" {
162-
fr["id"] = id
154+
fr, _ = sjson.Set(fr, "functionResponse.id", id)
163155
}
164-
return map[string]interface{}{"functionResponse": fr}
156+
return fr
165157
}
166158

167-
return map[string]interface{}{
168-
"functionResponse": map[string]interface{}{
169-
"name": "unknown",
170-
"response": map[string]interface{}{"result": response.String()},
171-
},
172-
}
159+
fr := `{"functionResponse":{"name":"unknown","response":{"result":""}}}`
160+
fr, _ = sjson.Set(fr, "functionResponse.response.result", response.String())
161+
return fr
173162
}
174163

175164
// fixCLIToolResponse performs sophisticated tool response format conversion and grouping.
@@ -196,7 +185,7 @@ func fixCLIToolResponse(input string) (string, error) {
196185
}
197186

198187
// Initialize data structures for processing and grouping
199-
var newContents []interface{} // Final processed contents array
188+
contentsWrapper := `{"contents":[]}`
200189
var pendingGroups []*FunctionCallGroup // Groups awaiting completion with responses
201190
var collectedResponses []gjson.Result // Standalone responses to be matched
202191

@@ -228,17 +217,16 @@ func fixCLIToolResponse(input string) (string, error) {
228217
collectedResponses = collectedResponses[group.ResponsesNeeded:]
229218

230219
// Create merged function response content
231-
var responseParts []interface{}
220+
functionResponseContent := `{"parts":[],"role":"function"}`
232221
for _, response := range groupResponses {
233-
responseParts = append(responseParts, parseFunctionResponse(response))
222+
partRaw := parseFunctionResponseRaw(response)
223+
if partRaw != "" {
224+
functionResponseContent, _ = sjson.SetRaw(functionResponseContent, "parts.-1", partRaw)
225+
}
234226
}
235227

236-
if len(responseParts) > 0 {
237-
functionResponseContent := map[string]interface{}{
238-
"parts": responseParts,
239-
"role": "function",
240-
}
241-
newContents = append(newContents, functionResponseContent)
228+
if gjson.Get(functionResponseContent, "parts.#").Int() > 0 {
229+
contentsWrapper, _ = sjson.SetRaw(contentsWrapper, "contents.-1", functionResponseContent)
242230
}
243231

244232
// Remove this group as it's been satisfied
@@ -252,50 +240,42 @@ func fixCLIToolResponse(input string) (string, error) {
252240

253241
// If this is a model with function calls, create a new group
254242
if role == "model" {
255-
var functionCallsInThisModel []gjson.Result
243+
functionCallsCount := 0
256244
parts.ForEach(func(_, part gjson.Result) bool {
257245
if part.Get("functionCall").Exists() {
258-
functionCallsInThisModel = append(functionCallsInThisModel, part)
246+
functionCallsCount++
259247
}
260248
return true
261249
})
262250

263-
if len(functionCallsInThisModel) > 0 {
251+
if functionCallsCount > 0 {
264252
// Add the model content
265-
var contentMap map[string]interface{}
266-
errUnmarshal := json.Unmarshal([]byte(value.Raw), &contentMap)
267-
if errUnmarshal != nil {
268-
log.Warnf("failed to unmarshal model content: %v\n", errUnmarshal)
253+
if !value.IsObject() {
254+
log.Warnf("failed to parse model content")
269255
return true
270256
}
271-
newContents = append(newContents, contentMap)
257+
contentsWrapper, _ = sjson.SetRaw(contentsWrapper, "contents.-1", value.Raw)
272258

273259
// Create a new group for tracking responses
274260
group := &FunctionCallGroup{
275-
ModelContent: contentMap,
276-
FunctionCalls: functionCallsInThisModel,
277-
ResponsesNeeded: len(functionCallsInThisModel),
261+
ResponsesNeeded: functionCallsCount,
278262
}
279263
pendingGroups = append(pendingGroups, group)
280264
} else {
281265
// Regular model content without function calls
282-
var contentMap map[string]interface{}
283-
errUnmarshal := json.Unmarshal([]byte(value.Raw), &contentMap)
284-
if errUnmarshal != nil {
285-
log.Warnf("failed to unmarshal content: %v\n", errUnmarshal)
266+
if !value.IsObject() {
267+
log.Warnf("failed to parse content")
286268
return true
287269
}
288-
newContents = append(newContents, contentMap)
270+
contentsWrapper, _ = sjson.SetRaw(contentsWrapper, "contents.-1", value.Raw)
289271
}
290272
} else {
291273
// Non-model content (user, etc.)
292-
var contentMap map[string]interface{}
293-
errUnmarshal := json.Unmarshal([]byte(value.Raw), &contentMap)
294-
if errUnmarshal != nil {
295-
log.Warnf("failed to unmarshal content: %v\n", errUnmarshal)
274+
if !value.IsObject() {
275+
log.Warnf("failed to parse content")
296276
return true
297277
}
298-
newContents = append(newContents, contentMap)
278+
contentsWrapper, _ = sjson.SetRaw(contentsWrapper, "contents.-1", value.Raw)
299279
}
300280

301281
return true
@@ -307,25 +287,23 @@ func fixCLIToolResponse(input string) (string, error) {
307287
groupResponses := collectedResponses[:group.ResponsesNeeded]
308288
collectedResponses = collectedResponses[group.ResponsesNeeded:]
309289

310-
var responseParts []interface{}
290+
functionResponseContent := `{"parts":[],"role":"function"}`
311291
for _, response := range groupResponses {
312-
responseParts = append(responseParts, parseFunctionResponse(response))
292+
partRaw := parseFunctionResponseRaw(response)
293+
if partRaw != "" {
294+
functionResponseContent, _ = sjson.SetRaw(functionResponseContent, "parts.-1", partRaw)
295+
}
313296
}
314297

315-
if len(responseParts) > 0 {
316-
functionResponseContent := map[string]interface{}{
317-
"parts": responseParts,
318-
"role": "function",
319-
}
320-
newContents = append(newContents, functionResponseContent)
298+
if gjson.Get(functionResponseContent, "parts.#").Int() > 0 {
299+
contentsWrapper, _ = sjson.SetRaw(contentsWrapper, "contents.-1", functionResponseContent)
321300
}
322301
}
323302
}
324303

325304
// Update the original JSON with the new contents
326305
result := input
327-
newContentsJSON, _ := json.Marshal(newContents)
328-
result, _ = sjson.Set(result, "request.contents", json.RawMessage(newContentsJSON))
306+
result, _ = sjson.SetRaw(result, "request.contents", gjson.Get(contentsWrapper, "contents").Raw)
329307

330308
return result, nil
331309
}

internal/translator/antigravity/openai/chat-completions/antigravity_openai_request.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
319319
log.Warnf("Failed to set default schema type for tool '%s': %v", fn.Get("name").String(), errSet)
320320
continue
321321
}
322-
fnRaw, errSet = sjson.Set(fnRaw, "parametersJsonSchema.properties", map[string]interface{}{})
322+
fnRaw, errSet = sjson.SetRaw(fnRaw, "parametersJsonSchema.properties", `{}`)
323323
if errSet != nil {
324324
log.Warnf("Failed to set default schema properties for tool '%s': %v", fn.Get("name").String(), errSet)
325325
continue
@@ -334,7 +334,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
334334
log.Warnf("Failed to set default schema type for tool '%s': %v", fn.Get("name").String(), errSet)
335335
continue
336336
}
337-
fnRaw, errSet = sjson.Set(fnRaw, "parametersJsonSchema.properties", map[string]interface{}{})
337+
fnRaw, errSet = sjson.SetRaw(fnRaw, "parametersJsonSchema.properties", `{}`)
338338
if errSet != nil {
339339
log.Warnf("Failed to set default schema properties for tool '%s': %v", fn.Get("name").String(), errSet)
340340
continue

internal/translator/antigravity/openai/chat-completions/antigravity_openai_response.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package chat_completions
88
import (
99
"bytes"
1010
"context"
11-
"encoding/json"
1211
"fmt"
1312
"strings"
1413
"sync/atomic"
@@ -171,21 +170,14 @@ func ConvertAntigravityResponseToOpenAI(_ context.Context, _ string, originalReq
171170
mimeType = "image/png"
172171
}
173172
imageURL := fmt.Sprintf("data:%s;base64,%s", mimeType, data)
174-
imagePayload, err := json.Marshal(map[string]any{
175-
"type": "image_url",
176-
"image_url": map[string]string{
177-
"url": imageURL,
178-
},
179-
})
180-
if err != nil {
181-
continue
182-
}
173+
imagePayload := `{"image_url":{"url":""},"type":"image_url"}`
174+
imagePayload, _ = sjson.Set(imagePayload, "image_url.url", imageURL)
183175
imagesResult := gjson.Get(template, "choices.0.delta.images")
184176
if !imagesResult.Exists() || !imagesResult.IsArray() {
185177
template, _ = sjson.SetRaw(template, "choices.0.delta.images", `[]`)
186178
}
187179
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
188-
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", string(imagePayload))
180+
template, _ = sjson.SetRaw(template, "choices.0.delta.images.-1", imagePayload)
189181
}
190182
}
191183
}

internal/translator/claude/gemini/claude_gemini_request.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
194194
if name := fc.Get("name"); name.Exists() {
195195
toolUse, _ = sjson.Set(toolUse, "name", name.String())
196196
}
197-
if args := fc.Get("args"); args.Exists() {
197+
if args := fc.Get("args"); args.Exists() && args.IsObject() {
198198
toolUse, _ = sjson.SetRaw(toolUse, "input", args.Raw)
199199
}
200200
msg, _ = sjson.SetRaw(msg, "content.-1", toolUse)
@@ -314,11 +314,11 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
314314
if mode := funcCalling.Get("mode"); mode.Exists() {
315315
switch mode.String() {
316316
case "AUTO":
317-
out, _ = sjson.Set(out, "tool_choice", map[string]interface{}{"type": "auto"})
317+
out, _ = sjson.SetRaw(out, "tool_choice", `{"type":"auto"}`)
318318
case "NONE":
319-
out, _ = sjson.Set(out, "tool_choice", map[string]interface{}{"type": "none"})
319+
out, _ = sjson.SetRaw(out, "tool_choice", `{"type":"none"}`)
320320
case "ANY":
321-
out, _ = sjson.Set(out, "tool_choice", map[string]interface{}{"type": "any"})
321+
out, _ = sjson.SetRaw(out, "tool_choice", `{"type":"any"}`)
322322
}
323323
}
324324
}

0 commit comments

Comments
 (0)