Skip to content

fix(kiro): recover native invoke tool calls and keep trailing system tools#146

Open
tonybase wants to merge 1 commit into
kaitranntt:mainfrom
tonybase:kiro/native-invoke-tool-recovery
Open

fix(kiro): recover native invoke tool calls and keep trailing system tools#146
tonybase wants to merge 1 commit into
kaitranntt:mainfrom
tonybase:kiro/native-invoke-tool-recovery

Conversation

@tonybase

Copy link
Copy Markdown

Summary

The Kiro-backed model (AI_EDITOR origin) frequently emits tool calls as inline text in Claude's XML <invoke name="..."> format — using Kiro IDE's own tool names — instead of structured toolUseEvent events. Left as plain text, the client never sees a tool_use block, so no tool runs and the model starts hallucinating fake tool results. This PR recovers those calls and fixes the upstream condition that triggers them.

Changes

Native <invoke> tool-call recovery (kiro_claude_tools.go, kiro_executor.go)

  • Parse <invoke> / <parameter> blocks (antml: namespace tolerated), preserving JSON types for array/number params.
  • Map native names onto the client's canonical Claude tools:
    • readFile/fsRead/readMultipleFilesRead
    • grepSearchGrep (with includePatternglob)
    • fileSearchGlob
    • listDirectoryBash (ls / ls -R)
    • writeFile/fsWrite/createFileWrite
    • strReplaceEditor/editFileEdit
    • executeBash/runCommandBash
    • unknown tools pass through unchanged.
  • Wired into both the buffered (parseEventStream) and streaming (streamToChannel) paths. InvokeStreamParser buffers partial tags across chunk boundaries and flushes incomplete markup as text so nothing is dropped.
  • Override end_turntool_use when calls are recovered, so the client actually runs them. Dedup is shared with the structured tool-use path.

Trailing in-array system message normalization (kiro_claude_request.go)

  • Claude Code's mid-conversation-system beta (mid-conversation-system-2026-04-07) can place role:"system" messages inside the messages array, including as the final entry. Kiro has no system role, so these are rewritten as user content wrapped in <system-reminder> tags before merging.
  • Critically, a trailing system message must still produce a current user message — otherwise no tool specs attach to currentMessage.userInputMessageContext and the model, seeing no tools, hallucinates text-format tool calls (the root cause of the recovery above).

New Kiro model aliases + definitions (oauth_model_alias_defaults.go, model_definitions.go)

  • Claude Sonnet 5, Opus 4.8, Fable 5.

Testing

  • gofmt -l internal/ — clean
  • go build ./cmd/server — passes
  • go test ./internal/translator/kiro/... ./internal/runtime/executor/... ./internal/config/... ./internal/registry/... — passes
  • New unit tests: kiro_claude_tools_test.go (parse/map/stream), plus TestBuildKiroPayload_TrailingSystemMessageKeepsTools.

🤖 Generated with Claude Code

…tools

The Kiro-backed model (AI_EDITOR origin) frequently emits tool calls as
inline text in Claude's XML <invoke name="..."> format using Kiro IDE's
own tool names instead of structured toolUseEvent events. Left as text,
the client never sees a tool_use block, so no tool runs and the model
starts hallucinating fake results.

Add invoke recovery in both the buffered and streaming paths:
- parse <invoke>/<parameter> blocks (antml: namespace tolerated)
- map native names (grepSearch, readFile, fileSearch, listDirectory,
  writeFile, strReplaceEditor, executeBash, ...) onto client canonical
  tools (Grep, Read, Glob, Bash, Write, Edit)
- emit recovered calls as tool_use blocks and override end_turn ->
  tool_use so the client runs them
- InvokeStreamParser buffers partial tags across chunk boundaries

Also normalize role:"system" messages placed inside the messages array
(Claude Code mid-conversation-system beta), including a trailing system
message, by rewriting them as user content wrapped in <system-reminder>.
Without this the current user message is dropped and tool specs never
attach, which is what triggers the text-format tool-call hallucination.

Register new Kiro aliases and model defs: Sonnet 5, Opus 4.8, Fable 5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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