Skip to content

fix(core): sanitize tool inputs before replay#1337

Open
omeraplak wants to merge 2 commits into
mainfrom
fix/issue-1336-tool-input-replay
Open

fix(core): sanitize tool inputs before replay#1337
omeraplak wants to merge 2 commits into
mainfrom
fix/issue-1336-tool-input-replay

Conversation

@omeraplak
Copy link
Copy Markdown
Member

@omeraplak omeraplak commented Jun 3, 2026

PR Checklist

Please check if your PR fulfills the following requirements:

Bugs / Features

What is the current behavior?

A malformed tool-call input can be persisted as a string in a UI tool part. When that conversation is later replayed to providers such as Anthropic, the historical tool_use.input is sent as a string instead of a dictionary/object, so the provider rejects the request.

This can poison the conversation history: a later follow-up message can fail even though the original tool input error already happened on a previous turn.

What is the new behavior?

Tool-call inputs are normalized before they are saved or replayed:

  • plain object inputs are preserved
  • stringified JSON objects are parsed and preserved as objects
  • malformed strings, arrays, null, and other non-dictionary values fall back to {}
  • legacy stored UI tool parts are sanitized before model replay, so existing bad memory rows no longer send string tool inputs to the provider

Fixes #1336

Notes for reviewers

Validation run:

  • pnpm --dir packages/core test:single src/utils/tool-input.spec.ts src/utils/message-converter.spec.ts src/agent/message-normalizer.spec.ts
  • pnpm --dir packages/core typecheck
  • pnpm --dir packages/core lint (passes with existing complexity warnings)
  • pnpm --dir examples/base build

I removed the local repro from this PR and kept the coverage in focused regression tests.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 3, 2026

🦋 Changeset detected

Latest commit: ac7d9c0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes issue #1336 by sanitizing tool-call input values during message conversion. Malformed tool arguments stored as strings can now be detected and normalized to empty objects before being replayed to provider APIs, preventing provider schema validation errors on conversation continuation.

Changes

Tool Input Sanitization

Layer / File(s) Summary
Tool input normalization utilities
packages/core/src/utils/tool-input.ts, packages/core/src/utils/tool-input.spec.ts
isPlainToolInput type guard and normalizeToolInputForModel function detect plain objects, parse stringified JSON when possible, and return empty objects for invalid or non-dictionary inputs.
Message converter integration
packages/core/src/utils/message-converter.ts, packages/core/src/utils/message-converter.spec.ts
convertResponseMessagesToUIMessages and convertModelMessagesToUIMessages apply normalization to tool-call inputs instead of raw fallback; tests validate string inputs are sanitized to empty objects in both conversion paths.
Agent message normalizer integration
packages/core/src/agent/message-normalizer.ts, packages/core/src/agent/message-normalizer.spec.ts
Tool-part input handling uses normalizeToolInputForModel for additional tool states; test verifies legacy non-object inputs are coerced to empty objects before conversion to model messages.
Reproduction script and release notes
examples/base/src/repro-1336.ts, examples/base/package.json, .changeset/clean-tools-sip.md
Standalone reproduction script seeds a conversation with malformed tool input and inspects handling through AI SDK and Volt replay paths; includes npm script to run and changeset documenting the patch.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • VoltAgent/voltagent#1149: Both PRs address tool-call input field handling during message conversion—this PR normalizes/sanitizes inputs to always be objects, while #1149 renames the emitted field from args to input in the UI layer.

Poem

A string walked in where an object should dwell,
Malformed and twisted, it broke the provider's spell.
But now we normalize, with care and with grace,
Converting all inputs to their rightful place. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(core): sanitize tool inputs before replay' clearly and concisely summarizes the main change: sanitizing tool inputs to prevent issues during replay.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from issue #1336: normalizes tool inputs (keeping objects, parsing JSON strings, falling back to {}), sanitizes legacy stored parts on replay, and prevents history poisoning.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing issue #1336: tool input normalization utilities, message converter updates, test coverage, and reproduction example are all in-scope for sanitizing tool inputs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description fully addresses the template requirements with all critical sections completed and well-documented.

✏️ 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 fix/issue-1336-tool-input-replay

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.

@joggrbot

This comment has been minimized.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jun 3, 2026

Deploying voltagent with  Cloudflare Pages  Cloudflare Pages

Latest commit: ac7d9c0
Status: ✅  Deploy successful!
Preview URL: https://9190a6b6.voltagent.pages.dev
Branch Preview URL: https://fix-issue-1336-tool-input-re.voltagent.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread examples/base/src/repro-1336.ts Outdated
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.

Bug: invalid tool-call input string can be persisted and replayed as normal tool input

1 participant