Skip to content

Commit af1c183

Browse files
authored
Merge branch 'main' into feat/evaluate-full-response
2 parents c95e333 + cbcb5e6 commit af1c183

21 files changed

Lines changed: 1567 additions & 19 deletions

File tree

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ test = [
123123
"a2a-sdk>=0.3.0,<0.4.0",
124124
"anthropic>=0.43.0", # For anthropic model tests
125125
"crewai[tools];python_version>='3.11' and python_version<'3.12'", # For CrewaiTool tests; chromadb/pypika fail on 3.12+
126+
"google-cloud-iamconnectorcredentials>=0.1.0, <0.2.0",
126127
"google-cloud-parametermanager>=0.4.0, <1.0.0",
127128
"kubernetes>=29.0.0", # For GkeCodeExecutor
128129
"langchain-community>=0.3.17",
@@ -176,6 +177,10 @@ toolbox = ["toolbox-adk>=1.0.0, <2.0.0"]
176177

177178
slack = ["slack-bolt>=1.22.0"]
178179

180+
agent-identity = [
181+
"google-cloud-iamconnectorcredentials>=0.1.0, <0.2.0",
182+
]
183+
179184
[tool.pyink]
180185
# Format py files following Google style-guide
181186
line-length = 80

src/google/adk/artifacts/file_artifact_service.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,39 @@ def _is_user_scoped(session_id: Optional[str], filename: str) -> bool:
138138
return session_id is None or _file_has_user_namespace(filename)
139139

140140

141+
def _validate_path_segment(value: str, field_name: str) -> None:
142+
"""Rejects values that could alter the constructed filesystem path.
143+
144+
Args:
145+
value: The caller-supplied identifier (e.g. user_id or session_id).
146+
field_name: Human-readable name used in the error message.
147+
148+
Raises:
149+
InputValidationError: If the value contains path separators, traversal
150+
segments, or null bytes.
151+
"""
152+
if not value:
153+
raise InputValidationError(f"{field_name} must not be empty.")
154+
if "\x00" in value:
155+
raise InputValidationError(f"{field_name} must not contain null bytes.")
156+
if "/" in value or "\\" in value:
157+
raise InputValidationError(
158+
f"{field_name} {value!r} must not contain path separators."
159+
)
160+
if value in (".", "..") or ".." in value.split("/"):
161+
raise InputValidationError(
162+
f"{field_name} {value!r} must not contain traversal segments."
163+
)
164+
165+
141166
def _user_artifacts_dir(base_root: Path) -> Path:
142167
"""Returns the path that stores user-scoped artifacts."""
143168
return base_root / "artifacts"
144169

145170

146171
def _session_artifacts_dir(base_root: Path, session_id: str) -> Path:
147172
"""Returns the path that stores session-scoped artifacts."""
173+
_validate_path_segment(session_id, "session_id")
148174
return base_root / "sessions" / session_id / "artifacts"
149175

150176

@@ -220,6 +246,7 @@ def __init__(self, root_dir: Path | str):
220246

221247
def _base_root(self, user_id: str, /) -> Path:
222248
"""Returns the artifacts root directory for a user."""
249+
_validate_path_segment(user_id, "user_id")
223250
return self.root_dir / "users" / user_id
224251

225252
def _scope_root(

src/google/adk/cli/cli_deploy.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,24 @@ def to_cloud_run(
808808
shutil.rmtree(temp_folder)
809809

810810

811+
def _print_agent_engine_url(resource_name: str) -> None:
812+
"""Prints the Google Cloud Console URL for the deployed agent."""
813+
parts = resource_name.split('/')
814+
if len(parts) >= 6 and parts[0] == 'projects' and parts[2] == 'locations':
815+
project_id = parts[1]
816+
region = parts[3]
817+
engine_id = parts[5]
818+
819+
url = (
820+
'https://console.cloud.google.com/agent-platform/runtimes'
821+
f'/locations/{region}/agent-engines/{engine_id}/playground'
822+
f'?project={project_id}'
823+
)
824+
click.secho(
825+
f'\n🎉 View your deployed agent here:\n{url}\n', fg='cyan', bold=True
826+
)
827+
828+
811829
def to_agent_engine(
812830
*,
813831
agent_folder: str,
@@ -1150,11 +1168,13 @@ def to_agent_engine(
11501168
f'✅ Created agent engine: {agent_engine.api_resource.name}',
11511169
fg='green',
11521170
)
1171+
_print_agent_engine_url(agent_engine.api_resource.name)
11531172
else:
11541173
if project and region and not agent_engine_id.startswith('projects/'):
11551174
agent_engine_id = f'projects/{project}/locations/{region}/reasoningEngines/{agent_engine_id}'
11561175
client.agent_engines.update(name=agent_engine_id, config=agent_config)
11571176
click.secho(f'✅ Updated agent engine: {agent_engine_id}', fg='green')
1177+
_print_agent_engine_url(agent_engine_id)
11581178
finally:
11591179
click.echo(f'Cleaning up the temp folder: {temp_folder}')
11601180
shutil.rmtree(agent_src_path)

src/google/adk/features/_feature_registry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ class FeatureConfig:
9999
FeatureStage.EXPERIMENTAL, default_on=True
100100
),
101101
FeatureName.BIG_QUERY_TOOLSET: FeatureConfig(
102-
FeatureStage.EXPERIMENTAL, default_on=True
102+
FeatureStage.STABLE, default_on=True
103103
),
104104
FeatureName.BIG_QUERY_TOOL_CONFIG: FeatureConfig(
105-
FeatureStage.EXPERIMENTAL, default_on=True
105+
FeatureStage.STABLE, default_on=True
106106
),
107107
FeatureName.BIGTABLE_TOOL_SETTINGS: FeatureConfig(
108108
FeatureStage.EXPERIMENTAL, default_on=True
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# GCP IAM Connector Auth
2+
3+
Manages the complete lifecycle of an access token using the Google Cloud
4+
Platform Agent Identity Credentials service.
5+
6+
## Usage
7+
8+
1. **Install Dependencies:**
9+
```bash
10+
pip install "google-adk[agent-identity]"
11+
```
12+
13+
2. **Register the provider:**
14+
Register the `GcpAuthProvider` with the `CredentialManager`. This is to be
15+
done one time.
16+
17+
``` py
18+
# user_agent_app.py
19+
from google.adk.auth.credential_manager import CredentialManager
20+
from google.adk.integrations.agent_identity import GcpAuthProvider
21+
22+
CredentialManager.register_auth_provider(GcpAuthProvider())
23+
```
24+
25+
3. **Configure the Auth provider:**
26+
Specify the Agent Identity provider configuration using the
27+
`GcpAuthProviderScheme`.
28+
``` py
29+
# user_agent_app.py
30+
from google.adk.integrations.agent_identity import GcpAuthProviderScheme
31+
32+
# Configures Toolset
33+
auth_scheme = GcpAuthProviderScheme(name="my-jira-auth_provider")
34+
mcp_toolset_jira = McpToolset(..., auth_scheme=auth_scheme)
35+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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 .gcp_auth_provider import GcpAuthProvider
16+
from .gcp_auth_provider_scheme import GcpAuthProviderScheme
17+
18+
__all__ = [
19+
"GcpAuthProvider",
20+
"GcpAuthProviderScheme",
21+
]

0 commit comments

Comments
 (0)