Repository navigation
fix(kiro): stop injecting placeholder user turn on tool-result turns - #5807
Conversation
Kiro accepts an empty user content field when the turn carries toolResults or images (the agentic tool-loop case), so the "(empty)" placeholder is only needed for a genuinely bare turn. Previously a trailing tool-result-only turn (no follow-up user text) would have its content unconditionally set to the literal "(empty)" placeholder, as if the user had typed it, which can confuse Kiro. The check is scoped to the flushPending "user" branch only, so the existing "(empty)" placeholder used elsewhere (assistant-first synthetic filler / session hashing) is unaffected. Co-authored-by: Bima Jatmiko Abadi <bja.devs@gmail.com> Inspired-by: decolua/9router#2183
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request prevents the translator from injecting the literal "(empty)" placeholder on trailing tool-result-only turns when converting OpenAI requests to Kiro. Instead, if tool results or images are present, the user content is allowed to remain empty, preventing Kiro from being confused by an artificial placeholder. A corresponding unit test has been added to tests/unit/translator-openai-to-kiro.test.ts to verify this behavior and prevent regressions. No review comments were provided, so there is no additional feedback.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…heaper-inference#5807) Integrated into release/v3.8.43
Summary
"(empty)"placeholder intouserInputMessage.contentwhenever a flushed user turn had no accumulated text — even when the turn was a trailing tool-result-only turn (an agentic loop ending inassistant.tool_calls→toolresult, with no follow-up user text). Kiro can read that placeholder as if the user actually typed it, disrupting the tool-use loop."(empty)"when the turn carries no context at all. When the turn already carriestoolResultsorimages, the content is now left as an empty string instead.Changes
open-sse/translator/request/openai-to-kiro.ts:flushPending'suserbranch now computeshasContext = pendingToolResults.length > 0 || pendingImages.length > 0and only falls back to"(empty)"whenhasContextis false (note: this keeps OmniRoute's existing"(empty)"placeholder for genuinely-bare turns — e.g. the assistant-first synthetic filler / session-id hashing logic elsewhere in the file still relies on that literal string; only this one site's unconditional fallback changes).tests/unit/translator-openai-to-kiro.test.ts: new regression case builds a payload ending in{role:"assistant", tool_calls:[...]}→{role:"tool", tool_call_id, content}with no trailing user message, and asserts the resultingcurrentMessage.userInputMessagecontent is empty (not"(empty)") whileuserInputMessageContext.toolResultsis still populated.Attribution
Thanks to @jetmiky for the original implementation.
Testing
node --import tsx/esm --test tests/unit/translator-openai-to-kiro.test.ts— new case FAILs before the fix ('(empty)' !== ''), PASSes after; full 30-test suite green (zero regression, including the "prepends synthetic user when conversation starts with assistant" case that legitimately depends on the"(empty)"placeholder).node --import tsx/esm --test tests/unit/translator-ai-sdk-image-parts.test.ts tests/unit/kiro-continue-filler-5231.test.ts— green (adjacent Kiro translator suites, no regression).npm run typecheck:core— clean.npx eslint open-sse/translator/request/openai-to-kiro.ts tests/unit/translator-openai-to-kiro.test.ts— 0 errors (pre-existinganywarnings only).npm run check:docs-sync— PASS.