fix: validate and coerce function tool argument types#4664
fix: validate and coerce function tool argument types#4664yuvrajangadsingh wants to merge 12 commits intogoogle:mainfrom
Conversation
_preprocess_args now uses pydantic.TypeAdapter to validate and coerce all annotated argument types (primitives, enums, containers), not just Pydantic models. Invalid arguments return a descriptive error to the LLM so it can self-correct and retry, matching the existing pattern for missing mandatory args. - Coerces compatible types (e.g. str "42" -> int 42, str "red" -> Color.RED) - Returns validation errors to LLM for incompatible types (e.g. "foobar" -> int) - Existing Pydantic BaseModel handling unchanged (graceful failure) - Updated all 3 call sites (FunctionTool, CrewAITool, sync tool path)
|
@cuihaoleo this implements the TypeAdapter-based validation you suggested in the issue comments. validation errors go back to the LLM so it can self-correct (the LangChain approach you mentioned). existing Pydantic model behavior is unchanged. @llalitkumarrr @xuanyang15 would appreciate a review when you get a chance. |
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the robustness of function tool argument handling by introducing comprehensive type validation and coercion. Previously, tools would accept incorrect argument types without validation, leading to runtime errors. Now, arguments are validated against their type annotations using Pydantic's Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable enhancement by adding argument type validation and coercion for function tools. The use of pydantic.TypeAdapter is a solid approach for this. The changes are well-implemented across the affected files, and the new tests provide good coverage for the new functionality.
I have a couple of suggestions to improve maintainability and robustness: one is to refactor the duplicated error message generation into a helper method, and the other is to use more specific exception handling instead of a broad except Exception. Overall, this is a great improvement to the framework's reliability.
|
@gemini-code-assist addressed both suggestions in 08c9f55:
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces robust type validation and coercion for function tool arguments by leveraging pydantic.TypeAdapter. This is a great improvement that will prevent runtime errors from incorrect argument types passed by the LLM and allow it to self-correct. The changes are well-implemented across FunctionTool, CrewAITool, and the synchronous tool path, and are accompanied by a comprehensive new test suite. I have a few suggestions to further improve the robustness and consistency of the implementation.
|
@gemini-code-assist addressed all 3 suggestions in 2d5b34f:
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces robust type validation and coercion for function tool arguments using pydantic.TypeAdapter. This is a significant improvement that prevents runtime errors from invalid data types passed by the LLM and enables self-correction by providing clear validation errors. The changes are well-implemented across FunctionTool and CrewAITool, and the new unit tests are comprehensive, covering various coercion and validation scenarios. The separation of concerns, preserving the existing graceful failure for Pydantic models while enforcing stricter validation for other types, is a sensible design choice.
|
@gemini-code-assist applied in 7507121. error messages now show /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding type validation and coercion for function tool arguments using pydantic.TypeAdapter. The changes are well-implemented, returning validation errors to the LLM for self-correction, and are accompanied by a comprehensive new test suite. I've identified a minor issue in a new test case and a small logging style improvement. Overall, this is a great enhancement to the tool's robustness.
|
@gemini-code-assist addressed in 6ed9ba1:
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding validation and coercion for function tool argument types using pydantic.TypeAdapter. The changes are well-implemented, robust, and thoroughly tested. My review found one minor area for improvement to ensure compatibility with newer Python syntax for optional types. Overall, this is an excellent contribution that enhances the reliability of tool function calls.
|
@gemini-code-assist the fixing the Union vs UnionType handling across the whole method would be a good follow-up but it's out of scope for this PR since it affects the pre-existing Pydantic model path too. /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable improvement by adding type validation and coercion for function tool arguments. The use of pydantic.TypeAdapter is a solid approach for this. The changes are well-implemented across FunctionTool, CrewAITool, and llm_flows/functions.py, ensuring consistent behavior. The new unit tests in test_function_tool_arg_validation.py are comprehensive and cover a wide range of scenarios, which is great for ensuring the new logic is robust. I have one suggestion to improve code clarity by removing a small piece of duplicated logic. Overall, this is a great enhancement that will improve the reliability of tool calls.
|
@gemini-code-assist applied in e35c130. hoisted the Optional None check before the Pydantic branch so it covers both paths in one place. /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces robust argument type validation and coercion for function tools using pydantic.TypeAdapter, which is an excellent enhancement for tool reliability. The core logic changes in function_tool.py are well-structured, and the new unit tests in test_function_tool_arg_validation.py are comprehensive. The necessary updates at the call sites in crewai_tool.py and functions.py correctly integrate the new error handling mechanism. I have one high-severity suggestion concerning src/google/adk/flows/llm_flows/functions.py to refactor the tool execution logic. This will address duplicated logic and inconsistent behavior between synchronous and asynchronous tool executions, leading to a more robust and maintainable implementation.
|
@gemini-code-assist the sync/async duplication in refactoring the entire sync tool execution path to go through /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding validation and type coercion for function tool arguments using pydantic.TypeAdapter. This makes tool execution more robust by catching type mismatches from the LLM early and providing feedback for self-correction. The changes are well-structured, with the core logic encapsulated in FunctionTool._preprocess_args, and updates are correctly propagated to CrewAITool and the synchronous tool execution path. The addition of a comprehensive new test suite (test_function_tool_arg_validation.py) is excellent and covers various coercion and validation scenarios. I have one suggestion to improve compatibility with modern Python type hints.
|
@gemini-code-assist applied in cb12206. added /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding type validation and coercion for function tool arguments using pydantic.TypeAdapter. This makes tool calls more robust and allows the LLM to self-correct based on validation feedback. The changes are well-implemented across FunctionTool and its usages, and are accompanied by a comprehensive new test suite.
My review includes two suggestions for src/google/adk/tools/function_tool.py to further improve the error handling:
- Make Pydantic
BaseModelvalidation failures consistent with other types by returning validation errors to the LLM instead of just logging a warning. - Refine the validation error messages to be more concise and easier for the LLM to parse by using structured error details from Pydantic's
ValidationError.
Overall, this is a valuable and well-executed change.
|
@gemini-code-assist pushing back on both:
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable enhancement by adding argument type validation and coercion for function tools using pydantic.TypeAdapter. This will improve the robustness of tool calls by catching type mismatches from the LLM and allowing it to self-correct. The changes are well-structured, touching FunctionTool, CrewAITool, and the synchronous tool path, and are accompanied by a comprehensive new test suite. My review found one issue in the new tests regarding an incorrect assumption about Pydantic's type coercion behavior.
|
@gemini-code-assist this is incorrect. pydantic v2 (2.12.5) does NOT coerce int to str in lax mode: the test asserting 3 errors is correct. all three params fail validation: int->str, "not_a_number"->int, "not_a_bool"->bool. /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable improvement by adding argument type validation and coercion for function tools using pydantic.TypeAdapter. The changes are well-structured, and the addition of comprehensive unit tests is commendable. The core logic in _preprocess_args is robust, handling various types, including optional types, and provides clear validation errors to the LLM for self-correction. The updates to FunctionTool, CrewAITool, and the LLM flow functions are consistent with the new error handling mechanism. I have one suggestion to improve consistency in error handling for Pydantic models.
|
@gemini-code-assist these are all repeat suggestions that have been addressed or explicitly declined in previous rounds:
no further changes needed on these. waiting for human review. |
|
Thank you for the detailed explanations and for addressing the previous suggestions. Regarding your points in comment #13:
It looks like all the points we discussed have been thoroughly considered and addressed or declined with valid justifications. I appreciate your diligent work on this pull request. |
…params Remove the Pydantic model special case from _preprocess_args so TypeAdapter handles primitives, enums, Pydantic models, and containers in one path. Skip framework-managed params (_ignore_params) to avoid validating injected values like credential=None.
|
@gemini-code-assist reconsidered the Pydantic model inconsistency point and agreed. fb7827d removes the special case so TypeAdapter handles all types uniformly. also skips framework-managed params ( /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces robust type validation and coercion for function tool arguments using pydantic.TypeAdapter. This is a great improvement, as it prevents runtime errors from invalid argument types provided by the LLM and provides clear feedback for self-correction. The implementation is clean and the new tests provide good coverage. I have one suggestion to cache TypeAdapter instances for a performance improvement.
|
@gemini-code-assist applied in 3b62f63. TypeAdapter instances are now cached per target_type on the FunctionTool instance, so they're only created once per param type across invocations. /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding validation and coercion for function tool argument types using pydantic.TypeAdapter. This enhances the robustness of tool calls by catching type mismatches and providing actionable feedback to the LLM for self-correction. The changes are well-implemented across the affected files, and the addition of a comprehensive test suite in test_function_tool_arg_validation.py is excellent. I have one suggestion to simplify the Optional type handling in function_tool.py by leveraging more of Pydantic's capabilities, which would improve code clarity and maintainability.
|
@gemini-code-assist good call. applied in 8ac8cb9. removed the entire Optional unwrap block since TypeAdapter handles /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding validation and type coercion for function tool arguments using pydantic.TypeAdapter. This makes the tools more robust against incorrect argument types provided by the LLM and allows for self-correction. The changes are well-implemented across FunctionTool, CrewAITool, and the synchronous tool path. The addition of a comprehensive test suite for the new validation logic is also a great contribution.
My review includes one high-severity comment regarding a potential bug in the TypeAdapter caching logic that could cause validation to be skipped for certain argument types.
|
@gemini-code-assist good catch. applied in 91e5a9d. cache lookup now uses try/except KeyError+TypeError so unhashable types like /gemini review |
There was a problem hiding this comment.
Code Review
This pull request is a great improvement, introducing robust type validation and coercion for function tool arguments using pydantic.TypeAdapter. This will prevent runtime type errors and allow the LLM to self-correct. The changes are well-implemented across FunctionTool and its consumers, and are accompanied by a comprehensive new test suite. I have one suggestion to improve error handling for invalid type annotations to make developer errors more visible.
|
@gemini-code-assist pushing back on this one. /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces robust type validation and coercion for function tool arguments by leveraging pydantic.TypeAdapter. The changes ensure that arguments passed to tools at runtime match their declared types, with automatic coercion for compatible types and clear validation errors returned to the LLM for incompatible ones. The implementation is solid, includes performance caching for type adapters, and is well-tested. I've suggested a minor refactoring to improve the readability of the adapter caching logic.
|
@gemini-code-assist applied in ba51ee0. split the cache except into separate /gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a significant improvement by adding validation and type coercion for function tool arguments using pydantic.TypeAdapter. This is a robust solution to handle type mismatches from the LLM, allowing for self-correction. The changes are well-implemented across FunctionTool, CrewAITool, and the synchronous tool path, and are supported by a comprehensive new test suite. I have one suggestion to improve the readability of the new caching logic.
| try: | ||
| adapter = self._type_adapter_cache[target_type] | ||
| except TypeError: | ||
| adapter = pydantic.TypeAdapter(target_type) | ||
| except KeyError: | ||
| adapter = pydantic.TypeAdapter(target_type) | ||
| self._type_adapter_cache[target_type] = adapter |
There was a problem hiding this comment.
The logic for caching TypeAdapter instances is correct, but it can be refactored to improve readability and reduce code duplication. By combining the KeyError and TypeError exception handling, you can create the adapter once and then attempt to cache it in a nested try...except block. This makes the intent of handling both cache misses and unhashable types more explicit.
| try: | |
| adapter = self._type_adapter_cache[target_type] | |
| except TypeError: | |
| adapter = pydantic.TypeAdapter(target_type) | |
| except KeyError: | |
| adapter = pydantic.TypeAdapter(target_type) | |
| self._type_adapter_cache[target_type] = adapter | |
| try: | |
| adapter = self._type_adapter_cache[target_type] | |
| except (KeyError, TypeError): | |
| # Create adapter if not in cache or type is unhashable. | |
| adapter = pydantic.TypeAdapter(target_type) | |
| try: | |
| # Attempt to cache it. This will fail for unhashable types. | |
| self._type_adapter_cache[target_type] = adapter | |
| except TypeError: | |
| # Can't cache unhashable types, but can still use the adapter. | |
| pass |
|
@gemini-code-assist this suggestion reverses the previous review's suggestion (which asked to split them apart). going to keep the current version with separate handlers since that's what the previous round asked for. no changes needed here. waiting for human review. |
|
You are absolutely right, and I apologize for the conflicting advice. My previous suggestion to split the |
|
@gemini-code-assist to be clear, this is now going in circles. the 09:11 review asked me to split @llalitkumarrr @cuihaoleo @xuanyang15 this PR is ready for human review. gemini has gone through ~8 review rounds and all actionable feedback has been addressed. the remaining suggestions are either contradictory (split vs combine exception handlers) or already declined with reasoning (logging vs error for developer-side TypeError/NameError). would appreciate a look when you get a chance. |
|
You are absolutely right, and I apologize for the conflicting advice. My previous suggestion to split the |
Fixes #4612
_preprocess_argscurrently only handles Pydantic model conversion but passes all other types through without any validation. This means a function declared withnum: inthappily accepts"foobar",3.14159, orNoneat runtime.This PR extends
_preprocess_argsto validate and coerce all annotated argument types usingpydantic.TypeAdapter. When coercion fails, the validation error is returned to the LLM so it can self-correct and retry (same pattern as the existing missing-mandatory-args check).What changed:
_preprocess_argsnow returns(args, validation_errors)tuplepydantic.TypeAdapter.validate_python()for all non-Pydantic-BaseModel annotated params"42"->42forint,"red"->Color.REDfor enum)FunctionTool.run_async,CrewAITool.run_async, sync tool path infunctions.pyBefore (no validation):
After (validates and coerces):
Tests: 17 new tests covering coercion (str->int, str->float, str->enum, list coercion, Optional handling, bool coercion), validation errors (invalid str for int, None for required int, multiple param errors), and run_async integration (error returned to LLM, valid coercion invokes function, enum validation). All 1776 existing tests continue to pass.