Skip to content

fix(session): normalize tool call blocks for cross-provider compatibility#4719

Closed
bse-ai wants to merge 1 commit intoopenclaw:mainfrom
bse-ai:fix/normalize-tool-call-blocks-cross-provider
Closed

fix(session): normalize tool call blocks for cross-provider compatibility#4719
bse-ai wants to merge 1 commit intoopenclaw:mainfrom
bse-ai:fix/normalize-tool-call-blocks-cross-provider

Conversation

@bse-ai
Copy link

@bse-ai bse-ai commented Jan 30, 2026

Summary

  • Fixes API validation failures when switching providers mid-session (e.g., "input: Field required")
  • Adds normalizeToolCallBlocks() to convert all tool call variants to canonical format
  • Handles toolCall, toolUse, and functionCall block types

Problem

When users switch providers mid-session, the session history may contain tool call blocks in different formats:

Provider Format
Anthropic / pi-ai { type: "toolCall", arguments: {} }
Google Antigravity { type: "toolUse", input: {} }

This mismatch causes the new provider's serializer to reject requests with validation errors.

Solution

Added normalizeToolCallBlocks() to the session sanitization pipeline in sanitizeSessionHistory(). It:

  1. Scans assistant message content blocks
  2. Identifies tool call variants (toolCall, toolUse, functionCall)
  3. Normalizes them to canonical { type: "toolCall", arguments: {} } shape
  4. Preserves all other fields via spread operator

Test plan

  • Switch from Google Antigravity to Anthropic mid-session
  • Verify no "input: Field required" errors
  • Verify tool calls work correctly after provider switch

🤖 Generated with Claude Code

Greptile Overview

Greptile Summary

This PR adds normalizeToolCallBlocks() to sanitizeSessionHistory() in src/agents/pi-embedded-runner/google.ts to rewrite provider-specific tool-call content blocks (toolUse, functionCall) into a canonical { type: "toolCall", arguments: ... } shape. The intent is to prevent cross-provider API validation failures when a session history recorded under one provider is later serialized for another (e.g., switching from Google Antigravity to Anthropic).

Confidence Score: 3/5

  • Moderately safe to merge, but normalization may still leave schema-incompatible fields on tool-call blocks.
  • Change is localized and straightforward, but the normalization spreads the original block fields into the canonical block; if downstream serializers strictly validate tool-call schemas, leftover variant-only fields (e.g., input on a toolCall) can still trigger validation errors in the exact scenario this PR targets.
  • src/agents/pi-embedded-runner/google.ts

(4/5) You can add custom instructions or style guidelines for the agent here!

…lity

When users switch providers mid-session (e.g., from Google Antigravity to
Anthropic), the session history may contain tool call blocks in different
formats:

- Anthropic / pi-ai: `{ type: "toolCall", arguments: {} }`
- Google Antigravity: `{ type: "toolUse", input: {} }`

This mismatch causes API validation failures like "input: Field required"
when the new provider's serializer encounters the old format.

This fix adds `normalizeToolCallBlocks()` to the session sanitization
pipeline, which converts all tool call variants (toolCall, toolUse,
functionCall) to the canonical `{ type: "toolCall", arguments: {} }` shape
before sending to any provider.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@greptile-apps greptile-apps 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 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +345 to +350
// Ensure `arguments` is populated — prefer existing `arguments`, fall back to `input`, default to {}.
const args = rec.arguments ?? rec.input ?? {};
if (type === "toolCall" && rec.arguments !== undefined) return block; // already canonical

contentChanged = true;
return { ...rec, type: "toolCall", arguments: args };
Copy link
Contributor

Choose a reason for hiding this comment

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

normalizeToolCallBlocks() rewrites { type: "toolUse", input: ... } / { type: "functionCall", ... } to { type: "toolCall", arguments: ... } but leaves the original provider-specific field (input) in place via { ...rec, ... }. If the goal is cross-provider validation, some serializers will still reject type: "toolCall" blocks that include unknown fields like input.

Consider deleting input when normalizing (and similarly any other variant-only keys) so the resulting block matches the canonical schema exactly.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/google.ts
Line: 345:350

Comment:
`normalizeToolCallBlocks()` rewrites `{ type: "toolUse", input: ... }` / `{ type: "functionCall", ... }` to `{ type: "toolCall", arguments: ... }` but leaves the original provider-specific field (`input`) in place via `{ ...rec, ... }`. If the goal is cross-provider validation, some serializers will still reject `type: "toolCall"` blocks that include unknown fields like `input`.

Consider deleting `input` when normalizing (and similarly any other variant-only keys) so the resulting block matches the canonical schema exactly.

How can I resolve this? If you propose a fix, please make it concise.

@bse-ai bse-ai closed this Feb 3, 2026
@bse-ai bse-ai deleted the fix/normalize-tool-call-blocks-cross-provider branch February 3, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant