Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions contributing/samples/api_registry_agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# BigQuery API Registry Agent

This agent demonstrates how to use `ApiRegistry` to discover and interact with Google Cloud services like BigQuery via tools exposed by an MCP server registered in an API Registry.

## Prerequisites

- A Google Cloud project with the API Registry API enabled.
- An MCP server exposing BigQuery tools registered in API Registry.

## Configuration & Running

1. **Configure:** Edit `agent.py` and replace `your-google-cloud-project-id` and `your-mcp-server-name` with your Google Cloud Project ID and the name of your registered MCP server.
2. **Run in CLI:**
```bash
adk run contributing/samples/api_registry_agent -- --log-level DEBUG
```
3. **Run in Web UI:**
```bash
adk web contributing/samples/
```
Navigate to `http://127.0.0.1:8080` and select the `api_registry_agent` agent.
15 changes: 15 additions & 0 deletions contributing/samples/api_registry_agent/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2025 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
39 changes: 39 additions & 0 deletions contributing/samples/api_registry_agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2025 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.tools.api_registry import ApiRegistry

# TODO: Fill in with your GCloud project id and MCP server name
PROJECT_ID = "your-google-cloud-project-id"
MCP_SERVER_NAME = "your-mcp-server-name"

# Header required for BigQuery MCP server
header_provider = lambda context: {
"x-goog-user-project": PROJECT_ID,
}
api_registry = ApiRegistry(PROJECT_ID, header_provider=header_provider)
registry_tools = api_registry.get_toolset(
mcp_server_name=MCP_SERVER_NAME,
)
root_agent = LlmAgent(
model="gemini-2.0-flash",
name="bigquery_assistant",
instruction="""
Help user access their BigQuery data via API Registry tools.
""",
tools=[registry_tools],
)
15 changes: 15 additions & 0 deletions contributing/samples/hello_world_stream_fc_args/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2025 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
55 changes: 55 additions & 0 deletions contributing/samples/hello_world_stream_fc_args/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2025 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 google.adk import Agent
from google.genai import types


def concat_number_and_string(num: int, s: str) -> str:
"""Concatenate a number and a string.

Args:
num: The number to concatenate.
s: The string to concatenate.

Returns:
The concatenated string.
"""
return str(num) + ': ' + s


