Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Before you begin, ensure you have:
uv run uvicorn app.fast_api_app:app --reload
```

## Running Tests
## Testing

To run the unit, integration, and runnability tests:

Expand All @@ -50,7 +50,9 @@ uv run pytest tests/unit
uv run pytest tests/integration
```

## Commands
## Running

Use the following commands as a quick reference for common operations. All commands must be run from the recipe root directory (`<OUTPUT_DIRECTORY>/<RECIPE_NAME>/`).

| Command | Description |
| ------- | ----------- |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "<RECIPE_NAME>"
version = "0.1.0"
requires-python = ">=3.11,<3.14"
requires-python = ">=3.11,<3.13"
dependencies = [
"google-adk[gcp]>=2.0.0,<3.0.0",
"python-dotenv>=1.0.0",
Expand All @@ -16,6 +16,11 @@ dev = [
requires = ["hatchling"]
build-backend = "hatchling.build"

# Allow pre-release packages when no stable version satisfies a constraint
# (e.g. opentelemetry-resourcedetector-gcp, a transitive dep of google-adk[gcp]).
[tool.uv]
prerelease = "if-necessary-or-explicit"

# Use public PyPI as the default index for this recipe.
[[tool.uv.index]]
url = "https://pypi.org/simple/"
Expand Down
34 changes: 34 additions & 0 deletions contrib/weather-assistant/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Model Configuration
MODEL_NAME=gemini-3.5-flash

# Google Cloud Platform Configuration (for Vertex AI)
# GOOGLE_CLOUD_PROJECT=<TODO: update-this-value>
# GOOGLE_CLOUD_LOCATION=global
# GOOGLE_GENAI_USE_VERTEXAI=True

# Google AI Studio Configuration (if using API Key instead of Vertex AI)
# GEMINI_API_KEY=<TODO: update-this-value>

# Web Server Configuration
# ALLOW_ORIGINS=http://localhost:3000,http://localhost:8080

# Telemetry and Logging Configuration
# LOGS_BUCKET_NAME=your-gcs-bucket-name
# OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=NO_CONTENT
# OTEL_INSTRUMENTATION_GENAI_UPLOAD_FORMAT=jsonl
# OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK=upload
# OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
# GENAI_TELEMETRY_PATH=completions
# COMMIT_SHA=dev

# Environment variables extracted by extract-python-environment-variables
ALLOW_ORIGINS=<TODO: update-this-value> # extracted-by:extract-env-vars; from getenv in app/fast_api_app.py; source had "" — empty string, please fix source too
COMMIT_SHA=dev # extracted-by:extract-env-vars; from environ_get in app/app_utils/telemetry.py
GENAI_TELEMETRY_PATH=completions # extracted-by:extract-env-vars; from environ_get in app/app_utils/telemetry.py
LOGS_BUCKET_NAME=<TODO: update-this-value> # extracted-by:extract-env-vars; no default in source
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=false # extracted-by:extract-env-vars; from environ_get in app/app_utils/telemetry.py
OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK=upload # extracted-by:extract-env-vars; from setdefault in app/app_utils/telemetry.py
OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH=<TODO: update-this-value> # extracted-by:extract-env-vars; no default in source
OTEL_INSTRUMENTATION_GENAI_UPLOAD_FORMAT=jsonl # extracted-by:extract-env-vars; from setdefault in app/app_utils/telemetry.py
OTEL_RESOURCE_ATTRIBUTES=<TODO: update-this-value> # extracted-by:extract-env-vars; no default in source
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental # extracted-by:extract-env-vars; from setdefault in app/app_utils/telemetry.py
59 changes: 59 additions & 0 deletions contrib/weather-assistant/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# weather-assistant

This is a simple agent using the ADK Python SDK to demonstrate its capabilities.

## Requirements

Before you begin, ensure you have:
- **uv**: Python package manager - [Install](https://docs.astral.sh/uv/getting-started/installation/)

## Quick Start

> **Note**: All commands below must be run from the recipe root directory (`contrib/weather-assistant/`).

1. Install required packages:
```bash
uv sync
```

2. Set up environment variables:
Copy `.env.example` to `.env` and uncomment/configure the variables you need (like `GEMINI_API_KEY`, `GOOGLE_CLOUD_PROJECT`, etc.):
```bash
cp .env.example .env
```

3. Test the agent in the command line (interactive mode):
```bash
uv run adk run app
```

4. Or start the local FastAPI web server:
```bash
uv run uvicorn app.fast_api_app:app --reload
```

## Running Tests

To run the unit, integration, and runnability tests:

```bash
uv run pytest
```

Or to run specific test suites:

```bash
# Run unit and runnability tests only
uv run pytest tests/unit

# Run integration tests only
uv run pytest tests/integration
```

## Commands

| Command | Description |
| ------- | ----------- |
| `uv run adk run app` | Run the agent in interactive CLI mode |
| `uv run uvicorn app.fast_api_app:app --reload` | Start the local FastAPI development server |
| `uv run pytest` | Run all test suites |
24 changes: 24 additions & 0 deletions contrib/weather-assistant/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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
#
# https://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 dotenv import load_dotenv

# Load variables from .env if present. In production the environment is
# already populated by the platform (Cloud Run, GKE, etc.), so a missing
# .env is expected and not an error.
load_dotenv()

from .agent import app # noqa: E402 -- must come after load_dotenv()

__all__ = ["app"]
59 changes: 59 additions & 0 deletions contrib/weather-assistant/app/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 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
#
# https://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 import Agent
from google.adk.apps import App
from google.adk.models import Gemini
from google.genai import types


def get_weather(query: str) -> str:
"""Simulates a web search. Use it get information on weather.

Args:
query: A string containing the location to get weather information for.

Returns:
A string with the simulated weather information for the queried
location.
"""
if "sf" in query.lower() or "san francisco" in query.lower():
return "It's 60 degrees and foggy."
return "It's 90 degrees and sunny."


def create_agent() -> Agent:
"""Creates a fresh, isolated instance of the Agent."""
return Agent(
name="root_agent",
model=Gemini(
model=os.getenv("MODEL_NAME"),
retry_options=types.HttpRetryOptions(attempts=3),
),
instruction=(
"You are a helpful AI assistant designed to provide"
" accurate and useful information."
),
tools=[get_weather],
)


root_agent = create_agent()

app = App(
root_agent=root_agent,
name="app",
)
1 change: 1 addition & 0 deletions contrib/weather-assistant/app/app_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Empty init file to make app_utils a package.
59 changes: 59 additions & 0 deletions contrib/weather-assistant/app/app_utils/telemetry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 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
#
# https://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 logging
import os


def setup_telemetry() -> None:
"""Configure OpenTelemetry and GenAI telemetry with GCS upload."""

bucket = os.environ.get("LOGS_BUCKET_NAME")
capture_content = os.environ.get(
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "false"
)
if bucket and capture_content != "false":
logging.info(
"Prompt-response logging enabled - mode: NO_CONTENT"
" (metadata only, no prompts/responses)"
)
os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = (
"NO_CONTENT"
)
os.environ.setdefault(
"OTEL_INSTRUMENTATION_GENAI_UPLOAD_FORMAT", "jsonl"
)
os.environ.setdefault(
"OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK", "upload"
)
os.environ.setdefault(
"OTEL_SEMCONV_STABILITY_OPT_IN", "gen_ai_latest_experimental"
)
commit_sha = os.environ.get("COMMIT_SHA", "dev")
os.environ.setdefault(
"OTEL_RESOURCE_ATTRIBUTES",
f"service.namespace=weather-assistant,service.version={commit_sha}",
)
path = os.environ.get("GENAI_TELEMETRY_PATH", "completions")
os.environ.setdefault(
"OTEL_INSTRUMENTATION_GENAI_UPLOAD_BASE_PATH",
f"gs://{bucket}/{path}",
)
else:
logging.info(
"Prompt-response logging disabled (set LOGS_BUCKET_NAME"
"=gs://your-bucket and"
" OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"
"=NO_CONTENT to enable)"
)
34 changes: 34 additions & 0 deletions contrib/weather-assistant/app/app_utils/typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# 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
#
# https://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 uuid
from typing import (
Literal,
)

from pydantic import (
BaseModel,
Field,
)


class Feedback(BaseModel):
"""Represents feedback for a conversation."""

score: int | float
text: str | None = ""
log_type: Literal["feedback"] = "feedback"
service_name: Literal["weather-assistant"] = "weather-assistant"
user_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
session_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
Loading
Loading