From b45ede0b71d82f45c6bdab2d8d924fd476fcbb28 Mon Sep 17 00:00:00 2001 From: taetaetae Date: Sun, 1 Feb 2026 15:47:18 +0900 Subject: [PATCH 1/2] fix(kiro): handle empty content in messages to prevent Bad Request errors Problem: - OpenCode's /compaction command and auto-compaction (at 80%+ context) sends requests that can result in empty assistant message content - Kiro API strictly requires non-empty content for all messages - This causes 'Bad Request: Improperly formed request' errors - After compaction failure, the malformed message stays in history, breaking all subsequent requests in the session Solution: - Add fallback content for empty assistant messages in buildAssistantMessageFromOpenAI() - Add history truncation (max 50 messages) to prevent oversized requests - This ensures all messages have valid content before sending to Kiro API Fixes issues with: - /compaction command returning Bad Request - Auto-compaction breaking sessions - Conversations becoming unresponsive after compaction failure --- .../kiro/openai/kiro_openai_request.go | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/internal/translator/kiro/openai/kiro_openai_request.go b/internal/translator/kiro/openai/kiro_openai_request.go index 93914c6d..a621eebc 100644 --- a/internal/translator/kiro/openai/kiro_openai_request.go +++ b/internal/translator/kiro/openai/kiro_openai_request.go @@ -576,9 +576,23 @@ func processOpenAIMessages(messages gjson.Result, modelID, origin string) ([]Kir } } + // Truncate history if too long to prevent Kiro API errors + history = truncateHistoryIfNeeded(history) + return history, currentUserMsg, currentToolResults } +const kiroMaxHistoryMessages = 50 + +func truncateHistoryIfNeeded(history []KiroHistoryMessage) []KiroHistoryMessage { + if len(history) <= kiroMaxHistoryMessages { + return history + } + + log.Debugf("kiro-openai: truncating history from %d to %d messages", len(history), kiroMaxHistoryMessages) + return history[len(history)-kiroMaxHistoryMessages:] +} + // buildUserMessageFromOpenAI builds a user message from OpenAI format and extracts tool results func buildUserMessageFromOpenAI(msg gjson.Result, modelID, origin string) (KiroUserInputMessage, []KiroToolResult) { content := msg.Get("content") @@ -677,8 +691,20 @@ func buildAssistantMessageFromOpenAI(msg gjson.Result) KiroAssistantResponseMess } } + // CRITICAL FIX: Kiro API requires non-empty content for assistant messages + // This can happen with compaction requests or error recovery scenarios + finalContent := contentBuilder.String() + if strings.TrimSpace(finalContent) == "" { + if len(toolUses) > 0 { + finalContent = "I'll help you with that." + } else { + finalContent = "I understand." + } + log.Debugf("kiro-openai: assistant content was empty, using default: %s", finalContent) + } + return KiroAssistantResponseMessage{ - Content: contentBuilder.String(), + Content: finalContent, ToolUses: toolUses, } } From 1f7c58f7ce11b0119c35aebec907d6db3fe70e53 Mon Sep 17 00:00:00 2001 From: taetaetae Date: Tue, 3 Feb 2026 07:10:38 +0900 Subject: [PATCH 2/2] refactor: use constants for default assistant messages Apply code review feedback from gemini-code-assist: - Define default messages as local constants to improve maintainability - Avoid magic strings in the empty content handling logic --- internal/translator/kiro/openai/kiro_openai_request.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/translator/kiro/openai/kiro_openai_request.go b/internal/translator/kiro/openai/kiro_openai_request.go index a621eebc..9c1eb895 100644 --- a/internal/translator/kiro/openai/kiro_openai_request.go +++ b/internal/translator/kiro/openai/kiro_openai_request.go @@ -695,10 +695,13 @@ func buildAssistantMessageFromOpenAI(msg gjson.Result) KiroAssistantResponseMess // This can happen with compaction requests or error recovery scenarios finalContent := contentBuilder.String() if strings.TrimSpace(finalContent) == "" { + const defaultAssistantContentWithTools = "I'll help you with that." + const defaultAssistantContent = "I understand." + if len(toolUses) > 0 { - finalContent = "I'll help you with that." + finalContent = defaultAssistantContentWithTools } else { - finalContent = "I understand." + finalContent = defaultAssistantContent } log.Debugf("kiro-openai: assistant content was empty, using default: %s", finalContent) }