root_agent = Agent(
model='gemini-3-pro-preview',
name='hello_world_stream_fc_args',
description='Demo agent showcasing streaming function call arguments.',
instruction="""
You are a helpful assistant.
You can use the `concat_number_and_string` tool to concatenate a number and a string.
You should always call the concat_number_and_string tool to concatenate a number and a string.
You should never concatenate on your own.
""",
tools=[
concat_number_and_string,
],
generate_content_config=types.GenerateContentConfig(
automatic_function_calling=types.AutomaticFunctionCallingConfig(
disable=True,
),
tool_config=types.ToolConfig(
function_calling_config=types.FunctionCallingConfig(
stream_function_call_arguments=True,
),
),
),
)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ dependencies = [
"google-cloud-spanner>=3.56.0, <4.0.0", # For Spanner database
"google-cloud-speech>=2.30.0, <3.0.0", # For Audio Transcription
"google-cloud-storage>=2.18.0, <4.0.0", # For GCS Artifact service
"google-genai>=1.45.0, <2.0.0", # Google GenAI SDK
"google-genai>=1.51.0, <2.0.0", # Google GenAI SDK
"graphviz>=0.20.2, <1.0.0", # Graphviz for graph rendering
"jsonschema>=4.23.0, <5.0.0", # Agent Builder config validation
"mcp>=1.10.0, <2.0.0", # For MCP Toolset
Expand Down
2 changes: 0 additions & 2 deletions src/google/adk/cli/fast_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,13 @@ def get_fast_api_app(
base_dir=agents_dir,
session_service_uri=session_service_uri,
session_db_kwargs=session_db_kwargs,
per_agent=True, # Multi-agent mode
)

# Build the Artifact service
try:
artifact_service = create_artifact_service_from_options(
base_dir=agents_dir,
artifact_service_uri=artifact_service_uri,
per_agent=True, # Multi-agent mode
)
except ValueError as exc:
raise click.ClickException(str(exc)) from exc
Expand Down
8 changes: 2 additions & 6 deletions src/google/adk/cli/service_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,18 +271,14 @@ def gcs_artifact_factory(uri: str, **kwargs):

kwargs_copy = kwargs.copy()
kwargs_copy.pop("agents_dir", None)
kwargs_copy.pop("per_agent", None)
parsed_uri = urlparse(uri)
bucket_name = parsed_uri.netloc
return GcsArtifactService(bucket_name=bucket_name, **kwargs_copy)

def file_artifact_factory(uri: str, **kwargs):
def file_artifact_factory(uri: str, **_):
from ..artifacts.file_artifact_service import FileArtifactService

per_agent = kwargs.get("per_agent", False)
if per_agent:
raise ValueError(
"file:// artifact URIs are not supported in multi-agent mode."
)
parsed_uri = urlparse(uri)
if parsed_uri.netloc not in ("", "localhost"):
raise ValueError(
Expand Down
11 changes: 2 additions & 9 deletions src/google/adk/cli/utils/local_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,20 @@ def create_local_database_session_service(


def create_local_artifact_service(
*, base_dir: Path | str, per_agent: bool = False
*, base_dir: Path | str
) -> BaseArtifactService:
"""Creates a file-backed artifact service rooted in `.adk/artifacts`.

Args:
base_dir: Directory whose `.adk` folder will store artifacts.
per_agent: Indicates whether the service is being used in multi-agent mode.

Returns:
A `FileArtifactService` scoped to the derived root directory.
"""
manager = DotAdkFolder(base_dir)
artifact_root = manager.artifacts_dir
artifact_root.mkdir(parents=True, exist_ok=True)
if per_agent:
logger.info(
"Using shared file artifact service rooted at %s for multi-agent mode",
artifact_root,
)
else:
logger.info("Using file artifact service at %s", artifact_root)
logger.info("Using file artifact service at %s", artifact_root)
return FileArtifactService(root_dir=artifact_root)


Expand Down
19 changes: 1 addition & 18 deletions src/google/adk/cli/utils/service_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,18 @@ def create_session_service_from_options(
base_dir: Path | str,
session_service_uri: Optional[str] = None,
session_db_kwargs: Optional[dict[str, Any]] = None,
per_agent: bool = False,
) -> BaseSessionService:
"""Creates a session service based on CLI/web options."""
base_path = Path(base_dir)
registry = get_service_registry()

kwargs: dict[str, Any] = {
"agents_dir": str(base_path),
"per_agent": per_agent,
}
if session_db_kwargs:
kwargs.update(session_db_kwargs)

if session_service_uri:
if per_agent:
logger.warning(
"per_agent is not supported with remote session service URIs,"
" ignoring"
)
logger.info("Using session service URI: %s", session_service_uri)
service = registry.create_session_service(session_service_uri, **kwargs)
if service is not None:
Expand All @@ -63,7 +56,6 @@ def create_session_service_from_options(

fallback_kwargs = dict(kwargs)
fallback_kwargs.pop("agents_dir", None)
fallback_kwargs.pop("per_agent", None)
logger.info(
"Falling back to DatabaseSessionService for URI: %s",
session_service_uri,
Expand Down Expand Up @@ -105,23 +97,16 @@ def create_artifact_service_from_options(
*,
base_dir: Path | str,
artifact_service_uri: Optional[str] = None,
per_agent: bool = False,
) -> BaseArtifactService:
"""Creates an artifact service based on CLI/web options."""
base_path = Path(base_dir)
registry = get_service_registry()

if artifact_service_uri:
if per_agent:
logger.warning(
"per_agent is not supported with remote artifact service URIs,"
" ignoring"
)
logger.info("Using artifact service URI: %s", artifact_service_uri)
service = registry.create_artifact_service(
artifact_service_uri,
agents_dir=str(base_path),
per_agent=per_agent,
)
if service is None:
logger.warning(
Expand All @@ -133,6 +118,4 @@ def create_artifact_service_from_options(
return InMemoryArtifactService()
return service

if per_agent:
logger.info("Using shared file artifact service rooted at %s", base_dir)
return create_local_artifact_service(base_dir=base_path, per_agent=per_agent)
return create_local_artifact_service(base_dir=base_path)
2 changes: 2 additions & 0 deletions src/google/adk/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
if TYPE_CHECKING:
from ..auth.auth_tool import AuthToolArguments
from .agent_tool import AgentTool
from .api_registry import ApiRegistry
from .apihub_tool.apihub_toolset import APIHubToolset
from .base_tool import BaseTool
from .discovery_engine_search_tool import DiscoveryEngineSearchTool
Expand Down Expand Up @@ -84,6 +85,7 @@
'VertexAiSearchTool': ('.vertex_ai_search_tool', 'VertexAiSearchTool'),
'MCPToolset': ('.mcp_tool.mcp_toolset', 'MCPToolset'),
'McpToolset': ('.mcp_tool.mcp_toolset', 'McpToolset'),
'ApiRegistry': ('.api_registry', 'ApiRegistry'),
}

__all__ = list(_LAZY_MAPPING.keys())
Expand Down
Loading
Loading