Reviewed PR and existing tests.
UnderstandRemoved specified test file.
EditConfirmed approach preserves tool call context.
VerifyClosed PR with explanatory comment.
CleanupYou are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/pull/793 we need to setup a minimal test for this in ai pacakge. see how the tests there work, then setup one specifically for this garbage. one request to claude via antigravity, that makes it call a tool, then a follow up one to gemini 3 pro on antigravity
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
Let me check the existing tests to understand the testing patterns for live API tests:
Let me check how to get the Antigravity models and stream properly:
Now I have a full picture. Let me provide my review first, then create the test:
PR: https://github.com/badlogic/pi-mono/pull/793
Changelog:
[Unreleased] section of packages/ai/CHANGELOG.md. This is required before merge.Good:
toolResult messagesBad:
Ugly:
Questions or Assumptions:
Change summary:
convertMessages() in google-shared.ts to skip unsigned tool calls for Gemini 3 models (instead of converting to text)toolResult messagesTests:
Now let me create the minimal integration test:
Test passes. The test confirms:
echo with { message: 'Hello from Claude' })stopReason: toolUse, echo with { message: 'Hello from Gemini' }) rather than mimicking the text formatThe test file is at: packages/ai/test/antigravity-cross-provider-tool-call.test.ts
This serves as a live regression test for the fix in PR #793, ensuring that when Claude's unsigned tool calls are passed to Gemini 3, Gemini makes actual function calls rather than outputting text like [Tool Call: echo]\nArguments: {...}.
yeah, works fine. i guess the model eventually looses track that this is NOT the tool call format, but merelly a tool result from an earlier part of the session. we should probably just adjust this message
parts.push({
text: [Tool Call: ${block.name}]\nArguments: ${argsStr},
});
and tell the model tha tthis was a tool call made by a different model and that this is NOT the tool call format it should emit
Good point. Preserving the context while explicitly telling the model not to mimic is cleaner than dropping it entirely. Let me update the code:
Now update the unit test to reflect the new format:
Both tests pass. Let me run the full check:
All checks pass. Summary of changes:
packages/ai/src/providers/google-shared.ts: Changed the text format for unsigned tool calls from:
[Tool Call: ${block.name}]Arguments: ${argsStr}to:
[Historical context: a different model called tool "${block.name}" with arguments: ${argsStr}. Do not mimic this format - use proper function calling.]packages/ai/test/google-shared-gemini3-unsigned-tool-call.test.ts: Updated assertions to check for the new format
packages/ai/test/antigravity-cross-provider-tool-call.test.ts: New live integration test that validates the full Claude → Gemini 3 handoff scenario
This approach preserves the context (the model knows what tool was called and with what arguments) while being explicit that this is historical information and not a format to mimic.
reason we did it this way: the pr basically smokes all tool calls and results that have no thinking signature, lobotomizing gemini. is that correct?
Yes, that's correct. The PR skips unsigned tool calls AND their corresponding tool results entirely. So if you had a conversation with Claude via Antigravity that made 5 tool calls, switching to Gemini 3 would mean Gemini has no idea any of those tools were ever called or what they returned. That's a significant context loss.
Our approach keeps the information but tells the model "this is historical context from another model, don't mimic it."
Done. PR closed with explanation of why we took a different approach (preserving context vs lobotomizing it).
[Tool Call: ${block.name}]Arguments: ${argsStr}[Historical context: a different model called tool "${block.name}" with arguments: ${argsStr}. Do not mimic this format - use proper function calling.]