Skip to content

Commit 4e26182

Browse files
committed
fix(antigravity): place tool_result images in functionResponse.parts and unify mimeType
Move base64 image data from Claude tool_result into functionResponse.parts as inlineData instead of outer sibling parts, preventing context bloat. Unify all inlineData field naming to camelCase mimeType across Claude, OpenAI, and Gemini translators. Add comprehensive edge case tests and Gemini-side regression test for functionResponse.parts preservation.
1 parent 713388d commit 4e26182

File tree

4 files changed

+562
-10
lines changed

4 files changed

+562
-10
lines changed

internal/translator/antigravity/claude/antigravity_claude_request.go

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,65 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
223223
functionResponseJSON, _ = sjson.Set(functionResponseJSON, "response.result", responseData)
224224
} else if functionResponseResult.IsArray() {
225225
frResults := functionResponseResult.Array()
226-
if len(frResults) == 1 {
227-
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", frResults[0].Raw)
226+
nonImageCount := 0
227+
lastNonImageRaw := ""
228+
filteredJSON := "[]"
229+
imagePartsJSON := "[]"
230+
for _, fr := range frResults {
231+
if fr.Get("type").String() == "image" && fr.Get("source.type").String() == "base64" {
232+
inlineDataJSON := `{}`
233+
if mimeType := fr.Get("source.media_type").String(); mimeType != "" {
234+
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "mimeType", mimeType)
235+
}
236+
if data := fr.Get("source.data").String(); data != "" {
237+
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "data", data)
238+
}
239+
240+
imagePartJSON := `{}`
241+
imagePartJSON, _ = sjson.SetRaw(imagePartJSON, "inlineData", inlineDataJSON)
242+
imagePartsJSON, _ = sjson.SetRaw(imagePartsJSON, "-1", imagePartJSON)
243+
continue
244+
}
245+
246+
nonImageCount++
247+
lastNonImageRaw = fr.Raw
248+
filteredJSON, _ = sjson.SetRaw(filteredJSON, "-1", fr.Raw)
249+
}
250+
251+
if nonImageCount == 1 {
252+
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", lastNonImageRaw)
253+
} else if nonImageCount > 1 {
254+
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", filteredJSON)
228255
} else {
229-
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", functionResponseResult.Raw)
256+
functionResponseJSON, _ = sjson.Set(functionResponseJSON, "response.result", "")
257+
}
258+
259+
// Place image data inside functionResponse.parts as inlineData
260+
// instead of as sibling parts in the outer content, to avoid
261+
// base64 data bloating the text context.
262+
if gjson.Get(imagePartsJSON, "#").Int() > 0 {
263+
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "parts", imagePartsJSON)
230264
}
231265

232266
} else if functionResponseResult.IsObject() {
233-
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", functionResponseResult.Raw)
267+
if functionResponseResult.Get("type").String() == "image" && functionResponseResult.Get("source.type").String() == "base64" {
268+
inlineDataJSON := `{}`
269+
if mimeType := functionResponseResult.Get("source.media_type").String(); mimeType != "" {
270+
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "mimeType", mimeType)
271+
}
272+
if data := functionResponseResult.Get("source.data").String(); data != "" {
273+
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "data", data)
274+
}
275+
276+
imagePartJSON := `{}`
277+
imagePartJSON, _ = sjson.SetRaw(imagePartJSON, "inlineData", inlineDataJSON)
278+
imagePartsJSON := "[]"
279+
imagePartsJSON, _ = sjson.SetRaw(imagePartsJSON, "-1", imagePartJSON)
280+
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "parts", imagePartsJSON)
281+
functionResponseJSON, _ = sjson.Set(functionResponseJSON, "response.result", "")
282+
} else {
283+
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", functionResponseResult.Raw)
284+
}
234285
} else if functionResponseResult.Raw != "" {
235286
functionResponseJSON, _ = sjson.SetRaw(functionResponseJSON, "response.result", functionResponseResult.Raw)
236287
} else {
@@ -248,7 +299,7 @@ func ConvertClaudeRequestToAntigravity(modelName string, inputRawJSON []byte, _
248299
if sourceResult.Get("type").String() == "base64" {
249300
inlineDataJSON := `{}`
250301
if mimeType := sourceResult.Get("media_type").String(); mimeType != "" {
251-
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "mime_type", mimeType)
302+
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "mimeType", mimeType)
252303
}
253304
if data := sourceResult.Get("data").String(); data != "" {
254305
inlineDataJSON, _ = sjson.Set(inlineDataJSON, "data", data)

0 commit comments

Comments
 (0)