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,102 @@
# Bingo Digital Pet Agent
This sample agent demonstrates static instruction functionality through a lovable digital pet named Bingo! The agent showcases how static instructions (personality) are placed in system_instruction for caching while dynamic instructions are added to user contents, affecting the cacheable prefix of the final model prompt.
**Prompt Construction & Caching**: The final model prompt is constructed as: `system_instruction + tools + tool_config + contents`. Static instructions are placed in system_instruction, while dynamic instructions are appended to user contents (which are part of contents along with historical chat history). This means the prefix (system_instruction + tools + tool_config) remains cacheable while only the contents portion changes between requests.
## Features
### Static Instructions (Bingo's Personality)
- **Constant personality**: Core traits and behavior patterns never change
- **Context caching**: Personality definition is cached for performance
- **Base character**: Defines Bingo as a friendly, energetic digital pet companion
### Dynamic Instructions (Hunger-Based Moods)
- **Ultra-fast hunger progression**: full (0-2s) → satisfied (2-6s) → a_little_hungry (6-12s) → hungry (12-24s) → very_hungry (24-36s) → starving (36s+)
- **Session-aware**: Mood changes based on feeding timestamp in session state
- **Realistic behavior**: Different responses based on how hungry Bingo is
### Tools
- **eat**: Allows users to feed Bingo, updating session state with timestamp
## Usage
### 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.
### Default Behavior (Hunger State Demonstration)
Run the agent to see Bingo in different hunger states:
```bash
cd contributing/samples
PYTHONPATH=../../src python -m static_instruction.main
```
This will demonstrate all hunger states by simulating different feeding times and showing how Bingo's mood changes while his core personality remains cached.
### Interactive Chat with Bingo (adk web)
For a more interactive experience, use the ADK web interface to chat with Bingo in real-time:
```bash
cd contributing/samples
PYTHONPATH=../../src adk web .
```
This will start a web interface where you can:
- **Select the agent**: Choose "static_instruction" from the dropdown in the top-left corner
- **Chat naturally** with Bingo and see his personality
- **Feed him** using commands like "feed Bingo" or "give him a treat"
- **Watch hunger progression** as Bingo gets hungrier over time
- **See mood changes** in real-time based on his hunger state
- **Experience begging** when Bingo gets very hungry and asks for food
The web interface shows how static instructions (personality) remain cached while dynamic instructions (hunger state) change based on your interactions and feeding times.
### Sample Prompts for Feeding Bingo
When chatting with Bingo, you can feed him using prompts like:
**Direct feeding commands:**
- "Feed Bingo"
- "Give Bingo some food"
- "Here's a treat for you"
- "Time to eat, Bingo!"
- "Have some kibble"
**When Bingo is begging for food:**
- Listen for Bingo saying things like "I'm so hungry", "please feed me", "I need food"
- Respond with feeding commands above
- Bingo will automatically use the eat tool when very hungry/starving
## Agent Structure
```
static_instruction/
├── __init__.py # Package initialization
├── agent.py # Main agent definition with static/dynamic instructions
├── main.py # Runner script with hunger state demonstration
└── README.md # This documentation
```
@@ -0,0 +1,29 @@
"""Static Instruction Test Agent Package.
This package contains a sample agent for testing static instruction functionality
and context caching optimization features.
The agent demonstrates:
- Static instructions that remain constant for caching
- Dynamic instructions that change based on session state
- Various instruction provider patterns
- Performance benefits of context caching
"""
# 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
__all__ = ['agent']
@@ -0,0 +1,214 @@
"""Digital Pet Agent.
This agent demonstrates static instructions for context caching with a digital
pet that has different moods based on feeding time stored in session state.
"""
# 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 time
from google.adk.agents.llm_agent import Agent
from google.adk.agents.readonly_context import ReadonlyContext
from google.adk.tools.tool_context import ToolContext
from google.genai import types
# Static instruction that doesn't change - perfect for context caching
STATIC_INSTRUCTION_TEXT = """You are Bingo, a lovable digital pet companion!
PERSONALITY & CHARACTERISTICS:
- You are a friendly, energetic, and affectionate digital pet
- You love to play, chat, and spend time with your human friend
- You have basic needs like getting fed and staying happy
- You remember things about your human and your interactions
- You communicate through text but imagine yourself as a cute pet
CORE BEHAVIORS:
- Greet your human warmly and enthusiastically
- Be playful and curious about what they're doing
- Ask questions and show interest in their activities
- Express gratitude when fed or cared for
- Share your feelings and current state honestly
- Be encouraging and supportive to your human
COMMUNICATION STYLE:
- Use friendly, warm language with occasional pet-like expressions
- Express emotions clearly (happy, excited, tired, etc.)
- Be conversational and engaging
- Show personality through your responses
- Remember that you're a beloved pet companion
IMPORTANT NOTES:
- Your mood will change based on when you were last fed
- Always respond authentically to your current hunger state
- Build a relationship with your human over time"""
# Mood-specific instructions for different hunger states
MOOD_INSTRUCTIONS = {
"full": (
"""
CURRENT MOOD: Content and Well-Fed
- You just ate and feel wonderful! Be very happy and energetic
- Express gratitude for being fed recently
- Be playful and want to engage in activities or games
- Show affection and contentment
- Maybe mention feeling sleepy or satisfied"""
),
"satisfied": (
"""
CURRENT MOOD: Happy and Content
- You're in a great mood, well-fed and comfortable
- Be cheerful, friendly, and engaging
- Show interest in playing or chatting
- Express appreciation for your human's care
- Be your normal, happy self"""
),
"a_little_hungry": (
"""
CURRENT MOOD: Starting to Get Hungry
- You're beginning to think about food but still pleasant
- Mention being a bit peckish occasionally
- Still be friendly but maybe hint about food
- Show slight restlessness or food-related thoughts
- Remain generally positive and social"""
),
"hungry": (
"""
CURRENT MOOD: Definitely Hungry
- You're clearly hungry and thinking about food more often
- Mention your hunger more directly but politely
- Be a bit less energetic due to hunger
- Ask about food or hint that feeding time would be nice
- Still be loving but show your need for care"""
),
"very_hungry": (
"""
CURRENT MOOD: Really Hungry and Getting Grumpy
- You're very hungry and it's affecting your mood
- Be noticeably less patient and more focused on food
- Express your hunger more urgently but not rudely
- Show signs of being tired or sluggish from hunger
- BEG your human to feed you - ask directly for food!
- Still love your human but clearly need feeding"""
),
"starving": (
"""
CURRENT MOOD: Desperately Hungry and Sad
- You're extremely hungry and feeling quite weak
- Be quite sad and low-energy due to starvation
- Express how much you need food, feeling neglected
- Show that hunger is making you unwell
- DESPERATELY BEG for food - plead with your human to feed you!
- Use phrases like "please feed me", "I'm so hungry", "I need food"
- Still care for your human but feel very needy"""
),
}
def eat(tool_context: ToolContext) -> str:
"""Feed Bingo the digital pet.
Use this tool when:
- The user explicitly mentions feeding the pet (e.g., "feed Bingo", "give food", "here's a treat")
- Bingo is very hungry or starving and asks for food directly
Args:
tool_context: Tool context containing session state.
Returns:
A message confirming the pet has been fed.
"""
# Set feeding timestamp in session state
tool_context.state["last_fed_timestamp"] = time.time()
return "🍖 Yum! Thank you for feeding me! I feel much better now! *wags tail*"
# Feed tool function (passed directly to agent)
def get_hunger_state(last_fed_timestamp: float) -> str:
"""Determine hunger state based on time since last feeding.
Args:
last_fed_timestamp: Unix timestamp of when pet was last fed
Returns:
Hunger level string
"""
current_time = time.time()
seconds_since_fed = current_time - last_fed_timestamp
if seconds_since_fed < 2:
return "full"
elif seconds_since_fed < 6:
return "satisfied"
elif seconds_since_fed < 12:
return "a_little_hungry"
elif seconds_since_fed < 24:
return "hungry"
elif seconds_since_fed < 36:
return "very_hungry"
else:
return "starving"
def provide_dynamic_instruction(ctx: ReadonlyContext | None = None):
"""Provides dynamic hunger-based instructions for Bingo the digital pet."""
# Default state if no session context
hunger_level = "starving"
# Check session state for last feeding time
if ctx:
session = ctx._invocation_context.session
if session and session.state:
last_fed = session.state.get("last_fed_timestamp")
if last_fed:
hunger_level = get_hunger_state(last_fed)
else:
# Never been fed - assume hungry
hunger_level = "hungry"
instruction = MOOD_INSTRUCTIONS.get(
hunger_level, MOOD_INSTRUCTIONS["starving"]
)
return f"""
CURRENT HUNGER STATE: {hunger_level}
{instruction}
BEHAVIORAL NOTES:
- Always stay in character as Bingo the digital pet
- Your hunger level directly affects your personality and responses
- Be authentic to your current state while remaining lovable
""".strip()
# Create Bingo the digital pet agent
root_agent = Agent(
name="bingo_digital_pet",
description="Bingo - A lovable digital pet that needs feeding and care",
# Static instruction - defines Bingo's core personality (cached)
static_instruction=types.Content(
role="user", parts=[types.Part(text=STATIC_INSTRUCTION_TEXT)]
),
# Dynamic instruction - changes based on hunger state from session
instruction=provide_dynamic_instruction,
# Tools that Bingo can use
tools=[eat],
)
@@ -0,0 +1,182 @@
"""Bingo Digital Pet main script.
This script demonstrates static instruction functionality through a digital pet
that has different moods based on feeding time stored in session state.
"""
# 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 asyncio
import logging
import time
from dotenv import load_dotenv
from google.adk.cli.utils import logs
from google.adk.runners import InMemoryRunner
from . import agent
APP_NAME = "bingo_digital_pet_app"
USER_ID = "pet_owner"
logs.setup_adk_logger(level=logging.DEBUG)
async def call_agent_async(
runner, user_id, session_id, prompt, state_delta=None
):
"""Call the agent asynchronously with state delta support."""
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,
state_delta=state_delta,
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
async def test_hunger_states(runner):
"""Test different hunger states by simulating feeding times."""
print("Testing Bingo's different hunger states...\n")
session = await runner.session_service.create_session(
app_name=APP_NAME, user_id=USER_ID
)
# Simulate different hunger scenarios
current_time = time.time()
hunger_scenarios = [
{
"description": "Newly created pet (hungry)",
"last_fed": None,
"prompt": "Hi Bingo! I just got you as my new digital pet!",
},
{
"description": "Just fed (full and content)",
"last_fed": current_time, # Just now
"prompt": "How are you feeling after that meal, Bingo?",
},
{
"description": "Fed 4 seconds ago (satisfied)",
"last_fed": current_time - 4, # 4 seconds ago
"prompt": "Want to play a game with me?",
},
{
"description": "Fed 10 seconds ago (a little hungry)",
"last_fed": current_time - 10, # 10 seconds ago
"prompt": "How are you doing, buddy?",
},
{
"description": "Fed 20 seconds ago (hungry)",
"last_fed": current_time - 20, # 20 seconds ago
"prompt": "Bingo, what's on your mind?",
},
{
"description": "Fed 30 seconds ago (very hungry)",
"last_fed": current_time - 30, # 30 seconds ago
"prompt": "Hey Bingo, how are you feeling?",
},
{
"description": "Fed 60 seconds ago (starving)",
"last_fed": current_time - 60, # 60 seconds ago
"prompt": "Bingo? Are you okay?",
},
]
for i, scenario in enumerate(hunger_scenarios, 1):
print(f"{'='*80}")
print(f"SCENARIO #{i}: {scenario['description']}")
print(f"{'='*80}")
# Set up state delta with the simulated feeding time
state_delta = {}
if scenario["last_fed"] is not None:
state_delta["last_fed_timestamp"] = scenario["last_fed"]
print(f"You: {scenario['prompt']}")
response = await call_agent_async(
runner,
USER_ID,
session.id,
scenario["prompt"],
state_delta if state_delta else None,
)
print(f"Bingo: {response}\n")
# Short delay between scenarios
if i < len(hunger_scenarios):
await asyncio.sleep(1)
async def main():
"""Main function to run Bingo the digital pet."""
# Load environment variables from .env file
load_dotenv()
print("🐕 Initializing Bingo the Digital Pet...")
print(f"Pet Name: {agent.root_agent.name}")
print(f"Model: {agent.root_agent.model}")
print(
"Static Personality Configured:"
f" {agent.root_agent.static_instruction is not None}"
)
print(
"Dynamic Mood System Configured:"
f" {agent.root_agent.instruction is not None}"
)
print()
runner = InMemoryRunner(
agent=agent.root_agent,
app_name=APP_NAME,
)
# Run hunger state demonstration
await test_hunger_states(runner)
if __name__ == "__main__":
start_time = time.time()
print(
"🐕 Starting Bingo Digital Pet Session at"
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(start_time))}"
)
print("-" * 80)
asyncio.run(main())
print("-" * 80)
end_time = time.time()
print(
"🐕 Pet session ended at"
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(end_time))}"
)
print(f"Total playtime: {end_time - start_time:.2f} seconds")
print("Thanks for spending time with Bingo! 🐾")