Repository navigation
[Bug] Kiro Final answer rendered twice when the model ends with plain text instead of codex_kiro_final_answer #6270
Description
Client or integration
Claude Code
Area
CLI
Summary
Version: 2.71.0, Claude Code 2.1.285, model claude-opus-5.5 via Kiro
What happens
In tool-enabled (completionMode "required") turns, when Kiro ends with plain text + END_TURN
and never calls codex_kiro_final_answer, the full answer is shown twice in Claude Code.
Reproduces across sessions.
Cause (from source)
- stream.ts:809 flushes the held text to the client (emitRetained(deferred)).
- stream.ts:876-885 then sets needsFallback for nativeCompletionStop.
- adapter.ts:200-206 replays that text as commentary and appends KIRO_COMPLETION_RETRY_MESSAGE.
- The model complies and calls codex_kiro_final_answer with the complete answer again,
which is emitted as final_answer (stream.ts:814-821).
Already-flushed first-attempt text cannot be retracted, so the answer appears twice.
(Comment at stream.ts:1057-1060 / fix(kiro): treat pre-output stream socket closes as retryable #520 confirms the flush is intentional.)
Expected
The answer appears once.
Possible fixes
- Keep holding the first attempt's text through the bounded fallback; if the fallback yields a
completionAnswer, drop the held text (same as consumeSupersededByCompletion) instead of flushing it. - Or, when the replayed commentary already looks complete, have the retry prompt ask for a
short/empty completion call rather than "the complete final answer".
Reproduction
- ocx running as the Claude Code gateway (ANTHROPIC_BASE_URL=http://127.0.0.1:10100), started via
ocx claude. - In Claude Code, select model
ocx-claude-kiro--claude-opus-5.5[1m](Kiro provider). - Ask anything that makes the model use at least one tool, then answer in plain text
(e.g. "check whether X exists and tell me where to put the files"). - Observe: the model ends with plain text + END_TURN and does not call codex_kiro_final_answer.
The answer is shown, then an almost identical answer is shown again ("Thought for 13s" answer,
followed by "Thought for 1s" answer).
Frequency: most tool-using turns that end with plain text; reproduces across separate sessions.
Observed live: right after a plain-text answer, the next model turn contains
KIRO_COMPLETION_RETRY_MESSAGE verbatim (kiro-constants.ts:35), so the bounded fallback fires every time.
Version
2.71.0 (also verified unchanged in 2.72.0)
Operating system
macOS 26.2 (25C56), Apple Silicon
Provider and model
kiro / claude-opus-5.5 (Claude Code model id: ocx-claude-kiro--claude-opus-5.5[1m])
Logs or error output
No error or stack trace — both sends return 200. Evidence is in the local usage log (~/.opencodex/usage.jsonl):
Kiro requests on this machine: 114 total, 11 with a second physical send.
Every one of those 11 has attempts[0].sendCount = 2 and recoveryKinds = ["empty-completion"],
which is the label kiro/adapter.ts:251 assigns to the bounded completion fallback send.
Recent examples (local time, requestId, sendCount, recoveryKinds, durationMs, outputTokens):
09-30 08:58:17 ocx-b5fff5fc9bec78dd9c4060f5e4774c15 2 ["empty-completion"] 46218 2198
09-30 09:01:47 ocx-a90c55c46f32dc6605af00dba05cd66b 2 ["empty-completion"] 28419 1419
09-30 09:03:13 ocx-08fef81997eb941afe29cabbbeac78e7 2 ["empty-completion"] 15139 718 <- matches the screenshot turn
09-30 09:07:01 ocx-23844856a1269a5ba69192c1d852ea99 2 ["empty-completion"] 43538 1609
09-30 09:10:35 ocx-cb9b743137e951c6ccdcbd01ff02525a 2 ["empty-completion"] 24309 1040
Requests without the fallback (sendCount = 1) render a single answer.
Model-side evidence: the turn following a plain-text answer receives KIRO_COMPLETION_RETRY_MESSAGE
(kiro-constants.ts:35) verbatim.Screenshots and supporting files
Redacted configuration
Claude Code settings.json: "model": "ocx-claude-kiro--claude-opus-5.5[1m]"
Env: ANTHROPIC_BASE_URL=http://127.0.0.1:10100, CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1
No custom Kiro adapter config.Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Sep 30, 2026
Fixed by #6283, merged into dev as db6e266. Kiro now holds first-attempt prose through bounded validation and emits one final answer; validated retry tool calls release genuine progress before EOF. Focused regressions and typecheck passed. Per the updated owner instruction, Cross-platform CI is deferred to the final union run.