From ae4638712e20e95d91333a09fe523f7a4dcc39fa Mon Sep 17 00:00:00 2001 From: taetaetae Date: Thu, 5 Feb 2026 07:08:14 +0900 Subject: [PATCH] fix(kiro): handle tool_use in content array for compaction requests Problem: - PR #162 fixed empty string content but missed array content with tool_use - OpenCode's compaction requests send assistant messages with content as array - When content array contains only tool_use (no text), content becomes empty - This causes 'Improperly formed request' errors from Kiro API Example of problematic message format: { "role": "assistant", "content": [ {"type": "tool_use", "id": "...", "name": "todowrite", "input": {...}} ] } Solution: - Extract tool_use from content array (Anthropic/OpenCode format) - This is in addition to existing tool_calls handling (OpenAI format) - The empty content fallback from PR #162 will then work correctly Fixes compaction failures that persisted after PR #162 merge. --- .../kiro/openai/kiro_openai_request.go | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/internal/translator/kiro/openai/kiro_openai_request.go b/internal/translator/kiro/openai/kiro_openai_request.go index 9c1eb895..2242187b 100644 --- a/internal/translator/kiro/openai/kiro_openai_request.go +++ b/internal/translator/kiro/openai/kiro_openai_request.go @@ -659,13 +659,42 @@ func buildAssistantMessageFromOpenAI(msg gjson.Result) KiroAssistantResponseMess contentBuilder.WriteString(content.String()) } else if content.IsArray() { for _, part := range content.Array() { - if part.Get("type").String() == "text" { + partType := part.Get("type").String() + switch partType { + case "text": contentBuilder.WriteString(part.Get("text").String()) + case "tool_use": + // Handle tool_use in content array (Anthropic/OpenCode format) + // This is different from OpenAI's tool_calls format + toolUseID := part.Get("id").String() + toolName := part.Get("name").String() + inputData := part.Get("input") + + var inputMap map[string]interface{} + if inputData.Exists() { + if inputData.IsObject() { + inputMap = make(map[string]interface{}) + inputData.ForEach(func(key, value gjson.Result) bool { + inputMap[key.String()] = value.Value() + return true + }) + } + } + if inputMap == nil { + inputMap = make(map[string]interface{}) + } + + toolUses = append(toolUses, KiroToolUse{ + ToolUseID: toolUseID, + Name: toolName, + Input: inputMap, + }) + log.Debugf("kiro-openai: extracted tool_use from content array: %s", toolName) } } } - // Handle tool_calls + // Handle tool_calls (OpenAI format) toolCalls := msg.Get("tool_calls") if toolCalls.IsArray() { for _, tc := range toolCalls.Array() {