fix(kiro): never send a top-level systemPrompt (400 REQUEST_BODY_INVALID)

kiro.dev rejects any body carrying a top-level systemPrompt with
400 REQUEST_BODY_INVALID. The translators stopped emitting the field in
v0.5.59 (the prompt travels in the first user turn via contentPrefix),
but two paths kept writing it back downstream of the translator:

- rtk/systemInject.js::injectKiroSystem() appended the RTK prompt to
  body.systemPrompt, so every kr/ model failed whenever an RTK injector
  (caveman, ponytail) was active. It now appends to the first history
  user turn's content (else currentMessage), reusing
  dedupStringAppend/hasPrompt so retries stay idempotent.
- executors/kiro.js::appendRepairInstruction() wrote the tool-call repair
  instruction to systemPrompt on the retry, turning every repair into a
  hard failure. It now appends to currentMessage.userInputMessage.content.

isKiroBody() no longer requires a string body.systemPrompt — that marker
is gone from the wire shape — and sniffs the conversation turn shape
instead, keeping the stray-conversationState guard intact. Stale comments
in both kiro translators corrected: the systemPrompt local is only a
session-replay cache key, not a wire field.

Also drops the mirror/rollback repair heuristic the injector no longer
needs: net -52 lines.

Fixes #3641, #3845, #2890, #2901, #2939, #3109, #3459, #3749
This commit is contained in:
Federico Liva
2026-09-10 22:23:01 +07:00
committed by decolua
parent 1f10f9e5c4
commit 1892ed77c8
6 changed files with 109 additions and 161 deletions

View File

@@ -127,12 +127,18 @@ async function readResponsePrefix(response, signal, maxBytes, timeoutMs) {
return decoder.decode(concatChunks(chunks, totalBytes));
}
// The instruction goes into the current user turn, never into a top-level
// `systemPrompt`: kiro.dev answers any body carrying that field with
// 400 REQUEST_BODY_INVALID, so writing it here turned every repair retry into
// a hard failure.
function appendRepairInstruction(body, kind) {
const repaired = structuredClone(body || {});
const instruction = REPAIR_INSTRUCTIONS[kind] || "Retry the previous incomplete Kiro response.";
repaired.systemPrompt = repaired.systemPrompt
? `${repaired.systemPrompt}\n\n${instruction}`
: instruction;
const msg = repaired?.conversationState?.currentMessage?.userInputMessage;
if (msg) {
const content = typeof msg.content === "string" ? msg.content : "";
msg.content = content ? `${content}\n\n${instruction}` : instruction;
}
return repaired;
}