Skip to content

Commit 11bac47

Browse files
authored
Merge branch 'main' into copybara/891919371
2 parents 364a96d + 064f0d2 commit 11bac47

45 files changed

Lines changed: 1174 additions & 410 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

contributing/samples/agent_registry_agent/agent.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from google.adk.agents.llm_agent import LlmAgent
2020
from google.adk.integrations.agent_registry import AgentRegistry
21+
from google.adk.models.google_llm import Gemini
2122

2223
# Project and location can be set via environment variables:
2324
# GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION
@@ -27,6 +28,8 @@
2728
# Initialize Agent Registry client
2829
registry = AgentRegistry(project_id=project_id, location=location)
2930

31+
# List agents, MCP servers, and endpoints resource names from the registry.
32+
# They can be used to initialize the agent, toolset, and model below.
3033
print(f"Listing agents in {project_id}/{location}...")
3134
agents = registry.list_agents()
3235
for agent in agents.get("agents", []):
@@ -37,6 +40,11 @@
3740
for server in mcp_servers.get("mcpServers", []):
3841
print(f"- MCP Server: {server.get('displayName')} ({server.get('name')})")
3942

43+
print(f"\nListing endpoints in {project_id}/{location}...")
44+
endpoints = registry.list_endpoints()
45+
for endpoint in endpoints.get("endpoints", []):
46+
print(f"- Endpoint: {endpoint.get('displayName')} ({endpoint.get('name')})")
47+
4048
# Example of using a specific agent or MCP server from the registry:
4149
# (Note: These names should be full resource names as returned by list methods)
4250

@@ -52,8 +60,19 @@
5260
f"projects/{project_id}/locations/{location}/mcpServers/MCP_SERVER_NAME"
5361
)
5462

