Commit Graph
1230 Commits
Author SHA1 Message Date
Xiang (Sean) ZhouandCopybara-Service 6ca2aee829 ADK changes
PiperOrigin-RevId: 810492858
2025-09-23 15:35:02 -07:00
Xuan YangandCopybara-Service 374522197f ADK changes
PiperOrigin-RevId: 810223422
2025-09-23 15:34:53 -07:00
Google Team MemberandCopybara-Service aef1ee97a5 fix: make a copy of the columns instead of modifying it in place
This avoid unintentional modifications, especially in the case of a wrapped tool.

PiperOrigin-RevId: 810175539
2025-09-23 15:34:43 -07:00
Xiang (Sean) ZhouandCopybara-Service 38bbde6d56 chore: Annotate CachePerformanceAnalyzer as experimental
PiperOrigin-RevId: 809434619
2025-09-23 15:34:34 -07:00
TanejaAnkisettyandCopybara-Service 78fd4803d5 chore: Set role to user if new_message doesn't have role in Runner.run_async()
Merge https://github.com/google/adk-python/pull/2458

**Summary**
Verifies that user-provided messages are always passed to the LLM as 'user' role, regardless of whether the role is explicitly set in types.Content. Before the current fix, if the LlmRequest from the user doesn't have the 'user' role, but has the user content, then the text is being replaced with the standard text - "Handle the requests as specified in the System Instruction." and the content from the user is completely ignored and not passed into the LLM.

**Code to replicate the problem**

```
from google.adk.agents import LlmAgent
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google.genai.types import Content, Part
from google.adk.models.lite_llm import LiteLlm
from google.adk.models import LlmRequest
from google.genai import types
from pydantic import Field

import litellm
litellm._turn_on_debug()

import warnings
warnings.filterwarnings("ignore", category=UserWarning, message=".*InMemoryCredentialService.*")

import os
from dotenv import load_dotenv

# Load environment variables from the agent directory's .env file
load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")

# Define agent with output_key
root_agent = LlmAgent(
    name="name_of_agent",
    model=LiteLlm(model="azure/gpt-4o-mini"),
    instruction="You are a customer agent to help the users with their concerns."
)

# --- Setup Runner and Session ---
app_name, user_id, session_id = "state_app", "user1", "session1"

session_service = InMemorySessionService()

runner = Runner(
    agent=root_agent,
    app_name=app_name,
    session_service=session_service
)

print(f"Runner created for agent '{runner.agent.name}'.")

session = await session_service.create_session(
    app_name=app_name,
    user_id=user_id,
    session_id=session_id
)

# --- Run the Agent ---

async def call_agent_async(query: str, runner, user_id, session_id):

    user_message = Content(parts=[Part(text=query)])

    async for event in runner.run_async(
        user_id=user_id,
        session_id=session_id,
        new_message=user_message
    ):
        print("event")
        print(f"  [Event]\n  Author: {event.author}\n  Type: {type(event).__name__}",
        f"\n  Final: {event.is_final_response()}\n  Content: {event.content}")

    return event

event = await call_agent_async("What is the capital of India.",runner=runner,user_id=user_id,session_id=session_id)
```
**Before the fix (current adk-python code output)**
```
00:29:24 - LiteLLM:DEBUG: utils.py:348 -

00:29:24 - LiteLLM:DEBUG: utils.py:348 - Request to litellm:
00:29:24 - LiteLLM:DEBUG: utils.py:348 - litellm.acompletion(model='azure/gpt-4o-mini', messages=[{'role': 'developer', 'content': 'You are a customer agent to help the users with their concerns.\n\nYou are an agent. Your internal name is "name_of_agent".'}, {'role': 'user', 'content': 'Handle the requests as specified in the System Instruction.'}], tools=None, response_format=None)
```

**After the fix (after resolving the fix)**
```
00:28:46 - LiteLLM:DEBUG: utils.py:349 -

00:28:46 - LiteLLM:DEBUG: utils.py:349 - Request to litellm:
00:28:46 - LiteLLM:DEBUG: utils.py:349 - litellm.acompletion(model='azure/gpt-4o-mini', messages=[{'role': 'developer', 'content': 'You are a customer agent to help the users with their concerns.\n\nYou are an agent. Your internal name is "name_of_agent".'}, {'role': 'user', 'content': 'What is the capital of India.'}], tools=None, response_format=None)
```

