Skip to content

Commit b21ca1e

Browse files
Merge branch 'main' into custom-session-id-with-agent-engine
2 parents f1a71e2 + 898c4e5 commit b21ca1e

33 files changed

+729
-136
lines changed

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."

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

src/google/adk/cli/adk_web_server.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,37 @@ async def event_generator():
19041904
media_type="text/event-stream",
19051905
)
19061906

1907+
@app.get(
1908+
"/dev/{app_name}/graph",
1909+
response_model_exclude_none=True,
1910+
tags=[TAG_DEBUG],
1911+
)
1912+
async def get_app_graph_dot(
1913+
app_name: str, dark_mode: bool = False
1914+
) -> GetEventGraphResult | dict:
1915+
"""Returns the base agent graph in DOT format without any highlights.
1916+
1917+
This endpoint allows the frontend to fetch the graph structure once
1918+
and compute highlights client-side for better performance.
1919+
1920+
Args:
1921+
app_name: The name of the agent/app
1922+
dark_mode: Whether to use dark theme background color
1923+
"""
1924+
agent_or_app = self.agent_loader.load_agent(app_name)
1925+
root_agent = self._get_root_agent(agent_or_app)
1926+
1927+
# Get graph with NO highlights (empty list) and specified theme
1928+
dot_graph = await agent_graph.get_agent_graph(
1929+
root_agent, [], dark_mode=dark_mode
1930+
)
1931+
1932+
if dot_graph and isinstance(dot_graph, graphviz.Digraph):
1933+
return GetEventGraphResult(dot_src=dot_graph.source)
1934+
else:
1935+
return {}
1936+
1937+
# TODO: This endpoint can be removed once we update adk web to stop consuming it
19071938
@app.get(
19081939
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/events/{event_id}/graph",
19091940
response_model_exclude_none=True,

src/google/adk/cli/agent_graph.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,12 @@ def draw_edge(from_name, to_name):
282282
draw_edge(agent.name, get_node_name(tool))
283283

284284

285-
async def get_agent_graph(root_agent, highlights_pairs, image=False):
285+
async def get_agent_graph(
286+
root_agent, highlights_pairs, image=False, dark_mode=True
287+
):
288+
bg_color = '#333537' if dark_mode else '#ffffff'
286289
graph = graphviz.Digraph(
287-
graph_attr={'rankdir': 'LR', 'bgcolor': '#333537'}, strict=True
290+
graph_attr={'rankdir': 'LR', 'bgcolor': bg_color}, strict=True
288291
)
289292
await build_graph(graph, root_agent, highlights_pairs)
290293
if image:

src/google/adk/cli/cli_tools_click.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,7 +1713,8 @@ def cli_api_server(
17131713
default=False,
17141714
help=(
17151715
"Optional. Deploy ADK Web UI if set. (default: deploy ADK API server"
1716-
" only)"
1716+
" only). WARNING: The web UI is for development and testing only — do"
1717+
" not use in production."
17171718
),
17181719
)
17191720
@click.option(
@@ -2229,7 +2230,8 @@ def cli_deploy_agent_engine(
22292230
default=False,
22302231
help=(
22312232
"Optional. Deploy ADK Web UI if set. (default: deploy ADK API server"
2232-
" only)"
2233+
" only). WARNING: The web UI is for development and testing only — do"
2234+
" not use in production."
22332235
),
22342236
)
22352237
@click.option(

0 commit comments

Comments
 (0)