Repository navigation
Conversation
Validate completed Chat Completions arguments before assigning them to FunctionCall.args. Drop invalid calls individually and report a structured MALFORMED_FUNCTION_CALL error while preserving valid siblings, text, and metadata. Preserve malformed-JSON exceptions and partial streaming, with provider MAX_TOKENS and SAFETY reasons retaining precedence. Fixes google#7740 AI assistance: OpenAI Codex generated the implementation and regression tests and performed automated review and validation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(models): report truncated Apigee tool calls as max tokens #7686
fix(models): keep streamed ApigeeLlm tool call fragments without an index together #7645
Problem:
Apigee Chat Completions tool-call arguments containing valid non-object JSON could raise exceptions or be silently converted into dictionaries in non-streaming mode. Streaming could expose those values directly as
FunctionCall.args.For example, JSON values such as
[1, 2],"x",5, andnullwere handled inconsistently between streaming and non-streaming responses.Solution:
Validate completed tool-call arguments as JSON objects before assigning them to
FunctionCall.args.MALFORMED_FUNCTION_CALL.MAX_TOKENSandSAFETYfinish-reason precedence.The per-call rejection policy follows existing LiteLLM behavior. Unlike coercing invalid arguments to
{}, it prevents rejected calls from executing with missing arguments or defaults.Testing Plan
Unit Tests:
Focused regression testing:
The new regression suite covers non-object JSON values, valid JSON objects, streaming and non-streaming paths, finish-reason precedence, valid sibling preservation, legacy function calls, fragmented arguments, metadata preservation, and downstream Runner execution.
Results:
The 77 failures against unchanged upstream demonstrate that the new regression tests detect the original behavior.
Full multi-version tox validation:
The repository's configured tox matrix was executed using Python 3.11 through 3.14.
Each completed run additionally reported:
The full tox matrix completed but did not pass.
Failure investigation:
A2A custom-factory failure (Python 3.11–3.14)
All four versions failed:
tests/unittests/a2a/agent/test_remote_a2a_agent.py::TestRemoteA2aAgentResolution::test_ensure_resolved_uses_custom_factoryThe failure is an
AttributeErrorinvolvingCustomFactory._httpx_client.Targeted comparisons reproduced the same failure on unchanged upstream using identical dependencies. The resolved
a2a-sdkversion is 1.3.0, where the relevant client is stored under_config.httpx_client.No A2A source or test files are modified by this PR.
Instrumentation timing failure (Python 3.14 only)
The full suite additionally failed:
test_sequential_tools_add_upThe measured time was approximately 0.843 seconds, compared with the expected 0.20 ± 0.05 seconds.
The test passed in isolated runs against both patched and baseline source. However, its full-suite failure remains unresolved and is not claimed to be baseline-only.
Python 3.14 completed using an external diagnostic-only pytest logger. No tests were filtered or excluded.
Additional validation:
git diff --checkpassed.Compatibility testing:
The patch was also tested in disposable integration snapshots:
These snapshots required documented merge-conflict resolutions, including preservation of #7686's incomplete-argument handling and finish-reason precedence.
These results demonstrate compatibility in the resolved test combinations, not conflict-free application of the patches.
Manual End-to-End (E2E) Tests
No live Apigee/manual E2E testing was performed.
Automated integration tests use synthetic Chat Completions responses with real local Runner and FunctionTool execution.
Under the tested default Runner configuration, these tests verify that:
Configured callbacks, plugins, or retry policies may alter downstream execution behavior.
To reproduce the relevant Runner tests:
Checklist
The downstream-dependency item is not applicable: no downstream dependency changes are required.
Additional Context
Alternative implementation:
Open PR #7763 (addresses the same issue by coercing non-object JSON arguments to an empty dictionary.
This PR takes a more defensive approach by rejecting invalid completed arguments individually with
MALFORMED_FUNCTION_CALL, consistent with the existing LiteLLM convention.In addition to preserving valid sibling calls, explicit rejection avoids silently substituting
{}for malformed arguments, which could otherwise allow tools to execute with unintended default parameters. This provides a clearer validation boundary between model-generated arguments and tool execution.Both approaches address the original crash and type-consistency issue. Maintainer guidance on the preferred behavior is welcome.
AI Assistance:
OpenAI Codex (GPT-6.1 sol) assisted in the implementation and regression tests and performed automated review and validation.
Acknowledgments:
Thanks to @surajksharma07 for identifying the related argument-handling issue during the #7686 discussion and clarifying the need for consistent behavior across streaming and non-streaming paths.
Thanks to @Somay-kousis for reporting #7740 and providing the detailed reproduction.
Their feedback helped inform the investigation and the scope of this fix.