From 086d8d0d0b9cfbcb806876c9c9220ab3e998b210 Mon Sep 17 00:00:00 2001 From: y Date: Thu, 12 Feb 2026 11:09:47 +0800 Subject: [PATCH] fix(kiro): prepend placeholder user message when conversation starts with assistant role Kiro/AmazonQ API requires the conversation history to start with a user message. Some clients (e.g., OpenClaw) send conversations starting with an assistant message, which is valid for the native Claude API but causes 'Improperly formed request' (400) on the Kiro endpoint. This fix detects when the first message has role=assistant and prepends a minimal placeholder user message ('.') to satisfy the Kiro API's message ordering requirement. Upstream error: {"message":"Improperly formed request.","reason":null} Verified: original request returns 400, fixed request returns 200. --- .../translator/kiro/claude/kiro_claude_request.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/translator/kiro/claude/kiro_claude_request.go b/internal/translator/kiro/claude/kiro_claude_request.go index c3c359e0..7012e644 100644 --- a/internal/translator/kiro/claude/kiro_claude_request.go +++ b/internal/translator/kiro/claude/kiro_claude_request.go @@ -586,6 +586,17 @@ func processMessages(messages gjson.Result, modelID, origin string) ([]KiroHisto // Merge adjacent messages with the same role messagesArray := kirocommon.MergeAdjacentMessages(messages.Array()) + + // FIX: Kiro API requires history to start with a user message. + // Some clients (e.g., OpenClaw) send conversations starting with an assistant message, + // which is valid for the Claude API but causes "Improperly formed request" on Kiro. + // Prepend a placeholder user message so the history alternation is correct. + if len(messagesArray) > 0 && messagesArray[0].Get("role").String() == "assistant" { + placeholder := `{"role":"user","content":"."}` + messagesArray = append([]gjson.Result{gjson.Parse(placeholder)}, messagesArray...) + log.Infof("kiro: messages started with assistant role, prepended placeholder user message for Kiro API compatibility") + } + for i, msg := range messagesArray { role := msg.Get("role").String() isLastMessage := i == len(messagesArray)-1