63+
# 3. Getting a specific model endpoint configuration
64+
# This returns a string like:
65+
# "projects/adk12345/locations/us-central1/publishers/google/models/gemini-2.5-flash"
66+
# TODO: Replace ENDPOINT_NAME with your endpoint name
67+
model_name = registry.get_model_name(
68+
f"projects/{project_id}/locations/{location}/endpoints/ENDPOINT_NAME"
69+
)
70+
71+
# Initialize the model using the resolved model name from registry.
72+
gemini_model = Gemini(model=model_name)
73+
5574
root_agent = LlmAgent(
56-
model="gemini-2.5-flash",
75+
model=gemini_model,
5776
name="discovery_agent",
5877
instruction=(
5978
"You have access to tools and sub-agents discovered via Registry."
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Simple Live (Bidi-Streaming) Agent with Parallel Tools
2+
This project provides a basic example of a live, [bidirectional streaming](https://google.github.io/adk-docs/streaming/) agent that demonstrates parallel tool execution.
3+
4+
## Getting Started
5+
6+
Follow these steps to get the agent up and running:
7+
8+
1. **Start the ADK Web Server**
9+
Open your terminal, navigate to the root directory that contains the
10+
`live_bidi_streaming_parallel_tools_agent` folder, and execute the following
11+
command:
12+
```bash
13+
adk web
14+
```
15+
16+
2. **Access the ADK Web UI**
17+
Once the server is running, open your web browser and navigate to the URL
18+
provided in the terminal (it will typically be `http://localhost:8000`).
19+
20+
3. **Select the Agent**
21+
In the top-left corner of the ADK Web UI, use the dropdown menu to select
22+
this agent (`live_bidi_streaming_parallel_tools_agent`).
23+
24+
4. **Start Streaming**
25+
Click on the **Audio** icon located near the chat input
26+
box to begin the streaming session.
27+
28+
5. **Interact with the Agent**
29+
You can now begin talking to the agent, and it will respond in real-time.
30+
Try asking it to perform multiple actions at once, for example: "Turn on the
31+
lights and the TV at the same time." The agent will be able to invoke both
32+
`turn_on_lights` and `turn_on_tv` tools in parallel.
33+
34+
## Usage Notes
35+
36+
* You only need to click the **Audio** button once to initiate the
37+
stream. The current version does not support stopping and restarting the stream
38+
by clicking the button again during a session.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from . import agent
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
from google.adk.agents.llm_agent import Agent
17+
18+
19+
def turn_on_lights():
20+
"""Turn on the lights."""
21+
print("turn_on_lights")
22+
return {"status": "OK"}
23+
24+
25+
def turn_on_tv():
26+
"""Turn on the tv."""
27+
print("turn_on_tv")
28+
return {"status": "OK"}
29+
30+
31+
root_agent = Agent(
32+
model="gemini-live-2.5-flash-native-audio",
33+
name="Home_helper",
34+
instruction="Be polite and answer all user's questions.",
35+
tools=[turn_on_lights, turn_on_tv],
36+
)

contributing/samples/skills_agent/agent.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ async def run_async(self, *, args: dict, tool_context) -> str:
5454
return f"The timezone for {args['location']} is UTC+00:00."
5555

5656

57-
def get_current_humidity(location: str) -> str:
58-
"""Returns the current humidity for a given location."""
59-
return f"The humidity in {location} is 45%."
57+
def get_wind_speed(location: str) -> str:
58+
"""Returns the current wind speed for a given location."""
59+
return f"The wind speed in {location} is 10 mph."
6060

6161

6262
greeting_skill = models.Skill(
@@ -87,7 +87,7 @@ def get_current_humidity(location: str) -> str:
8787
# be used in production environments.
8888
my_skill_toolset = SkillToolset(
8989
skills=[greeting_skill, weather_skill],
90-
additional_tools=[GetTimezoneTool(), get_current_humidity],
90+
additional_tools=[GetTimezoneTool(), get_wind_speed],
9191
code_executor=UnsafeLocalCodeExecutor(),
9292
)
9393

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
---
22
name: weather-skill
33
description: A skill that provides weather information based on reference data.
4+
metadata:
5+
adk_additional_tools:
6+
- get_wind_speed
47
---
58

69
Step 1: Check 'references/weather_info.md' for the current weather.
710
Step 2: If humidity is requested, use run 'scripts/get_humidity.py' with the `location` argument.
8-
Step 3: Provide the update to the user.
11+
Step 3: If wind speed is requested, use the `get_wind_speed` tool.
12+
Step 4: Provide the update to the user.

contributing/samples/skills_agent/skills/weather_skill/SKILL.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/google/adk/a2a/agent/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from __future__ import annotations
1818

19+
import copy
1920
from typing import Any
2021
from typing import Awaitable
2122
from typing import Callable
@@ -108,3 +109,16 @@ class A2aRemoteAgentConfig(BaseModel):
108109
)
109110

110111
request_interceptors: Optional[list[RequestInterceptor]] = None
112+
113+
def __deepcopy__(self, memo):
114+
cls = self.__class__
115+
copied_values = {}
116+
for k, v in self.__dict__.items():
117+
if not k.startswith('_'):
118+
if callable(v):
119+
copied_values[k] = v
120+
else:
121+
copied_values[k] = copy.deepcopy(v, memo)
122+
result = cls.model_construct(**copied_values)
123+
memo[id(self)] = result
124+
return result

src/google/adk/a2a/executor/a2a_agent_executor_impl.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from typing_extensions import override
3939

4040
from ...runners import Runner
41+
from ...sessions import base_session_service
4142
from ...utils.context_utils import Aclosing
4243
from ..agent.interceptors.new_integration_extension import _NEW_A2A_ADK_INTEGRATION_EXTENSION
4344
from ..converters.from_adk_event import create_error_status_event
@@ -287,6 +288,8 @@ async def _resolve_session(
287288
app_name=runner.app_name,
288289
user_id=user_id,
289290
session_id=session_id,
291+
# Checking existence doesn't require event history.
292+
config=base_session_service.GetSessionConfig(num_recent_events=0),
290293
)
291294
if session is None:
292295
session = await runner.session_service.create_session(

src/google/adk/auth/auth_credential.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class OAuth2Auth(BaseModelWithConfig):
7373
# tool or adk can generate the auth_uri with the state info thus client
7474
# can verify the state
7575
auth_uri: Optional[str] = None
76+
# A unique value generated at the start of the OAuth flow to bind the user's
77+
# session to the authorization request. This value is typically stored with
78+
# user session and passed to backend for validation.
79+
nonce: Optional[str] = None
7680
state: Optional[str] = None
7781
# tool or adk can decide the redirect_uri if they don't want client to decide
7882
redirect_uri: Optional[str] = None

0 commit comments

Comments
 (0)