chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:25:13 +08:00
commit ec2b666284
2231 changed files with 491535 additions and 0 deletions
@@ -0,0 +1,109 @@
# Spanner Tools Sample
## Introduction
This sample agent demonstrates the Spanner first-party tools in ADK,
distributed via the `google.adk.tools.spanner` module. These tools include:
1. `list_table_names`
Fetches Spanner table names present in a GCP Spanner database.
1. `list_table_indexes`
Fetches Spanner table indexes present in a GCP Spanner database.
1. `list_table_index_columns`
Fetches Spanner table index columns present in a GCP Spanner database.
1. `list_named_schemas`
Fetches named schema for a Spanner database.
1. `get_table_schema`
Fetches Spanner database table schema and metadata information.
1. `execute_sql`
Runs a SQL query in Spanner database.
## How to use
Set up environment variables in your `.env` file for using
[Google AI Studio](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-ai-studio)
or
[Google Cloud Vertex AI](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai)
for the LLM service for your agent. For example, for using Google AI Studio you
would set:
- GOOGLE_GENAI_USE_ENTERPRISE=FALSE
- GOOGLE_API_KEY={your api key}
### With Application Default Credentials
This mode is useful for quick development when the agent builder is the only
user interacting with the agent. The tools are run with these credentials.
1. Create application default credentials on the machine where the agent would
be running by following https://cloud.google.com/docs/authentication/provide-credentials-adc.
1. Set `CREDENTIALS_TYPE=None` in `agent.py`
1. Run the agent
### With Service Account Keys
This mode is useful for quick development when the agent builder wants to run
the agent with service account credentials. The tools are run with these
credentials.
1. Create service account key by following https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys.
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.SERVICE_ACCOUNT` in `agent.py`
1. Download the key file and replace `"service_account_key.json"` with the path
1. Run the agent
### With Interactive OAuth
1. Follow
https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name.
to get your client id and client secret. Be sure to choose "web" as your client
type.
1. Follow https://developers.google.com/workspace/guides/configure-oauth-consent
to add scope "https://www.googleapis.com/auth/spanner.data" and
"https://www.googleapis.com/auth/spanner.admin" as declaration, this is used
for review purpose.
1. Follow
https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred
to add http://localhost/dev-ui/ to "Authorized redirect URIs".
Note: localhost here is just a hostname that you use to access the dev ui,
replace it with the actual hostname you use to access the dev ui.
1. For 1st run, allow popup for localhost in Chrome.
1. Configure your `.env` file to add two more variables before running the
agent:
- OAUTH_CLIENT_ID={your client id}
- OAUTH_CLIENT_SECRET={your client secret}
Note: don't create a separate .env, instead put it to the same .env file that
stores your Vertex AI or Dev ML credentials
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.OAUTH2` in `agent.py` and run the
agent
## Sample prompts
- Show me all tables in the product_db Spanner database.
- Describe the schema of the product_table table.
- List all indexes on the product_table table.
- Show me the first 10 rows of data from the product_table table.
- Write a query to find the most popular product by joining the product_table and sales_table tables.
@@ -0,0 +1,15 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
@@ -0,0 +1,206 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from google.adk.agents.llm_agent import LlmAgent
from google.adk.auth.auth_credential import AuthCredentialTypes
from google.adk.tools.google_tool import GoogleTool
from google.adk.tools.spanner.settings import Capabilities
from google.adk.tools.spanner.settings import QueryResultMode
from google.adk.tools.spanner.settings import SpannerToolSettings
from google.adk.tools.spanner.spanner_credentials import SpannerCredentialsConfig
from google.adk.tools.spanner.spanner_toolset import SpannerToolset
import google.adk.tools.spanner.utils as spanner_tool_utils
from google.adk.tools.tool_context import ToolContext
import google.auth
from google.auth.credentials import Credentials
from google.cloud.spanner_v1 import param_types as spanner_param_types
# Define an appropriate credential type
# Set to None to use the application default credentials (ADC) for a quick
# development.
CREDENTIALS_TYPE = None
# Define Spanner tool config with read capability set to allowed.
tool_settings = SpannerToolSettings(
capabilities=[Capabilities.DATA_READ],
query_result_mode=QueryResultMode.DICT_LIST,
)
if CREDENTIALS_TYPE == AuthCredentialTypes.OAUTH2:
# Initialize the tools to do interactive OAuth
# The environment variables OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET
# must be set
credentials_config = SpannerCredentialsConfig(
client_id=os.getenv("OAUTH_CLIENT_ID"),
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
scopes=[
"https://www.googleapis.com/auth/spanner.admin",
"https://www.googleapis.com/auth/spanner.data",
],
)
elif CREDENTIALS_TYPE == AuthCredentialTypes.SERVICE_ACCOUNT:
# Initialize the tools to use the credentials in the service account key.
# If this flow is enabled, make sure to replace the file path with your own
# service account key file
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
creds, _ = google.auth.load_credentials_from_file("service_account_key.json")
credentials_config = SpannerCredentialsConfig(credentials=creds)
else:
# Initialize the tools to use the application default credentials.
# https://cloud.google.com/docs/authentication/provide-credentials-adc
application_default_credentials, _ = google.auth.default()
credentials_config = SpannerCredentialsConfig(
credentials=application_default_credentials
)
# Example 1: Use tools from the Spanner toolset.
# For example, data exploration agents help the Spanner database developer or
# data engineer of the organization.
spanner_toolset = SpannerToolset(
credentials_config=credentials_config,
spanner_tool_settings=tool_settings,
# Uncomment to explicitly specify allowed tools.
# tool_filter=["execute_sql", "get_table_schema"],
)
# Replace the following settings with your specific Spanner database for example
# 2 and 3.
# For example, these settings can also be read from a configuration file or
# environment variables.
_SPANNER_PROJECT_ID = "<PROJECT_ID>"
_SPANNER_INSTANCE_ID = "<INSTANCE_ID>"
_SPANNER_DATABASE_ID = "<DATABASE_ID>"
# Example 2: Create a customized Spanner query tool with a template SQL query.
# Note that this approach makes it **more vulnerable to SQL injection**. This
# might be suitable for some specific use cases, and **adding additional checks
# or callbacks** is recommended.
def count_rows_in_table(
table_name: str,
credentials: Credentials,
settings: SpannerToolSettings,
tool_context: ToolContext,
):
"""Counts the total number of rows for a specified table.
Args:
table_name: The name of the table for which to count rows.
Returns:
The total number of rows in the table.
"""
# Example of adding additional checks:
# if table_name not in ["table1", "table2"]:
# raise ValueError("Table name is not allowed.")
sql_template = f"SELECT COUNT(*) FROM {table_name}"
return spanner_tool_utils.execute_sql(
project_id=_SPANNER_PROJECT_ID,
instance_id=_SPANNER_INSTANCE_ID,
database_id=_SPANNER_DATABASE_ID,
query=sql_template,
credentials=credentials,
settings=settings,
tool_context=tool_context,
)
# Example 3: Create a customized Spanner query tool with a template
# parameterized SQL query.
# For example, it could query data that all authenticated users of the system
# have access to. This can also work for searching public knowledge bases, such
# as company policies and FAQs.
def search_hotels(
location_name: str,
credentials: Credentials,
settings: SpannerToolSettings,
tool_context: ToolContext,
):
"""Search hotels for a specific location.
This function takes a geographical location name and returns a list of hotels
in that area, including key details for each.
Args:
location_name (str): The geographical location (e.g., city or town) for the
hotel search.
Example:
{
"location_name": "Seattle"
}
Example:
{
"location_name": "New York"
}
Example:
{
"location_name": "Los Angeles"
}
Returns:
The hotels name, rating and description.
"""
sql_template = """
SELECT name, rating, description FROM hotels
WHERE location_name = @location_name
"""
return spanner_tool_utils.execute_sql(
project_id=_SPANNER_PROJECT_ID,
instance_id=_SPANNER_INSTANCE_ID,
database_id=_SPANNER_DATABASE_ID,
query=sql_template,
credentials=credentials,
settings=settings,
tool_context=tool_context,
params={"location_name": location_name},
params_types={"location_name": spanner_param_types.STRING},
)
# The variable name `root_agent` determines what your root agent is for the
# debug CLI
root_agent = LlmAgent(
name="spanner_agent",
description=(
"Agent to answer questions about Spanner database tables and"
" execute SQL queries."
),
instruction="""\
You are a data agent with access to several Spanner tools.
Make use of those tools to answer the user's questions.
""",
tools=[
# Use tools from Spanner toolset.
spanner_toolset,
# Or, uncomment to use customized Spanner tools.
# GoogleTool(
# func=count_rows_in_table,
# credentials_config=credentials_config,
# tool_settings=tool_settings,
# ),
# GoogleTool(
# func=search_hotels,
# credentials_config=credentials_config,
# tool_settings=tool_settings,
# ),
],
)