Merge branch 'main' into fix/missing-path-level-parameters

This commit is contained in:
Hangfei Lin
2025-05-30 11:33:24 -07:00
committed by GitHub
206 changed files with 9043 additions and 2452 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ assignees: ''
---
** Please make sure you read the contribution guide and file the issues in the rigth place. **
** Please make sure you read the contribution guide and file the issues in the right place. **
[Contribution guide.](https://google.github.io/adk-docs/contributing-guide/)
**Describe the bug**
+1 -1
View File
@@ -7,7 +7,7 @@ assignees: ''
---
** Please make sure you read the contribution guide and file the issues in the rigth place. **
** Please make sure you read the contribution guide and file the issues in the right place. **
[Contribution guide.](https://google.github.io/adk-docs/contributing-guide/)
**Is your feature request related to a problem? Please describe.**
+86
View File
@@ -1,5 +1,91 @@
# Changelog
## 1.1.1
### Features
* Add BigQuery first-party tools. See [here](https://github.com/google/adk-python/commit/d6c6bb4b2489a8b7a4713e4747c30d6df0c07961) for more details.
## 1.1.0
### Features
* Extract agent loading logic from fast_api.py to a separate AgentLoader class and support more agent definition folder/file structure.
* Added audio play in web UI.
* Added input transcription support for live/streaming.
* Added support for storing eval run history locally in adk eval cli.
* Image artifacts can now be clicked directly in chat message to view.
* Left side panel can now be resized.
### Bug Fixes
* Avoid duplicating log in stderr.
* Align event filtering and ordering logic.
* Add handling for None param.annotation.
* Fixed several minor bugs regarding eval tab in web UI.
### Miscellaneous Chores
* Updates mypy config in pyproject.toml.
* Add google search agent in samples.
* Update filtered schema parameters for Gemini API.
* Adds autoformat.sh for formatting codebase.
## 1.0.0
### ⚠ BREAKING CHANGES
* Evaluation dataset schema is finalized with strong-type pydantic models.
(previously saved eval file needs re-generation, for both adk eval cli and
the eval tab in adk web UI).
* `BuiltInCodeExecutor` (in code_executors package) replaces
`BuiltInCodeExecutionTool` (previously in tools package).
* All methods in services are now async, including session service, artifact
service and memory service.
* `list_events` and `close_session` methods are removed from session service.
* agent.py file structure with MCP tools are now easier and simpler ([now](https://github.com/google/adk-python/blob/3b5232c14f48e1d5b170f3698d91639b079722c8/contributing/samples/mcp_stdio_server_agent/agent.py#L33) vs [before](https://github.com/google/adk-python/blob/a4adb739c0d86b9ae4587547d2653d568f6567f2/contributing/samples/mcp_agent/agent.py#L41)).
Old format is not working anymore.
* `Memory` schema and `MemoryService` is redesigned.
* Mark various class attributes as private in the classes in the `tools` package.
* Disabled session state injection if instruction provider is used.
(so that you can have `{var_name}` in the instruction, which is required for code snippets)
* Toolbox integration is revamped: tools/toolbox_tool.py → tools/toolbox_toolset.py.
* Removes the experimental `remote_agent.py`. We'll redesign it and bring it back.
### Features
* Dev UI:
* A brand new trace view for overall agent invocation.
* A revamped evaluation tab and comparison view for checking eval results.
* Introduced `BaseToolset` to allow dynamically add/remove tools for agents.
* Revamped MCPToolset with the new BaseToolset interface.
* Revamped GoogleApiTool, GoogleApiToolset and ApplicationIntegrationToolset with the new BaseToolset interface.
* Resigned agent.py file structure when needing MCPToolset.
* Added ToolboxToolset.
* Redesigned strong-typed agent evaluation schema.
* Allows users to create more cohesive eval sets.
* Allows evals to be extended for non-text modality.
* Allows for a structured interaction with the uber eval system.
* Redesigned Memory schema and MemoryService interfaces.
* Added token usage to LlmResponse.
* Allowed specifying `--adk_version` in `adk deploy cloud_run` cli. Default is the current version.
### Bug Fixes
* Fixed `adk deploy cloud_run` failing bug.
* Fixed logs not being printed due to `google-auth` library.
### Miscellaneous Chores
* Display full help text when adk cli receives invalid arguments.
* `adk web` now binds `127.0.0.1` by default, instead of 0.0.0.0.
* `InMemoryRunner` now takes `BaseAgent` in constructor.
* Various docstring improvements.
* Various UI tweaks.
* Various bug fixes.
* Update various contributing/samples for contributors to validate the implementation.
## 0.5.0
### ⚠ BREAKING CHANGES
+79 -34
View File
@@ -2,8 +2,7 @@
We'd love to accept your patches and contributions to this project.
## Table of Contents
- [How to contribute](#how-to-contribute)
- [Before you begin](#before-you-begin)
- [Sign our Contributor License Agreement](#sign-our-contributor-license-agreement)
- [Review our community guidelines](#review-our-community-guidelines)
@@ -12,16 +11,16 @@ We'd love to accept your patches and contributions to this project.
- [Requirement for PRs](#requirement-for-prs)
- [Large or Complex Changes](#large-or-complex-changes)
- [Testing Requirements](#testing-requirements)
- [Unit Tests](#unit-tests)
- [End-to-End (E2E) Tests](#manual-end-to-end-e2e-tests)
- [Unit Tests](#unit-tests)
- [Manual End-to-End (E2E) Tests](#manual-end-to-end-e2e-tests)
- [Documentation](#documentation)
- [Development Setup](#development-setup)
- [Code reviews](#code-reviews)
- [Code reviews](#code-reviews)
## Before you begin
# Before you begin
### Sign our Contributor License Agreement
## Sign our Contributor License Agreement
Contributions to this project must be accompanied by a
[Contributor License Agreement](https://cla.developers.google.com/about) (CLA).
@@ -35,38 +34,38 @@ was for a different project), you probably don't need to do it again.
Visit <https://cla.developers.google.com/> to see your current agreements or to
sign a new one.
### Review our community guidelines
## Review our community guidelines
This project follows
[Google's Open Source Community Guidelines](https://opensource.google/conduct/).
## Contribution workflow
# Contribution workflow
### Finding Issues to Work On
## Finding Issues to Work On
- Browse issues labeled **`good first issue`** (newcomer-friendly) or **`help wanted`** (general contributions).
- For other issues, please kindly ask before contributing to avoid duplication.
### Requirement for PRs
## Requirement for PRs
- All PRs, other than small documentation or typo fixes, should have a Issue assoicated. If not, please create one.
- Small, focused PRs. Keep changes minimal—one concern per PR.
- For bug fixes or features, please provide logs or screenshot after the fix is applied to help reviewers better understand the fix.
- Please include a `testing plan` section in your PR to talk about how you will test. This will save time for PR review. See `Testing Requirements` section for more details.
### Large or Complex Changes
## Large or Complex Changes
For substantial features or architectural revisions:
- Open an Issue First: Outline your proposal, including design considerations and impact.
- Gather Feedback: Discuss with maintainers and the community to ensure alignment and avoid duplicate work
### Testing Requirements
## Testing Requirements
To maintain code quality and prevent regressions, all code changes must include comprehensive tests and verifiable end-to-end (E2E) evidence.
#### Unit Tests
### Unit Tests
Please add or update unit tests for your change. Please include a summary of passed `pytest` results.
@@ -80,7 +79,7 @@ Requirements for unit tests:
- Free of external dependencies (use mocks or fixtures as needed).
- **Quality:** Aim for high readability and maintainability; include docstrings or comments for complex scenarios.
#### Manual End-to-End (E2E) Tests
### Manual End-to-End (E2E) Tests
Manual E2E tests ensure integrated flows work as intended. Your tests should cover all scenarios. Sometimes, it's also good to ensure relevant functionality is not impacted.
@@ -97,23 +96,34 @@ Depending on your change:
- Include the command used and console output showing test results.
- Highlight sections of the log that directly relate to your change.
### Documentation
## Documentation
For any changes that impact user-facing documentation (guides, API reference, tutorials), please open a PR in the [adk-docs](https://github.com/google/adk-docs) repository to update relevant part before or alongside your code PR.
### Development Setup
## Development Setup
1. **Clone the repository:**
```shell
git clone git@github.com:google/adk-python.git
gh repo clone google/adk-python
cd adk-python
```
2. **Create and activate a virtual environment:**
2. **Install uv:**
Check out [uv installation guide](https://docs.astral.sh/uv/getting-started/installation/).
3. **Create and activate a virtual environment:**
**NOTE**: ADK supports Python 3.9+. Python 3.11 and above is strongly recommended.
Create a workspace venv using uv.
```shell
python -m venv .venv
uv venv --python "python3.11" ".venv"
```
Activate the workspace venv.
```shell
source .venv/bin/activate
```
@@ -123,39 +133,74 @@ For any changes that impact user-facing documentation (guides, API reference, tu
source .\.venv\Scripts\activate
```
3. **Install dependencies:**
4. **Install dependencies:**
```shell
pip install uv
uv sync --all-extras
```
4. **Run unit tests:**
**NOTE**: for convenience, installing all extra deps as a starting point.
5. **Run unit tests:**
```shell
uv run pytest ./tests/unittests
pytest ./tests/unittests
```
5. **Run pyink to format codebase:**
NOTE: for accurately repro test failure, only include `test` and `eval` as
extra dependencies.
```shell
uv run pyink --config pyproject.toml ./src
uv sync --extra test --extra eval
pytest ./tests/unittests
```
6. **Build the package**
6. **Auto-format the code:**
**NOTE**: We use `isort` and `pyink` for styles. Use the included
autoformat.sh to auto-format.
```shell
./autoformat.sh
```
7. **Build the wheel file:**
```shell
uv build
```
7. **Local Testing**
Have a simple testing folder setup as mentioned in the [quickstart](https://google.github.io/adk-docs/get-started/quickstart/)
then install the local package with changes after building it using the below command to test the changes.
8. **Test the locally built wheel file:**
Have a simple testing folder setup as mentioned in the
[quickstart](https://google.github.io/adk-docs/get-started/quickstart/).
Then following below steps to test your changes:
Create a clean venv and activate it:
```shell
uv pip install <YOUR_WHL_FILE_PATH>
[eg]: uv pip install <ADK_PROJECT_PATH>/dist/google_adk-0.4.0-py3-none-any.whl
VENV_PATH=~/venvs/adk-quickstart
```
### Code reviews
```shell
command -v deactivate >/dev/null 2>&1 && deactivate
```
```shell
rm -rf $VENV_PATH \
&& python3 -m venv $VENV_PATH \
&& source $VENV_PATH/bin/activate
```
Install the locally built wheel file:
```shell
pip install dist/google_adk-<version>-py3-none-any.whl
```
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
+11 -14
View File
@@ -13,8 +13,10 @@
</h3>
<h3 align="center">
Important Links:
<a href="https://google.github.io/adk-docs/">Docs</a> &
<a href="https://github.com/google/adk-samples">Samples</a>.
<a href="https://google.github.io/adk-docs/">Docs</a>,
<a href="https://github.com/google/adk-samples">Samples</a>,
<a href="https://github.com/google/adk-java">Java ADK</a> &
<a href="https://github.com/google/adk-web">ADK Web</a>.
</h3>
</html>
@@ -38,6 +40,12 @@ Agent Development Kit (ADK) is a flexible and modular framework for developing a
- **Deploy Anywhere**: Easily containerize and deploy agents on Cloud Run or
scale seamlessly with Vertex AI Agent Engine.
## 🤖 Agent2Agent (A2A) Protocol and ADK Integration
For remote agent-to-agent communication, ADK integrates with the
[A2A protocol](https://github.com/google-a2a/A2A/).
See this [example](https://github.com/google-a2a/a2a-samples/tree/main/samples/python/agents/google_adk)
for how they can work together.
## 🚀 Installation
@@ -123,16 +131,9 @@ adk eval \
samples_for_testing/hello_world/hello_world_eval_set_001.evalset.json
```
## 🤖 A2A and ADK integration
For remote agent-to-agent communication, ADK integrates with the
[A2A protocol](https://github.com/google/A2A/).
See this [example](https://github.com/google/A2A/tree/main/samples/python/agents/google_adk)
for how they can work together.
## 🤝 Contributing
We welcome contributions from the community! Whether it's bug reports, feature requests, documentation improvements, or code contributions, please see our
We welcome contributions from the community! Whether it's bug reports, feature requests, documentation improvements, or code contributions, please see our
- [General contribution guideline and flow](https://google.github.io/adk-docs/contributing-guide/#questions).
- Then if you want to contribute code, please read [Code Contributing Guidelines](./CONTRIBUTING.md) to get started.
@@ -140,10 +141,6 @@ We welcome contributions from the community! Whether it's bug reports, feature r
This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.
## Preview
This feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of the [Service Specific Terms](https://cloud.google.com/terms/service-terms#1). Pre-GA features are available "as is" and might have limited support. For more information, see the [launch stage descriptions](https://cloud.google.com/products?hl=en#product-launch-stages).
---
*Happy Agent Building!*
Executable
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# 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.
# Autoformat ADK codebase.
if ! command -v isort &> /dev/null
then
echo "isort not found, refer to CONTRIBUTING.md to set up dev environment first."
exit
fi
if ! command -v pyink &> /dev/null
then
echo "pyink not found, refer to CONTRIBUTING.md to set up dev environment first."
exit
fi
echo '---------------------------------------'
echo '| Organizing imports for src/...'
echo '---------------------------------------'
isort src/
echo 'All done! ✨ 🍰 ✨'
echo '---------------------------------------'
echo '| Organizing imports for tests/...'
echo '---------------------------------------'
isort tests/
echo 'All done! ✨ 🍰 ✨'
echo '---------------------------------------'
echo '| Auto-formatting src/...'
echo '---------------------------------------'
find -L src/ -type f -name "*.py" -exec pyink --config pyproject.toml {} +
echo '---------------------------------------'
echo '| Auto-formatting tests/...'
echo '---------------------------------------'
find -L tests/ -type f -name "*.py" -exec pyink --config pyproject.toml {} +
+83
View File
@@ -0,0 +1,83 @@
# BigQuery Tools Sample
## Introduction
This sample agent demonstrates the BigQuery first-party tools in ADK,
distributed via the `google.adk.tools.bigquery` module. These tools include:
1. `list_dataset_ids`
Fetches BigQuery dataset ids present in a GCP project.
1. `get_dataset_info`
Fetches metadata about a BigQuery dataset.
1. `list_table_ids`
Fetches table ids present in a BigQuery dataset.
1. `get_table_info`
Fetches metadata about a BigQuery table.
1. `execute_sql`
Runs a SQL query in BigQuery.
## How to use
Set up environment variables in your `.env` file for using
[Google AI Studio](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-ai-studio)
or
[Google Cloud Vertex AI](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai)
for the LLM service for your agent. For example, for using Google AI Studio you
would set:
* GOOGLE_GENAI_USE_VERTEXAI=FALSE
* GOOGLE_API_KEY={your api key}
### With Application Default Credentials
This mode is useful for quick development when the agent builder is the only
user interacting with the agent. The tools are initialized with the default
credentials present on the machine running the agent.
1. Create application default credentials on the machine where the agent would
be running by following https://cloud.google.com/docs/authentication/provide-credentials-adc.
1. Set `RUN_WITH_ADC=True` in `agent.py` and run the agent
### With Interactive OAuth
1. Follow
https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name.
to get your client id and client secret. Be sure to choose "web" as your client
type.
1. Follow https://developers.google.com/workspace/guides/configure-oauth-consent to add scope "https://www.googleapis.com/auth/bigquery".
1. Follow https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred to add http://localhost/dev-ui/ to "Authorized redirect URIs".
Note: localhost here is just a hostname that you use to access the dev ui,
replace it with the actual hostname you use to access the dev ui.
1. For 1st run, allow popup for localhost in Chrome.
1. Configure your `.env` file to add two more variables before running the agent:
* OAUTH_CLIENT_ID={your client id}
* OAUTH_CLIENT_SECRET={your client secret}
Note: don't create a separate .env, instead put it to the same .env file that
stores your Vertex AI or Dev ML credentials
1. Set `RUN_WITH_ADC=False` in `agent.py` and run the agent
## Sample prompts
* which weather datasets exist in bigquery public data?
* tell me more about noaa_lightning
* which tables exist in the ml_datasets dataset?
* show more details about the penguins table
* compute penguins population per island.
+58
View File
@@ -0,0 +1,58 @@
# 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.
import os
from google.adk.agents import llm_agent
from google.adk.tools.bigquery import BigQueryCredentialsConfig
from google.adk.tools.bigquery import BigQueryToolset
import google.auth
RUN_WITH_ADC = False
if RUN_WITH_ADC:
# Initialize the tools to use the application default credentials.
application_default_credentials, _ = google.auth.default()
credentials_config = BigQueryCredentialsConfig(
credentials=application_default_credentials
)
else:
# Initiaze the tools to do interactive OAuth
# The environment variables OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET
# must be set
credentials_config = BigQueryCredentialsConfig(
client_id=os.getenv("OAUTH_CLIENT_ID"),
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
scopes=["https://www.googleapis.com/auth/bigquery"],
)
bigquery_toolset = BigQueryToolset(credentials_config=credentials_config)
# The variable name `root_agent` determines what your root agent is for the
# debug CLI
root_agent = llm_agent.Agent(
model="gemini-2.0-flash",
name="hello_agent",
description=(
"Agent to answer questions about BigQuery data and models and execute"
" SQL queries."
),
instruction="""\
You are a data science agent with access to several BigQuery tools.
Make use of those tools to answer the user's questions.
""",
tools=[bigquery_toolset],
)
@@ -1,8 +1,8 @@
# OAuth Sample
# BigQuery Sample
## Introduction
This sample tests and demos the OAuth support in ADK via two tools:
This sample tests and demos the BigQuery support in ADK via two tools:
* 1. bigquery_datasets_list:
@@ -28,14 +28,14 @@ This sample tests and demos the OAuth support in ADK via two tools:
* 1. Follow https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name. to get your client id and client secret.
Be sure to choose "web" as your client type.
* 2. Configure your .env file to add two variables:
* 2. Configure your `.env` file to add two variables:
* GOOGLE_CLIENT_ID={your client id}
* GOOGLE_CLIENT_SECRET={your client secret}
* OAUTH_CLIENT_ID={your client id}
* OAUTH_CLIENT_SECRET={your client secret}
Note: done't create a separate .env , instead put it to the same .env file that stores your Vertex AI or Dev ML credentials
Note: don't create a separate `.env` file , instead put it to the same `.env` file that stores your Vertex AI or Dev ML credentials
* 3. Follow https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred to add http://localhost/dev-ui to "Authorized redirect URIs".
* 3. Follow https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred to add http://localhost/dev-ui/ to "Authorized redirect URIs".
Note: localhost here is just a hostname that you use to access the dev ui, replace it with the actual hostname you use to access the dev ui.
@@ -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
@@ -0,0 +1,30 @@
# 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 google.genai import Client
from google.adk import Agent
from google.adk.tools import google_search
# Only Vertex AI supports image generation for now.
client = Client()
root_agent = Agent(
model='gemini-2.0-flash-001',
name='root_agent',
description="""an agent whose job it is to perform Google search queries and answer questions about the results.""",
instruction="""You are an agent whose job is to perform Google search queries and answer questions about the results.
""",
tools=[google_search],
)
@@ -0,0 +1,43 @@
# Agent with Long-Running Tools
This example demonstrates an agent using a long-running tool (`ask_for_approval`).
## Key Flow for Long-Running Tools
1. **Initial Call**: The agent calls the long-running tool (e.g., `ask_for_approval`).
2. **Initial Tool Response**: The tool immediately returns an initial response, typically indicating a "pending" status and a way to track the request (e.g., a `ticket-id`). This is sent back to the agent as a `types.FunctionResponse` (usually processed internally by the runner and then influencing the agent's next turn).
3. **Agent Acknowledges**: The agent processes this initial response and usually informs the user about the pending status.
4. **External Process/Update**: The long-running task progresses externally (e.g., a human approves the request).
5. **❗️Crucial Step: Provide Updated Tool Response❗️**:
* Once the external process completes or updates, your application **must** construct a new `types.FunctionResponse`.
* This response should use the **same `id` and `name`** as the original `FunctionCall` to the long-running tool.
* The `response` field within this `types.FunctionResponse` should contain the *updated data* (e.g., `{'status': 'approved', ...}`).
* Send this `types.FunctionResponse` back to the agent as a part within a new message using `role="user"`.
```python
# Example: After external approval
updated_tool_output_data = {
"status": "approved",
"ticket-id": ticket_id, # from original call
# ... other relevant updated data
}
updated_function_response_part = types.Part(
function_response=types.FunctionResponse(
id=long_running_function_call.id, # Original call ID
name=long_running_function_call.name, # Original call name
response=updated_tool_output_data,
)
)
# Send this back to the agent
await runner.run_async(
# ... session_id, user_id ...
new_message=types.Content(
parts=[updated_function_response_part], role="user"
),
)
```
6. **Agent Acts on Update**: The agent receives this message containing the `types.FunctionResponse` and, based on its instructions, proceeds with the next steps (e.g., calling another tool like `reimburse`).
**Why is this important?** The agent relies on receiving this subsequent `types.FunctionResponse` (provided in a message with `role="user"` containing the specific `Part`) to understand that the long-running task has concluded or its state has changed. Without it, the agent will remain unaware of the outcome of the pending task.
+8 -2
View File
@@ -22,14 +22,20 @@ from google.genai import types
def reimburse(purpose: str, amount: float) -> str:
"""Reimburse the amount of money to the employee."""
return {'status': 'ok'}
return {
'status': 'ok',
}
def ask_for_approval(
purpose: str, amount: float, tool_context: ToolContext
) -> dict[str, Any]:
"""Ask for approval for the reimbursement."""
return {'status': 'pending'}
return {
'status': 'pending',
'amount': amount,
'ticketId': 'reimbursement-ticket-001',
}
root_agent = Agent(
+194
View File
@@ -0,0 +1,194 @@
# 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.
import asyncio
import agent
from dotenv import load_dotenv
from typing import Any
from typing import Union
from google.adk.agents import Agent
from google.adk.events import Event
from google.adk.runners import Runner
from google.adk.tools import LongRunningFunctionTool
from google.adk.sessions import InMemorySessionService
from google.genai import types
import os
from opentelemetry import trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.sdk.trace import export
from opentelemetry.sdk.trace import TracerProvider
load_dotenv(override=True)
APP_NAME = "human_in_the_loop"
USER_ID = "1234"
SESSION_ID = "session1234"
session_service = InMemorySessionService()
async def main():
session = await session_service.create_session(
app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID
)
runner = Runner(
agent=agent.root_agent,
app_name=APP_NAME,
session_service=session_service,
)
async def call_agent(query: str):
content = types.Content(role="user", parts=[types.Part(text=query)])
print(f'>>> User Query: "{query}"')
print("--- Running agent's initial turn ---")
events_async = runner.run_async(
session_id=session.id, user_id=USER_ID, new_message=content
)
long_running_function_call: Union[types.FunctionCall, None] = None
initial_tool_response: Union[types.FunctionResponse, None] = None
ticket_id: Union[str, None] = None
async for event in events_async:
if event.content and event.content.parts:
for i, part in enumerate(event.content.parts):
if part.text:
print(f" Part {i} [Text]: {part.text.strip()}")
if part.function_call:
print(
f" Part {i} [FunctionCall]:"
f" {part.function_call.name}({part.function_call.args}) ID:"
f" {part.function_call.id}"
)
if not long_running_function_call and part.function_call.id in (
event.long_running_tool_ids or []
):
long_running_function_call = part.function_call
print(
" (Captured as long_running_function_call for"
f" '{part.function_call.name}')"
)
if part.function_response:
print(
f" Part {i} [FunctionResponse]: For"
f" '{part.function_response.name}', ID:"
f" {part.function_response.id}, Response:"
f" {part.function_response.response}"
)
if (
long_running_function_call
and part.function_response.id == long_running_function_call.id
):
initial_tool_response = part.function_response
if initial_tool_response.response:
ticket_id = initial_tool_response.response.get("ticketId")
print(
" (Captured as initial_tool_response for"
f" '{part.function_response.name}', Ticket ID: {ticket_id})"
)
print("--- End of agent's initial turn ---\n")
if (
long_running_function_call
and initial_tool_response
and initial_tool_response.response.get("status") == "pending"
):
print(f"--- Simulating external approval for ticket: {ticket_id} ---\n")
updated_tool_output_data = {
"status": "approved",
"ticketId": ticket_id,
"approver_feedback": "Approved by manager at " + str(
asyncio.get_event_loop().time()
),
}
updated_function_response_part = types.Part(
function_response=types.FunctionResponse(
id=long_running_function_call.id,
name=long_running_function_call.name,
response=updated_tool_output_data,
)
)
print(
"--- Sending updated tool result to agent for call ID"
f" {long_running_function_call.id}: {updated_tool_output_data} ---"
)
print("--- Running agent's turn AFTER receiving updated tool result ---")
async for event in runner.run_async(
session_id=session.id,
user_id=USER_ID,
new_message=types.Content(
parts=[updated_function_response_part], role="user"
),
):
if event.content and event.content.parts:
for i, part in enumerate(event.content.parts):
if part.text:
print(f" Part {i} [Text]: {part.text.strip()}")
if part.function_call:
print(
f" Part {i} [FunctionCall]:"
f" {part.function_call.name}({part.function_call.args}) ID:"
f" {part.function_call.id}"
)
if part.function_response:
print(
f" Part {i} [FunctionResponse]: For"
f" '{part.function_response.name}', ID:"
f" {part.function_response.id}, Response:"
f" {part.function_response.response}"
)
print("--- End of agent's turn AFTER receiving updated tool result ---")
elif long_running_function_call and not initial_tool_response:
print(
f"--- Long running function '{long_running_function_call.name}' was"
" called, but its initial response was not captured. ---"
)
elif not long_running_function_call:
print(
"--- No long running function call was detected in the initial"
" turn. ---"
)
await call_agent("Please reimburse $50 for meals")
print("=" * 70)
await call_agent("Please reimburse $200 for conference travel")
if __name__ == "__main__":
provider = TracerProvider()
project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
if not project_id:
raise ValueError("GOOGLE_CLOUD_PROJECT environment variable is not set.")
print("Tracing to project", project_id)
processor = export.BatchSpanProcessor(
CloudTraceSpanExporter(project_id=project_id)
)
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
asyncio.run(main())
provider.force_flush()
print("Done tracing to project", project_id)
@@ -0,0 +1,75 @@
# Application Integration Agent Sample with End-User Credentials
## Introduction
This sample demonstrates how to use the `ApplicationIntegrationToolset` within
an ADK agent to interact with external applications using **end-user OAuth 2.0
credentials**. Specifically, this agent (`agent.py`) is configured to interact
with Google Calendar using a pre-configured Application Integration connection
and authenticating as the end user.
## Prerequisites
1. **Set up Integration Connection:**
* You need an existing
[Integration connection](https://cloud.google.com/integration-connectors/docs/overview)
configured to interact with Google Calendar APIs. Follow the
[documentation](https://google.github.io/adk-docs/tools/google-cloud-tools/#use-integration-connectors)
to provision the Integration Connector in Google Cloud. You will need
the `Connection Name`, `Project ID`, and `Location` of your connection.
* Ensure the connection is configured to use Google Calendar (e.g., by
enabling the `google-calendar-connector` or a similar connector).
2. **Configure OAuth 2.0 Client:**
* You need an OAuth 2.0 Client ID and Client Secret that is authorized to
access the required Google Calendar scopes (e.g.,
`https://www.googleapis.com/auth/calendar.readonly`). You can create
OAuth credentials in the Google Cloud Console under "APIs & Services"
-> "Credentials".
3. **Configure Environment Variables:**
* Create a `.env` file in the same directory as `agent.py` (or add to
your existing one).
* Add the following variables to the `.env` file, replacing the
placeholder values with your actual connection details:
```dotenv
CONNECTION_NAME=<YOUR_CALENDAR_CONNECTION_NAME>
CONNECTION_PROJECT=<YOUR_GOOGLE_CLOUD_PROJECT_ID>
CONNECTION_LOCATION=<YOUR_CONNECTION_LOCATION>
CLIENT_ID=<YOUR_OAUTH_CLIENT_ID>
CLIENT_SECRET=<YOUR_OAUTH_CLIENT_SECRET>
```
## End-User Authentication (OAuth 2.0)
This agent utilizes the `AuthCredential` and `OAuth2Auth` classes from the ADK
to handle authentication.
* It defines an OAuth 2.0 scheme (`oauth2_scheme`) based on Google Cloud's
OAuth endpoints and required scopes.
* It uses the `CLIENT_ID` and `CLIENT_SECRET` from the environment variables
(or hardcoded values in the sample) to configure `OAuth2Auth`.
* This `AuthCredential` is passed to the `ApplicationIntegrationToolset`,
enabling the tool to make authenticated API calls to Google Calendar on
behalf of the user running the agent. The ADK framework will typically
handle the OAuth flow (e.g., prompting the user for consent) when the tool
is first invoked.
## How to Use
1. **Install Dependencies:** Ensure you have the necessary libraries installed
(e.g., `google-adk`, `python-dotenv`).
2. **Run the Agent:** Execute the agent script from your terminal:
```bash
python agent.py
```
3. **Interact:** Once the agent starts, you can interact with it. If it's the
first time using the tool requiring OAuth, you might be prompted to go
through the OAuth consent flow in your browser. After successful
authentication, you can ask the agent to perform tasks.
## Sample Prompts
Here are some examples of how you can interact with the agent:
* `Can you list events from my primary calendar?`
@@ -0,0 +1 @@
from . import agent
@@ -0,0 +1,95 @@
# 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.
import os
from dotenv import load_dotenv
from google.adk import Agent
from google.adk.auth import AuthCredential
from google.adk.auth import AuthCredentialTypes
from google.adk.auth import OAuth2Auth
from google.adk.tools.application_integration_tool.application_integration_toolset import ApplicationIntegrationToolset
from google.adk.tools.openapi_tool.auth.auth_helpers import dict_to_auth_scheme
from google.genai import types
# Load environment variables from .env file
load_dotenv()
connection_name = os.getenv("CONNECTION_NAME")
connection_project = os.getenv("CONNECTION_PROJECT")
connection_location = os.getenv("CONNECTION_LOCATION")
client_secret = os.getenv("CLIENT_SECRET")
client_id = os.getenv("CLIENT_ID")
oauth2_data_google_cloud = {
"type": "oauth2",
"flows": {
"authorizationCode": {
"authorizationUrl": "https://accounts.google.com/o/oauth2/auth",
"tokenUrl": "https://oauth2.googleapis.com/token",
"scopes": {
"https://www.googleapis.com/auth/cloud-platform": (
"View and manage your data across Google Cloud Platform"
" services"
),
"https://www.googleapis.com/auth/calendar.readonly": (
"View your calendars"
),
},
}
},
}
oauth2_scheme = dict_to_auth_scheme(oauth2_data_google_cloud)
auth_credential = AuthCredential(
auth_type=AuthCredentialTypes.OAUTH2,
oauth2=OAuth2Auth(
client_id=client_id,
client_secret=client_secret,
),
)
calendar_tool = ApplicationIntegrationToolset(
project=connection_project,
location=connection_location,
tool_name_prefix="calendar_tool",
connection=connection_name,
actions=["GET_calendars/%7BcalendarId%7D/events"],
tool_instructions="""
Use this tool to list events in a calendar. Get calendarId from the user and use it in tool as following example:
connectorInputPayload: { "Path parameters": { "calendarId": "primary" } }. Follow the schema correctly. Note its "Path parameters" and not "Path_parameters".
""",
auth_scheme=oauth2_scheme,
auth_credential=auth_credential,
)
root_agent = Agent(
model="gemini-2.0-flash",
name="data_processing_agent",
description="Agent that can list events in a calendar.",
instruction="""
Helps you with calendar related tasks.
""",
tools=calendar_tool.get_tools(),
generate_content_config=types.GenerateContentConfig(
safety_settings=[
types.SafetySetting(
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
threshold=types.HarmBlockThreshold.OFF,
),
]
),
)
@@ -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
@@ -0,0 +1,49 @@
# 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.
"""
This agent aims to test the Langchain tool with Langchain's StructuredTool
"""
from google.adk.agents import Agent
from google.adk.tools.langchain_tool import LangchainTool
from langchain_core.tools.structured import StructuredTool
from pydantic import BaseModel
def add(x, y) -> int:
return x + y
class AddSchema(BaseModel):
x: int
y: int
test_langchain_tool = StructuredTool.from_function(
add,
name="add",
description="Adds two numbers",
args_schema=AddSchema,
)
root_agent = Agent(
model="gemini-2.0-flash-001",
name="test_app",
description="A helpful assistant for user questions.",
instruction=(
"You are a helpful assistant for user questions, you have access to a"
" tool that adds two numbers."
),
tools=[LangchainTool(tool=test_langchain_tool)],
)

Some files were not shown because too many files have changed in this diff Show More