Skip to content

fix: Incomplete and malformed tool-call part in conversation - #679

Merged
lixun910 merged 1 commit into
mainfrom
678-incomplete-and-malformed-tool-call-part-in-conversation
Jun 3, 2026
Merged

lixun910 merged 1 commit into
mainfrom
678-incomplete-and-malformed-tool-call-part-in-conversation

Conversation

@lixun910

@lixun910 lixun910 commented Jun 3, 2026 •

Copy link
Copy Markdown
Collaborator

In some cases (e.g. dynamic tool composition), the tool name may be hallucinated. When tool-input parsing fails, the AI SDK emits an output-error part with only rawInput. The incomplete and malformed tool-call part will be persisted in conversation, and it breaks every later request.

This fix is to enhance message sanitization and tool handling in chat transportation to avoid incomplete and malformed tool-call parts.

Summary by CodeRabbit

  • Bug Fixes
    • Improved stream error handling to properly mark pending tool operations as cancelled and sync state updates.
    • Enhanced message validation to correctly filter unavailable tool references and prevent validation failures.

@lixun910 lixun910 linked an issue Jun 3, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR refines tool handling in the AI core pipeline. Message sanitization now filters tool-call parts whose tool names are unavailable, incomplete error tool calls are repaired with backfilled input, available tool names are wired through the streaming transport layer, and sub-agent error handling synchronizes pending tool-call state earlier in the failure path.

Changes

Tool Availability Filtering and Error Handling

Layer / File(s) Summary
Message sanitization with tool availability filtering
packages/ai-core/src/utils.ts
sanitizeMessagesForLLM accepts an optional availableToolNames parameter and filters out tool parts whose referenced tool name is not in that set (including dynamic and prefixed tools); the implementation adds an isUnavailableToolPart predicate used during message part filtering.
Incomplete tool call completion and error backfill
packages/ai-core/src/utils.ts
When fixIncompleteToolCalls synthesizes completion for an output-error tool part, it backfills the missing input field from rawInput (defaulting to {}) to satisfy downstream validateUIMessages type-validation expectations.
Tool availability integration and error synchronization
packages/ai-core/src/chatTransport.ts, packages/ai-core/src/agents/AgentUtils.ts
Local chat transport factory now passes Object.keys(tools) to createAgentUIStreamResponse call; streamSubAgent reorders error handling to mark pending tool calls as cancelled and push updated progress immediately upon error, before constructing and persisting the abort snapshot.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • sqlrooms/sqlrooms#678: The changes to sanitizeMessagesForLLM (filtering unavailable tools) and fixIncompleteToolCalls (backfilling missing input for output-error parts) directly address the persisted incomplete or malformed tool-call handling described in this issue.

Possibly related PRs

  • sqlrooms/sqlrooms#404: Both PRs modify sanitizeMessagesForLLM and adjust chatTransport.ts to preprocess messages; this PR further extends tool filtering and adjusts UI stream response arguments.
  • sqlrooms/sqlrooms#505: This PR reorders sub-agent tool-call progress updates during failures, which directly impacts the same progress state that PR #505 introduces and renders via AiSlice.agentProgress.
  • sqlrooms/sqlrooms#497: Both PRs refine the v6 tool-call pipeline—error handling in streamSubAgent and tool-call completion in fixIncompleteToolCalls—as part of the ToolLoopAgent v6 refactor.

Suggested reviewers

  • ilyabo
  • dmitriy-kostianetskiy

Poem

🐰 Tool calls now filter clean and true,
Unavailable ones we bid adieu,
When errors strike, we fix with grace,
Input backfilled to its place,
Sub-agents sync their states just right,
The pipeline flows—all tools in sight! 🎪

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: addressing incomplete and malformed tool-call parts in conversation, which directly matches the PR objectives and changes across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 678-incomplete-and-malformed-tool-call-part-in-conversation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/ai-core/src/utils.ts (1)

511-527: 💤 Low value

Consider handling non-object rawInput values.

The backfill toolPart.rawInput ?? {} assumes rawInput is either undefined or an object. If rawInput is a primitive (e.g., a malformed string from a hallucinated tool call), passing it directly as input could cause downstream issues if consumers expect an object.

However, looking at the broader context, this fallback to {} when rawInput is falsy is reasonable, and the AI SDK's schema validation would catch truly malformed inputs. The fix addresses the immediate "input: Value: undefined" validation failure.

Optional: Defensive coercion to object
         if (toolPart.state === 'output-error' && toolPart.input === undefined) {
+          const backfilledInput =
+            toolPart.rawInput && typeof toolPart.rawInput === 'object'
+              ? toolPart.rawInput
+              : {};
           updatedParts[i] = {
             ...updatedParts[i],
-            input: toolPart.rawInput ?? {},
+            input: backfilledInput,
           } as (typeof message.parts)[number];
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ai-core/src/utils.ts` around lines 511 - 527, The backfill currently
assigns toolPart.rawInput ?? {} directly to input, which can propagate
primitives; update the branch inside the toolPart.state === 'output-error' check
to coerce non-object rawInput into a safe object before assigning to
updatedParts[i]. Specifically, when populating input for the updatedParts entry,
use toolPart.rawInput if it's a non-null object, otherwise wrap the primitive
(e.g., String(toolPart.rawInput) or {raw: toolPart.rawInput}) into an object so
input is always an object; modify the logic around toolPart, updatedParts,
rawInput and input accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/ai-core/src/utils.ts`:
- Around line 511-527: The backfill currently assigns toolPart.rawInput ?? {}
directly to input, which can propagate primitives; update the branch inside the
toolPart.state === 'output-error' check to coerce non-object rawInput into a
safe object before assigning to updatedParts[i]. Specifically, when populating
input for the updatedParts entry, use toolPart.rawInput if it's a non-null
object, otherwise wrap the primitive (e.g., String(toolPart.rawInput) or {raw:
toolPart.rawInput}) into an object so input is always an object; modify the
logic around toolPart, updatedParts, rawInput and input accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8555d7c6-fd53-407e-a007-25b946d8a7fa

📥 Commits

Reviewing files that changed from the base of the PR and between 42eb60c and aa03bbe.

📒 Files selected for processing (3)
  • packages/ai-core/src/agents/AgentUtils.ts
  • packages/ai-core/src/chatTransport.ts
  • packages/ai-core/src/utils.ts

@lixun910
lixun910 merged commit 0290981 into main Jun 3, 2026
4 checks passed
@lixun910
lixun910 deleted the 678-incomplete-and-malformed-tool-call-part-in-conversation branch June 3, 2026 15:30
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.

Incomplete and malformed tool-call part in conversation

2 participants