To register a custom service:
- Create a factory function that takes a URI and returns an instance of your custom service. This function will parse any details it needs from the URI.
- Register your factory with the global service registry. You need to define a unique URI scheme for your service (e.g., custom).
PiperOrigin-RevId: 822310466
Merge https://github.com/google/adk-python/pull/3170
Addresses Feature Request: #3116
This PR adds a `speech_config` to the **LLM Agent configuration** for the **live use case**. When an **asynchronous LLM** call is made to the **Gemini Live API**, it prioritizes the most specific agent configuration's speech_config. If that is null, it then uses the run configuration's speech_config. Unit tests have been added to verify this behavior.
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3170 from qyuo:bidi_agent_speech_config af1bd277d4f95c4a7d9aa0b16828ba3de826ce08
PiperOrigin-RevId: 822305427
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
Previously BuiltInCodeExecutor was missing the logic to save output files from executed code as artifacts, so images/visualizations wouldn't show up in the UI. This fix will iterate through all parts of the LlmResponse, and if any of them are images, it will save the image data using artifact_service (similar to what is done in VertexAICodeExecutor).
This fixes the backend, but there are still UI bugs that should be fixed -- events without content are currently ignored, so the image doesn't appear even though it is saved. We will add the UI fix in a separate change.
PiperOrigin-RevId: 822245140
- let _enforce_app_name_alignment warn instead of raising while caching the hint that now augments the existing “Session not found …” error
- tighten _infer_agent_origin so it ignores hidden folders (like .venv)
- make AgentTool reuse the parent runner’s app_name, stopping internal runners from conflicting in multi-agent setups
PiperOrigin-RevId: 822205860
Details:
- Adds the `StaticUserSimulator` which implements the current functionality of supplying a fixed set of user prompts for an EvalCase.
- Adds the `UserSimulatorProvider` which determines the type of user simulator required for an EvalCase (StaticUserSimulator or LlmBackedUserSimulator).
- Integrates the UserSimulatorProvider and UserSimulator into the CLI and evaluation infrastructure.
- Updates and adds unit tests for the new functionality.
- Miscellaneous updates to lay groundwork for a full implementation of the LlmBackedUserSimulator in the future.
PiperOrigin-RevId: 822198401
Merge https://github.com/google/adk-python/pull/3196
## Summary
Enhances the `AgentLoader` error message to provide clear guidance when users run `adk web` from incorrect directories.
## Motivation
During internal workshops, multiple teams encountered confusion when starting `adk web` from the wrong directory. This often happened when:
- Running `adk web my_agent/` instead of `adk web .`
- Being inside an agent directory when executing the command
- Configuring incorrect start paths during development
## Changes
- **Smart detection**: Checks if `agent.py` or `root_agent.yaml` exists in the current directory
- **Visual diagram**: Shows expected directory structure with actual agent name
- **Explicit command**: Includes `adk web <agents_dir>` usage example
- **Conditional hint**: Provides targeted guidance when user is detected to be inside an agent directory
## Example Error Message
### Before
```
ValueError: No root_agent found for 'my_agent'. Searched in 'my_agent.agent.root_agent', 'my_agent.root_agent' and 'my_agent/root_agent.yaml'. Ensure 'path/my_agent' is structured correctly, an .env file can be loaded if present, and a root_agent is exposed.
```
### After
```
ValueError: No root_agent found for 'my_agent'. Searched in 'my_agent.agent.root_agent', 'my_agent.root_agent' and 'my_agent/root_agent.yaml'.
Expected directory structure:
<agents_dir>/
my_agent/
agent.py (with root_agent) OR
root_agent.yaml
Then run: adk web <agents_dir>
Ensure 'path/my_agent' is structured correctly, an .env file can be loaded if present, and a root_agent is exposed.
HINT: It looks like you might be running 'adk web' from inside an agent directory. Try running 'adk web .' from the parent directory that contains your agent folder, not from within the agent folder itself.
```
## Testing
- ✅ Existing unit tests pass (17/22, with 5 pre-existing failures unrelated to this change)
- ✅ `test_agent_not_found_error` passes, confirming error message enhancement works correctly
- ✅ Code follows ADK contribution guidelines
## Type
- [x] Bug fix (improved error messaging)
- [ ] Feature
- [ ] Breaking change
- [ ] Documentation
## Related
Fixes#3195
---
**Tags**: #non-breaking
🤖 Generated with [Claude Code](https://claude.com/claude-code)
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3196 from jpantsjoha:fix/improve-adk-web-error-message a73b190f5b021dbe0afa8426172696ee9eeae8da
PiperOrigin-RevId: 822186700
Merge https://github.com/google/adk-python/pull/3060
## Description
Fixes#3059
This PR fixes two endpoints in `adk web` that fail when using App objects instead of bare agents.
## Changes
- **Eval execution endpoint** (line ~969): Extract root_agent from App objects before passing to LocalEvalService
- **Graph visualization endpoint** (line ~1308): Extract root_agent from App objects before graph operations
Both endpoints now properly handle both BaseAgent and App objects by checking the type and extracting `.root_agent` when needed.
## Testing Plan
### Manual E2E Testing with ADK Web
Tested with an App object that includes context caching:
```python
from google.adk.apps import App
from google.adk.agents import LlmAgent
root_agent = LlmAgent(name="MyAgent", model="gemini-1.5-pro-002")
app = App(
name="my_agent",
root_agent=root_agent,
context_cache_config=ContextCacheConfig(...)
)
```
**Before fix:**
- Graph visualization failed (tried to call agent methods on App object)
- Eval execution failed (LocalEvalService received App instead of agent)
**After fix:**
- Graph visualization works correctly
- Eval execution works correctly
- Both endpoints properly extract root_agent from App objects
## Checklist
- [x] Code follows project style (autoformat.sh passed)
- [x] Changes are focused and minimal
- [x] Issue #3059 created and referenced
- [x] Manual E2E testing completed
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3060 from ejfn:ejfn/bugfix-app-object-endpoints 01c30191bfd9487a8c8463ccf24b297cb9a4ce37
PiperOrigin-RevId: 821746910