**Testing**
Following unit test is created to test the applied changes and added in the location as suggested in the guidelines.
adk-python\tests\unittests\models\test_base_llm.py

```
import pytest
from google.genai import types
from google.adk.models.llm_request import LlmRequest
from google.adk.models.lite_llm import _get_completion_inputs

@pytest.mark.parametrize("content_kwargs", [
    # Case 1: Explicit role provided
    {"role": "user", "parts": [types.Part(text="This is an input text from user.")]},
    # Case 2: Role omitted, should still be treated as 'user'
    {"parts": [types.Part(text="This is an input text from user.")]}
])
def test_user_content_role_defaults_to_user(content_kwargs):
    """
    Verifies that user-provided messages are always passed to the LLM as 'user' role,
    regardless of whether the role is explicitly set in types.Content.

    The helper `_get_completion_inputs` should give normalize messages so that
    explicit 'user' and implicit (missing role) are equivalent.
    """
    llm_request = LlmRequest(
        contents=[types.Content(**content_kwargs)],
        config=types.GenerateContentConfig()
    )

    messages, _, _, _ = _get_completion_inputs(llm_request)

    assert all(
        msg.get("role") == "user" for msg in messages
    ), f"Expected role 'user' but got {messages}"
    assert any(
        "This is an input text from user." == (msg.get("content") or "")
        for msg in messages
    ), f"Expected the user text to be preserved, but got {messages}"
```

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2458 from TanejaAnkisetty:bug/agent-user-content 381b01418d249b9e6bd91ebb518ff25339a8e47b
PiperOrigin-RevId: 809281620
2025-09-23 15:34:21 -07:00
Google Team MemberandCopybara-Service 632bf8b0bc fix: Filter out thought parts when saving agent output to state
PiperOrigin-RevId: 809270320
2025-09-19 18:58:59 -07:00
Wei Sun (Jack)andCopybara-Service 6e834d3fac feat(conformance): Skips recording for inner runner of AgentTool in conformance tests
PiperOrigin-RevId: 809252704
2025-09-19 17:36:18 -07:00
Xiang (Sean) ZhouandCopybara-Service 9be9cc2fee feat: Support static instructions
Static instructions:
Always added to system instructions for context caching

Dynamic instructions:
Added to system instructions when no static instruction exists (for backward compatibility), OR inserted before last batch of continuous user content when static instructions exist

PiperOrigin-RevId: 809170679
2025-09-19 13:46:36 -07:00
Xiang (Sean) ZhouandCopybara-Service f4e1fd962e chore: Add sample agent for content cache and basic profiling
PiperOrigin-RevId: 809166922
2025-09-19 13:37:57 -07:00
Xiang (Sean) ZhouandCopybara-Service c66245a3b8 feat: support context caching
1. add a context cache config in app level which will apply to all agents in the app
2. pass on cache config through invocation context to llm_reqeust
3. store cache metadata in llm_response
4. lookup old cache metadata from latest event for reusing old cache
5. create new cache if old cache cannot be reused

PiperOrigin-RevId: 809158578
2025-09-19 13:17:02 -07:00
Xinran (Sherry) TangandCopybara-Service 13a95c463d feat: Add get_events util function in invocation_context
PiperOrigin-RevId: 809111315
2025-09-19 11:21:35 -07:00
Kacper JawoszekandCopybara-Service f157b2ee4c feat(otel): support standard OTel env variables for exporter endpoints
ADK web server will automatically setup OTel providers with exporters if any of the .*_ENDPOINT variables from https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/ is set.

PiperOrigin-RevId: 809079453
2025-09-19 09:59:58 -07:00
Bastien Jacot-GuillarmodandCopybara-Service ccd0e12b42 chore: Internal change
PiperOrigin-RevId: 809077633
2025-09-19 09:55:17 -07:00
Kacper JawoszekandCopybara-Service 3b80337faf feat(otel): temporarily disable Cloud Monitoring integration in --otel_to_cloud
Currently there is chance for Cloud Monitoring-related errors in logs during shutdown. Let's disable metrics part until it is fixed.

