feat(tools): support additional headers for google api toolset #non-breaking

Merge https://github.com/google/adk-python/pull/3194

Allow Google API toolsets to accept optional per-request headers
#3105

## Testing Plan

### Unit Tests
-  Added `test_init_with_additional_headers` in `test_google_api_tool.py` to verify headers are passed to RestApiTool
-  Added `test_prepare_request_params_merges_default_headers` in `test_rest_api_tool.py` to verify custom headers are merged into requests
-  Added `test_prepare_request_params_preserves_existing_headers` in `test_rest_api_tool.py` to verify critical headers (Content-Type, User-Agent) are not overridden by additional_headers
-  Updated `test_init` and `test_get_tools` in `test_google_api_toolset.py` to verify the parameter is properly stored and passed through

### Manual Testing
Tested with Google Ads API scenario (the original use case from issue #3105):

```python
import os
from google.adk.tools.google_api_tool import GoogleApiToolset

# Create toolset with developer-token header required by Google Ads API
google_ads_toolset = GoogleApiToolset(
    client_id=os.environ["CLIENT_ID"],
    client_secret=os.environ["CLIENT_SECRET"],
    api_name="googleads",
    api_version="v21",
    additional_headers={"developer-token": os.environ["GOOGLE_ADS_DEV_TOKEN"]}
)

# Verify headers are included in API requests
tools = await google_ads_toolset.get_tools()
# Successfully made requests with the developer-token header
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3194 from Prhmma:feature/google-api-toolset-additional-headers-3105 e10489e82bfde5cf2bfd3f1bced3e1f5cea1f8b2
PiperOrigin-RevId: 822273582
This commit is contained in:
Parham MohammadAlizadeh
2025-10-21 14:16:37 -07:00
committed by Copybara-Service
parent ce3418a69d
commit ed37e343f0
6 changed files with 102 additions and 4 deletions
@@ -56,6 +56,14 @@ class TestGoogleApiTool:
assert tool.is_long_running is False
assert tool._rest_api_tool == mock_rest_api_tool
def test_init_with_additional_headers(self, mock_rest_api_tool):
"""Test GoogleApiTool initialization with additional headers."""
headers = {"developer-token": "test-token"}
GoogleApiTool(mock_rest_api_tool, additional_headers=headers)
mock_rest_api_tool.set_default_headers.assert_called_once_with(headers)
def test_get_declaration(self, mock_rest_api_tool):
"""Test _get_declaration method."""
tool = GoogleApiTool(mock_rest_api_tool)
@@ -126,12 +126,14 @@ class TestGoogleApiToolset:
client_id = "test_client_id"
client_secret = "test_client_secret"
additional_headers = {"developer-token": "abc123"}
tool_set = GoogleApiToolset(
api_name=TEST_API_NAME,
api_version=TEST_API_VERSION,
client_id=client_id,
client_secret=client_secret,
additional_headers=additional_headers,
)
assert tool_set.api_name == TEST_API_NAME
@@ -141,6 +143,7 @@ class TestGoogleApiToolset:
assert tool_set._service_account is None
assert tool_set.tool_filter is None
assert tool_set._openapi_toolset == mock_openapi_toolset_instance
assert tool_set._additional_headers == additional_headers
mock_converter_class.assert_called_once_with(
TEST_API_NAME, TEST_API_VERSION
@@ -191,6 +194,7 @@ class TestGoogleApiToolset:
client_id = "cid"
client_secret = "csecret"
sa_mock = mock.MagicMock(spec=ServiceAccount)
additional_headers = {"developer-token": "token"}
tool_set = GoogleApiToolset(
api_name=TEST_API_NAME,
@@ -198,6 +202,7 @@ class TestGoogleApiToolset:
client_id=client_id,
client_secret=client_secret,
service_account=sa_mock,
additional_headers=additional_headers,
)
tools = await tool_set.get_tools(mock_readonly_context)
@@ -209,7 +214,11 @@ class TestGoogleApiToolset:
for i, rest_tool in enumerate(mock_rest_api_tools):
mock_google_api_tool_class.assert_any_call(
rest_tool, client_id, client_secret, sa_mock
rest_tool,
client_id,
client_secret,
sa_mock,
additional_headers=additional_headers,
)
assert tools[i] is mock_google_api_tool_instances[i]