You've already forked adk-python
mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da34692231 | |||
| d263afd91b | |||
| c85330eae8 | |||
| adef7b297a | |||
| 18cd3844db | |||
| e545e5a570 | |||
| e33161b4f8 | |||
| b5d9f8f3e3 | |||
| 75699fbeca | |||
| 45d60a1906 | |||
| bf39c00610 | |||
| 28d0ea876f | |||
| 4ca77bc056 | |||
| dc414cb507 | |||
| a021222077 | |||
| 4442167dd5 | |||
| e437c7aac6 | |||
| 3fa2ea7cb9 | |||
| 6a39c854e0 | |||
| b04a5cebb8 | |||
| 362fb3f2b7 | |||
| 0bd05df471 | |||
| 62c4a85917 | |||
| 08869ccc07 | |||
| df141db60c | |||
| 9bd539eca9 | |||
| 3d2f13cecd | |||
| d0fdfb8c8e | |||
| 0959b06dbd | |||
| 9af2394e0a | |||
| 873beca088 | |||
| a903c54bac | |||
| b0d88bf172 | |||
| 17d6042995 | |||
| 43083baddc | |||
| 9b75e24d8c | |||
| a58cc3d882 | |||
| 37108be855 | |||
| b6c7b5b64f | |||
| ffa9b361db | |||
| dc43d518c9 | |||
| e2748b3ed5 | |||
| 379810dd6a | |||
| 1cf5cf0d0a | |||
| f0183a9b98 | |||
| 3f621ae6f2 | |||
| 4e765ae2f3 | |||
| c13c9875cf | |||
| 045aea9b15 | |||
| 20279d9a50 | |||
| 09e487df3c | |||
| 51a559eb2a | |||
| 1fe9c47cc6 | |||
| 31e41bdd06 | |||
| 9029b8a66e | |||
| e153d07593 | |||
| e79651cd86 | |||
| 22629a17bd | |||
| 5356f20ead | |||
| ed09cd840f | |||
| 630f1674cb | |||
| 2f55de6ded | |||
| 77b869f5e3 | |||
| 04de3e197d | |||
| 3901fade71 | |||
| a71dbdf9e2 | |||
| 832a633351 | |||
| 738d1a8b84 | |||
| 5306ddad4d | |||
| a623467299 | |||
| f54b9b6ad1 | |||
| 6729edd08e | |||
| 917a8a19f7 | |||
| ef3c745d65 | |||
| 88a4402d14 | |||
| 09f1269bf7 | |||
| 9e473e0abd | |||
| acbdca0d84 | |||
| ed7a21e189 | |||
| a1e1441115 | |||
| f33e0903b2 | |||
| abc89d2c81 | |||
| 00cc8cd643 | |||
| 9597a446fd | |||
| fa025d7559 | |||
| 120cbabeb2 | |||
| 29cd183aa1 | |||
| bd67e8480f | |||
| ea69c9093a | |||
| f033e405c1 | |||
| 3b1d9a8a3e | |||
| 7c670f638b | |||
| fb13963ded | |||
| 2fd8feb65d |
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"contextFileName": "AGENTS.md"
|
||||
}
|
||||
@@ -31,5 +31,8 @@ If applicable, add screenshots to help explain your problem.
|
||||
- Python version(python -V):
|
||||
- ADK version(pip show google-adk):
|
||||
|
||||
**Model Information:**
|
||||
For example, which model is being used.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
# Use grep -L to find files that DO NOT contain the pattern.
|
||||
# This command will output a list of non-compliant files.
|
||||
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES)
|
||||
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES || true)
|
||||
|
||||
# Check if the list of non-compliant files is empty
|
||||
if [ -z "$FILES_MISSING_IMPORT" ]; then
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# .github/workflows/pr-commit-check.yml
|
||||
# This GitHub Action workflow checks if a pull request has more than one commit.
|
||||
# If it does, it fails the check and instructs the user to squash their commits.
|
||||
|
||||
name: 'PR Commit Check'
|
||||
|
||||
# This workflow runs on pull request events.
|
||||
# It's configured to run on any pull request that is opened or synchronized (new commits pushed).
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
# Defines the jobs that will run as part of the workflow.
|
||||
jobs:
|
||||
check-commit-count:
|
||||
# The type of runner that the job will run on. 'ubuntu-latest' is a good default.
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# The steps that will be executed as part of the job.
|
||||
steps:
|
||||
# Step 1: Check out the code
|
||||
# This action checks out your repository under $GITHUB_WORKSPACE, so your workflow can access it.
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# We need to fetch all commits to accurately count them.
|
||||
# '0' means fetch all history for all branches and tags.
|
||||
fetch-depth: 0
|
||||
|
||||
# Step 2: Count the commits in the pull request
|
||||
# This step runs a script to get the number of commits in the PR.
|
||||
- name: Count Commits
|
||||
id: count_commits
|
||||
# We use `git rev-list --count` to count the commits.
|
||||
# ${{ github.event.pull_request.base.sha }} is the commit SHA of the base branch.
|
||||
# ${{ github.event.pull_request.head.sha }} is the commit SHA of the head branch (the PR branch).
|
||||
# The '..' syntax gives us the list of commits in the head branch that are not in the base branch.
|
||||
# The output of the command (the count) is stored in a step output variable named 'count'.
|
||||
run: |
|
||||
count=$(git rev-list --count ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }})
|
||||
echo "commit_count=$count" >> $GITHUB_OUTPUT
|
||||
|
||||
# Step 3: Check if the commit count is greater than 1
|
||||
# This step uses the output from the previous step to decide whether to pass or fail.
|
||||
- name: Check Commit Count
|
||||
# This step only runs if the 'commit_count' output from the 'count_commits' step is greater than 1.
|
||||
if: steps.count_commits.outputs.commit_count > 1
|
||||
# If the condition is met, the workflow will exit with a failure status.
|
||||
run: |
|
||||
echo "This pull request has ${{ steps.count_commits.outputs.commit_count }} commits."
|
||||
echo "Please squash them into a single commit before merging."
|
||||
echo "You can use git rebase -i HEAD~N"
|
||||
echo "...where N is the number of commits you want to squash together. The PR check conveniently tells you this number! For example, if the check says you have 3 commits, you would run: git rebase -i HEAD~3."
|
||||
echo "Because you have rewritten the commit history, you must use the --force flag to update the pull request: git push --force"
|
||||
exit 1
|
||||
|
||||
# Step 4: Success message
|
||||
# This step runs if the commit count is not greater than 1 (i.e., it's 1).
|
||||
- name: Success
|
||||
if: steps.count_commits.outputs.commit_count <= 1
|
||||
run: |
|
||||
echo "This pull request has a single commit. Great job!"
|
||||
@@ -36,8 +36,8 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install uv
|
||||
run: curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
- name: Install the latest version of uv
|
||||
uses: astral-sh/setup-uv@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@@ -40,4 +40,5 @@ jobs:
|
||||
ISSUE_TITLE: ${{ github.event.issue.title }}
|
||||
ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
ISSUE_COUNT_TO_PROCESS: '3' # Process 3 issues at a time on schedule
|
||||
run: python contributing/samples/adk_triaging_agent/main.py
|
||||
PYTHONPATH: contributing/samples
|
||||
run: python -m adk_triaging_agent.main
|
||||
|
||||
@@ -82,6 +82,7 @@ log/
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
uv.lock
|
||||
|
||||
# Google Cloud specific
|
||||
.gcloudignore
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
# Gemini CLI / Gemini Code Assist Context
|
||||
|
||||
This document provides context for the Gemini CLI and Gemini Code Assist to understand the project and assist with development.
|
||||
|
||||
## Project Overview
|
||||
|
||||
The Agent Development Kit (ADK) is an open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control. While optimized for Gemini and the Google ecosystem, ADK is model-agnostic, deployment-agnostic, and is built for compatibility with other frameworks. ADK was designed to make agent development feel more like software development, to make it easier for developers to create, deploy, and orchestrate agentic architectures that range from simple tasks to complex workflows.
|
||||
|
||||
## Project Architecture
|
||||
|
||||
Please refer to [ADK Project Overview and Architecture](https://github.com/google/adk-python/blob/main/contributing/adk_project_overview_and_architecture.md) for details.
|
||||
|
||||
## ADK: Style Guides
|
||||
|
||||
### Python Style Guide
|
||||
|
||||
The project follows the Google Python Style Guide. Key conventions are enforced using `pylint` with the provided `pylintrc` configuration file. Here are some of the key style points:
|
||||
|
||||
* **Indentation**: 2 spaces.
|
||||
* **Line Length**: Maximum 80 characters.
|
||||
* **Naming Conventions**:
|
||||
* `function_and_variable_names`: `snake_case`
|
||||
* `ClassNames`: `CamelCase`
|
||||
* `CONSTANTS`: `UPPERCASE_SNAKE_CASE`
|
||||
* **Docstrings**: Required for all public modules, functions, classes, and methods.
|
||||
* **Imports**: Organized and sorted.
|
||||
* **Error Handling**: Specific exceptions should be caught, not general ones like `Exception`.
|
||||
|
||||
### Autoformat
|
||||
|
||||
We have autoformat.sh to help solve import organize and formatting issues.
|
||||
|
||||
```bash
|
||||
# Run in open_source_workspace/
|
||||
$ ./autoformat.sh
|
||||
```
|
||||
|
||||
### In ADK source
|
||||
|
||||
Below styles applies to the ADK source code (under `src/` folder of the Github.
|
||||
repo).
|
||||
|
||||
#### Use relative imports
|
||||
|
||||
```python
|
||||
# DO
|
||||
from ..agents.llm_agent import LlmAgent
|
||||
|
||||
# DON'T
|
||||
from google.adk.agents.llm_agent import LlmAgent
|
||||
```
|
||||
|
||||
#### Import from module, not from `__init__.py`
|
||||
|
||||
```python
|
||||
# DO
|
||||
from ..agents.llm_agent import LlmAgent
|
||||
|
||||
# DON'T
|
||||
from ..agents import LlmAgent # import from agents/__init__.py
|
||||
```
|
||||
|
||||
#### Always do `from __future__ import annotations`
|
||||
|
||||
```python
|
||||
# DO THIS, right after the open-source header.
|
||||
from __future__ import annotations
|
||||
```
|
||||
|
||||
Like below:
|
||||
|
||||
```python
|
||||
# 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 __future__ import annotations
|
||||
|
||||
# ... the rest of the file.
|
||||
```
|
||||
|
||||
This allows us to forward-reference a class without quotes.
|
||||
|
||||
Check out go/pep563 for details.
|
||||
|
||||
### In ADK tests
|
||||
|
||||
#### Use absolute imports
|
||||
|
||||
In tests, we use `google.adk` same as how our users uses.
|
||||
|
||||
```python
|
||||
# DO
|
||||
from google.adk.agents.llm_agent import LlmAgent
|
||||
|
||||
# DON'T
|
||||
from ..agents.llm_agent import LlmAgent
|
||||
```
|
||||
|
||||
## ADK: Local testing
|
||||
|
||||
### Unit tests
|
||||
|
||||
Run below command:
|
||||
|
||||
```bash
|
||||
$ pytest tests/unittests
|
||||
```
|
||||
|
||||
## Docstring and comments
|
||||
|
||||
### Comments - Explaining the Why, Not the What
|
||||
Philosophy: Well-written code should be largely self-documenting. Comments
|
||||
serve a different purpose: they should explain the complex algorithms,
|
||||
non-obvious business logic, or the rationale behind a particular implementation
|
||||
choice—the things the code cannot express on its own. Avoid comments that
|
||||
merely restate what the code does (e.g., # increment i above i += 1).
|
||||
|
||||
Style: Comments should be written as complete sentences. Block comments must
|
||||
begin with a # followed by a single space.
|
||||
|
||||
## Versioning
|
||||
ADK adherence to Semantic Versioning 2.0.0
|
||||
|
||||
Core Principle: The adk-python project strictly adheres to the Semantic
|
||||
Versioning 2.0.0 specification. All release versions will follow the
|
||||
MAJOR.MINOR.PATCH format.
|
||||
|
||||
### Breaking Change
|
||||
|
||||
A breaking change is any modification that introduces backward-incompatible
|
||||
changes to the public API. In the context of the ADK, this means a change that
|
||||
could force a developer using the framework to alter their existing code to
|
||||
upgrade to the new version. The public API is not limited to just the Python
|
||||
function and class signatures; it also encompasses data schemas for stored
|
||||
information (like evaluation datasets), the command-line interface (CLI),
|
||||
and the data format used for server communications.
|
||||
|
||||
### Public API Surface Definition
|
||||
|
||||
The "public API" of ADK is a broad contract that extends beyond its Python
|
||||
function signatures. A breaking change in any of the following areas can
|
||||
disrupt user workflows and the wider ecosystem of agents and tools built with
|
||||
ADK. The analysis of the breaking changes introduced in v1.0.0 demonstrates the
|
||||
expansive nature of this contract. For the purposes of versioning, the ADK
|
||||
Public API Surface is defined as:
|
||||
|
||||
- All public classes, methods, and functions in the google.adk namespace.
|
||||
|
||||
- The names, required parameters, and expected behavior of all built-in Tools
|
||||
(e.g., google_search, BuiltInCodeExecutor).
|
||||
|
||||
- The structure and schema of persisted data, including Session data, Memory,
|
||||
and Evaluation datasets.
|
||||
|
||||
- The JSON request/response format of the ADK API server(FastAPI server)
|
||||
used by adk web, including field casing conventions.
|
||||
|
||||
- The command-line interface (CLI) commands, arguments, and flags (e.g., adk deploy).
|
||||
|
||||
- The expected file structure for agent definitions that are loaded by the
|
||||
framework (e.g., the agent.py convention).
|
||||
|
||||
#### Checklist for Breaking Changes:
|
||||
|
||||
The following changes are considered breaking and necessitate a MAJOR version
|
||||
bump.
|
||||
|
||||
- API Signature Change: Renaming, removing, or altering the required parameters
|
||||
of any public class, method, or function (e.g., the removal of the list_events
|
||||
method from BaseSessionService).
|
||||
|
||||
- Architectural Shift: A fundamental change to a core component's behavior
|
||||
(e.g., making all service methods async, which requires consumers to use await).
|
||||
|
||||
- Data Schema Change: A non-additive change to a persisted data schema that
|
||||
renders old data unreadable or invalid (e.g., the redesign of the
|
||||
MemoryService and evaluation dataset schemas).
|
||||
|
||||
- Tool Interface Change: Renaming a built-in tool, changing its required
|
||||
parameters, or altering its fundamental purpose (e.g., replacing
|
||||
BuiltInCodeExecutionTool with BuiltInCodeExecutor and moving it from the tools
|
||||
parameter to the code_executor parameter of an Agent).
|
||||
|
||||
- Configuration Change: Altering the required structure of configuration files
|
||||
or agent definition files that the framework loads (e.g., the simplification
|
||||
of the agent.py structure for MCPToolset).
|
||||
|
||||
- Wire Format Change: Modifying the data format for API server interactions
|
||||
(e.g., the switch from snake_case to camelCase for all JSON payloads).
|
||||
|
||||
- Dependency Removal: Removing support for a previously integrated third-party
|
||||
library or tool type.
|
||||
+104
@@ -1,5 +1,109 @@
|
||||
# Changelog
|
||||
|
||||
## [1.6.1](https://github.com/google/adk-python/compare/v1.5.0...v1.6.1) (2025-07-09)
|
||||
|
||||
### Features
|
||||
|
||||
* Add A2A support as experimental features [f0183a9](https://github.com/google/adk-python/commit/f0183a9b98b0bcf8aab4f948f467cef204ddc9d6)
|
||||
* Install google-adk with a2a extra: pip install google-adk[a2a]
|
||||
* Users can serve agents as A2A agent with `--a2a` option for `adk web` and
|
||||
`adk api_server`
|
||||
* Users can run a remote A2A agent with `RemoteA2AAgent` class
|
||||
* Three A2A agent samples are added:
|
||||
* contributing/samples/a2a_basic
|
||||
* contributing/samples/a2a_auth
|
||||
* contributing/samples/a2a_human_in_loop
|
||||
|
||||
* Support agent hot reload.[e545e5a](https://github.com/google/adk-python/commit/e545e5a570c1331d2ed8fda31c7244b5e0f71584)
|
||||
Users can add `--reload_agents` flag to `adk web` and `adk api_server` command
|
||||
to reload agents automatically when new changes are detected.
|
||||
|
||||
* Eval features
|
||||
* Implement auto rater-based evaluator for responses [75699fb](https://github.com/google/adk-python/commit/75699fbeca06f99c6f2415938da73bb423ec9b9b)
|
||||
* Add Safety evaluator metric [0bd05df](https://github.com/google/adk-python/commit/0bd05df471a440159a44b5864be4740b0f1565f9)
|
||||
* Add BaseEvalService declaration and surrounding data models [b0d88bf](https://github.com/google/adk-python/commit/b0d88bf17242e738bcd409b3d106deed8ce4d407)
|
||||
|
||||
* Minor features
|
||||
* Add `custom_metadata` to VertexAiSessionService when adding events [a021222](https://github.com/google/adk-python/commit/a02122207734cabb26f7c23e84d2336c4b8b0375)
|
||||
* Support protected write in BigQuery `execute_sql` tool [dc43d51](https://github.com/google/adk-python/commit/dc43d518c90b44932b3fdedd33fca9e6c87704e2)
|
||||
* Added clone() method to BaseAgent to allow users to create copies of an agent [d263afd] (https://github.com/google/adk-python/commit/d263afd91ba4a3444e5321c0e1801c499dec4c68)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Support project-based gemini model path to use enterprise_web_search_tool [e33161b](https://github.com/google/adk-python/commit/e33161b4f8650e8bcb36c650c4e2d1fe79ae2526)
|
||||
* Use inspect.signature() instead of typing.get_type_hints for examining function signatures[4ca77bc](https://github.com/google/adk-python/commit/4ca77bc056daa575621a80d3c8d5014b78209233)
|
||||
* Replace Event ID generation with UUID4 to prevent SQLite integrity constraint failures [e437c7a](https://github.com/google/adk-python/commit/e437c7aac650ac6a53fcfa71bd740e3e5ec0f230)
|
||||
* Remove duplicate options from `adk deploy` [3fa2ea7](https://github.com/google/adk-python/commit/3fa2ea7cb923c9f8606d98b45a23bd58a7027436)
|
||||
* Fix scenario where a user can access another users events given the same session id [362fb3f](https://github.com/google/adk-python/commit/362fb3f2b7ac4ad15852d00ce4f3935249d097f6)
|
||||
* Handle unexpected 'parameters' argument in FunctionTool.run_async [0959b06](https://github.com/google/adk-python/commit/0959b06dbdf3037fe4121f12b6d25edca8fb9afc)
|
||||
* Make sure each partial event has different timestamp [17d6042](https://github.com/google/adk-python/commit/17d604299505c448fcb55268f0cbaeb6c4fa314a)
|
||||
* Avoid pydantic.ValidationError when the model stream returns empty final chunk [9b75e24](https://github.com/google/adk-python/commit/9b75e24d8c01878c153fec26ccfea4490417d23b)
|
||||
* Fix google_search_tool.py to support updated Gemini LIVE model naming [77b869f](https://github.com/google/adk-python/commit/77b869f5e35a66682cba35563824fd23a9028d7c)
|
||||
* Adding detailed information on each metric evaluation [04de3e1](https://github.com/google/adk-python/commit/04de3e197d7a57935488eb7bfa647c7ab62cd9d9)
|
||||
* Converts litellm generate config err [3901fad](https://github.com/google/adk-python/commit/3901fade71486a1e9677fe74a120c3f08efe9d9e)
|
||||
* Save output in state via output_key only when the event is authored by current agent [20279d9](https://github.com/google/adk-python/commit/20279d9a50ac051359d791dea77865c17c0bbf9e)
|
||||
* Treat SQLite database update time as UTC for session's last update time [3f621ae](https://github.com/google/adk-python/commit/3f621ae6f2a5fac7f992d3d833a5311b4d4e7091)
|
||||
* Raise ValueError when sessionId and userId are incorrect combination(#1653) [4e765ae](https://github.com/google/adk-python/commit/4e765ae2f3821318e581c26a52e11d392aaf72a4)
|
||||
* Support API-Key for MCP Tool authentication [045aea9](https://github.com/google/adk-python/commit/045aea9b15ad0190a960f064d6e1e1fc7f964c69)
|
||||
* Lock LangGraph version to <= 0.4.10 [9029b8a](https://github.com/google/adk-python/commit/9029b8a66e9d5e0d29d9a6df0e5590cc7c0e9038)
|
||||
* Update the retry logic of create session polling [3d2f13c](https://github.com/google/adk-python/commit/3d2f13cecd3fef5adfa1c98bf23d7b68ff355f4d)
|
||||
|
||||
### Chores
|
||||
|
||||
* Extract mcp client creation logic to a separate method [45d60a1](https://github.com/google/adk-python/commit/45d60a1906bfe7c43df376a829377e2112ea3d17)
|
||||
* Add tests for live streaming configs [bf39c00](https://github.com/google/adk-python/commit/bf39c006102ef3f01e762e7bb744596a4589f171)
|
||||
* Update ResponseEvaluator to use newer version of Eval SDK [62c4a85](https://github.com/google/adk-python/commit/62c4a8591780a9a3fdb03a0de11092d84118a1b9)
|
||||
* Add util to build our llms.txt and llms-full.txt files [a903c54](https://github.com/google/adk-python/commit/a903c54bacfcb150dc315bec9c67bf7ce9551c07)
|
||||
* Create an example for multi agent live streaming [a58cc3d](https://github.com/google/adk-python/commit/a58cc3d882e59358553e8ea16d166b1ab6d3aa71)
|
||||
* Refactor the ADK Triaging Agent to make the code easier to read [b6c7b5b](https://github.com/google/adk-python/commit/b6c7b5b64fcd2e83ed43f7b96ea43791733955d8)
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* Update the a2a exmaple link in README.md [d0fdfb8](https://github.com/google/adk-python/commit/d0fdfb8c8e2e32801999c81de8d8ed0be3f88e76)
|
||||
* Adds AGENTS.md to provide relevant project context for the Gemini CLI [37108be](https://github.com/google/adk-python/commit/37108be8557e011f321de76683835448213f8515)
|
||||
* Update CONTRIBUTING.md [ffa9b36](https://github.com/google/adk-python/commit/ffa9b361db615ae365ba62c09a8f4226fb761551)
|
||||
* Add adk project overview and architecture [28d0ea8](https://github.com/google/adk-python/commit/28d0ea876f2f8de952f1eccbc788e98e39f50cf5)
|
||||
* Add docstring to clarify that inmemory service are not suitable for production [dc414cb](https://github.com/google/adk-python/commit/dc414cb5078326b8c582b3b9072cbda748766286)
|
||||
* Update agents.md to include versioning strategy [6a39c85](https://github.com/google/adk-python/commit/6a39c854e032bda3bc15f0e4fe159b41cf2f474b)
|
||||
* Add tenacity into project.toml [df141db](https://github.com/google/adk-python/commit/df141db60c1137a6bcddd6d46aad3dc506868543)
|
||||
* Updating CONTRIBUTING.md with missing extra [e153d07](https://github.com/google/adk-python/commit/e153d075939fb628a7dc42b12e1b3461842db541)
|
||||
|
||||
## [1.5.0](https://github.com/google/adk-python/compare/v1.4.2...v1.5.0) (2025-06-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add a new option `eval_storage_uri` in adk web & adk eval to specify GCS bucket to store eval data ([fa025d7](https://github.com/google/adk-python/commit/fa025d755978e1506fa0da1fecc49775bebc1045))
|
||||
* Add ADK examples for litellm with add_function_to_prompt ([f33e090](https://github.com/google/adk-python/commit/f33e0903b21b752168db3006dd034d7d43f7e84d))
|
||||
* Add implementation of VertexAiMemoryBankService and support in FastAPI endpoint ([abc89d2](https://github.com/google/adk-python/commit/abc89d2c811ba00805f81b27a3a07d56bdf55a0b))
|
||||
* Add rouge_score library to ADK eval dependencies, and implement RougeEvaluator that is computes ROUGE-1 for "response_match_score" metric ([9597a44](https://github.com/google/adk-python/commit/9597a446fdec63ad9e4c2692d6966b14f80ff8e2))
|
||||
* Add usage span attributes to telemetry ([#356](https://github.com/google/adk-python/issues/356)) ([ea69c90](https://github.com/google/adk-python/commit/ea69c9093a16489afdf72657136c96f61c69cafd))
|
||||
* Add Vertex Express mode compatibility for VertexAiSessionService ([00cc8cd](https://github.com/google/adk-python/commit/00cc8cd6433fc45ecfc2dbaa04dbbc1a81213b4d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Include current turn context when include_contents='none' ([9e473e0](https://github.com/google/adk-python/commit/9e473e0abdded24e710fd857782356c15d04b515))
|
||||
* Make LiteLLM streaming truly asynchronous ([bd67e84](https://github.com/google/adk-python/commit/bd67e8480f6e8b4b0f8c22b94f15a8cda1336339))
|
||||
* Make raw_auth_credential and exchanged_auth_credential optional given their default value is None ([acbdca0](https://github.com/google/adk-python/commit/acbdca0d8400e292ba5525931175e0d6feab15f1))
|
||||
* Minor typo fix in the agent instruction ([ef3c745](https://github.com/google/adk-python/commit/ef3c745d655538ebd1ed735671be615f842341a8))
|
||||
* Typo fix in sample agent instruction ([ef3c745](https://github.com/google/adk-python/commit/ef3c745d655538ebd1ed735671be615f842341a8))
|
||||
* Update contributing links ([a1e1441](https://github.com/google/adk-python/commit/a1e14411159fd9f3e114e15b39b4949d0fd6ecb1))
|
||||
* Use starred tuple unpacking on GCS artifact blob names ([3b1d9a8](https://github.com/google/adk-python/commit/3b1d9a8a3e631ca2d86d30f09640497f1728986c))
|
||||
|
||||
|
||||
### Chore
|
||||
|
||||
* Do not send api request when session does not have events ([88a4402](https://github.com/google/adk-python/commit/88a4402d142672171d0a8ceae74671f47fa14289))
|
||||
* Leverage official uv action for install([09f1269](https://github.com/google/adk-python/commit/09f1269bf7fa46ab4b9324e7f92b4f70ffc923e5))
|
||||
* Update google-genai package and related deps to latest([ed7a21e](https://github.com/google/adk-python/commit/ed7a21e1890466fcdf04f7025775305dc71f603d))
|
||||
* Add credential service backed by session state([29cd183](https://github.com/google/adk-python/commit/29cd183aa1b47dc4f5d8afe22f410f8546634abc))
|
||||
* Clarify the behavior of Event.invocation_id([f033e40](https://github.com/google/adk-python/commit/f033e405c10ff8d86550d1419a9d63c0099182f9))
|
||||
* Send user message to the agent that returned a corresponding function call if user message is a function response([7c670f6](https://github.com/google/adk-python/commit/7c670f638bc17374ceb08740bdd057e55c9c2e12))
|
||||
* Add request converter to convert a2a request to ADK request([fb13963](https://github.com/google/adk-python/commit/fb13963deda0ff0650ac27771711ea0411474bf5))
|
||||
* Support allow_origins in cloud_run deployment ([2fd8feb](https://github.com/google/adk-python/commit/2fd8feb65d6ae59732fb3ec0652d5650f47132cc))
|
||||
|
||||
## [1.4.2](https://github.com/google/adk-python/compare/v1.4.1...v1.4.2) (2025-06-20)
|
||||
|
||||
|
||||
|
||||
+5
-4
@@ -49,6 +49,7 @@ This project follows
|
||||
|
||||
## Requirement for PRs
|
||||
|
||||
- Each PR should only have one commit. Please squash it if there are multiple 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.
|
||||
@@ -147,11 +148,11 @@ For any changes that impact user-facing documentation (guides, API reference, tu
|
||||
pytest ./tests/unittests
|
||||
```
|
||||
|
||||
NOTE: for accurately repro test failure, only include `test` and `eval` as
|
||||
extra dependencies.
|
||||
NOTE: for accurate repro of test failure, only include `test`, `eval` and
|
||||
`a2a` as extra dependencies.
|
||||
|
||||
```shell
|
||||
uv sync --extra test --extra eval
|
||||
uv sync --extra test --extra eval --extra a2a
|
||||
pytest ./tests/unittests
|
||||
```
|
||||
|
||||
@@ -200,7 +201,7 @@ For any changes that impact user-facing documentation (guides, API reference, tu
|
||||
|
||||
## Contributing Resources
|
||||
|
||||
[Contributing folder](https://github.com/google/adk-python/tree/main/contributing/samples) has resources that is helpful for contributors.
|
||||
[Contributing folder](https://github.com/google/adk-python/tree/main/contributing) has resources that is helpful for contributors.
|
||||
|
||||
|
||||
## Code reviews
|
||||
|
||||
@@ -45,7 +45,7 @@ Agent Development Kit (ADK) is a flexible and modular framework for developing a
|
||||
|
||||
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)
|
||||
See this [example](https://github.com/a2aproject/a2a-samples/tree/main/samples/python/agents)
|
||||
for how they can work together.
|
||||
|
||||
## 🚀 Installation
|
||||
@@ -135,7 +135,7 @@ adk eval \
|
||||
## 🤝 Contributing
|
||||
|
||||
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).
|
||||
- [General contribution guideline and flow](https://google.github.io/adk-docs/contributing-guide/).
|
||||
- Then if you want to contribute code, please read [Code Contributing Guidelines](./CONTRIBUTING.md) to get started.
|
||||
|
||||
## 📄 License
|
||||
|
||||
@@ -7,3 +7,10 @@ This folder host resources for ADK contributors, for example, testing samples et
|
||||
Samples folder host samples to test different features. The samples are usually minimal and simplistic to test one or a few scenarios.
|
||||
|
||||
**Note**: This is different from the [google/adk-samples](https://github.com/google/adk-samples) repo, which hosts more complex e2e samples for customers to use or modify directly.
|
||||
|
||||
## ADK project and architecture overview
|
||||
|
||||
The [adk_project_overview_and_architecture.md](adk_project_overview_and_architecture.md) describes the ADK project overview and its technical architecture from high-level.
|
||||
|
||||
This is helpful for contributors to understand the project and design philosophy.
|
||||
It can also be feed into LLMs for vibe-coding.
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# ADK Project Overview and Architecture
|
||||
|
||||
Google Agent Development Kit (ADK) for Python
|
||||
|
||||
## Core Philosophy & Architecture
|
||||
|
||||
- Code-First: Everything is defined in Python code for versioning, testing, and IDE support. Avoid GUI-based logic.
|
||||
|
||||
- Modularity & Composition: We build complex multi-agent systems by composing multiple, smaller, specialized agents.
|
||||
|
||||
- Deployment-Agnostic: The agent's core logic is separate from its deployment environment. The same agent.py can be run locally for testing, served via an API, or deployed to the cloud.
|
||||
|
||||
## Foundational Abstractions (Our Vocabulary)
|
||||
|
||||
- Agent: The blueprint. It defines an agent's identity, instructions, and tools. It's a declarative configuration object.
|
||||
|
||||
- Tool: A capability. A Python function an agent can call to interact with the world (e.g., search, API call).
|
||||
|
||||
- Runner: The engine. It orchestrates the "Reason-Act" loop, manages LLM calls, and executes tools.
|
||||
|
||||
- Session: The conversation state. It holds the history for a single, continuous dialogue.
|
||||
|
||||
- Memory: Long-term recall across different sessions.
|
||||
|
||||
- Artifact Service: Manages non-textual data like files.
|
||||
|
||||
## Canonical Project Structure
|
||||
|
||||
Adhere to this structure for compatibility with ADK tooling.
|
||||
|
||||
my_adk_project/ \
|
||||
└── src/ \
|
||||
└── my_app/ \
|
||||
├── agents/ \
|
||||
│ ├── my_agent/ \
|
||||
│ │ ├── __init__.py # Must contain: from. import agent \
|
||||
│ │ └── agent.py # Must contain: root_agent = Agent(...) \
|
||||
│ └── another_agent/ \
|
||||
│ ├── __init__.py \
|
||||
│ └── agent.py\
|
||||
|
||||
agent.py: Must define the agent and assign it to a variable named root_agent. This is how ADK's tools find it.
|
||||
|
||||
__init__.py: In each agent directory, it must contain from. import agent to make the agent discoverable.
|
||||
|
||||
## Local Development & Debugging
|
||||
|
||||
Interactive UI (adk web): This is our primary debugging tool. It's a decoupled system:
|
||||
|
||||
Backend: A FastAPI server started with adk api_server.
|
||||
|
||||
Frontend: An Angular app that connects to the backend.
|
||||
|
||||
Use the "Events" tab to inspect the full execution trace (prompts, tool calls, responses).
|
||||
|
||||
CLI (adk run): For quick, stateless functional checks in the terminal.
|
||||
|
||||
Programmatic (pytest): For writing automated unit and integration tests.
|
||||
|
||||
## The API Layer (FastAPI)
|
||||
|
||||
We expose agents as production APIs using FastAPI.
|
||||
|
||||
- get_fast_api_app: This is the key helper function from google.adk.cli.fast_api that creates a FastAPI app from our agent directory.
|
||||
|
||||
- Standard Endpoints: The generated app includes standard routes like /list-apps and /run_sse for streaming responses. The wire format is camelCase.
|
||||
|
||||
- Custom Endpoints: We can add our own routes (e.g., /health) to the app object returned by the helper.
|
||||
|
||||
Python
|
||||
|
||||
from google.adk.cli.fast_api import get_fast_api_app
|
||||
app = get_fast_api_app(agent_dir="./agents")
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
## Deployment to Production
|
||||
|
||||
The adk cli provides the "adk deploy" command to deploy to Google Vertex Agent Engine, Google CloudRun, Google GKE.
|
||||
|
||||
## Testing & Evaluation Strategy
|
||||
|
||||
Testing is layered, like a pyramid.
|
||||
|
||||
### Layer 1: Unit Tests (Base)
|
||||
|
||||
What: Test individual Tool functions in isolation.
|
||||
|
||||
How: Use pytest in tests/test_tools.py. Verify deterministic logic.
|
||||
|
||||
### Layer 2: Integration Tests (Middle)
|
||||
|
||||
What: Test the agent's internal logic and interaction with tools.
|
||||
|
||||
How: Use pytest in tests/test_agent.py, often with mocked LLMs or services.
|
||||
|
||||
### Layer 3: Evaluation Tests (Top)
|
||||
|
||||
What: Assess end-to-end performance with a live LLM. This is about quality, not just pass/fail.
|
||||
|
||||
How: Use the ADK Evaluation Framework.
|
||||
|
||||
Test Cases: Create JSON files with input and a reference (expected tool calls and final response).
|
||||
|
||||
Metrics: tool_trajectory_avg_score (does it use tools correctly?) and response_match_score (is the final answer good?).
|
||||
|
||||
Run via: adk web (UI), pytest (for CI/CD), or adk eval (CLI).
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
build_llms_txt.py – produce llms.txt and llms-full.txt
|
||||
– skips ```java``` blocks
|
||||
– README can be next to docs/ or inside docs/
|
||||
– includes Python API reference from HTML files
|
||||
– includes adk-python repository README
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from typing import List
|
||||
from typing import Tuple
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
RE_JAVA = re.compile(r"```java[ \t\r\n][\s\S]*?```", re.I | re.M)
|
||||
RE_SNIPPET = re.compile(r"^(\s*)--8<--\s+\"([^\"]+?)(?::([^\"]+))?\"$", re.M)
|
||||
|
||||
|
||||
def fetch_adk_python_readme() -> str:
|
||||
"""Fetch README content from adk-python repository"""
|
||||
try:
|
||||
url = "https://raw.githubusercontent.com/google/adk-python/main/README.md"
|
||||
with urllib.request.urlopen(url) as response:
|
||||
return response.read().decode("utf-8")
|
||||
except (urllib.error.URLError, urllib.error.HTTPError) as e:
|
||||
print(f"Warning: Could not fetch adk-python README: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def strip_java(md: str) -> str:
|
||||
return RE_JAVA.sub("", md)
|
||||
|
||||
|
||||
def first_heading(md: str) -> str | None:
|
||||
for line in md.splitlines():
|
||||
if line.startswith("#"):
|
||||
return line.lstrip("#").strip()
|
||||
return None
|
||||
|
||||
|
||||
def md_to_text(md: str) -> str:
|
||||
import bs4
|
||||
import markdown
|
||||
|
||||
html = markdown.markdown(
|
||||
md, extensions=["fenced_code", "tables", "attr_list"]
|
||||
)
|
||||
return bs4.BeautifulSoup(html, "html.parser").get_text("\n")
|
||||
|
||||
|
||||
def html_to_text(html_file: Path) -> str:
|
||||
"""Extract text content from HTML files (for Python API reference)"""
|
||||
import bs4
|
||||
|
||||
try:
|
||||
html_content = html_file.read_text(encoding="utf-8")
|
||||
soup = bs4.BeautifulSoup(html_content, "html.parser")
|
||||
|
||||
# Remove script and style elements
|
||||
for script in soup(["script", "style"]):
|
||||
script.decompose()
|
||||
|
||||
# Get text and clean it up
|
||||
text = soup.get_text()
|
||||
lines = (line.strip() for line in text.splitlines())
|
||||
chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
|
||||
text = "\n".join(chunk for chunk in chunks if chunk)
|
||||
|
||||
return text
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not process {html_file}: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def count_tokens(text: str, model: str = "cl100k_base") -> int:
|
||||
try:
|
||||
import tiktoken
|
||||
|
||||
return len(tiktoken.get_encoding(model).encode(text))
|
||||
except Exception:
|
||||
return len(text.split())
|
||||
|
||||
|
||||
def expand_code_snippets(content: str, project_root: Path) -> str:
|
||||
"""
|
||||
Expands code snippets marked with --8<-- "path/to/file.py" or
|
||||
--8<-- "path/to/file.py:section_name" into the content.
|
||||
"""
|
||||
|
||||
def replace_snippet(match):
|
||||
indent = match.group(1) # Capture leading spaces
|
||||
snippet_path_str = match.group(
|
||||
2
|
||||
) # Capture the file path (e.g., "examples/python/snippets/file.py")
|
||||
section_name = match.group(
|
||||
3
|
||||
) # Capture the section name if present (e.g., "init")
|
||||
snippet_full_path = (
|
||||
project_root / snippet_path_str
|
||||
) # Changed from base_path to project_root
|
||||
|
||||
# If not found in project root, try adk-docs directory
|
||||
if not snippet_full_path.exists():
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
adk_docs_path = script_dir / "adk-docs" / snippet_path_str
|
||||
if adk_docs_path.exists():
|
||||
snippet_full_path = adk_docs_path
|
||||
|
||||
if snippet_full_path.exists():
|
||||
try:
|
||||
file_content = snippet_full_path.read_text(encoding="utf-8")
|
||||
if section_name:
|
||||
# Extract content based on section markers
|
||||
# Handle both single and double hash markers with optional spacing
|
||||
start_marker_patterns = [
|
||||
f"# --8<-- [start:{section_name.strip()}]",
|
||||
f"## --8<-- [start:{section_name.strip()}]",
|
||||
]
|
||||
end_marker_patterns = [
|
||||
f"# --8<-- [end:{section_name.strip()}]",
|
||||
f"## --8<-- [end:{section_name.strip()}]",
|
||||
f"## --8<-- [end:{section_name.strip()}]", # Handle extra space
|
||||
]
|
||||
|
||||
start_index = -1
|
||||
end_index = -1
|
||||
|
||||
# Find start marker
|
||||
for pattern in start_marker_patterns:
|
||||
start_index = file_content.find(pattern)
|
||||
if start_index != -1:
|
||||
start_marker = pattern
|
||||
break
|
||||
|
||||
# Find end marker
|
||||
for pattern in end_marker_patterns:
|
||||
end_index = file_content.find(pattern)
|
||||
if end_index != -1:
|
||||
break
|
||||
|
||||
if start_index != -1 and end_index != -1 and start_index < end_index:
|
||||
# Adjust start_index to begin immediately after the start_marker
|
||||
start_of_code = start_index + len(start_marker)
|
||||
temp_content = file_content[start_of_code:end_index]
|
||||
lines = temp_content.splitlines(keepends=True)
|
||||
extracted_lines = []
|
||||
for line in lines:
|
||||
if (
|
||||
not line.strip().startswith("# --8<--")
|
||||
and not line.strip().startswith("## --8<--")
|
||||
and line.strip() != ""
|
||||
):
|
||||
extracted_lines.append(line)
|
||||
extracted_content = "".join(extracted_lines).strip("\n")
|
||||
|
||||
return textwrap.indent(extracted_content, indent)
|
||||
else:
|
||||
print(
|
||||
f"Warning: Section '{section_name}' not found or markers"
|
||||
f" malformed in {snippet_full_path}"
|
||||
)
|
||||
return match.group(0)
|
||||
else:
|
||||
# Read entire file if no section name
|
||||
return textwrap.indent(file_content, indent)
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not read snippet file {snippet_full_path}: {e}")
|
||||
return match.group(0)
|
||||
else:
|
||||
print(f"Warning: Snippet file not found: {snippet_full_path}")
|
||||
return match.group(0)
|
||||
|
||||
expanded_content = RE_SNIPPET.sub(replace_snippet, content)
|
||||
return expanded_content
|
||||
|
||||
|
||||
# ---------- index (llms.txt) ----------
|
||||
def build_index(docs: Path) -> str:
|
||||
# Locate README
|
||||
for cand in (docs / "README.md", docs.parent / "README.md"):
|
||||
if cand.exists():
|
||||
readme = cand.read_text(encoding="utf-8")
|
||||
break
|
||||
else:
|
||||
sys.exit("README.md not found in docs/ or its parent")
|
||||
|
||||
title = first_heading(readme) or "Documentation"
|
||||
summary = md_to_text(readme).split("\n\n")[0]
|
||||
lines = [f"# {title}", "", f"> {summary}", ""]
|
||||
|
||||
# Add adk-python repository README content
|
||||
adk_readme = fetch_adk_python_readme()
|
||||
if adk_readme:
|
||||
lines.append("## ADK Python Repository")
|
||||
lines.append("")
|
||||
# Include the full README content, properly formatted
|
||||
adk_text = md_to_text(strip_java(adk_readme))
|
||||
lines.append(adk_text)
|
||||
lines.append("")
|
||||
lines.append(
|
||||
f"**Source:** [adk-python"
|
||||
f" repository](https://github.com/google/adk-python)"
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
primary: List[Tuple[str, str]] = []
|
||||
secondary: List[Tuple[str, str]] = []
|
||||
|
||||
# Process Markdown files
|
||||
for md in sorted(docs.rglob("*.md")):
|
||||
# Skip Java API reference files
|
||||
if "api-reference" in md.parts and "java" in md.parts:
|
||||
continue
|
||||
|
||||
rel = md.relative_to(docs)
|
||||
# Construct the correct GitHub URL for the Markdown file
|
||||
url = f"https://github.com/google/adk-docs/blob/main/docs/{rel}".replace(
|
||||
" ", "%20"
|
||||
)
|
||||
h = first_heading(strip_java(md.read_text(encoding="utf-8"))) or rel.stem
|
||||
(
|
||||
secondary
|
||||
if "sample" in rel.parts or "tutorial" in rel.parts
|
||||
else primary
|
||||
).append((h, url))
|
||||
|
||||
# Add Python API reference
|
||||
python_api_dir = docs / "api-reference" / "python"
|
||||
if python_api_dir.exists():
|
||||
primary.append((
|
||||
"Python API Reference",
|
||||
"https://github.com/google/adk-docs/blob/main/docs/api-reference/python/",
|
||||
))
|
||||
|
||||
def emit(name: str, items: List[Tuple[str, str]]):
|
||||
nonlocal lines
|
||||
if items:
|
||||
lines.append(f"## {name}")
|
||||
lines += [f"- [{h}]({u})" for h, u in items]
|
||||
lines.append("")
|
||||
|
||||
emit("Documentation", primary)
|
||||
emit("Optional", secondary)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ---------- full corpus ----------
|
||||
def build_full(docs: Path) -> str:
|
||||
out = []
|
||||
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
project_root = script_dir.parents[2] # Correct project root
|
||||
print(f"DEBUG: Project Root: {project_root}")
|
||||
print(f"DEBUG: Docs Dir: {docs}")
|
||||
|
||||
# Add adk-python repository README content at the beginning
|
||||
adk_readme = fetch_adk_python_readme()
|
||||
if adk_readme:
|
||||
# Expand snippets in README if any
|
||||
expanded_adk_readme = expand_code_snippets(
|
||||
strip_java(adk_readme), project_root
|
||||
) # Pass project_root
|
||||
out.append("# ADK Python Repository")
|
||||
out.append("")
|
||||
out.append(expanded_adk_readme) # Use expanded content
|
||||
out.append("")
|
||||
out.append("---")
|
||||
out.append("")
|
||||
|
||||
# Process Markdown files
|
||||
for md in sorted(docs.rglob("*.md")):
|
||||
# Skip Java API reference files
|
||||
if "api-reference" in md.parts and "java" in md.parts:
|
||||
continue
|
||||
|
||||
md_content = md.read_text(encoding="utf-8")
|
||||
print(f"DEBUG: Processing markdown file: {md.relative_to(docs)}")
|
||||
expanded_md_content = expand_code_snippets(
|
||||
strip_java(md_content), project_root
|
||||
) # Changed back to project_root
|
||||
out.append(expanded_md_content) # Use expanded content
|
||||
|
||||
# Process Python API reference HTML files
|
||||
python_api_dir = docs / "api-reference" / "python"
|
||||
if python_api_dir.exists():
|
||||
# Add a separator and header for Python API reference
|
||||
out.append("\n\n# Python API Reference\n")
|
||||
|
||||
# Process main HTML files (skip static assets and generated files)
|
||||
html_files = [
|
||||
python_api_dir / "index.html",
|
||||
python_api_dir / "google-adk.html",
|
||||
python_api_dir / "genindex.html",
|
||||
python_api_dir / "py-modindex.html",
|
||||
]
|
||||
|
||||
for html_file in html_files:
|
||||
if html_file.exists():
|
||||
text = html_to_text(html_file)
|
||||
if text.strip():
|
||||
out.append(f"\n## {html_file.stem}\n")
|
||||
out.append(text)
|
||||
|
||||
return "\n\n".join(out)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(
|
||||
description="Generate llms.txt / llms-full.txt",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
ap.add_argument("--docs-dir", required=True, type=Path)
|
||||
ap.add_argument("--out-root", default=Path("."), type=Path)
|
||||
ap.add_argument("--index-limit", type=int, default=50_000)
|
||||
ap.add_argument("--full-limit", type=int, default=500_000)
|
||||
args = ap.parse_args()
|
||||
|
||||
idx, full = build_index(args.docs_dir), build_full(args.docs_dir)
|
||||
if (tok := count_tokens(idx)) > args.index_limit:
|
||||
sys.exit(f"Index too big: {tok:,}")
|
||||
if (tok := count_tokens(full)) > args.full_limit:
|
||||
sys.exit(f"Full text too big: {tok:,}")
|
||||
|
||||
(args.out_root / "llms.txt").write_text(idx, encoding="utf-8")
|
||||
(args.out_root / "llms-full.txt").write_text(full, encoding="utf-8")
|
||||
print("✅ Generated llms.txt and llms-full.txt successfully")
|
||||
print(f"llms.txt tokens: {count_tokens(idx)}")
|
||||
print(f"llms-full.txt tokens: {count_tokens(full)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,183 @@
|
||||
# A2A OAuth Authentication Sample Agent
|
||||
|
||||
This sample demonstrates the **Agent-to-Agent (A2A)** architecture with **OAuth Authentication** workflows in the Agent Development Kit (ADK). The sample implements a multi-agent system where a remote agent can surface OAuth authentication requests to the local agent, which then guides the end user through the OAuth flow before returning the authentication credentials to the remote agent for API access.
|
||||
|
||||
## Overview
|
||||
|
||||
The A2A OAuth Authentication sample consists of:
|
||||
|
||||
- **Root Agent** (`root_agent`): The main orchestrator that handles user requests and delegates tasks to specialized agents
|
||||
- **YouTube Search Agent** (`youtube_search_agent`): A local agent that handles YouTube video searches using LangChain tools
|
||||
- **BigQuery Agent** (`bigquery_agent`): A remote A2A agent that manages BigQuery operations and requires OAuth authentication for Google Cloud access
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌────────────────────┐ ┌──────────────────┐
|
||||
│ End User │───▶│ Root Agent │───▶│ BigQuery Agent │
|
||||
│ (OAuth Flow) │ │ (Local) │ │ (Remote A2A) │
|
||||
│ │ │ │ │ (localhost:8001) │
|
||||
│ OAuth UI │◀───│ │◀───│ OAuth Request │
|
||||
└─────────────────┘ └────────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. **Multi-Agent Architecture**
|
||||
- Root agent coordinates between local YouTube search and remote BigQuery operations
|
||||
- Demonstrates hybrid local/remote agent workflows
|
||||
- Seamless task delegation based on user request types
|
||||
|
||||
### 2. **OAuth Authentication Workflow**
|
||||
- Remote BigQuery agent surfaces OAuth authentication requests to the root agent
|
||||
- Root agent guides end users through Google OAuth flow for BigQuery access
|
||||
- Secure token exchange between agents for authenticated API calls
|
||||
|
||||
### 3. **Google Cloud Integration**
|
||||
- BigQuery toolset with comprehensive dataset and table management capabilities
|
||||
- OAuth-protected access to user's Google Cloud BigQuery resources
|
||||
- Support for listing, creating, and managing datasets and tables
|
||||
|
||||
### 4. **LangChain Tool Integration**
|
||||
- YouTube search functionality using LangChain community tools
|
||||
- Demonstrates integration of third-party tools in agent workflows
|
||||
|
||||
## Setup and Usage
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Set up OAuth Credentials**:
|
||||
```bash
|
||||
export OAUTH_CLIENT_ID=your_google_oauth_client_id
|
||||
export OAUTH_CLIENT_SECRET=your_google_oauth_client_secret
|
||||
```
|
||||
|
||||
2. **Start the Remote BigQuery Agent server**:
|
||||
```bash
|
||||
# Start the remote a2a server that serves the BigQuery agent on port 8001
|
||||
adk api_server --a2a --port 8001 contributing/samples/a2a_auth/remote_a2a
|
||||
```
|
||||
|
||||
3. **Run the Main Agent**:
|
||||
```bash
|
||||
# In a separate terminal, run the adk web server
|
||||
adk web contributing/samples/
|
||||
```
|
||||
|
||||
### Example Interactions
|
||||
|
||||
Once both services are running, you can interact with the root agent:
|
||||
|
||||
**YouTube Search (No Authentication Required):**
|
||||
```
|
||||
User: Search for 3 Taylor Swift music videos
|
||||
Agent: I'll help you search for Taylor Swift music videos on YouTube.
|
||||
[Agent delegates to YouTube Search Agent]
|
||||
Agent: I found 3 Taylor Swift music videos:
|
||||
1. "Anti-Hero" - Official Music Video
|
||||
2. "Shake It Off" - Official Music Video
|
||||
3. "Blank Space" - Official Music Video
|
||||
```
|
||||
|
||||
**BigQuery Operations (OAuth Required):**
|
||||
```
|
||||
User: List my BigQuery datasets
|
||||
Agent: I'll help you access your BigQuery datasets. This requires authentication with your Google account.
|
||||
[Agent delegates to BigQuery Agent]
|
||||
Agent: To access your BigQuery data, please complete the OAuth authentication.
|
||||
[OAuth flow initiated - user redirected to Google authentication]
|
||||
User: [Completes OAuth flow in browser]
|
||||
Agent: Authentication successful! Here are your BigQuery datasets:
|
||||
- dataset_1: Customer Analytics
|
||||
- dataset_2: Sales Data
|
||||
- dataset_3: Marketing Metrics
|
||||
```
|
||||
|
||||
**Dataset Management:**
|
||||
```
|
||||
User: Show me details for my Customer Analytics dataset
|
||||
Agent: I'll get the details for your Customer Analytics dataset.
|
||||
[Using existing OAuth token]
|
||||
Agent: Customer Analytics Dataset Details:
|
||||
- Created: 2024-01-15
|
||||
- Location: US
|
||||
- Tables: 5
|
||||
- Description: Customer behavior and analytics data
|
||||
```
|
||||
|
||||
## Code Structure
|
||||
|
||||
### Main Agent (`agent.py`)
|
||||
|
||||
- **`youtube_search_agent`**: Local agent with LangChain YouTube search tool
|
||||
- **`bigquery_agent`**: Remote A2A agent configuration for BigQuery operations
|
||||
- **`root_agent`**: Main orchestrator with task delegation logic
|
||||
|
||||
### Remote BigQuery Agent (`remote_a2a/bigquery_agent/`)
|
||||
|
||||
- **`agent.py`**: Implementation of the BigQuery agent with OAuth toolset
|
||||
- **`agent.json`**: Agent card of the A2A agent
|
||||
- **`BigQueryToolset`**: OAuth-enabled tools for BigQuery dataset and table management
|
||||
|
||||
## OAuth Authentication Workflow
|
||||
|
||||
The OAuth authentication process follows this pattern:
|
||||
|
||||
1. **Initial Request**: User requests BigQuery operation through root agent
|
||||
2. **Delegation**: Root agent delegates to remote BigQuery agent
|
||||
3. **Auth Check**: BigQuery agent checks for valid OAuth token
|
||||
4. **Auth Request**: If no token, agent surfaces OAuth request to root agent
|
||||
5. **User OAuth**: Root agent guides user through Google OAuth flow
|
||||
6. **Token Exchange**: Root agent sends OAuth token to BigQuery agent
|
||||
7. **API Call**: BigQuery agent uses token to make authenticated API calls
|
||||
8. **Result Return**: BigQuery agent returns results through root agent to user
|
||||
|
||||
## Supported BigQuery Operations
|
||||
|
||||
The BigQuery agent supports the following operations:
|
||||
|
||||
### Dataset Operations:
|
||||
- **List Datasets**: `bigquery_datasets_list` - Get all user's datasets
|
||||
- **Get Dataset**: `bigquery_datasets_get` - Get specific dataset details
|
||||
- **Create Dataset**: `bigquery_datasets_insert` - Create new dataset
|
||||
|
||||
### Table Operations:
|
||||
- **List Tables**: `bigquery_tables_list` - Get tables in a dataset
|
||||
- **Get Table**: `bigquery_tables_get` - Get specific table details
|
||||
- **Create Table**: `bigquery_tables_insert` - Create new table in dataset
|
||||
|
||||
## Extending the Sample
|
||||
|
||||
You can extend this sample by:
|
||||
|
||||
- Adding more Google Cloud services (Cloud Storage, Compute Engine, etc.)
|
||||
- Implementing token refresh and expiration handling
|
||||
- Adding role-based access control for different BigQuery operations
|
||||
- Creating OAuth flows for other providers (Microsoft, Facebook, etc.)
|
||||
- Adding audit logging for authentication events
|
||||
- Implementing multi-tenant OAuth token management
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Connection Issues:**
|
||||
- Ensure the local ADK web server is running on port 8000
|
||||
- Ensure the remote A2A server is running on port 8001
|
||||
- Check that no firewall is blocking localhost connections
|
||||
- Verify the agent.json URL matches the running A2A server
|
||||
|
||||
**OAuth Issues:**
|
||||
- Verify OAuth client ID and secret are correctly set in .env file
|
||||
- Ensure OAuth redirect URIs are properly configured in Google Cloud Console
|
||||
- Check that the OAuth scopes include BigQuery access permissions
|
||||
- Verify the user has access to the BigQuery projects/datasets
|
||||
|
||||
**BigQuery Access Issues:**
|
||||
- Ensure the authenticated user has BigQuery permissions
|
||||
- Check that the Google Cloud project has BigQuery API enabled
|
||||
- Verify dataset and table names are correct and accessible
|
||||
- Check for quota limits on BigQuery API calls
|
||||
|
||||
**Agent Communication Issues:**
|
||||
- Check the logs for both the local ADK web server and remote A2A server
|
||||
- Verify OAuth tokens are properly passed between agents
|
||||
- Ensure agent instructions are clear about authentication requirements
|
||||
@@ -0,0 +1,62 @@
|
||||
# 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.adk.agents import Agent
|
||||
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
||||
from google.adk.tools.langchain_tool import LangchainTool
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
|
||||
# Instantiate the tool
|
||||
langchain_yt_tool = YouTubeSearchTool()
|
||||
|
||||
# Wrap the tool in the LangchainTool class from ADK
|
||||
adk_yt_tool = LangchainTool(
|
||||
tool=langchain_yt_tool,
|
||||
)
|
||||
|
||||
youtube_search_agent = Agent(
|
||||
name="youtube_search_agent",
|
||||
model="gemini-2.0-flash", # Replace with the actual model name
|
||||
instruction="""
|
||||
Ask customer to provide singer name, and the number of videos to search.
|
||||
""",
|
||||
description="Help customer to search for a video on Youtube.",
|
||||
tools=[adk_yt_tool],
|
||||
output_key="youtube_search_output",
|
||||
)
|
||||
|
||||
bigquery_agent = RemoteA2aAgent(
|
||||
name="bigquery_agent",
|
||||
description="Help customer to manage notion workspace.",
|
||||
agent_card=(
|
||||
"http://localhost:8001/a2a/bigquery_agent/.well-known/agent.json"
|
||||
),
|
||||
)
|
||||
|
||||
root_agent = Agent(
|
||||
model="gemini-2.0-flash",
|
||||
name="root_agent",
|
||||
instruction="""
|
||||
You are a helpful assistant that can help search youtube videos, look up BigQuery datasets and tables.
|
||||
You delegate youtube search tasks to the youtube_search_agent.
|
||||
You delegate BigQuery tasks to the bigquery_agent.
|
||||
Always clarify the results before proceeding.
|
||||
""",
|
||||
global_instruction=(
|
||||
"You are a helpful assistant that can help search youtube videos, look"
|
||||
" up BigQuery datasets and tables."
|
||||
),
|
||||
sub_agents=[youtube_search_agent, bigquery_agent],
|
||||
)
|
||||
Executable → Regular
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"capabilities": {},
|
||||
"defaultInputModes": ["text/plain"],
|
||||
"defaultOutputModes": ["application/json"],
|
||||
"description": "A Google BigQuery agent that helps manage users' data on Google BigQuery. Can list, get, and create datasets, as well as manage tables within datasets. Supports OAuth authentication for secure access to BigQuery resources.",
|
||||
"name": "bigquery_agent",
|
||||
"skills": [
|
||||
{
|
||||
"id": "dataset_management",
|
||||
"name": "Dataset Management",
|
||||
"description": "List, get details, and create BigQuery datasets",
|
||||
"tags": ["bigquery", "datasets", "google-cloud"]
|
||||
},
|
||||
{
|
||||
"id": "table_management",
|
||||
"name": "Table Management",
|
||||
"description": "List, get details, and create BigQuery tables within datasets",
|
||||
"tags": ["bigquery", "tables", "google-cloud"]
|
||||
},
|
||||
{
|
||||
"id": "oauth_authentication",
|
||||
"name": "OAuth Authentication",
|
||||
"description": "Secure authentication with Google BigQuery using OAuth",
|
||||
"tags": ["authentication", "oauth", "security"]
|
||||
}
|
||||
],
|
||||
"url": "http://localhost:8000/a2a/bigquery_agent",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user