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

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,142 @@
# Static Non-Text Content Sample Agent
This sample demonstrates ADK's static instruction feature with non-text content (images and files).
## Features Demonstrated
- **Static instructions with mixed content**: Text, images, and file references in a single static instruction
- **Reference ID generation**: Non-text parts are automatically given reference IDs (`inline_data_0`, `file_data_1`, etc.)
- **Gemini Files API integration**: Demonstrates uploading documents and using file_data
- **Mixed content types**: inline_data for images, file_data for documents
- **API variant detection**: Different behavior for Gemini API vs Vertex AI
- **GCS file references**: Support for both GCS URI and HTTPS URL access methods in Vertex AI
## Static Instruction Content
The agent includes:
1. **Text instructions**: Guide the agent on how to behave
1. **Sample image**: A 1x1 yellow pixel PNG (`sample_chart.png`) as inline binary data
**Gemini Developer API:**
3\. **Contributing guide**: A sample document uploaded to Gemini Files API and referenced via file_data
**Vertex AI:**
3\. **Research paper**: Gemma research paper from Google Cloud Storage via GCS file reference
4\. **AI research paper**: Same research paper accessed via HTTPS URL for comparison
## Content Used
**All API variants:**
- **Image**: Base64-encoded 1x1 yellow pixel PNG (embedded in code as `inline_data`)
**Gemini Developer API:**
- **Document**: Sample contributing guide text (uploaded to Gemini Files API as `file_data`)
- Contains sample guidelines and best practices for development
- Demonstrates Files API upload and file_data reference functionality
- Files are automatically cleaned up after 48 hours by the Gemini API
**Vertex AI:**
- **Gemma Research Paper**: Research paper accessed via GCS URI (as `file_data`)
- GCS URI: `gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf`
- Demonstrates native GCS file access in Vertex AI
- PDF format with technical AI research content about Gemini 1.5
- **AI Research Paper**: Same research paper accessed via HTTPS URL (as `file_data`)
- HTTPS URL: `https://storage.googleapis.com/cloud-samples-data/generative-ai/pdf/2403.05530.pdf`
- Demonstrates HTTPS file access in Vertex AI
- Agent can discover these are the same document and compare access methods
## Setup
### Setup API Credentials
Create a `.env` file in the project root with your API credentials:
```bash
# Choose Model Backend: 0 -> ML Dev, 1 -> Vertex
GOOGLE_GENAI_USE_ENTERPRISE=1
# ML Dev backend config
GOOGLE_API_KEY=your_google_api_key_here
# Vertex backend config
GOOGLE_CLOUD_PROJECT=your_project_id
GOOGLE_CLOUD_LOCATION=us-central1
```
The agent will automatically load environment variables on startup.
## Usage
### Default Test Prompts (Recommended)
```bash
cd contributing/samples
python -m static_non_text_content.main
```
This runs test prompts that demonstrate the static content features:
- **Gemini Developer API**: 4 prompts testing inline_data + Files API upload
- **Vertex AI**: 5 prompts testing inline_data + GCS/HTTPS file access comparison
### Interactive Mode
```bash
cd contributing/samples
adk run static_non_text_content
```
Use ADK's built-in interactive mode for free-form conversation.
### Single Prompt
```bash
cd contributing/samples
python -m static_non_text_content.main --prompt "What reference materials do you have access to?"
```
### With Debug Logging
```bash
cd contributing/samples
python -m static_non_text_content.main --debug --prompt "What is the Gemma research paper about?"
```
## Default Test Prompts
The sample automatically runs test prompts when no `--prompt` is specified:
**All API variants:**
1. "What reference materials do you have access to?"
1. "Can you describe the sample chart that was provided to you?"
1. "How do the inline image and file references in your instructions help you answer questions?"
**Gemini Developer API only:**
4\. "What does the contributing guide document say about best practices?"
**Vertex AI only (additional prompts):**
5\. "What is the Gemma research paper about and what are its key contributions?"
6\. "Can you compare the research papers you have access to? Are they related or different?"
**Gemini Developer API** tests: `inline_data` (image) + Files API `file_data` (uploaded document)
**Vertex AI** tests: `inline_data` (image) + GCS URI `file_data` + HTTPS URL `file_data` (same document via different access methods)
## How It Works
1. **Static Instruction Processing**: The `static_instruction` content is processed during agent initialization
1. **Reference Generation**: Non-text parts get references like `[Reference to inline binary data: inline_data_0 ('sample_chart.png', type: image/png)]` in the system instruction
1. **User Content Creation**: The actual binary data/file references are moved to user contents with proper role attribution
1. **Model Understanding**: The model receives both the descriptive references and the actual content for analysis
## Code Structure
- `agent.py`: Defines the agent with static instruction containing mixed content
- `main.py`: Runnable script with interactive and single-prompt modes
- `__init__.py`: Package initialization following ADK conventions
This sample serves as a test case for the static instruction with non-text parts feature using both `inline_data` and `file_data`.
@@ -0,0 +1,17 @@
# 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.
"""Static non-text content sample agent package."""
from . import agent
@@ -0,0 +1,226 @@
# 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.
"""Static non-text content sample agent demonstrating static instructions with non-text parts."""
import base64
from dotenv import load_dotenv
from google.adk.agents.llm_agent import Agent
from google.genai import types
# Load environment variables from .env file
load_dotenv()
# Sample image data (a simple 1x1 yellow pixel PNG)
SAMPLE_IMAGE_DATA = base64.b64decode(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
)
# Sample document content (simplified contributing guide)
SAMPLE_DOCUMENT = """# Contributing Guide
## Best Practices
1. **Code Quality**: Always write clean, well-documented code
2. **Testing**: Include comprehensive tests for new features
3. **Documentation**: Update documentation when adding new functionality
4. **Review Process**: Submit pull requests for code review
5. **Conventions**: Follow established coding conventions and style guides
## Guidelines
- Use meaningful variable and function names
- Write descriptive commit messages
- Keep functions small and focused
- Handle errors gracefully
- Consider performance implications
- Maintain backward compatibility when possible
This guide helps ensure consistent, high-quality contributions to the project.
"""
def create_static_instruction_with_file_upload():
"""Create static instruction content with both inline_data and file_data.
This function creates a static instruction that demonstrates both inline_data
(for images) and file_data (for documents). Always includes Files API upload,
and adds additional GCS file reference when using Vertex AI.
"""
import os
import tempfile
from google.adk.utils.variant_utils import get_google_llm_variant
from google.adk.utils.variant_utils import GoogleLLMVariant
from google import genai
# Determine API variant
api_variant = get_google_llm_variant()
print(f"Using API variant: {api_variant}")
# Prepare file data parts based on API variant
file_data_parts = []
if api_variant == GoogleLLMVariant.VERTEX_AI:
print("Using Vertex AI - adding GCS URI and HTTPS URL references")
# Add GCS file reference
file_data_parts.append(
types.Part(
file_data=types.FileData(
file_uri=(
"gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf"
),
mime_type="application/pdf",
display_name="Gemma Research Paper",
)
)
)
# Add the same document via HTTPS URL to demonstrate both access methods
file_data_parts.append(
types.Part(
file_data=types.FileData(
file_uri="https://storage.googleapis.com/cloud-samples-data/generative-ai/pdf/2403.05530.pdf",
mime_type="application/pdf",
display_name="AI Research Paper (HTTPS)",
)
)
)
additional_text = (
" You also have access to a Gemma research paper from GCS"
" and an AI research paper from HTTPS URL."
)
else:
print("Using Gemini Developer API - uploading to Files API")
client = genai.Client()
# Check if file already exists
display_name = "Contributing Guide"
uploaded_file = None
# List existing files to see if we already uploaded this document
existing_files = client.files.list()
for file in existing_files:
if file.display_name == display_name:
uploaded_file = file
print(f"Reusing existing file: {file.name} ({file.display_name})")
break
# If file doesn't exist, upload it
if uploaded_file is None:
# Create a temporary file with the sample document
with tempfile.NamedTemporaryFile(
mode="w", suffix=".md", delete=False
) as f:
f.write(SAMPLE_DOCUMENT)
temp_file_path = f.name
try:
# Upload the file to Gemini Files API
uploaded_file = client.files.upload(file=temp_file_path)
print(
"Uploaded new file:"
f" {uploaded_file.name} ({uploaded_file.display_name})"
)
finally:
# Clean up temporary file
if os.path.exists(temp_file_path):
os.unlink(temp_file_path)
# Add Files API file data part
file_data_parts.append(
types.Part(
file_data=types.FileData(
file_uri=uploaded_file.uri,
mime_type="text/markdown",
display_name="Contributing Guide",
)
)
)
additional_text = (
" You also have access to the contributing guide document."
)
# Create static instruction with mixed content
parts = [
types.Part.from_text(
text=(
"You are an AI assistant that analyzes images and documents."
" You have access to the following reference materials:"
)
),
# Add a sample image as inline_data
types.Part(
inline_data=types.Blob(
data=SAMPLE_IMAGE_DATA,
mime_type="image/png",
display_name="sample_chart.png",
)
),
types.Part.from_text(
text=f"This is a sample chart showing color data.{additional_text}"
),
]
# Add all file_data parts
parts.extend(file_data_parts)
# Add instruction text
if api_variant == GoogleLLMVariant.VERTEX_AI:
instruction_text = """
When users ask questions, you should:
1. Use the reference chart above to provide context when discussing visual data or charts
2. Reference the Gemma research paper (from GCS) when discussing AI research, model architectures, or technical details
3. Reference the AI research paper (from HTTPS) when discussing research topics
4. Be helpful and informative in your responses
5. Explain how the provided reference materials relate to their questions"""
else:
instruction_text = """
When users ask questions, you should:
1. Use the reference chart above to provide context when discussing visual data or charts
2. Reference the contributing guide document when explaining best practices and guidelines
3. Be helpful and informative in your responses
4. Explain how the provided reference materials relate to their questions"""
instruction_text += """
Remember: The reference materials above are available to help you provide better answers."""
parts.append(types.Part.from_text(text=instruction_text))
static_instruction_content = types.Content(parts=parts)
return static_instruction_content
# Create the root agent with Files API integration
root_agent = Agent(
name="static_non_text_content_demo_agent",
description=(
"Demonstrates static instructions with non-text content (inline_data"
" and file_data features)"
),
static_instruction=create_static_instruction_with_file_upload(),
instruction=(
"Please analyze the user's question and provide helpful insights."
" Reference the materials provided in your static instructions when"
" relevant."
),
)
@@ -0,0 +1,223 @@
"""Static non-text content sample agent main script."""
# 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 argparse
import asyncio
import logging
import sys
import time
from google.adk.cli.utils import logs
from google.adk.runners import InMemoryRunner
from . import agent
APP_NAME = "static_non_text_content_demo"
USER_ID = "demo_user"
logs.setup_adk_logger(level=logging.INFO)
async def call_agent_async(
runner, user_id: str, session_id: str, prompt: str
) -> str:
"""Helper function to call agent and return final response."""
from google.adk.agents.run_config import RunConfig
from google.genai import types
content = types.Content(
role="user", parts=[types.Part.from_text(text=prompt)]
)
final_response_text = ""
async for event in runner.run_async(
user_id=user_id,
session_id=session_id,
new_message=content,
run_config=RunConfig(save_input_blobs_as_artifacts=False),
):
if event.content and event.content.parts:
if text := "".join(part.text or "" for part in event.content.parts):
if event.author != "user":
final_response_text += text
return final_response_text or "No response received"
def process_arguments():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser(
description=(
"A demo script that tests static instructions with non-text content."
),
epilog=(
"Example usage: \n\tpython -m static_non_text_content.main --prompt"
" 'What can you see in the reference chart?'\n\tpython -m"
" static_non_text_content.main --prompt 'What is the Gemma research"
" paper about?'\n\tpython -m static_non_text_content.main # Runs"
" default test prompts\n\tadk run"
" contributing/samples/static_non_text_content # Interactive mode\n"
),
formatter_class=argparse.RawTextHelpFormatter,
)
parser.add_argument(
"--prompt",
type=str,
help=(
"Single prompt to send to the agent. If not provided, runs"
" default test prompts."
),
)
parser.add_argument(
"--debug",
action="store_true",
help="Enable debug logging to see internal processing details.",
)
return parser.parse_args()
async def run_default_test_prompts(runner):
"""Run default test prompts to demonstrate static content features."""
from google.adk.utils.variant_utils import get_google_llm_variant
from google.adk.utils.variant_utils import GoogleLLMVariant
api_variant = get_google_llm_variant()
print("=== Static Non-Text Content Demo Agent - Default Test Prompts ===")
print(
"Running test prompts to demonstrate inline_data and file_data"
" features..."
)
print(f"API Variant: {api_variant}")
print(
"Use 'adk run contributing/samples/static_non_text_content' for"
" interactive mode.\n"
)
# Create session
session = await runner.session_service.create_session(
app_name=APP_NAME, user_id=USER_ID
)
# Common test prompts for all API variants
test_prompts = [
"What reference materials do you have access to?",
"Can you describe the sample chart that was provided to you?",
(
"How do the inline image and file references in your instructions "
"help you answer questions?"
),
]
# Add API-specific prompts
if api_variant == GoogleLLMVariant.VERTEX_AI:
# Vertex AI has research papers instead of contributing guide
test_prompts.extend([
(
"What is the Gemma research paper about and what are its key "
"contributions?"
),
(
"Can you compare the research papers you have access to? Are they "
"related or different?"
),
])
else:
# Gemini Developer API has contributing guide document
test_prompts.append(
"What does the contributing guide document say about best practices?"
)
for i, prompt in enumerate(test_prompts, 1):
print(f"Test {i}/{len(test_prompts)}: {prompt}")
print("-" * 60)
try:
response = await call_agent_async(runner, USER_ID, session.id, prompt)
print(f"Response: {response}")
except (ConnectionError, TimeoutError, ValueError) as e:
print(f"Error: {e}")
print(f"\n{'=' * 60}\n")
async def single_prompt_mode(runner, prompt: str):
"""Run the agent with a single prompt."""
print("=== Static Non-Text Content Demo Agent - Single Prompt Mode ===")
print(f"Prompt: {prompt}")
print("-" * 50)
# Create session
session = await runner.session_service.create_session(
app_name=APP_NAME, user_id=USER_ID
)
response = await call_agent_async(runner, USER_ID, session.id, prompt)
print(f"Agent Response:\n{response}")
async def main():
args = process_arguments()
if args.debug:
logs.setup_adk_logger(level=logging.DEBUG)
print("Debug logging enabled. You'll see internal processing details.\n")
print("Initializing Static Non-Text Content Demo Agent...")
print(f"Agent: {agent.root_agent.name}")
print(f"Model: {agent.root_agent.model}")
print(f"Description: {agent.root_agent.description}")
# Show information about static instruction content
if agent.root_agent.static_instruction:
static_parts = agent.root_agent.static_instruction.parts
text_parts = sum(1 for part in static_parts if part.text)
image_parts = sum(1 for part in static_parts if part.inline_data)
file_parts = sum(1 for part in static_parts if part.file_data)
print("Static instruction contains:")
print(f" - {text_parts} text parts")
print(f" - {image_parts} inline image(s)")
print(f" - {file_parts} file reference(s)")
print("-" * 50)
runner = InMemoryRunner(
agent=agent.root_agent,
app_name=APP_NAME,
)
if args.prompt:
await single_prompt_mode(runner, args.prompt)
else:
await run_default_test_prompts(runner)
if __name__ == "__main__":
start_time = time.time()
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nExiting...")
except Exception as e:
print(f"Unexpected error: {e}", file=sys.stderr)
sys.exit(1)
finally:
end_time = time.time()
print(f"\nExecution time: {end_time - start_time:.2f} seconds")