Merge https://github.com/google/adk-python/pull/4136
**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**
### Link to Issue or Description of Change
**1. Link to an existing issue (if applicable):**
Allow google search tool to set different model #4135
**2. Or, if no issue exists, describe the change:**
_If applicable, please follow the issue templates to provide as much detail as
possible._
**Problem:**
Currently, the Google Search tool inherits and uses the same LLM model set from the parent agent for processing and summarizing search results. This creates a limitation for users who wish to decouple the agent's reasoning model from the model used for search summarization (e.g., for cost optimization or using a lightweight model for simpler summarization tasks).
**Solution:**
I have updated the Google Search tool to accept an optional LLM model parameter.
Custom Model: Users can now explicitly specify which model should be used for processing search results.
Default Behavior: If no model is specified, the tool defaults to the parent agent's model, ensuring backward compatibility.
```
# If a custom model is specified, use it instead of the original model
if self.model is not None:
llm_request.model = self.model
```
### Testing Plan
Added a new test case test_process_llm_request_with_custom_model in [test_google_search_tool.py] that verifies:
When a custom model parameter is provided to GoogleSearchTool, it overrides the model from the incoming llm_request during process_llm_request
The tool correctly uses the custom model for LLM calls while maintaining other request parameters
**Unit Tests:**
- [X] I have added or updated unit tests for my change.
- [X] All unit tests pass locally.
(base) wanglu2:adk-python/ (feature/allow-google-search-tool-set-different-llm✗) $ uv run pytest ./tests/unittests/tools/test_google_search_tool.py [22:07:32]
======================================================================== test session starts ========================================================================
platform darwin -- Python 3.13.1, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/wanglu2/Documents/Git/adk-python
configfile: pyproject.toml
plugins: mock-3.15.1, anyio-4.12.0, xdist-3.8.0, asyncio-1.3.0, langsmith-0.6.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collected 21 items
tests/unittests/tools/test_google_search_tool.py ..................... [100%]
======================================================================== 21 passed in 7.91s =========================================================================
### Checklist
- [X] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [X] I have performed a self-review of my own code.
- [X] I have commented my code, particularly in hard-to-understand areas.
- [X] I have added tests that prove my fix is effective or that my feature works.
- [X] New and existing unit tests pass locally with my changes.
- [X] I have manually tested my changes end-to-end.
- [ ] Any dependent changes have been merged and published in downstream modules.
### Additional context
Co-authored-by: Kathy Wu <wukathy@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4136 from lwangverizon:feature/allow-google-search-tool-set-different-llm 239ea9577bd7befc9a3574aca48dc8243d55192c
PiperOrigin-RevId: 859265757
Currently only tool calling supports MCP auth. This refactors the auth logic into a auth_utils file and uses it for tool listing as well. Fixes https://github.com/google/adk-python/issues/2168.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 856798589
Merge https://github.com/google/adk-python/pull/3988
### Link to Issue or Description of Change
**1. Link to an existing issue (if applicable):**
- Closes: https://github.com/google/adk-python/issues/3987
- Related: https://github.com/google/adk-python/issues/3596
**2. Or, if no issue exists, describe the change:**
**Problem:**
Idea about my use case
I'm building the report generation system using google-ask (1.18.0) and building multiple subagents here, I'm passing the one subagent Agent as a tool to another Parent Agent. Note: Sub-agent can do web search.
here, parent agent triggers multiple sub-agent (same agent) multiple times according to use case or complexity of the user input
Describe the bug
here, the bug sometimes sub agents doesn't provide the proper output and resulted in the
```
merged_text = '\n'.join(p.text for p in last_content.parts if p.text)
^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable
and it's breaking the system of Agents workflow
```
**Solution:**
Creating fallback if there is no **last_content.parts** it will return the empty parts so we won't face the NoneType issue
### Testing Plan
Created a unit test file for this issue
test_google_search_agent_tool_repro.py
**Unit Tests:**
- [X] I have added or updated unit tests for my change.
- [X] All unit tests pass locally.
_Please include a summary of passed `pytest` results._
3677 passed, 2208 warnings in 42.64s
**Manual End-to-End (E2E) Tests:**
N/A
### Checklist
- [X] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [X] I have performed a self-review of my own code.
- [X] I have commented my code, particularly in hard-to-understand areas.
- [X] I have added tests that prove my fix is effective or that my feature works.
- [X] New and existing unit tests pass locally with my changes.
- [X] I have manually tested my changes end-to-end.
- [ ] Any dependent changes have been merged and published in downstream modules.
### Additional context
N/A
Co-authored-by: Liang Wu <wuliang@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3988 from ananthanarayanan-28:none-type-issue e6ba948345adfc5ac73a5e39d11c68236f117179
PiperOrigin-RevId: 856515019
Merge https://github.com/google/adk-python/pull/4025
**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**
### Link to Issue or Description of Change
**1. Link to an existing issue (if applicable):**
- Closes:
- #3950
- #3731
- #3708
**2. Or, if no issue exists, describe the change:**
**Problem:**
- `ClientSession` of https://github.com/modelcontextprotocol/python-sdk uses AnyIO for async task management.
- AnyIO TaskGroup requires its start and close must happen in a same task.
- Since `McpSessionManager` does not create task per client, the client might be closed by different task, cause the error: `Attempted to exit cancel scope in a different task than it was entered in`.
**Solution:**
I Suggest 2 changes:
Handling the `ClientSession` in a single task
- To start and close `ClientSession` by the same task, we need to wrap the whole lifecycle of `ClientSession` to a single task.
- `SessionContext` wraps the initialization and disposal of `ClientSession` to a single task, ensures that the `ClientSession` will be handled only in a dedicated task.
Add timeout for `ClientSession`
- Since now we are using task per `ClientSession`, task should never be leaked.
- But `McpSessionManager` does not deliver timeout directly to `ClientSession` when the type is not STDIO.
- There is only timeout for `httpx` client when MCP type is SSE or StreamableHTTP.
- But the timeout applys only to `httpx` client, so if there is an issue in MCP client itself(e.g. https://github.com/modelcontextprotocol/python-sdk/issues/262), a tool call waits the result **FOREVER**!
- To overcome this issue, I propagated the `sse_read_timeout` to `ClientSession`.
- `timeout` is too short for timeout for tool call, since its default value is only 5s.
- `sse_read_timeout` is originally made for read timeout of SSE(default value of 5m or 300s), but actually most of SSE implementations from server (e.g. FastAPI, etc.) sends ping periodically(about 15s I assume), so in a normal circumstances this timeout is quite useless.
- If the server does not send ping, the timeout is equal to tool call timeout. Therefore, it would be appropriate to use `sse_read_timeout` as tool call timeout.
- Most of tool calls should finish within 5 minutes, and sse timeout is adjustable if not.
- If this change is not acceptable, we could make a dedicate parameter for tool call timeout(e.g. `tool_call_timeout`).
### Testing Plan
- Although this does not change the interface itself, it changes its own session management logics, some existing tests are no longer valid.
- I made changes to those tests, especially those of which validate session states(e.g. checking whether `initialize()` called).
- Since now session is encapsulated with `SessionContext`, we cannot validate the initialized state of the session in `TestMcpSessionManager`, should validate it at `TestSessionContext`.
- Added a simple test for reproducing the issue(`test_create_and_close_session_in_different_tasks`).
- Also made a test for the new component: `SessionContext`.
**Unit Tests:**
- [x] I have added or updated unit tests for my change.
- [x] All unit tests pass locally.
```plaintext
=================================================================================== 3689 passed, 1 skipped, 2205 warnings in 63.39s (0:01:03) ===================================================================================
```
**Manual End-to-End (E2E) Tests:**
_Please provide instructions on how to manually test your changes, including any
necessary setup or configuration. Please provide logs or screenshots to help
reviewers better understand the fix._
### Checklist
- [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly in hard-to-understand areas.
- [x] I have added tests that prove my fix is effective or that my feature works.
- [x] New and existing unit tests pass locally with my changes.
- [x] I have manually tested my changes end-to-end.
- [ ] ~~Any dependent changes have been merged and published in downstream modules.~~ `no deps has been changed`
### Additional context
This PR is related to https://github.com/modelcontextprotocol/python-sdk/pull/1817 since it also fixes endless tool call awaiting.
Co-authored-by: Kathy Wu <wukathy@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4025 from challenger71498:feat/task-based-mcp-session-manager f7f7cd0c9c96840361c30499d08c33a189f57d86
PiperOrigin-RevId: 856438147
There was an extra test_mcp_toolset in the tools/ directory with only one test; I moved it into the main file.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 856419611
The LoadArtifactsTool now checks if an artifact's inline data MIME type is supported by Gemini. If not, it attempts to convert the artifact content into a text Part
Close#4028
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 856404510
gcloud auth team requested that we audit ADK's codebase for places where ADC (google.auth.default) is used, and make sure that the quota project id header is being populated.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 855322964
API registry uses a nextPageToken for pagination, so we should loop through all the pages by sending the received nextPageToken to subsequent requests until no token is returned. The first page contains 1P MCP servers, and later pages contain 3P customer servers.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 853880449
Fix discovery engine search tool, bigquery agent analytics plugin, and application integration tool to correctly handle the ADC quota project override -- the x-goog-user-project should be set based on the ADC quota project, per gcloud auth team's requirements.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 853841124
This change introduces a `_sanitize_schema_types` method to the OpenAPI spec parser. This method recursively removes or filters out non-standard schema types (e.g., "Any", "Unknown") from the OpenAPI specification
Close#3704Close#3108
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 852986491
The retry_on_errors decorator in mcp_session_manager.py now catches asyncio.CancelledError and re-raises it immediately, ensuring that cancellation requests are not suppressed or retried
Close#4009
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 852468382