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
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| 8677d5c8dc | |||
| 4d72d31b13 | |||
| 742478fdb7 | |||
| ffcba70686 | |||
| 2f716ada7f | |||
| 17beb32880 | |||
| 7f8dc8927a | |||
| 9a1115c504 | |||
| 913d771d6d | |||
| 58e07cae83 | |||
| 157d9be88d | |||
| 18a541c8fa | |||
| dcea7767c6 | |||
| 2c739ab581 | |||
| 9a207cb832 | |||
| a17ebe6ebd | |||
| 55201cb6a1 | |||
| 0a9625317a | |||
| f9fa7841df | |||
| 5f89a469ec | |||
| 6d174eba30 | |||
| c04adaade1 | |||
| 1ae176ad2f | |||
| 694b71256c | |||
| e1812797ad | |||
| c755cf23c5 | |||
| 94caccc148 | |||
| 476805d5b9 | |||
| e2a81365ec | |||
| 28dfcd2512 | |||
| a6b1baa61b | |||
| e384fa4ad7 | |||
| aafa80bd85 | |||
| 4bda245171 | |||
| 31b81a342d | |||
| fef8778429 | |||
| fe1d5aa439 | |||
| 8201f9aebd | |||
| 1cfc555e70 | |||
| badbcbd7a4 | |||
| 675faefc67 | |||
| a4d432a9e6 | |||
| d1bda9d946 | |||
| a19d617ed8 | |||
| 8ebf229c47 | |||
| b51a1f45fd | |||
| 8932106246 | |||
| 233fd20243 | |||
| d129fd636b | |||
| 131957c531 | |||
| 8e285874da | |||
| cb55970969 | |||
| 40b15ad278 | |||
| dbdeb49090 | |||
| 177980106b | |||
| c5b063f1ff | |||
| 313f1b0913 | |||
| b2fc7740b3 | |||
| 29e4ca9152 | |||
| 4ccda99e8e | |||
| d22920bd7f | |||
| 2ff9b1f639 | |||
| 0a5cf45a75 | |||
| 1551bd4f4d | |||
| bbceb4f2e8 | |||
| b08bdbcd7f | |||
| fc65873d7c | |||
| a7ea374dfb |
@@ -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.
|
||||
|
||||
@@ -36,18 +36,26 @@ 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: |
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv sync --extra test --extra eval
|
||||
uv sync --extra test --extra eval --extra a2a
|
||||
|
||||
- name: Run unit tests with pytest
|
||||
run: |
|
||||
source .venv/bin/activate
|
||||
pytest tests/unittests \
|
||||
--ignore=tests/unittests/artifacts/test_artifact_service.py \
|
||||
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
|
||||
if [[ "${{ matrix.python-version }}" == "3.9" ]]; then
|
||||
pytest tests/unittests \
|
||||
--ignore=tests/unittests/a2a \
|
||||
--ignore=tests/unittests/tools/mcp_tool \
|
||||
--ignore=tests/unittests/artifacts/test_artifact_service.py \
|
||||
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
|
||||
else
|
||||
pytest tests/unittests \
|
||||
--ignore=tests/unittests/artifacts/test_artifact_service.py \
|
||||
--ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
|
||||
fi
|
||||
@@ -0,0 +1,43 @@
|
||||
name: ADK Issue Triaging Agent
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
schedule:
|
||||
- cron: '0 */6 * * *' # every 6h
|
||||
|
||||
jobs:
|
||||
agent-triage-issues:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install requests google-adk
|
||||
|
||||
- name: Run Triaging Script
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GOOGLE_GENAI_USE_VERTEXAI: 0
|
||||
OWNER: 'google'
|
||||
REPO: 'adk-python'
|
||||
INTERACTIVE: 0
|
||||
EVENT_NAME: ${{ github.event_name }} # 'issues', 'schedule', etc.
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
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
|
||||
@@ -82,6 +82,7 @@ log/
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
uv.lock
|
||||
|
||||
# Google Cloud specific
|
||||
.gcloudignore
|
||||
|
||||
@@ -1,5 +1,84 @@
|
||||
# Changelog
|
||||
|
||||
## [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add type checking to handle different response type of genai API client ([4d72d31](https://github.com/google/adk-python/commit/4d72d31b13f352245baa72b78502206dcbe25406))
|
||||
* This fixes the broken VertexAiSessionService
|
||||
* Allow more credentials types for BigQuery tools ([2f716ad](https://github.com/google/adk-python/commit/2f716ada7fbcf8e03ff5ae16ce26a80ca6fd7bf6))
|
||||
|
||||
## [1.4.1](https://github.com/google/adk-python/compare/v1.3.0...v1.4.1) (2025-06-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add Authenticated Tool (Experimental) ([dcea776](https://github.com/google/adk-python/commit/dcea7767c67c7edfb694304df32dca10b74c9a71))
|
||||
* Add enable_affective_dialog and proactivity to run_config and llm_request ([fe1d5aa](https://github.com/google/adk-python/commit/fe1d5aa439cc56b89d248a52556c0a9b4cbd15e4))
|
||||
* Add import session API in the fast API ([233fd20](https://github.com/google/adk-python/commit/233fd2024346abd7f89a16c444de0cf26da5c1a1))
|
||||
* Add integration tests for litellm with and without turning on add_function_to_prompt ([8e28587](https://github.com/google/adk-python/commit/8e285874da7f5188ea228eb4d7262dbb33b1ae6f))
|
||||
* Allow data_store_specs pass into ADK VAIS built-in tool ([675faef](https://github.com/google/adk-python/commit/675faefc670b5cd41991939fe0fc604df331111a))
|
||||
* Enable MCP Tool Auth (Experimental) ([157d9be](https://github.com/google/adk-python/commit/157d9be88d92f22320604832e5a334a6eb81e4af))
|
||||
* Implement GcsEvalSetResultsManager to handle storage of eval sets on GCS, and refactor eval set results manager ([0a5cf45](https://github.com/google/adk-python/commit/0a5cf45a75aca7b0322136b65ca5504a0c3c7362))
|
||||
* Re-factor some eval sets manager logic, and implement GcsEvalSetsManager to handle storage of eval sets on GCS ([1551bd4](https://github.com/google/adk-python/commit/1551bd4f4d7042fffb497d9308b05f92d45d818f))
|
||||
* Support real time input config ([d22920b](https://github.com/google/adk-python/commit/d22920bd7f827461afd649601326b0c58aea6716))
|
||||
* Support refresh access token automatically for rest_api_tool ([1779801](https://github.com/google/adk-python/commit/177980106b2f7be9a8c0a02f395ff0f85faa0c5a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix Agent generate config err ([#1305](https://github.com/google/adk-python/issues/1305)) ([badbcbd](https://github.com/google/adk-python/commit/badbcbd7a464e6b323cf3164d2bcd4e27cbc057f))
|
||||
* Fix Agent generate config error ([#1450](https://github.com/google/adk-python/issues/1450)) ([694b712](https://github.com/google/adk-python/commit/694b71256c631d44bb4c4488279ea91d82f43e26))
|
||||
* Fix liteLLM test failures ([fef8778](https://github.com/google/adk-python/commit/fef87784297b806914de307f48c51d83f977298f))
|
||||
* Fix tracing for live ([58e07ca](https://github.com/google/adk-python/commit/58e07cae83048d5213d822be5197a96be9ce2950))
|
||||
* Merge custom http options with adk specific http options in model api request ([4ccda99](https://github.com/google/adk-python/commit/4ccda99e8ec7aa715399b4b83c3f101c299a95e8))
|
||||
* Remove unnecessary double quote on Claude docstring ([bbceb4f](https://github.com/google/adk-python/commit/bbceb4f2e89f720533b99cf356c532024a120dc4))
|
||||
* Set explicit project in the BigQuery client ([6d174eb](https://github.com/google/adk-python/commit/6d174eba305a51fcf2122c0fd481378752d690ef))
|
||||
* Support streaming in litellm + adk and add corresponding integration tests ([aafa80b](https://github.com/google/adk-python/commit/aafa80bd85a49fb1c1a255ac797587cffd3fa567))
|
||||
* Support project-based gemini model path to use google_search_tool ([b2fc774](https://github.com/google/adk-python/commit/b2fc7740b363a4e33ec99c7377f396f5cee40b5a))
|
||||
* Update conversion between Celsius and Fahrenheit ([1ae176a](https://github.com/google/adk-python/commit/1ae176ad2fa2b691714ac979aec21f1cf7d35e45))
|
||||
|
||||
### Chores
|
||||
|
||||
* Set `agent_engine_id` in the VertexAiSessionService constructor, also use the `agent_engine_id` field instead of overriding `app_name` in FastAPI endpoint ([fc65873](https://github.com/google/adk-python/commit/fc65873d7c31be607f6cd6690f142a031631582a))
|
||||
|
||||
|
||||
|
||||
## [1.3.0](https://github.com/google/adk-python/compare/v1.2.1...v1.3.0) (2025-06-11)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -200,7 +200,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
# 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 pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from adk_issue_formatting_agent.settings import GITHUB_BASE_URL
|
||||
from adk_issue_formatting_agent.settings import IS_INTERACTIVE
|
||||
from adk_issue_formatting_agent.settings import OWNER
|
||||
from adk_issue_formatting_agent.settings import REPO
|
||||
from adk_issue_formatting_agent.utils import error_response
|
||||
from adk_issue_formatting_agent.utils import get_request
|
||||
from adk_issue_formatting_agent.utils import post_request
|
||||
from adk_issue_formatting_agent.utils import read_file
|
||||
from google.adk import Agent
|
||||
import requests
|
||||
|
||||
BUG_REPORT_TEMPLATE = read_file(
|
||||
Path(__file__).parent / "../../../../.github/ISSUE_TEMPLATE/bug_report.md"
|
||||
)
|
||||
FREATURE_REQUEST_TEMPLATE = read_file(
|
||||
Path(__file__).parent
|
||||
/ "../../../../.github/ISSUE_TEMPLATE/feature_request.md"
|
||||
)
|
||||
|
||||
APPROVAL_INSTRUCTION = (
|
||||
"**Do not** wait or ask for user approval or confirmation for adding the"
|
||||
" comment."
|
||||
)
|
||||
if IS_INTERACTIVE:
|
||||
APPROVAL_INSTRUCTION = (
|
||||
"Ask for user approval or confirmation for adding the comment."
|
||||
)
|
||||
|
||||
|
||||
def list_open_issues(issue_count: int) -> dict[str, Any]:
|
||||
"""List most recent `issue_count` numer of open issues in the repo.
|
||||
|
||||
Args:
|
||||
issue_count: number of issues to return
|
||||
|
||||
Returns:
|
||||
The status of this request, with a list of issues when successful.
|
||||
"""
|
||||
url = f"{GITHUB_BASE_URL}/search/issues"
|
||||
query = f"repo:{OWNER}/{REPO} is:open is:issue"
|
||||
params = {
|
||||
"q": query,
|
||||
"sort": "created",
|
||||
"order": "desc",
|
||||
"per_page": issue_count,
|
||||
"page": 1,
|
||||
}
|
||||
|
||||
try:
|
||||
response = get_request(url, params)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
issues = response.get("items", None)
|
||||
return {"status": "success", "issues": issues}
|
||||
|
||||
|
||||
def get_issue(issue_number: int) -> dict[str, Any]:
|
||||
"""Get the details of the specified issue number.
|
||||
|
||||
Args:
|
||||
issue_number: issue number of the Github issue.
|
||||
|
||||
Returns:
|
||||
The status of this request, with the issue details when successful.
|
||||
"""
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}"
|
||||
try:
|
||||
response = get_request(url)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
return {"status": "success", "issue": response}
|
||||
|
||||
|
||||
def add_comment_to_issue(issue_number: int, comment: str) -> dict[str, any]:
|
||||
"""Add the specified comment to the given issue number.
|
||||
|
||||
Args:
|
||||
issue_number: issue number of the Github issue
|
||||
comment: comment to add
|
||||
|
||||
Returns:
|
||||
The the status of this request, with the applied comment when successful.
|
||||
"""
|
||||
print(f"Attempting to add comment '{comment}' to issue #{issue_number}")
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/comments"
|
||||
payload = {"body": comment}
|
||||
|
||||
try:
|
||||
response = post_request(url, payload)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
return {
|
||||
"status": "success",
|
||||
"added_comment": response,
|
||||
}
|
||||
|
||||
|
||||
def list_comments_on_issue(issue_number: int) -> dict[str, any]:
|
||||
"""List all comments on the given issue number.
|
||||
|
||||
Args:
|
||||
issue_number: issue number of the Github issue
|
||||
|
||||
Returns:
|
||||
The the status of this request, with the list of comments when successful.
|
||||
"""
|
||||
print(f"Attempting to list comments on issue #{issue_number}")
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/comments"
|
||||
|
||||
try:
|
||||
response = get_request(url)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
return {"status": "success", "comments": response}
|
||||
|
||||
|
||||
root_agent = Agent(
|
||||
model="gemini-2.5-pro",
|
||||
name="adk_issue_formatting_assistant",
|
||||
description="Check ADK issue format and content.",
|
||||
instruction=f"""
|
||||
# 1. IDENTITY
|
||||
You are an AI assistant designed to help maintain the quality and consistency of issues in our GitHub repository.
|
||||
Your primary role is to act as a "GitHub Issue Format Validator." You will analyze new and existing **open** issues
|
||||
to ensure they contain all the necessary information as required by our templates. You are helpful, polite,
|
||||
and precise in your feedback.
|
||||
|
||||
# 2. CONTEXT & RESOURCES
|
||||
* **Repository:** You are operating on the GitHub repository `{OWNER}/{REPO}`.
|
||||
* **Bug Report Template:** (`{BUG_REPORT_TEMPLATE}`)
|
||||
* **Feature Request Template:** (`{FREATURE_REQUEST_TEMPLATE}`)
|
||||
|
||||
# 3. CORE MISSION
|
||||
Your goal is to check if a GitHub issue, identified as either a "bug" or a "feature request,"
|
||||
contains all the information required by the corresponding template. If it does not, your job is
|
||||
to post a single, helpful comment asking the original author to provide the missing information.
|
||||
{APPROVAL_INSTRUCTION}
|
||||
|
||||
**IMPORTANT NOTE:**
|
||||
* You add one comment at most each time you are invoked.
|
||||
* Don't proceed to other issues which are not the target issues.
|
||||
* Don't take any action on closed issues.
|
||||
|
||||
# 4. BEHAVIORAL RULES & LOGIC
|
||||
|
||||
## Step 1: Identify Issue Type & Applicability
|
||||
|
||||
Your first task is to determine if the issue is a valid target for validation.
|
||||
|
||||
1. **Assess Content Intent:** You must perform a quick semantic check of the issue's title, body, and comments.
|
||||
If you determine the issue's content is fundamentally *not* a bug report or a feature request
|
||||
(for example, it is a general question, a request for help, or a discussion prompt), then you must ignore it.
|
||||
2. **Exit Condition:** If the issue does not clearly fall into the categories of "bug" or "feature request"
|
||||
based on both its labels and its content, **take no action**.
|
||||
|
||||
## Step 2: Analyze the Issue Content
|
||||
|
||||
If you have determined the issue is a valid bug or feature request, your analysis depends on whether it has comments.
|
||||
|
||||
**Scenario A: Issue has NO comments**
|
||||
1. Read the main body of the issue.
|
||||
2. Compare the content of the issue body against the required headings/sections in the relevant template (Bug or Feature).
|
||||
3. Check for the presence of content under each heading. A heading with no content below it is considered incomplete.
|
||||
4. If one or more sections are missing or empty, proceed to Step 3.
|
||||
5. If all sections are filled out, your task is complete. Do nothing.
|
||||
|
||||
**Scenario B: Issue HAS one or more comments**
|
||||
1. First, analyze the main issue body to see which sections of the template are filled out.
|
||||
2. Next, read through **all** the comments in chronological order.
|
||||
3. As you read the comments, check if the information provided in them satisfies any of the template sections that were missing from the original issue body.
|
||||
4. After analyzing the body and all comments, determine if any required sections from the template *still* remain unaddressed.
|
||||
5. If one or more sections are still missing information, proceed to Step 3.
|
||||
6. If the issue body and comments *collectively* provide all the required information, your task is complete. Do nothing.
|
||||
|
||||
## Step 3: Formulate and Post a Comment (If Necessary)
|
||||
|
||||
If you determined in Step 2 that information is missing, you must post a **single comment** on the issue.
|
||||
|
||||
Please include a bolded note in your comment that this comment was added by an ADK agent.
|
||||
|
||||
**Comment Guidelines:**
|
||||
* **Be Polite and Helpful:** Start with a friendly tone.
|
||||
* **Be Specific:** Clearly list only the sections from the template that are still missing. Do not list sections that have already been filled out.
|
||||
* **Address the Author:** Mention the issue author by their username (e.g., `@username`).
|
||||
* **Provide Context:** Explain *why* the information is needed (e.g., "to help us reproduce the bug" or "to better understand your request").
|
||||
* **Do not be repetitive:** If you have already commented on an issue asking for information, do not comment again unless new information has been added and it's still incomplete.
|
||||
|
||||
**Example Comment for a Bug Report:**
|
||||
> **Response from ADK Agent**
|
||||
>
|
||||
> Hello @[issue-author-username], thank you for submitting this issue!
|
||||
>
|
||||
> To help us investigate and resolve this bug effectively, could you please provide the missing details for the following sections of our bug report template:
|
||||
>
|
||||
> * **To Reproduce:** (Please provide the specific steps required to reproduce the behavior)
|
||||
> * **Desktop (please complete the following information):** (Please provide OS, Python version, and ADK version)
|
||||
>
|
||||
> This information will give us the context we need to move forward. Thanks!
|
||||
|
||||
**Example Comment for a Feature Request:**
|
||||
> **Response from ADK Agent**
|
||||
>
|
||||
> Hi @[issue-author-username], thanks for this great suggestion!
|
||||
>
|
||||
> To help our team better understand and evaluate your feature request, could you please provide a bit more information on the following section:
|
||||
>
|
||||
> * **Is your feature request related to a problem? Please describe.**
|
||||
>
|
||||
> We look forward to hearing more about your idea!
|
||||
|
||||
# 5. FINAL INSTRUCTION
|
||||
|
||||
Execute this process for the given GitHub issue. Your final output should either be **[NO ACTION]**
|
||||
if the issue is complete or invalid, or **[POST COMMENT]** followed by the exact text of the comment you will post.
|
||||
|
||||
Please include your justification for your decision in your output.
|
||||
""",
|
||||
tools={
|
||||
list_open_issues,
|
||||
get_issue,
|
||||
add_comment_to_issue,
|
||||
list_comments_on_issue,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
# 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
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
GITHUB_BASE_URL = "https://api.github.com"
|
||||
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||
if not GITHUB_TOKEN:
|
||||
raise ValueError("GITHUB_TOKEN environment variable not set")
|
||||
|
||||
OWNER = os.getenv("OWNER", "google")
|
||||
REPO = os.getenv("REPO", "adk-python")
|
||||
EVENT_NAME = os.getenv("EVENT_NAME")
|
||||
ISSUE_NUMBER = os.getenv("ISSUE_NUMBER")
|
||||
ISSUE_COUNT_TO_PROCESS = os.getenv("ISSUE_COUNT_TO_PROCESS")
|
||||
|
||||
IS_INTERACTIVE = os.environ.get("INTERACTIVE", "1").lower() in ["true", "1"]
|
||||
@@ -0,0 +1,53 @@
|
||||
# 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 typing import Any
|
||||
|
||||
from adk_issue_formatting_agent.settings import GITHUB_TOKEN
|
||||
import requests
|
||||
|
||||
headers = {
|
||||
"Authorization": f"token {GITHUB_TOKEN}",
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
}
|
||||
|
||||
|
||||
def get_request(
|
||||
url: str, params: dict[str, Any] | None = None
|
||||
) -> dict[str, Any]:
|
||||
if params is None:
|
||||
params = {}
|
||||
response = requests.get(url, headers=headers, params=params, timeout=60)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def post_request(url: str, payload: Any) -> dict[str, Any]:
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=60)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def error_response(error_message: str) -> dict[str, Any]:
|
||||
return {"status": "error", "message": error_message}
|
||||
|
||||
|
||||
def read_file(file_path: str) -> str:
|
||||
"""Read the content of the given file."""
|
||||
try:
|
||||
with open(file_path, "r") as f:
|
||||
return f.read()
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File not found: {file_path}.")
|
||||
return ""
|
||||
@@ -0,0 +1,67 @@
|
||||
# ADK Issue Triaging Assistant
|
||||
|
||||
The ADK Issue Triaging Assistant is a Python-based agent designed to help manage and triage GitHub issues for the `google/adk-python` repository. It uses a large language model to analyze new and unlabelled issues, recommend appropriate labels based on a predefined set of rules, and apply them.
|
||||
|
||||
This agent can be operated in two distinct modes: an interactive mode for local use or as a fully automated GitHub Actions workflow.
|
||||
|
||||
---
|
||||
|
||||
## Interactive Mode
|
||||
|
||||
This mode allows you to run the agent locally to review its recommendations in real-time before any changes are made to your repository's issues.
|
||||
|
||||
### Features
|
||||
* **Web Interface**: The agent's interactive mode can be rendered in a web browser using the ADK's `adk web` command.
|
||||
* **User Approval**: In interactive mode, the agent is instructed to ask for your confirmation before applying a label to a GitHub issue.
|
||||
|
||||
### Running in Interactive Mode
|
||||
To run the agent in interactive mode, first set the required environment variables. Then, execute the following command in your terminal:
|
||||
|
||||
```bash
|
||||
adk web
|
||||
```
|
||||
This will start a local server and provide a URL to access the agent's web interface in your browser.
|
||||
|
||||
---
|
||||
|
||||
## GitHub Workflow Mode
|
||||
|
||||
For automated, hands-off issue triaging, the agent can be integrated directly into your repository's CI/CD pipeline using a GitHub Actions workflow.
|
||||
|
||||
### Workflow Triggers
|
||||
The GitHub workflow is configured to run on specific triggers:
|
||||
|
||||
1. **Issue Events**: The workflow executes automatically whenever a new issue is `opened` or an existing one is `reopened`.
|
||||
|
||||
2. **Scheduled Runs**: The workflow also runs on a recurring schedule (every 6 hours) to process any unlabelled issues that may have been missed.
|
||||
|
||||
### Automated Labeling
|
||||
When running as part of the GitHub workflow, the agent operates non-interactively. It identifies the best label and applies it directly without requiring user approval. This behavior is configured by setting the `INTERACTIVE` environment variable to `0` in the workflow file.
|
||||
|
||||
### Workflow Configuration
|
||||
The workflow is defined in a YAML file (`.github/workflows/triage.yml`). This file contains the steps to check out the code, set up the Python environment, install dependencies, and run the triaging script with the necessary environment variables and secrets.
|
||||
|
||||
---
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Whether running in interactive or workflow mode, the agent requires the following setup.
|
||||
|
||||
### Dependencies
|
||||
The agent requires the following Python libraries.
|
||||
|
||||
```bash
|
||||
pip install --upgrade pip
|
||||
pip install google-adk requests
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
The following environment variables are required for the agent to connect to the necessary services.
|
||||
|
||||
* `GITHUB_TOKEN`: **(Required)** A GitHub Personal Access Token with `issues:write` permissions. Needed for both interactive and workflow modes.
|
||||
* `GOOGLE_API_KEY`: **(Required)** Your API key for the Gemini API. Needed for both interactive and workflow modes.
|
||||
* `OWNER`: The GitHub organization or username that owns the repository (e.g., `google`). Needed for both modes.
|
||||
* `REPO`: The name of the GitHub repository (e.g., `adk-python`). Needed for both modes.
|
||||
* `INTERACTIVE`: Controls the agent's interaction mode. For the automated workflow, this is set to `0`. For interactive mode, it should be set to `1` or left unset.
|
||||
|
||||
For local execution in interactive mode, you can place these variables in a `.env` file in the project's root directory. For the GitHub workflow, they should be configured as repository secrets.
|
||||
+15
@@ -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
|
||||
@@ -13,61 +13,73 @@
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.tools.tool_context import ToolContext
|
||||
from google.genai import types
|
||||
import requests
|
||||
|
||||
# Read the PAT from the environment variable
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") # Ensure you've set this in your shell
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||
if not GITHUB_TOKEN:
|
||||
raise ValueError("GITHUB_TOKEN environment variable not set")
|
||||
|
||||
# Repository information
|
||||
OWNER = "google"
|
||||
REPO = "adk-python"
|
||||
OWNER = os.getenv("OWNER", "google")
|
||||
REPO = os.getenv("REPO", "adk-python")
|
||||
BOT_LABEL = os.getenv("BOT_LABEL", "bot_triaged")
|
||||
|
||||
# Base URL for the GitHub API
|
||||
BASE_URL = "https://api.github.com"
|
||||
|
||||
# Headers including the Authorization header
|
||||
headers = {
|
||||
"Authorization": f"token {GITHUB_TOKEN}",
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
}
|
||||
|
||||
ALLOWED_LABELS = [
|
||||
"documentation",
|
||||
"services",
|
||||
"question",
|
||||
"tools",
|
||||
"eval",
|
||||
"live",
|
||||
"models",
|
||||
"tracing",
|
||||
"core",
|
||||
"web",
|
||||
]
|
||||
|
||||
def list_issues(per_page: int):
|
||||
|
||||
def is_interactive():
|
||||
return os.environ.get("INTERACTIVE", "1").lower() in ["true", "1"]
|
||||
|
||||
|
||||
def list_issues(issue_count: int):
|
||||
"""
|
||||
Generator to list all issues for the repository by handling pagination.
|
||||
|
||||
Args:
|
||||
per_page: number of pages to return per page.
|
||||
issue_count: number of issues to return
|
||||
|
||||
"""
|
||||
state = "open"
|
||||
# only process the 1st page for testing for now
|
||||
page = 1
|
||||
results = []
|
||||
url = ( # :contentReference[oaicite:16]{index=16}
|
||||
f"{BASE_URL}/repos/{OWNER}/{REPO}/issues"
|
||||
)
|
||||
# Warning: let's only handle max 10 issues at a time to avoid bad results
|
||||
params = {"state": state, "per_page": per_page, "page": page}
|
||||
response = requests.get(url, headers=headers, params=params)
|
||||
response.raise_for_status() # :contentReference[oaicite:17]{index=17}
|
||||
issues = response.json()
|
||||
query = f"repo:{OWNER}/{REPO} is:open is:issue no:label"
|
||||
|
||||
unlabelled_issues = []
|
||||
url = f"{BASE_URL}/search/issues"
|
||||
|
||||
params = {
|
||||
"q": query,
|
||||
"sort": "created",
|
||||
"order": "desc",
|
||||
"per_page": issue_count,
|
||||
"page": 1,
|
||||
}
|
||||
response = requests.get(url, headers=headers, params=params, timeout=60)
|
||||
response.raise_for_status()
|
||||
json_response = response.json()
|
||||
issues = json_response.get("items", None)
|
||||
if not issues:
|
||||
return []
|
||||
for issue in issues:
|
||||
# Skip pull requests (issues API returns PRs as well)
|
||||
if "pull_request" in issue:
|
||||
continue
|
||||
results.append(issue)
|
||||
return results
|
||||
if not issue.get("labels", None) or len(issue["labels"]) == 0:
|
||||
unlabelled_issues.append(issue)
|
||||
return unlabelled_issues
|
||||
|
||||
|
||||
def add_label_to_issue(issue_number: str, label: str):
|
||||
@@ -78,41 +90,56 @@ def add_label_to_issue(issue_number: str, label: str):
|
||||
issue_number: issue number of the Github issue, in string foramt.
|
||||
label: label to assign
|
||||
"""
|
||||
print(f"Attempting to add label '{label}' to issue #{issue_number}")
|
||||
if label not in ALLOWED_LABELS:
|
||||
error_message = (
|
||||
f"Error: Label '{label}' is not an allowed label. Will not apply."
|
||||
)
|
||||
print(error_message)
|
||||
return {"status": "error", "message": error_message, "applied_label": None}
|
||||
|
||||
url = f"{BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/labels"
|
||||
payload = [label]
|
||||
response = requests.post(url, headers=headers, json=payload)
|
||||
payload = [label, BOT_LABEL]
|
||||
response = requests.post(url, headers=headers, json=payload, timeout=60)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
approval_instruction = (
|
||||
"Only label them when the user approves the labeling!"
|
||||
if is_interactive()
|
||||
else (
|
||||
"Do not ask for user approval for labeling! If you can't find a"
|
||||
" appropriate labels for the issue, do not label it."
|
||||
)
|
||||
)
|
||||
|
||||
root_agent = Agent(
|
||||
model="gemini-2.5-pro-preview-05-06",
|
||||
name="adk_triaging_assistant",
|
||||
description="Triage ADK issues.",
|
||||
instruction="""
|
||||
You are a Github adk-python repo triaging bot. You will help get issues, and label them.
|
||||
instruction=f"""
|
||||
You are a Github adk-python repo triaging bot. You will help get issues, and recommend a label.
|
||||
IMPORTANT: {approval_instruction}
|
||||
Here are the rules for labeling:
|
||||
- If the user is asking about documentation-related questions, label it with "documentation".
|
||||
- If it's about session, memory services, label it with "services"
|
||||
- If it's about UI/web, label it with "question"
|
||||
- If it's about UI/web, label it with "web"
|
||||
- If the user is asking about a question, label it with "question"
|
||||
- If it's related to tools, label it with "tools"
|
||||
- If it's about agent evalaution, then label it with "eval".
|
||||
- If it's about streaming/live, label it with "live".
|
||||
- If it's about model support(non-Gemini, like Litellm, Ollama, OpenAI models), label it with "models".
|
||||
- If it's about tracing, label it with "tracing".
|
||||
- If it's agent orchestration, agent definition, label it with "core".
|
||||
- If you can't find a appropriate labels for the issue, return the issues to user to decide.
|
||||
- If you can't find a appropriate labels for the issue, follow the previous instruction that starts with "IMPORTANT:".
|
||||
|
||||
Present the followings in an easy to read format highlighting issue number and your label.
|
||||
- the issue summary in a few sentence
|
||||
- your label recommendation and justification
|
||||
""",
|
||||
tools=[
|
||||
list_issues,
|
||||
add_label_to_issue,
|
||||
],
|
||||
generate_content_config=types.GenerateContentConfig(
|
||||
safety_settings=[
|
||||
types.SafetySetting( # avoid false alarm about rolling dice.
|
||||
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
|
||||
threshold=types.HarmBlockThreshold.OFF,
|
||||
),
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# 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 os
|
||||
import time
|
||||
|
||||
import agent
|
||||
from dotenv import load_dotenv
|
||||
from google.adk.agents.run_config import RunConfig
|
||||
from google.adk.runners import InMemoryRunner
|
||||
from google.adk.sessions import Session
|
||||
from google.genai import types
|
||||
import requests
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
OWNER = os.getenv("OWNER", "google")
|
||||
REPO = os.getenv("REPO", "adk-python")
|
||||
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||
BASE_URL = "https://api.github.com"
|
||||
headers = {
|
||||
"Authorization": f"token {GITHUB_TOKEN}",
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
}
|
||||
|
||||
if not GITHUB_TOKEN:
|
||||
print(
|
||||
"Warning: GITHUB_TOKEN environment variable not set. API calls might"
|
||||
" fail."
|
||||
)
|
||||
|
||||
|
||||
async def fetch_specific_issue_details(issue_number: int):
|
||||
"""Fetches details for a single issue if it's unlabelled."""
|
||||
if not GITHUB_TOKEN:
|
||||
print("Cannot fetch issue details: GITHUB_TOKEN is not set.")
|
||||
return None
|
||||
|
||||
url = f"{BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}"
|
||||
print(f"Fetching details for specific issue: {url}")
|
||||
try:
|
||||
response = requests.get(url, headers=headers, timeout=60)
|
||||
response.raise_for_status()
|
||||
issue_data = response.json()
|
||||
if not issue_data.get("labels") or len(issue_data["labels"]) == 0:
|
||||
print(f"Issue #{issue_number} is unlabelled. Proceeding.")
|
||||
return {
|
||||
"number": issue_data["number"],
|
||||
"title": issue_data["title"],
|
||||
"body": issue_data.get("body", ""),
|
||||
}
|
||||
else:
|
||||
print(f"Issue #{issue_number} is already labelled. Skipping.")
|
||||
return None
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error fetching issue #{issue_number}: {e}")
|
||||
if hasattr(e, "response") and e.response is not None:
|
||||
print(f"Response content: {e.response.text}")
|
||||
return None
|
||||
|
||||
|
||||
async def main():
|
||||
app_name = "triage_app"
|
||||
user_id_1 = "triage_user"
|
||||
runner = InMemoryRunner(
|
||||
agent=agent.root_agent,
|
||||
app_name=app_name,
|
||||
)
|
||||
session_11 = await runner.session_service.create_session(
|
||||
app_name=app_name, user_id=user_id_1
|
||||
)
|
||||
|
||||
async def run_agent_prompt(session: Session, prompt_text: str):
|
||||
content = types.Content(
|
||||
role="user", parts=[types.Part.from_text(text=prompt_text)]
|
||||
)
|
||||
print(f"\n>>>> Agent Prompt: {prompt_text}")
|
||||
final_agent_response_parts = []
|
||||
async for event in runner.run_async(
|
||||
user_id=user_id_1,
|
||||
session_id=session.id,
|
||||
new_message=content,
|
||||
run_config=RunConfig(save_input_blobs_as_artifacts=False),
|
||||
):
|
||||
if event.content.parts and event.content.parts[0].text:
|
||||
print(f"** {event.author} (ADK): {event.content.parts[0].text}")
|
||||
if event.author == agent.root_agent.name:
|
||||
final_agent_response_parts.append(event.content.parts[0].text)
|
||||
print(f"<<<< Agent Final Output: {''.join(final_agent_response_parts)}\n")
|
||||
|
||||
event_name = os.getenv("EVENT_NAME")
|
||||
issue_number_str = os.getenv("ISSUE_NUMBER")
|
||||
|
||||
if event_name == "issues" and issue_number_str:
|
||||
print(f"EVENT: Processing specific issue due to '{event_name}' event.")
|
||||
try:
|
||||
issue_number = int(issue_number_str)
|
||||
specific_issue = await fetch_specific_issue_details(issue_number)
|
||||
|
||||
if specific_issue:
|
||||
prompt = (
|
||||
f"A new GitHub issue #{specific_issue['number']} has been opened or"
|
||||
f" reopened. Title: \"{specific_issue['title']}\"\nBody:"
|
||||
f" \"{specific_issue['body']}\"\n\nBased on the rules, recommend an"
|
||||
" appropriate label and its justification."
|
||||
" Then, use the 'add_label_to_issue' tool to apply the label "
|
||||
"directly to this issue."
|
||||
f" The issue number is {specific_issue['number']}."
|
||||
)
|
||||
await run_agent_prompt(session_11, prompt)
|
||||
else:
|
||||
print(
|
||||
f"No unlabelled issue details found for #{issue_number} or an error"
|
||||
" occurred. Skipping agent interaction."
|
||||
)
|
||||
|
||||
except ValueError:
|
||||
print(f"Error: Invalid ISSUE_NUMBER received: {issue_number_str}")
|
||||
|
||||
else:
|
||||
print(f"EVENT: Processing batch of issues (event: {event_name}).")
|
||||
issue_count_str = os.getenv("ISSUE_COUNT_TO_PROCESS", "3")
|
||||
try:
|
||||
num_issues_to_process = int(issue_count_str)
|
||||
except ValueError:
|
||||
print(f"Warning: Invalid ISSUE_COUNT_TO_PROCESS. Defaulting to 3.")
|
||||
num_issues_to_process = 3
|
||||
|
||||
prompt = (
|
||||
f"List the first {num_issues_to_process} unlabelled open issues from"
|
||||
f" the {OWNER}/{REPO} repository. For each issue, provide a summary,"
|
||||
" recommend a label with justification, and then use the"
|
||||
" 'add_label_to_issue' tool to apply the recommended label directly."
|
||||
)
|
||||
await run_agent_prompt(session_11, prompt)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_time = time.time()
|
||||
print(
|
||||
"Script start time:",
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(start_time)),
|
||||
)
|
||||
print("------------------------------------")
|
||||
asyncio.run(main())
|
||||
end_time = time.time()
|
||||
print("------------------------------------")
|
||||
print(
|
||||
"Script end time:",
|
||||
time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(end_time)),
|
||||
)
|
||||
print("Total script execution time:", f"{end_time - start_time:.2f} seconds")
|
||||
@@ -31,7 +31,7 @@ root_agent = Agent(
|
||||
model='gemini-2.0-flash',
|
||||
name='log_agent',
|
||||
description='Log user query.',
|
||||
instruction="""Always log the user query and reploy "kk, I've logged."
|
||||
instruction="""Always log the user query and reply "kk, I've logged."
|
||||
""",
|
||||
tools=[log_query],
|
||||
generate_content_config=types.GenerateContentConfig(
|
||||
|
||||
@@ -40,13 +40,28 @@ would set:
|
||||
### 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.
|
||||
user interacting with the agent. The tools are run with these credentials.
|
||||
|
||||
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
|
||||
1. Set `CREDENTIALS_TYPE=None` in `agent.py`
|
||||
|
||||
1. Run the agent
|
||||
|
||||
### With Service Account Keys
|
||||
|
||||
This mode is useful for quick development when the agent builder wants to run
|
||||
the agent with service account credentials. The tools are run with these
|
||||
credentials.
|
||||
|
||||
1. Create service account key by following https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys.
|
||||
|
||||
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.SERVICE_ACCOUNT` in `agent.py`
|
||||
|
||||
1. Download the key file and replace `"service_account_key.json"` with the path
|
||||
|
||||
1. Run the agent
|
||||
|
||||
### With Interactive OAuth
|
||||
|
||||
@@ -72,7 +87,7 @@ type.
|
||||
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
|
||||
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.OAUTH2` in `agent.py` and run the agent
|
||||
|
||||
## Sample prompts
|
||||
|
||||
|
||||
@@ -15,24 +15,21 @@
|
||||
import os
|
||||
|
||||
from google.adk.agents import llm_agent
|
||||
from google.adk.auth import AuthCredentialTypes
|
||||
from google.adk.tools.bigquery import BigQueryCredentialsConfig
|
||||
from google.adk.tools.bigquery import BigQueryToolset
|
||||
from google.adk.tools.bigquery.config import BigQueryToolConfig
|
||||
from google.adk.tools.bigquery.config import WriteMode
|
||||
import google.auth
|
||||
|
||||
RUN_WITH_ADC = False
|
||||
# Define an appropriate credential type
|
||||
CREDENTIALS_TYPE = AuthCredentialTypes.OAUTH2
|
||||
|
||||
|
||||
# Define BigQuery tool config
|
||||
tool_config = BigQueryToolConfig(write_mode=WriteMode.ALLOWED)
|
||||
|
||||
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:
|
||||
if CREDENTIALS_TYPE == AuthCredentialTypes.OAUTH2:
|
||||
# Initiaze the tools to do interactive OAuth
|
||||
# The environment variables OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET
|
||||
# must be set
|
||||
@@ -40,6 +37,20 @@ else:
|
||||
client_id=os.getenv("OAUTH_CLIENT_ID"),
|
||||
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
|
||||
)
|
||||
elif CREDENTIALS_TYPE == AuthCredentialTypes.SERVICE_ACCOUNT:
|
||||
# Initialize the tools to use the credentials in the service account key.
|
||||
# If this flow is enabled, make sure to replace the file path with your own
|
||||
# service account key file
|
||||
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
|
||||
creds, _ = google.auth.load_credentials_from_file("service_account_key.json")
|
||||
credentials_config = BigQueryCredentialsConfig(credentials=creds)
|
||||
else:
|
||||
# Initialize the tools to use the application default credentials.
|
||||
# https://cloud.google.com/docs/authentication/provide-credentials-adc
|
||||
application_default_credentials, _ = google.auth.default()
|
||||
credentials_config = BigQueryCredentialsConfig(
|
||||
credentials=application_default_credentials
|
||||
)
|
||||
|
||||
bigquery_toolset = BigQueryToolset(
|
||||
credentials_config=credentials_config, bigquery_tool_config=tool_config
|
||||
@@ -49,7 +60,7 @@ bigquery_toolset = BigQueryToolset(
|
||||
# debug CLI
|
||||
root_agent = llm_agent.Agent(
|
||||
model="gemini-2.0-flash",
|
||||
name="hello_agent",
|
||||
name="bigquery_agent",
|
||||
description=(
|
||||
"Agent to answer questions about BigQuery data and models and execute"
|
||||
" SQL queries."
|
||||
|
||||
+14
-19
@@ -1,45 +1,40 @@
|
||||
# BigQuery Sample
|
||||
# Google API Tools Sample
|
||||
|
||||
## Introduction
|
||||
|
||||
This sample tests and demos the BigQuery support in ADK via two tools:
|
||||
This sample tests and demos Google API tools available in the
|
||||
`google.adk.tools.google_api_tool` module. We pick the following BigQuery API
|
||||
tools for this sample agent:
|
||||
|
||||
* 1. bigquery_datasets_list:
|
||||
1. `bigquery_datasets_list`: List user's datasets.
|
||||
|
||||
List user's datasets.
|
||||
2. `bigquery_datasets_get`: Get a dataset's details.
|
||||
|
||||
* 2. bigquery_datasets_get:
|
||||
Get a dataset's details.
|
||||
3. `bigquery_datasets_insert`: Create a new dataset.
|
||||
|
||||
* 3. bigquery_datasets_insert:
|
||||
Create a new dataset.
|
||||
4. `bigquery_tables_list`: List all tables in a dataset.
|
||||
|
||||
* 4. bigquery_tables_list:
|
||||
List all tables in a dataset.
|
||||
5. `bigquery_tables_get`: Get a table's details.
|
||||
|
||||
* 5. bigquery_tables_get:
|
||||
Get a table's details.
|
||||
|
||||
* 6. bigquery_tables_insert:
|
||||
Insert a new table into a dataset.
|
||||
6. `bigquery_tables_insert`: Insert a new table into a dataset.
|
||||
|
||||
## How to use
|
||||
|
||||
* 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.
|
||||
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:
|
||||
|
||||
* OAUTH_CLIENT_ID={your client id}
|
||||
* OAUTH_CLIENT_SECRET={your client secret}
|
||||
|
||||
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.
|
||||
|
||||
* 4. For 1st run, allow popup for localhost in Chrome.
|
||||
4. For 1st run, allow popup for localhost in Chrome.
|
||||
|
||||
## Sample prompt
|
||||
|
||||
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user