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
15 changes: 15 additions & 0 deletions contributing/samples/plugin_debug_logging/__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
124 changes: 124 additions & 0 deletions contributing/samples/plugin_debug_logging/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# 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.

"""Sample agent demonstrating DebugLoggingPlugin usage.
This sample shows how to use the DebugLoggingPlugin to capture complete
debug information (LLM requests/responses, tool calls, events, session state)
to a YAML file for debugging purposes.
Usage:
adk run contributing/samples/plugin_debug_logging
After running, check the generated `adk_debug.yaml` file for detailed logs.
"""

from typing import Any

from google.adk.agents import LlmAgent
from google.adk.apps import App
from google.adk.plugins import DebugLoggingPlugin


def get_weather(city: str) -> dict[str, Any]:
"""Get the current weather for a city.
Args:
city: The name of the city to get weather for.
Returns:
A dictionary containing weather information.
"""
# Simulated weather data
weather_data = {
"new york": {"temperature": 22, "condition": "sunny", "humidity": 45},
"london": {"temperature": 15, "condition": "cloudy", "humidity": 70},
"tokyo": {"temperature": 28, "condition": "humid", "humidity": 85},
"paris": {"temperature": 18, "condition": "rainy", "humidity": 80},
}

city_lower = city.lower()
if city_lower in weather_data:
data = weather_data[city_lower]
return {
"city": city,
"temperature_celsius": data["temperature"],
"condition": data["condition"],
"humidity_percent": data["humidity"],
}
else:
return {
"city": city,
"error": f"Weather data not available for {city}",
}


def calculate(expression: str) -> dict[str, Any]:
"""Evaluate a simple mathematical expression.
Args:
expression: A mathematical expression to evaluate (e.g., "2 + 2").
Returns:
A dictionary containing the result or error.
"""
try:
# Only allow safe mathematical operations
allowed_chars = set("0123456789+-*/.() ")
if not all(c in allowed_chars for c in expression):
return {"error": "Invalid characters in expression"}

result = eval(expression) # Safe due to character restriction
return {"expression": expression, "result": result}
except Exception as e:
return {"expression": expression, "error": str(e)}


# Sample queries to try:
# - "What's the weather in Tokyo?"
# - "Calculate 15 * 7 + 3"
# - "What's the weather in London and calculate 100 / 4"
root_agent = LlmAgent(
name="debug_demo_agent",
description="A demo agent that shows DebugLoggingPlugin capabilities",
instruction="""You are a helpful assistant that can:
1. Get weather information for cities (New York, London, Tokyo, Paris)
2. Perform simple calculations
When asked about weather, use the get_weather tool.
When asked to calculate, use the calculate tool.
Be concise in your responses.""",
model="gemini-2.0-flash",
tools=[get_weather, calculate],
)


# Create the app with DebugLoggingPlugin
# The plugin will write detailed debug information to adk_debug.yaml
app = App(
name="plugin_debug_logging",
root_agent=root_agent,
plugins=[
# DebugLoggingPlugin captures complete interaction data to a YAML file
# Options:
# output_path: Path to output file (default: "adk_debug.yaml")
# include_session_state: Include session state snapshot (default: True)
# include_system_instruction: Include full system instruction (default: True)
DebugLoggingPlugin(
output_path="adk_debug.yaml",
include_session_state=True,
include_system_instruction=True,
),
],
)
56 changes: 56 additions & 0 deletions src/google/adk/cli/cli_tools_click.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
from . import cli_deploy
from .. import version
from ..evaluation.constants import MISSING_EVAL_DEPENDENCIES_MESSAGE
from ..features import FeatureName
from ..features import override_feature_enabled
from .cli import run_cli
from .fast_api import get_fast_api_app
from .utils import envs
Expand All @@ -48,6 +50,56 @@
)


def _apply_feature_overrides(enable_features: tuple[str, ...]) -> None:
"""Apply feature overrides from CLI flags.

Args:
enable_features: Tuple of feature names to enable.
"""
for features_str in enable_features:
for feature_name_str in features_str.split(","):
feature_name_str = feature_name_str.strip()
if not feature_name_str:
continue
try:
feature_name = FeatureName(feature_name_str)
override_feature_enabled(feature_name, True)
except ValueError:
valid_names = ", ".join(f.value for f in FeatureName)
click.secho(
f"WARNING: Unknown feature name '{feature_name_str}'. "
f"Valid names are: {valid_names}",
fg="yellow",
err=True,
)


def feature_options():
"""Decorator to add feature override options to click commands."""

def decorator(func):
@click.option(
"--enable_features",
help=(
"Optional. Comma-separated list of feature names to enable. "
"This provides an alternative to environment variables for "
"enabling experimental features. Example: "
"--enable_features=JSON_SCHEMA_FOR_FUNC_DECL,PROGRESSIVE_SSE_STREAMING"
),
multiple=True,
)
@functools.wraps(func)
def wrapper(*args, **kwargs):
enable_features = kwargs.pop("enable_features", ())
if enable_features:
_apply_feature_overrides(enable_features)
return func(*args, **kwargs)

return wrapper

return decorator


class HelpfulCommand(click.Command):
"""Command that shows full help on error instead of just the error message.

Expand Down Expand Up @@ -451,6 +503,7 @@ def wrapper(*args, **kwargs):


@main.command("run", cls=HelpfulCommand)
@feature_options()
@adk_services_options(default_use_local_storage=True)
@click.option(
"--save_session",
Expand Down Expand Up @@ -576,6 +629,7 @@ def wrapper(*args, **kwargs):


@main.command("eval", cls=HelpfulCommand)
@feature_options()
@click.argument(
"agent_module_file_path",
type=click.Path(
Expand Down Expand Up @@ -1141,6 +1195,7 @@ def wrapper(ctx, *args, **kwargs):


@main.command("web")
@feature_options()
@fast_api_common_options()
@web_options()
@adk_services_options(default_use_local_storage=True)
Expand Down Expand Up @@ -1243,6 +1298,7 @@ async def _lifespan(app: FastAPI):


@main.command("api_server")
@feature_options()
# The directory of agents, where each sub-directory is a single agent.
# By default, it is the current working directory
@click.argument(
Expand Down
2 changes: 2 additions & 0 deletions src/google/adk/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
# limitations under the License.

from .base_plugin import BasePlugin
from .debug_logging_plugin import DebugLoggingPlugin
from .logging_plugin import LoggingPlugin
from .plugin_manager import PluginManager
from .reflect_retry_tool_plugin import ReflectAndRetryToolPlugin

__all__ = [
'BasePlugin',
'DebugLoggingPlugin',
'LoggingPlugin',
'PluginManager',
'ReflectAndRetryToolPlugin',
Expand Down
Loading
Loading