PiperOrigin-RevId: 808930635
2025-09-19 01:28:15 -07:00
Xuan YangandCopybara-Service d4eaa06041 chore: update ADK release analyzer agent to use the compare link instead of commit link
PiperOrigin-RevId: 808900352
2025-09-18 23:44:12 -07:00
Xuan YangandCopybara-Service 4d39563ea4 chore: add yaml files to the ADK Vertex AI Search datastore
PiperOrigin-RevId: 808895175
2025-09-18 23:27:34 -07:00
Wei Sun (Jack)andCopybara-Service 006a406f5b chore: Allow outputting non-acsii without escape and excludes fields in the dumped yaml files in the yaml_utils.py
Also excludes `_adk_recordings_config` for `adk conformance create` command.

PiperOrigin-RevId: 808865049
2025-09-18 21:24:14 -07:00
Wei Sun (Jack)andCopybara-Service f39df4155e feat(conformance): Supports content and state_delta in TestCase.user_messages and initial_state for session creation
PiperOrigin-RevId: 808827170
2025-09-18 18:55:38 -07:00
Hangfei LinandCopybara-Service 1a91bb2a59 chore: Update comments in Compaction to clarify timestamp-based ranges
The docstrings for `compaction_range` and `compacted_content` are updated to reflect that compaction is based on timestamp ranges rather than sequence IDs, and to use consistent terminology ("compacted" instead of "summarized").

PiperOrigin-RevId: 808770610
2025-09-18 15:51:40 -07:00
Wei Sun (Jack)andCopybara-Service 9c2b7091ee refactor(comformance): Improves field comparison logic in replay plugin with nested exclude dict from pydantic v2
Also use `ReplayConfigError` to replace `ValueError`s

PiperOrigin-RevId: 808750606
2025-09-18 15:01:19 -07:00
Nikhil PurwantandCopybara-Service 21c26f92d4 chore: Added ADK Authentication End2End Samples
Merge https://github.com/google/adk-python/pull/2960

1. All in one authentication sample (has an IDP, Agent and the application) under `contributing/samples/authn-adk-all-in-one/`
2. Documented for all the steps.
3. OAuth 2.0 Authorization Code Grant type used by the agent.

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2960 from nikhilpurwant:main dfcc821602d265c4ae7cc42eb1f5739beaad6f87
PiperOrigin-RevId: 808672120
2025-09-18 11:44:21 -07:00
guillaume blaquiereandCopybara-Service 25958242db feat: add endpoint to generate memory from session
Merge https://github.com/google/adk-python/pull/2900

In relation with #2416

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2900 from guillaumeblaquiere:add-session-to-memory 0507de43021c62f9223167dca8f53b536227ad04
PiperOrigin-RevId: 808658162
2025-09-18 11:13:21 -07:00
Kel MarkertandCopybara-Service 6b49391546 feat: Add Google Maps Grounding Tool to ADK
This add `GoogleMapsGroundingTool`, a built-in tool for Gemini 2 models to ground query results with Google Maps. This tool operates internally within the model and is only available when using the VertexAI Gemini API.

PiperOrigin-RevId: 808650501
2025-09-18 10:54:27 -07:00
Xuan YangandCopybara-Service 8a92fd18b6 fix: ignore empty function chunk in LiteLlm streaming response
Fixes https://github.com/google/adk-python/issues/1532

PiperOrigin-RevId: 808636127
2025-09-18 10:18:53 -07:00
Hangfei LinandCopybara-Service c37bd2742c feat: Introduce LLM context compaction interface
Provide a more efficient way to compact LLM context for better agentic performance.

* `app`: the top level abstraction for an ADK application. It contains an root agent, and plugins.
* `content_strategy`: the abstraction for selecting the contents for LLM request.
* `compaction_strategy`: the abstraction for compacting the events.
* Added `sequence_id` and `summary_range` in event class.

PiperOrigin-RevId: 808634224
2025-09-18 10:14:12 -07:00