-
Notifications
You must be signed in to change notification settings - Fork 2.1k
fix: #3036 parameter filtering for CrewAI functions with **kwargs #3037
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
omarcevi
wants to merge
17
commits into
google:main
Choose a base branch
from
omarcevi:fix/function-tool-kwargs-parameter-filtering
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f5949f6
fix: improve parameter filtering for functions with **kwargs
omarcevi 1e97f35
fix: correct tool_context handling in **kwargs parameter filtering
omarcevi dffd106
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi 31b7ec2
fix: Improve handling of **kwargs in FunctionTool by removing 'self' …
omarcevi 619d5a1
Update src/google/adk/tools/function_tool.py
omarcevi 574db75
test: Enhance FunctionTool tests with CrewAI-style functions and cont…
omarcevi 45d1142
Update src/google/adk/tools/function_tool.py
omarcevi d1234aa
test: Verify filtering of unexpected parameters in FunctionTool tests
omarcevi dc6a5f4
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi f7f5a38
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi 3c251b2
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi 9ef73e0
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi 14b89ed
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi ef010b8
feat: Enhance CrewaiTool with async run method and parameter filtering
omarcevi 8d81f2c
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi 9de9de4
docs: Update CrewaiTool docstring for parameter filtering clarification
omarcevi 75467d7
Merge branch 'main' into fix/function-tool-kwargs-parameter-filtering
omarcevi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
# Copyright 2025 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
omarcevi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
from unittest.mock import MagicMock | ||
|
||
from google.adk.agents.invocation_context import InvocationContext | ||
from google.adk.sessions.session import Session | ||
from google.adk.tools.crewai_tool import CrewaiTool | ||
from google.adk.tools.tool_context import ToolContext | ||
import pytest | ||
|
||
|
||
@pytest.fixture | ||
def mock_tool_context() -> ToolContext: | ||
"""Fixture that provides a mock ToolContext for testing.""" | ||
mock_invocation_context = MagicMock(spec=InvocationContext) | ||
mock_invocation_context.session = MagicMock(spec=Session) | ||
mock_invocation_context.session.state = MagicMock() | ||
return ToolContext(invocation_context=mock_invocation_context) | ||
|
||
|
||
def _simple_crewai_tool(*args, **kwargs): | ||
"""Simple CrewAI-style tool that accepts any keyword arguments.""" | ||
return { | ||
"search_query": kwargs.get("search_query"), | ||
"other_param": kwargs.get("other_param"), | ||
} | ||
|
||
|
||
def _crewai_tool_with_context(tool_context: ToolContext, *args, **kwargs): | ||
"""CrewAI tool with explicit tool_context parameter.""" | ||
return { | ||
"search_query": kwargs.get("search_query"), | ||
"tool_context_present": bool(tool_context), | ||
} | ||
|
||
|
||
class MockCrewaiBaseTool: | ||
"""Mock CrewAI BaseTool for testing.""" | ||
|
||
def __init__(self, run_func, name="mock_tool", description="Mock tool"): | ||
self.run = run_func | ||
self.name = name | ||
self.description = description | ||
self.args_schema = MagicMock() | ||
self.args_schema.model_json_schema.return_value = { | ||
"type": "object", | ||
"properties": { | ||
"search_query": { | ||
"type": "string", | ||
"description": "Search query" | ||
} | ||
} | ||
} | ||
|
||
|
||
def test_crewai_tool_initialization(): | ||
"""Test CrewaiTool initialization with various parameters.""" | ||
mock_crewai_tool = MockCrewaiBaseTool(_simple_crewai_tool) | ||
|
||
# Test with custom name and description | ||
tool = CrewaiTool( | ||
mock_crewai_tool, | ||
name="custom_search_tool", | ||
description="Custom search tool description" | ||
) | ||
|
||
assert tool.name == "custom_search_tool" | ||
assert tool.description == "Custom search tool description" | ||
assert tool.tool == mock_crewai_tool | ||
|
||
|
||
def test_crewai_tool_initialization_with_tool_defaults(): | ||
"""Test CrewaiTool initialization using tool's default name and description.""" | ||
mock_crewai_tool = MockCrewaiBaseTool( | ||
_simple_crewai_tool, | ||
name="Serper Dev Tool", | ||
description="Search the internet with Serper" | ||
) | ||
|
||
# Test with empty name and description (should use tool defaults) | ||
tool = CrewaiTool(mock_crewai_tool, name="", description="") | ||
|
||
assert tool.name == "serper_dev_tool" # Spaces replaced with underscores, lowercased | ||
assert tool.description == "Search the internet with Serper" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_crewai_tool_basic_functionality(mock_tool_context): | ||
"""Test basic CrewaiTool functionality with **kwargs parameter passing.""" | ||
mock_crewai_tool = MockCrewaiBaseTool(_simple_crewai_tool) | ||
tool = CrewaiTool(mock_crewai_tool, name="test_tool", description="Test tool") | ||
|
||
# Test that **kwargs parameters are passed through correctly | ||
result = await tool.run_async( | ||
args={"search_query": "test query", "other_param": "test value"}, | ||
tool_context=mock_tool_context, | ||
) | ||
|
||
assert result["search_query"] == "test query" | ||
assert result["other_param"] == "test value" | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_crewai_tool_with_tool_context(mock_tool_context): | ||
"""Test CrewaiTool with a tool that has explicit tool_context parameter.""" | ||
mock_crewai_tool = MockCrewaiBaseTool(_crewai_tool_with_context) | ||
tool = CrewaiTool(mock_crewai_tool, name="context_tool", description="Context tool") | ||
|
||
# Test that tool_context is properly injected | ||
result = await tool.run_async( | ||
args={"search_query": "test query"}, | ||
tool_context=mock_tool_context, | ||
) | ||
|
||
assert result["search_query"] == "test query" | ||
assert result["tool_context_present"] is True | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_crewai_tool_parameter_filtering(mock_tool_context): | ||
"""Test that CrewaiTool filters parameters for non-**kwargs functions.""" | ||
|
||
def explicit_params_func(arg1: str, arg2: int): | ||
"""Function with explicit parameters (no **kwargs).""" | ||
return {"arg1": arg1, "arg2": arg2} | ||
|
||
mock_crewai_tool = MockCrewaiBaseTool(explicit_params_func) | ||
tool = CrewaiTool(mock_crewai_tool, name="explicit_tool", description="Explicit tool") | ||
|
||
# Test that unexpected parameters are filtered out | ||
result = await tool.run_async( | ||
args={ | ||
"arg1": "test", | ||
"arg2": 42, | ||
"unexpected_param": "should_be_filtered" | ||
}, | ||
tool_context=mock_tool_context, | ||
) | ||
|
||
assert result == {"arg1": "test", "arg2": 42} | ||
# Verify unexpected parameter was filtered out | ||
assert "unexpected_param" not in result | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_crewai_tool_get_declaration(): | ||
"""Test that CrewaiTool properly builds function declarations.""" | ||
mock_crewai_tool = MockCrewaiBaseTool(_simple_crewai_tool) | ||
tool = CrewaiTool(mock_crewai_tool, name="test_tool", description="Test tool") | ||
|
||
# Test function declaration generation | ||
declaration = tool._get_declaration() | ||
|
||
# Verify the declaration object structure and content | ||
assert declaration is not None | ||
assert declaration.name == "test_tool" | ||
assert declaration.description == "Test tool" | ||
assert declaration.parameters is not None | ||
|
||
# Verify that the args_schema was used to build the declaration | ||
mock_crewai_tool.args_schema.model_json_schema.assert_called_once() |
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
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.
Uh oh!
There was an error while loading. Please reload this page.