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