Skip to content

fix(kiro): retry malformed tool_call wrappers once#2688

Open
SemonCat wants to merge 7 commits into
decolua:masterfrom
SemonCat:fix/kiro-one-shot-tool-call-repair
Open

fix(kiro): retry malformed tool_call wrappers once#2688
SemonCat wants to merge 7 commits into
decolua:masterfrom
SemonCat:fix/kiro-one-shot-tool-call-repair

Conversation

@SemonCat

@SemonCat SemonCat commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a guarded, one-shot repair path for malformed Kiro tool_call wrappers
  • run the repair gate unconditionally for every successful streaming Kiro response — there is no feature toggle or provider option
  • preserve normal streaming TTFT by opening the gate on the first meaningful valid SSE chunk
  • retry only when a malformed wrapper is detected before visible output
  • suppress the failed first attempt, append a corrective instruction, and retry at most once
  • propagate retry HTTP errors such as 429 to existing account rotation/fallback logic
  • add Node 18-compatible abort-signal handling, separate TTFT/stall timeouts, buffer limits, and cancellation cleanup

Root cause confirmed in production

The first implementation made the repair path opt-in. AWS live Kiro credentials did not set the option, so the real path was:

chatCore → getExecutor("kiro") → KiroExecutor.execute() → transformEventStreamToSSE()

The malformed wrapper was validated and returned as invalid_kiro_tool_call without entering the one-shot repair gate. This matched the live failure:

Invalid Kiro tool_call payload: missing nested MCP tool name at input.name

This PR now removes that option entirely. Successful streaming Kiro responses always enter the bounded one-shot repair gate. Non-streaming and unsuccessful HTTP responses remain unchanged.

Dependency

Depends on #2681. This is intentionally a stacked PR; until #2681 merges, the GitHub diff also contains its commits. The repair-only diff is:

git diff fa842ae..4bbba26

After #2681 merges, this branch can be rebased onto master so only the repair commits remain.

Behavior

The repair gate:

  • releases normal text/valid wrapper streams on the first meaningful valid SSE chunk
  • never treats keepalives or [DONE] as meaningful output
  • classifies malformed output before opening the stream
  • never leaks a failed first-attempt tool call
  • performs exactly one retry
  • returns kiro_tool_call_repair_retry_failed if the retry is also malformed
  • does not invent or silently drop ambiguous nested tool names

Operational safety limits remain configurable; these are bounds, not enable/disable switches:

  • KIRO_TOOL_CALL_REPAIR_BUFFER_MAX_BYTES
  • KIRO_TOOL_CALL_REPAIR_TTFT_TIMEOUT_MS
  • KIRO_TOOL_CALL_REPAIR_STALL_TIMEOUT_MS

Tests

  • exported live path regression via getExecutor("kiro").execute() with empty provider-specific data
  • malformed → repaired valid wrapper, with no first-attempt leakage
  • malformed → malformed retry returns the repair failure code
  • valid streaming opens before upstream completion and does not retry
  • retry 429 remains a non-OK response for existing account rotation
  • buffer cap, TTFT/stall timeout, abort, client cancellation, and ordering
  • related Kiro/base suites: 9 files / 83 tests passed
  • changed-file ESLint
  • git diff --check
  • npm run build

The branch was deployed to AWS internal 9Router before the toggle removal and passed direct Kiro text and real terminal tool-call smoke tests; post-deploy logs showed zero invalid_kiro_tool_call, kiro_tool_call_repair_retry_failed, or response.failed markers during the smoke window. The final toggle-removal commit does not change the already-active live behavior when no option is set; it removes the ability to bypass it.

fazulfi added a commit to fazulfi/9router-mw that referenced this pull request Jul 23, 2026
Backport missing test coverage from upstream decolua#2681 (tool-call validation) and decolua#2688 (one-shot repair-all). The corresponding kiro.js features were already present in the codebase; these tests close the coverage gap.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant