Skip to content

fix(google): fail closed on MALFORMED_FUNCTION_CALL without a call part - #943

Draft
DevMello wants to merge 1 commit into
lidge-jun:devfrom
DevMello:fix/google-malformed-function-call
Draft

fix(google): fail closed on MALFORMED_FUNCTION_CALL without a call part#943
DevMello wants to merge 1 commit into
lidge-jun:devfrom
DevMello:fix/google-malformed-function-call

Conversation

@DevMello

@DevMello DevMello commented Aug 3, 2026

Copy link
Copy Markdown

Summary

When Gemini ends a turn with finishReason MALFORMED_FUNCTION_CALL, the malformed call is usually dropped upstream and never arrives as a functionCall part. The fail-closed guard only fired when a call part had been emitted, so the common case surfaced as a clean empty completion and the client treated the turn as answered. The guard now fails closed on MALFORMED_FUNCTION_CALL even with zero started calls, on both the stream and non-stream paths. MAX_TOKENS with no started call keeps its plain token-limit stop, and ai-studio mode is unchanged.

Verification

  • Three new tests in tests/google-vertex-stream.test.ts: the helper distinction, and the no-call-part malformed case erroring on both the stream and non-stream paths.
  • Repro harness: an empty malformed turn previously bridged to response.completed with empty output, now response.failed with the truncation error. The existing MAX_TOKENS-without-call test stays green.
  • bun run test, typecheck, lint:gui, privacy:scan.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of incomplete Google responses involving malformed tool calls.
    • Responses that end unexpectedly now correctly report an error instead of appearing successfully completed.
    • Token-limit responses without started tool calls continue to be handled normally.
  • Tests

    • Added coverage for streaming and non-streaming truncation scenarios.

Gemini usually drops the malformed call upstream, so the final chunk
carries only the finishReason and the started-calls guard never fired.
The turn surfaced as a clean empty completion instead of an error.
MAX_TOKENS with no started call keeps its plain token-limit stop.
@github-actions github-actions Bot added the bug Something isn't working label Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Google Vertex truncation handling now uses a shared classifier. MALFORMED_FUNCTION_CALL results fail even without emitted tool calls, while zero-tool-call MAX_TOKENS results remain successful.

Changes

Google Vertex truncation handling

Layer / File(s) Summary
Truncation classification and adapter wiring
src/adapters/google-truncation.ts, src/adapters/google.ts
Added isVertexTruncatedTurn and applied it to streaming and non-streaming response parsing.
Classification and response regression coverage
tests/google-vertex-stream.test.ts
Added coverage for malformed function calls, token limits, normal stops, undefined reasons, and terminal errors without emitted tool calls.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: lidge-j, ingwannu, wibias

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: failing closed on MALFORMED_FUNCTION_CALL responses without an emitted function-call part.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@lidge-jun

Copy link
Copy Markdown
Owner

Carried onto the review stack as #953 (stack 3/3), unmodified.

Your commits were taken with git cherry-pick -x, so they keep your authorship — git log --format='%an' on the stack branch shows you, not me. No content was changed; the diff on the stack is byte-identical to what you wrote here, and it applied to dev with no conflict resolution.

Verified on the stack: bun x tsc --noEmit exit 0, and the full suite at 7691 pass / 8 skip / 0 fail across 507 files.

This PR stays open until #953 lands. If a maintainer prefers to take yours directly instead, that path is unaffected — the stack commits get dropped and this one merges. Once #953 merges I'll close this as carried, with the credit already in the commit history rather than in a comment.

Stack: #951 (plan, base dev) → #952 (#908 long-context pricing) → #953 (this carry). Review bottom-up.

Thanks for the fix.

@Wibias

Wibias commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Leave it as draft. Thanks. It doesnt need any more changes as you can see in juns comment on which you didn't respond to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants