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
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 20c30d5819 | |||
| 83e5df7862 | |||
| 25b2806301 | |||
| f6a022cda3 | |||
| e0a8355219 | |||
| d9ce2e691c | |||
| dc193f7969 | |||
| 6277dae749 | |||
| ef837015f3 | |||
| 54cc849de7 | |||
| e73d71d324 | |||
| e528749a1c | |||
| 1686cc57c2 | |||
| 53803522b6 | |||
| e3c2bf3062 | |||
| 2fff882fb0 | |||
| a3b31ca950 | |||
| 8dc0c949af | |||
| 71fbc9275b | |||
| 423542a43f | |||
| 37dae9b631 | |||
| 0e28d64712 | |||
| 6da6c2a44c | |||
| 8ef2177658 | |||
| 97318bcd19 | |||
| 283303032a | |||
| e369c283b3 | |||
| 74589a1db7 | |||
| e41dbccf7f | |||
| d620bcb384 | |||
| 90b9193a20 | |||
| 57cd41f424 | |||
| 7556ebc76a | |||
| 2bb20411f4 | |||
| 86a44873e9 | |||
| faadef167e | |||
| bead607364 | |||
| 041f04e89c | |||
| 16a15c8709 | |||
| 9656ccc407 | |||
| db975dfe2a | |||
| 0ccbf6f2f8 | |||
| a54c7024cf | |||
| 1cfe6e9ffe | |||
| 314d6a4f95 | |||
| 247fd2066c | |||
| 7d06fb735e | |||
| d5dcef2cf0 | |||
| 6191412b07 | |||
| 3be1bb37d9 | |||
| 7c9b0a2567 | |||
| 0c6086cb15 | |||
| 9db5d9a3e8 | |||
| de6ebddcd2 | |||
| bcac9ba44c | |||
| 2f73cfde18 | |||
| ec8dd5721a | |||
| 646eb42533 | |||
| bf72426af2 | |||
| 9c0721beaa | |||
| 5eff66a132 | |||
| 282d67f253 | |||
| 3432b22172 | |||
| af35e2673f | |||
| f68d4d5cd0 | |||
| 16e8419e32 | |||
| 0c855877c5 | |||
| f29ab5db05 | |||
| f1889ae440 | |||
| c69dcf8779 | |||
| ec7d9b0ff6 | |||
| 6419a2aa9b | |||
| b83b0a6eec | |||
| a3ff21eb0b | |||
| 1778490e64 | |||
| a858d79b3a | |||
| c8f8b4a20a | |||
| 11037fc133 | |||
| 206a13271e | |||
| 3be0882c63 | |||
| e176f03e8f | |||
| 7206e0a0eb | |||
| fbe6a7b8d3 | |||
| bfc203a92f | |||
| 5e8aa15a50 | |||
| 16392984c5 | |||
| 20537e8bfa | |||
| 00afaaf2fc | |||
| dfc25c17a9 | |||
| 32ae882a49 | |||
| 884c201958 | |||
| 70c461686e | |||
| 1355bd643b | |||
| 927c75f0ee | |||
| 430b82024f | |||
| 70266abfc2 | |||
| a911469616 | |||
| ce7253f63f | |||
| bda3df2480 |
@@ -0,0 +1,44 @@
|
||||
name: ADK Answering Agent for Discussions
|
||||
|
||||
on:
|
||||
discussion:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
agent-answer-questions:
|
||||
if: github.event.discussion.category.name == 'Q&A'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Authenticate to Google Cloud
|
||||
id: auth
|
||||
uses: 'google-github-actions/auth@v2'
|
||||
with:
|
||||
credentials_json: '${{ secrets.ADK_GCP_SA_KEY }}'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install google-adk
|
||||
|
||||
- name: Run Answering Script
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
|
||||
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
|
||||
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
|
||||
VERTEXAI_DATASTORE_ID: ${{ secrets.VERTEXAI_DATASTORE_ID }}
|
||||
GOOGLE_GENAI_USE_VERTEXAI: 1
|
||||
OWNER: 'google'
|
||||
REPO: 'adk-python'
|
||||
INTERACTIVE: 0
|
||||
DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
|
||||
PYTHONPATH: contributing/samples
|
||||
run: python -m adk_answering_agent.main
|
||||
@@ -0,0 +1,38 @@
|
||||
name: ADK Pull Request Triaging Agent
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, edited]
|
||||
|
||||
jobs:
|
||||
agent-triage-pull-request:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: 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'
|
||||
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
|
||||
INTERACTIVE: ${{ vars.PR_TRIAGE_INTERACTIVE }}
|
||||
PYTHONPATH: contributing/samples
|
||||
run: python -m adk_pr_triaging_agent.main
|
||||
+113
@@ -1,5 +1,118 @@
|
||||
# Changelog
|
||||
|
||||
## [1.10.0](https://github.com/google/adk-python/compare/v1.9.0...v1.10.0) (2025-08-07)
|
||||
|
||||
### Features
|
||||
|
||||
* [Live] Implement Live Session Resumption ([71fbc92](https://github.com/google/adk-python/commit/71fbc9275b3d74700ec410cb4155ba0cb18580b7))
|
||||
* [Tool] Support parallel execution of parallel function calls ([57cd41f](https://github.com/google/adk-python/commit/57cd41f424b469fb834bb8f2777b5f7be9aa6cdf))
|
||||
* [Models] Allow max tokens to be customizable in Claude ([7556ebc](https://github.com/google/adk-python/commit/7556ebc76abd3c776922c2803aed831661cf7f82))
|
||||
* [Tool] Create enterprise_web_search_tool as a tool instance ([0e28d64](https://github.com/google/adk-python/commit/0e28d64712e481cfd3b964be0166f529657024f6))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix shared default plugin manager and cost manager instances among multiple invocations ([423542a](https://github.com/google/adk-python/commit/423542a43fb8316195e9f79d97f87593751bebd3))
|
||||
* Correct the type annotation in anthropic_llm implementation ([97318bc](https://github.com/google/adk-python/commit/97318bcd199acdacadfe8664da3fbfc3c806cdd2))
|
||||
* Fix adk deploy cloud_run cli, which was broken in v1.9.0 ([e41dbcc](https://github.com/google/adk-python/commit/e41dbccf7f610e249108f9321f60f71fe2cc10f4))
|
||||
* Remove thoughts from contents in llm requests from history contents ([d620bcb](https://github.com/google/adk-python/commit/d620bcb384d3068228ea2059fb70274e68e69682))
|
||||
* Annotate response type as None for transfer_to_agent tool ([86a4487](https://github.com/google/adk-python/commit/86a44873e9b2dfc7e62fa31a9ac3be57c0bbff7b))
|
||||
* Fix incompatible a2a sdk changes ([faadef1](https://github.com/google/adk-python/commit/faadef167ee8e4dd1faf4da5685a577c3155556e))
|
||||
* Fix adk cli options and method parameters mismatching ([8ef2177](https://github.com/google/adk-python/commit/8ef2177658fbfc74b1a74b0c3ea8150bae866796))
|
||||
|
||||
### Improvements
|
||||
|
||||
* Add Github workflow config for the ADK Answering agent ([8dc0c94](https://github.com/google/adk-python/commit/8dc0c949afb9024738ff7ac1b2c19282175c3200))
|
||||
* Import AGENT_CARD_WELL_KNOWN_PATH from adk instead of from a2a directly ([37dae9b](https://github.com/google/adk-python/commit/37dae9b631db5060770b66fce0e25cf0ffb56948))
|
||||
* Make `LlmRequest.LiveConnectConfig` field default to a factory ([74589a1](https://github.com/google/adk-python/commit/74589a1db7df65e319d1ad2f0676ee0cf5d6ec1d))
|
||||
* Update the prompt to make the ADK Answering Agent more objective ([2833030](https://github.com/google/adk-python/commit/283303032a174d51b8d72f14df83c794d66cb605))
|
||||
* Add sample agent for testing parallel functions execution ([90b9193](https://github.com/google/adk-python/commit/90b9193a20499b8dd7f57d119cda4c534fcfda10))
|
||||
* Hide the ask_data_insights tool until the API is publicly available ([bead607](https://github.com/google/adk-python/commit/bead607364be7ac8109357c9d3076d9b345e9e8a))
|
||||
* Change `LlmRequest.config`'s default value to be `types.GenerateContentConfig()` ([041f04e](https://github.com/google/adk-python/commit/041f04e89cee30532facccce4900d10f1b8c69ce))
|
||||
* Prevent triggering of _load_from_yaml_config in AgentLoader ([db975df](https://github.com/google/adk-python/commit/db975dfe2a09a6d056d02bc03c1247ac10f6da7d))
|
||||
|
||||
### Documentation
|
||||
|
||||
* Fix typos ([16a15c8](https://github.com/google/adk-python/commit/16a15c8709b47c9bebe7cffe888e8e7e48ec605a))
|
||||
|
||||
|
||||
## [1.9.0](https://github.com/google/adk-python/compare/v1.8.0...v1.9.0) (2025-07-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* [CLI] Add `-v`, `--verbose` flag to enable DEBUG logging as a shortcut for `--log_level DEBUG` ([3be0882](https://github.com/google/adk-python/commit/3be0882c63bf9b185c34bcd17e03769b39f0e1c5))
|
||||
* [CLI] Add a CLI option to update an agent engine instance ([206a132](https://github.com/google/adk-python/commit/206a13271e5f1bb0bb8114b3bb82f6ec3f030cd7))
|
||||
* [CLI] Modularize fast_api.py to allow simpler construction of API Server ([bfc203a](https://github.com/google/adk-python/commit/bfc203a92fdfbc4abaf776e76dca50e7ca59127b), [dfc25c1](https://github.com/google/adk-python/commit/dfc25c17a98aaad81e1e2f140db83d17cd78f393), [e176f03](https://github.com/google/adk-python/commit/e176f03e8fe13049187abd0f14e63afca9ccff01))
|
||||
* [CLI] Refactor AgentLoader into base class and add InMemory impl alongside existing filesystem impl ([bda3df2](https://github.com/google/adk-python/commit/bda3df24802d0456711a5cd05544aea54a13398d))
|
||||
* [CLI] Respect the .ae_ignore file when deploying to agent engine ([f29ab5d](https://github.com/google/adk-python/commit/f29ab5db0563a343d6b8b437a12557c89b7fc98b))
|
||||
* [Core] Add new callbacks to handle tool and model errors ([00afaaf](https://github.com/google/adk-python/commit/00afaaf2fc18fba85709754fb1037bb47f647243))
|
||||
* [Core] Add sample plugin for logging ([20537e8](https://github.com/google/adk-python/commit/20537e8bfa31220d07662dad731b4432799e1802))
|
||||
* [Core] Expose Gemini RetryOptions to client ([1639298](https://github.com/google/adk-python/commit/16392984c51b02999200bd4f1d6781d5ec9054de))
|
||||
* [Evals] Added an Fast API new endpoint to serve eval metric info ([c69dcf8](https://github.com/google/adk-python/commit/c69dcf87795c4fa2ad280b804c9b0bd3fa9bf06f))
|
||||
* [Evals] Refactored AgentEvaluator and updated it to use LocalEvalService ([1355bd6](https://github.com/google/adk-python/commit/1355bd643ba8f7fd63bcd6a7284cc48e325d138e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add absolutize_imports option when deploying to agent engine ([fbe6a7b](https://github.com/google/adk-python/commit/fbe6a7b8d3a431a1d1400702fa534c3180741eb3))
|
||||
* Add space to allow adk deploy cloud_run --a2a ([70c4616](https://github.com/google/adk-python/commit/70c461686ec2c60fcbaa384a3f1ea2528646abba))
|
||||
* Copy the original function call args before passing it to callback or tools to avoid being modified ([3432b22](https://github.com/google/adk-python/commit/3432b221727b52af2682d5bf3534d533a50325ef))
|
||||
* Eval module not found exception string ([7206e0a](https://github.com/google/adk-python/commit/7206e0a0eb546a66d47fb411f3fa813301c56f42))
|
||||
* Fix incorrect token count mapping in telemetry ([c8f8b4a](https://github.com/google/adk-python/commit/c8f8b4a20a886a17ce29abd1cfac2858858f907d))
|
||||
* Import cli's artifact dependencies directly ([282d67f](https://github.com/google/adk-python/commit/282d67f253935af56fae32428124a385f812c67d))
|
||||
* Keep existing header values while merging tracking headers for `llm_request.config.http_options` in `Gemini.generate_content_async` ([6191412](https://github.com/google/adk-python/commit/6191412b07c3b5b5a58cf7714e475f63e89be847))
|
||||
* Merge tracking headers even when `llm_request.config.http_options` is not set in `Gemini.generate_content_async` ([ec8dd57](https://github.com/google/adk-python/commit/ec8dd5721aa151cfc033cc3aad4733df002ae9cb))
|
||||
* Restore bigquery sample agent to runnable form ([16e8419](https://github.com/google/adk-python/commit/16e8419e32b54298f782ba56827e5139effd8780))
|
||||
* Return session state in list_session API endpoint ([314d6a4](https://github.com/google/adk-python/commit/314d6a4f95c6d37c7da3afbc7253570564623322))
|
||||
* Runner was expecting Event object instead of Content object when using early exist feature ([bf72426](https://github.com/google/adk-python/commit/bf72426af2bfd5c2e21c410005842e48b773deb3))
|
||||
* Unable to acquire impersonated credentials ([9db5d9a](https://github.com/google/adk-python/commit/9db5d9a3e87d363c1bac0f3d8e45e42bd5380d3e))
|
||||
* Update `agent_card_builder` to follow grammar rules ([9c0721b](https://github.com/google/adk-python/commit/9c0721beaa526a4437671e6cc70915073be835e3)), closes [#2223](https://github.com/google/adk-python/issues/2223)
|
||||
* Use correct type for actions parameter in ApplicationIntegrationToolset ([ce7253f](https://github.com/google/adk-python/commit/ce7253f63ff8e78bccc7805bd84831f08990b881))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* Update documents about the information of vibe coding ([0c85587](https://github.com/google/adk-python/commit/0c855877c57775ad5dad930594f9f071164676da))
|
||||
|
||||
|
||||
## [1.8.0](https://github.com/google/adk-python/compare/v1.7.0...v1.8.0) (2025-07-23)
|
||||
|
||||
### Features
|
||||
|
||||
* [Core]Add agent card builder ([18f5bea](https://github.com/google/adk-python/commit/18f5bea411b3b76474ff31bfb2f62742825b45e5))
|
||||
* [Core]Add an to_a2a util to convert adk agent to A2A ASGI application ([a77d689](https://github.com/google/adk-python/commit/a77d68964a1c6b7659d6117d57fa59e43399e0c2))
|
||||
* [Core]Add camel case converter for agents ([0e173d7](https://github.com/google/adk-python/commit/0e173d736334f8c6c171b3144ac6ee5b7125c846))
|
||||
* [Evals]Use LocalEvalService to run all evals in cli and web ([d1f182e](https://github.com/google/adk-python/commit/d1f182e8e68c4a5a4141592f3f6d2ceeada78887))
|
||||
* [Evals]Enable FinalResponseMatchV2 metric as an experiment ([36e45cd](https://github.com/google/adk-python/commit/36e45cdab3bbfb653eee3f9ed875b59bcd525ea1))
|
||||
* [Models]Add support for `model-optimizer-*` family of models in vertex ([ffe2bdb](https://github.com/google/adk-python/commit/ffe2bdbe4c2ea86cc7924eb36e8e3bb5528c0016))
|
||||
* [Services]Added a sample for History Management ([67284fc](https://github.com/google/adk-python/commit/67284fc46667b8c2946762bc9234a8453d48a43c))
|
||||
* [Services]Support passing fully qualified agent engine resource name when constructing session service and memory service ([2e77804](https://github.com/google/adk-python/commit/2e778049d0a675e458f4e
|
||||
35fe4104ca1298dbfcf))
|
||||
* [Tools]Add ComputerUseToolset ([083dcb4](https://github.com/google/adk-python/commit/083dcb44650eb0e6b70219ede731f2fa78ea7d28))
|
||||
* [Tools]Allow toolset to process llm_request before tools returned by it ([3643b4a](https://github.com/google/adk-python/commit/3643b4ae196fd9e38e52d5dc9d1cd43ea0733d36))
|
||||
* [Tools]Support input/output schema by fully-qualified code reference ([dfee06a](https://github.com/google/adk-python/commit/dfee06ac067ea909251d6fb016f8331065d430e9))
|
||||
* [Tools]Enhance LangchainTool to accept more forms of functions ([0ec69d0](https://github.com/google/adk-python/commit/0ec69d05a4016adb72abf9c94f2e9ff4bdd1848c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Attention**: Logging level for some API requests and responses was moved from `INFO` to `DEBUG` ([ff31f57](https://github.com/google/adk-python/commit/ff31f57dc95149f8f309f83f2ec983ef40f1122c))
|
||||
* Please set `--log_level=DEBUG`, if you are interested in having those API request and responses in logs.
|
||||
* Add buffer to the write file option ([f2caf2e](https://github.com/google/adk-python/commit/f2caf2eecaf0336495fb42a2166b1b79e57d82d8))
|
||||
* Allow current sub-agent to finish execution before exiting the loop agent due to a sub-agent's escalation. ([2aab1cf](https://github.com/google/adk-python/commit/2aab1cf98e1d0e8454764b549fac21475a633409))
|
||||
* Check that `mean_score` is a valid float value ([65cb6d6](https://github.com/google/adk-python/commit/65cb6d6bf3278e6c3529938a7b932e3ef6d6c2ae))
|
||||
* Handle non-json-serializable values in the `execute_sql` tool ([13ff009](https://github.com/google/adk-python/commit/13ff009d34836a80f107cb43a632df15f7c215e4))
|
||||
* Raise `NotFoundError` in `list_eval_sets` function when app_name doesn't exist ([b17d8b6](https://github.com/google/adk-python/commit/b17d8b6e362a5b2a1b6a2dd0cff5e27a71c27925))
|
||||
* Fixed serialization of tools with nested schema ([53df35e](https://github.com/google/adk-python/commit/53df35ee58599e9816bd4b9c42ff48457505e599))
|
||||
* Set response schema for function tools that returns `None` ([33ac838](https://github.com/google/adk-python/commit/33ac8380adfff46ed8a7d518ae6f27345027c074))
|
||||
* Support path level parameters for open_api_spec_parser ([6f01660](https://github.com/google/adk-python/commit/6f016609e889bb0947877f478de0c5729cfcd0c3))
|
||||
* Use correct type for actions parameter in ApplicationIntegrationToolset ([ce7253f](https://github.com/google/adk-python/commit/ce7253f63ff8e78bccc7805bd84831f08990b881))
|
||||
* Use the same word extractor for query and event contents in InMemoryMemoryService ([1c4c887](https://github.com/google/adk-python/commit/1c4c887bec9326aad2593f016540160d95d03f33))
|
||||
|
||||
### Documentation
|
||||
|
||||
* Fix missing toolbox-core dependency and improve installation guide ([2486349](https://github.com/google/adk-python/commit/24863492689f36e3c7370be40486555801858bac))
|
||||
|
||||
|
||||
## 1.7.0 (2025-07-16)
|
||||
|
||||
### Features
|
||||
|
||||
@@ -210,3 +210,7 @@ All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
|
||||
# Vibe Coding
|
||||
|
||||
If you want to contribute by leveraging viber coding, the AGENTS.md (https://github.com/google/adk-python/tree/main/AGENTS.md) could be used as context to your LLM.
|
||||
@@ -138,6 +138,10 @@ We welcome contributions from the community! Whether it's bug reports, feature r
|
||||
- [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.
|
||||
|
||||
## Vibe Coding
|
||||
|
||||
If you are to develop agent via vibe coding the [llms.txt](./llms.txt) and the [llms-full.txt](./llms-full.txt) can be used as context to LLM. While the former one is a summarized one and the later one has the full information in case your LLM has big enough context window.
|
||||
|
||||
## đź“„ License
|
||||
|
||||
This project is licensed under the Apache 2.0 License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
|
||||
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
||||
from google.adk.tools.langchain_tool import LangchainTool
|
||||
from langchain_community.tools import YouTubeSearchTool
|
||||
from langchain_community.tools.youtube.search import YouTubeSearchTool
|
||||
|
||||
# Instantiate the tool
|
||||
langchain_yt_tool = YouTubeSearchTool()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import random
|
||||
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
|
||||
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
||||
from google.adk.tools.example_tool import ExampleTool
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
|
||||
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
||||
from google.genai import types
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
from typing import Any
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.tools import ToolContext
|
||||
from google.adk.tools.long_running_tool import LongRunningFunctionTool
|
||||
from google.adk.tools.tool_context import ToolContext
|
||||
from google.genai import types
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH
|
||||
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
|
||||
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
||||
|
||||
root_agent = RemoteA2aAgent(
|
||||
|
||||
@@ -21,8 +21,8 @@ from adk_answering_agent.settings import REPO
|
||||
from adk_answering_agent.settings import VERTEXAI_DATASTORE_ID
|
||||
from adk_answering_agent.utils import error_response
|
||||
from adk_answering_agent.utils import run_graphql_query
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.tools import VertexAiSearchTool
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
|
||||
import requests
|
||||
|
||||
if IS_INTERACTIVE:
|
||||
@@ -137,6 +137,12 @@ def add_comment_to_discussion(
|
||||
}
|
||||
}
|
||||
"""
|
||||
comment_body = (
|
||||
"**Response from ADK Answering Agent (experimental, answer may be"
|
||||
" inaccurate)**\n\n"
|
||||
+ comment_body
|
||||
)
|
||||
|
||||
variables = {"discussionId": discussion_id, "body": comment_body}
|
||||
try:
|
||||
response = run_graphql_query(query, variables)
|
||||
@@ -247,10 +253,8 @@ root_agent = Agent(
|
||||
* {APPROVAL_INSTRUCTION}
|
||||
* Your response should be based on the information you found in the document store. Do not invent
|
||||
information that is not in the document store. Do not invent citations which are not in the document store.
|
||||
* **Be Objective**: your answer should be based on the facts you found in the document store, do not be misled by user's assumptions or user's understanding of ADK.
|
||||
* If you can't find the answer or information in the document store, **do not** respond.
|
||||
* Include a bolded note (e.g. "Response from ADK Answering Agent") in your comment
|
||||
to indicate this comment was added by an ADK Answering Agent.
|
||||
* Have an empty line between the note and the rest of your response.
|
||||
* Inlclude a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
|
||||
* Have a divider line between the TLDR and your detail response.
|
||||
* Do not respond to any other discussion except the one specified by the user.
|
||||
|
||||
@@ -20,7 +20,7 @@ import time
|
||||
import agent
|
||||
from google.adk.agents.run_config import RunConfig
|
||||
from google.adk.runners import InMemoryRunner
|
||||
from google.adk.sessions import Session
|
||||
from google.adk.sessions.session import Session
|
||||
from google.genai import types
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# ADK Pull Request Triaging Assistant
|
||||
|
||||
The ADK Pull Request (PR) Triaging Assistant is a Python-based agent designed to help manage and triage GitHub pull requests for the `google/adk-python` repository. It uses a large language model to analyze new and unlabelled pull requests, recommend appropriate labels, assign a reviewer, and check contribution guides based on a predefined set of rules.
|
||||
|
||||
This agent can be operated in two distinct modes:
|
||||
|
||||
* an interactive mode for local use
|
||||
* 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 pull requests.
|
||||
|
||||
### 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 or posting a comment to a GitHub pull request.
|
||||
|
||||
### 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 PR 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:
|
||||
|
||||
* **Pull Request Events**: The workflow executes automatically whenever a new PR is `opened` or an existing one is `reopened` or `edited`.
|
||||
|
||||
### Automated Labeling
|
||||
When running as part of the GitHub workflow, the agent operates non-interactively. It identifies and applies the best label or posts a comment 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/pr-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
|
||||
```
|
||||
|
||||
### 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 `pull_requests: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.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from . import agent
|
||||
@@ -0,0 +1,317 @@
|
||||
# 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_pr_triaging_agent.settings import BOT_LABEL
|
||||
from adk_pr_triaging_agent.settings import GITHUB_BASE_URL
|
||||
from adk_pr_triaging_agent.settings import IS_INTERACTIVE
|
||||
from adk_pr_triaging_agent.settings import OWNER
|
||||
from adk_pr_triaging_agent.settings import REPO
|
||||
from adk_pr_triaging_agent.utils import error_response
|
||||
from adk_pr_triaging_agent.utils import get_diff
|
||||
from adk_pr_triaging_agent.utils import post_request
|
||||
from adk_pr_triaging_agent.utils import read_file
|
||||
from adk_pr_triaging_agent.utils import run_graphql_query
|
||||
from google.adk import Agent
|
||||
import requests
|
||||
|
||||
LABEL_TO_OWNER = {
|
||||
"documentation": "polong-lin",
|
||||
"services": "DeanChensj",
|
||||
"tools": "seanzhou1023",
|
||||
"eval": "ankursharmas",
|
||||
"live": "hangfei",
|
||||
"models": "genquan9",
|
||||
"tracing": "Jacksunwei",
|
||||
"core": "Jacksunwei",
|
||||
"web": "wyf7107",
|
||||
}
|
||||
|
||||
CONTRIBUTING_MD = read_file(
|
||||
Path(__file__).resolve().parents[3] / "CONTRIBUTING.md"
|
||||
)
|
||||
|
||||
APPROVAL_INSTRUCTION = (
|
||||
"Do not ask for user approval for labeling or commenting! If you can't find"
|
||||
" appropriate labels for the PR, do not label it."
|
||||
)
|
||||
if IS_INTERACTIVE:
|
||||
APPROVAL_INSTRUCTION = (
|
||||
"Only label or comment when the user approves the labeling or commenting!"
|
||||
)
|
||||
|
||||
|
||||
def get_pull_request_details(pr_number: int) -> str:
|
||||
"""Get the details of the specified pull request.
|
||||
|
||||
Args:
|
||||
pr_number: number of the Github pull request.
|
||||
|
||||
Returns:
|
||||
The status of this request, with the details when successful.
|
||||
"""
|
||||
print(f"Fetching details for PR #{pr_number} from {OWNER}/{REPO}")
|
||||
query = """
|
||||
query($owner: String!, $repo: String!, $prNumber: Int!) {
|
||||
repository(owner: $owner, name: $repo) {
|
||||
pullRequest(number: $prNumber) {
|
||||
id
|
||||
title
|
||||
body
|
||||
author {
|
||||
login
|
||||
}
|
||||
labels(last: 10) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
files(last: 50) {
|
||||
nodes {
|
||||
path
|
||||
}
|
||||
}
|
||||
comments(last: 50) {
|
||||
nodes {
|
||||
id
|
||||
body
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
commits(last: 50) {
|
||||
nodes {
|
||||
commit {
|
||||
url
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
statusCheckRollup {
|
||||
state
|
||||
contexts(last: 20) {
|
||||
nodes {
|
||||
... on StatusContext {
|
||||
context
|
||||
state
|
||||
targetUrl
|
||||
}
|
||||
... on CheckRun {
|
||||
name
|
||||
status
|
||||
conclusion
|
||||
detailsUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
variables = {"owner": OWNER, "repo": REPO, "prNumber": pr_number}
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/pulls/{pr_number}"
|
||||
|
||||
try:
|
||||
response = run_graphql_query(query, variables)
|
||||
if "errors" in response:
|
||||
return error_response(str(response["errors"]))
|
||||
|
||||
pr = response.get("data", {}).get("repository", {}).get("pullRequest")
|
||||
if not pr:
|
||||
return error_response(f"Pull Request #{pr_number} not found.")
|
||||
|
||||
# Filter out main merge commits.
|
||||
original_commits = pr.get("commits", {}).get("nodes", {})
|
||||
if original_commits:
|
||||
filtered_commits = [
|
||||
commit_node
|
||||
for commit_node in original_commits
|
||||
if not commit_node["commit"]["message"].startswith(
|
||||
"Merge branch 'main' into"
|
||||
)
|
||||
]
|
||||
pr["commits"]["nodes"] = filtered_commits
|
||||
|
||||
# Get diff of the PR and truncate it to avoid exceeding the maximum tokens.
|
||||
pr["diff"] = get_diff(url)[:10000]
|
||||
|
||||
return {"status": "success", "pull_request": pr}
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(str(e))
|
||||
|
||||
|
||||
def add_label_and_reviewer_to_pr(pr_number: int, label: str) -> dict[str, Any]:
|
||||
"""Adds a specified label and requests a review from a mapped reviewer on a PR.
|
||||
|
||||
Args:
|
||||
pr_number: the number of the Github pull request
|
||||
label: the label to add
|
||||
|
||||
Returns:
|
||||
The the status of this request, with the applied label and assigned
|
||||
reviewer when successful.
|
||||
"""
|
||||
print(f"Attempting to add label '{label}' and a reviewer to PR #{pr_number}")
|
||||
if label not in LABEL_TO_OWNER:
|
||||
return error_response(
|
||||
f"Error: Label '{label}' is not an allowed label. Will not apply."
|
||||
)
|
||||
|
||||
# Pull Request is a special issue in Github, so we can use issue url for PR.
|
||||
label_url = (
|
||||
f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{pr_number}/labels"
|
||||
)
|
||||
label_payload = [label, BOT_LABEL]
|
||||
|
||||
try:
|
||||
response = post_request(label_url, label_payload)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
|
||||
owner = LABEL_TO_OWNER.get(label, None)
|
||||
if not owner:
|
||||
return {
|
||||
"status": "warning",
|
||||
"message": (
|
||||
f"{response}\n\nLabel '{label}' does not have an owner. Will not"
|
||||
" assign."
|
||||
),
|
||||
"applied_label": label,
|
||||
}
|
||||
reviewer_url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/pulls/{pr_number}/requested_reviewers"
|
||||
reviewer_payload = {"reviewers": [owner]}
|
||||
try:
|
||||
post_request(reviewer_url, reviewer_payload)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return {
|
||||
"status": "warning",
|
||||
"message": f"Reviewer not assigned: {e}",
|
||||
"applied_label": label,
|
||||
}
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"applied_label": label,
|
||||
"assigned_reviewer": owner,
|
||||
}
|
||||
|
||||
|
||||
def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
|
||||
"""Add the specified comment to the given PR number.
|
||||
|
||||
Args:
|
||||
pr_number: the number of the Github pull request
|
||||
comment: the 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 #{pr_number}")
|
||||
|
||||
# Pull Request is a special issue in Github, so we can use issue url for PR.
|
||||
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{pr_number}/comments"
|
||||
payload = {"body": comment}
|
||||
|
||||
try:
|
||||
post_request(url, payload)
|
||||
except requests.exceptions.RequestException as e:
|
||||
return error_response(f"Error: {e}")
|
||||
return {
|
||||
"status": "success",
|
||||
"added_comment": comment,
|
||||
}
|
||||
|
||||
|
||||
root_agent = Agent(
|
||||
model="gemini-2.5-pro",
|
||||
name="adk_pr_triaging_assistant",
|
||||
description="Triage ADK pull requests.",
|
||||
instruction=f"""
|
||||
# 1. Identity
|
||||
You are a Pull Request (PR) triaging bot for the Github {REPO} repo with the owner {OWNER}.
|
||||
|
||||
# 2. Responsibilities
|
||||
Your core responsibility includes:
|
||||
- Get the pull request details.
|
||||
- Add a label to the pull request.
|
||||
- Assign a reviewer to the pull request.
|
||||
- Check if the pull request is following the contribution guidelines.
|
||||
- Add a comment to the pull request if it's not following the guidelines.
|
||||
|
||||
**IMPORTANT: {APPROVAL_INSTRUCTION}**
|
||||
|
||||
# 3. Guidelines & Rules
|
||||
Here are the rules for labeling:
|
||||
- If the PR is about documentations, label it with "documentation".
|
||||
- If it's about session, memory, artifacts services, label it with "services"
|
||||
- If it's about UI/web, label it with "web"
|
||||
- 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 PR, follow the previous instruction that starts with "IMPORTANT:".
|
||||
|
||||
Here is the contribution guidelines:
|
||||
`{CONTRIBUTING_MD}`
|
||||
|
||||
Here are the guidelines for checking if the PR is following the guidelines:
|
||||
- The "statusCheckRollup" in the pull request details may help you to identify if the PR is following some of the guidelines (e.g. CLA compliance).
|
||||
|
||||
Here are the guidelines for the comment:
|
||||
- **Be Polite and Helpful:** Start with a friendly tone.
|
||||
- **Be Specific:** Clearly list only the sections from the contribution guidelines that are still missing.
|
||||
- **Address the Author:** Mention the PR author by their username (e.g., `@username`).
|
||||
- **Provide Context:** Explain *why* the information or action is needed.
|
||||
- **Do not be repetitive:** If you have already commented on an PR asking for information, do not comment again unless new information has been added and it's still incomplete.
|
||||
- **Identify yourself:** Include a bolded note (e.g. "Response from ADK Triaging Agent") in your comment to indicate this comment was added by an ADK Answering Agent.
|
||||
|
||||
**Example Comment for a PR:**
|
||||
> **Response from ADK Triaging Agent**
|
||||
>
|
||||
> Hello @[pr-author-username], thank you for creating this PR!
|
||||
>
|
||||
> This PR is a bug fix, could you please associate the github issue with this PR? If there is no existing issue, could you please create one?
|
||||
>
|
||||
> In addition, could you please provide logs or screenshot after the fix is applied?
|
||||
>
|
||||
> This information will help reviewers to review your PR more efficiently. Thanks!
|
||||
|
||||
# 4. Steps
|
||||
When you are given a PR, here are the steps you should take:
|
||||
- Call the `get_pull_request_details` tool to get the details of the PR.
|
||||
- Skip the PR (i.e. do not label or comment) if the PR is closed or is labeled with "{BOT_LABEL}" or "google-contributior".
|
||||
- Check if the PR is following the contribution guidelines.
|
||||
- If it's not following the guidelines, recommend or add a comment to the PR that points to the contribution guidelines (https://github.com/google/adk-python/blob/main/CONTRIBUTING.md).
|
||||
- If it's following the guidelines, recommend or add a label to the PR.
|
||||
|
||||
# 5. Output
|
||||
Present the followings in an easy to read format highlighting PR number and your label.
|
||||
- The PR summary in a few sentence
|
||||
- The label you recommended or added with the justification
|
||||
- The owner of the label if you assigned a reviewer to the PR
|
||||
- The comment you recommended or added to the PR with the justification
|
||||
""",
|
||||
tools=[
|
||||
get_pull_request_details,
|
||||
add_label_and_reviewer_to_pr,
|
||||
add_comment_to_pr,
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
# 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 time
|
||||
|
||||
from adk_pr_triaging_agent import agent
|
||||
from adk_pr_triaging_agent.settings import OWNER
|
||||
from adk_pr_triaging_agent.settings import PULL_REQUEST_NUMBER
|
||||
from adk_pr_triaging_agent.settings import REPO
|
||||
from adk_pr_triaging_agent.utils import call_agent_async
|
||||
from adk_pr_triaging_agent.utils import parse_number_string
|
||||
from google.adk.runners import InMemoryRunner
|
||||
|
||||
APP_NAME = "adk_pr_triaging_app"
|
||||
USER_ID = "adk_pr_triaging_user"
|
||||
|
||||
|
||||
async def main():
|
||||
runner = InMemoryRunner(
|
||||
agent=agent.root_agent,
|
||||
app_name=APP_NAME,
|
||||
)
|
||||
session = await runner.session_service.create_session(
|
||||
app_name=APP_NAME, user_id=USER_ID
|
||||
)
|
||||
|
||||
pr_number = parse_number_string(PULL_REQUEST_NUMBER)
|
||||
if not pr_number:
|
||||
print(
|
||||
f"Error: Invalid pull request number received: {PULL_REQUEST_NUMBER}."
|
||||
)
|
||||
return
|
||||
|
||||
prompt = f"Please triage pull request #{pr_number}!"
|
||||
response = await call_agent_async(runner, USER_ID, session.id, prompt)
|
||||
print(f"<<<< Agent Final Output: {response}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_time = time.time()
|
||||
print(
|
||||
f"Start triaging {OWNER}/{REPO} pull request #{PULL_REQUEST_NUMBER} at"
|
||||
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(start_time))}"
|
||||
)
|
||||
print("-" * 80)
|
||||
asyncio.run(main())
|
||||
print("-" * 80)
|
||||
end_time = time.time()
|
||||
print(
|
||||
"Triaging finished at"
|
||||
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(end_time))}",
|
||||
)
|
||||
print("Total script execution time:", f"{end_time - start_time:.2f} seconds")
|
||||
@@ -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_GRAPHQL_URL = GITHUB_BASE_URL + "/graphql"
|
||||
|
||||
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")
|
||||
BOT_LABEL = os.getenv("BOT_LABEL", "bot triaged")
|
||||
PULL_REQUEST_NUMBER = os.getenv("PULL_REQUEST_NUMBER")
|
||||
|
||||
IS_INTERACTIVE = os.environ.get("INTERACTIVE", "1").lower() in ["true", "1"]
|
||||
@@ -0,0 +1,120 @@
|
||||
# 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 sys
|
||||
from typing import Any
|
||||
|
||||
from adk_pr_triaging_agent.settings import GITHUB_GRAPHQL_URL
|
||||
from adk_pr_triaging_agent.settings import GITHUB_TOKEN
|
||||
from google.adk.agents.run_config import RunConfig
|
||||
from google.adk.runners import Runner
|
||||
from google.genai import types
|
||||
import requests
|
||||
|
||||
headers = {
|
||||
"Authorization": f"token {GITHUB_TOKEN}",
|
||||
"Accept": "application/vnd.github.v3+json",
|
||||
}
|
||||
|
||||
diff_headers = {
|
||||
"Authorization": f"token {GITHUB_TOKEN}",
|
||||
"Accept": "application/vnd.github.v3.diff",
|
||||
}
|
||||
|
||||
|
||||
def run_graphql_query(query: str, variables: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Executes a GraphQL query."""
|
||||
payload = {"query": query, "variables": variables}
|
||||
response = requests.post(
|
||||
GITHUB_GRAPHQL_URL, headers=headers, json=payload, timeout=60
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def get_request(url: str, params: dict[str, Any] | None = None) -> Any:
|
||||
"""Executes a GET request."""
|
||||
if params is None:
|
||||
params = {}
|
||||
response = requests.get(url, headers=headers, params=params, timeout=60)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def get_diff(url: str) -> str:
|
||||
"""Executes a GET request for a diff."""
|
||||
response = requests.get(url, headers=diff_headers)
|
||||
response.raise_for_status()
|
||||
return response.text
|
||||
|
||||
|
||||
def post_request(url: str, payload: Any) -> dict[str, Any]:
|
||||
"""Executes a POST request."""
|
||||
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]:
|
||||
"""Returns an error response."""
|
||||
return {"status": "error", "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 ""
|
||||
|
||||
|
||||
def parse_number_string(number_str: str | None, default_value: int = 0) -> int:
|
||||
"""Parse a number from the given string."""
|
||||
if not number_str:
|
||||
return default_value
|
||||
|
||||
try:
|
||||
return int(number_str)
|
||||
except ValueError:
|
||||
print(
|
||||
f"Warning: Invalid number string: {number_str}. Defaulting to"
|
||||
f" {default_value}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return default_value
|
||||
|
||||
|
||||
async def call_agent_async(
|
||||
runner: Runner, user_id: str, session_id: str, prompt: str
|
||||
) -> str:
|
||||
"""Call the agent asynchronously with the user's prompt."""
|
||||
content = types.Content(
|
||||
role="user", parts=[types.Part.from_text(text=prompt)]
|
||||
)
|
||||
|
||||
final_response_text = ""
|
||||
async for event in runner.run_async(
|
||||
user_id=user_id,
|
||||
session_id=session_id,
|
||||
new_message=content,
|
||||
run_config=RunConfig(save_input_blobs_as_artifacts=False),
|
||||
):
|
||||
if event.content and event.content.parts:
|
||||
if text := "".join(part.text or "" for part in event.content.parts):
|
||||
if event.author != "user":
|
||||
final_response_text += text
|
||||
|
||||
return final_response_text
|
||||
@@ -23,7 +23,7 @@ from adk_triaging_agent.utils import error_response
|
||||
from adk_triaging_agent.utils import get_request
|
||||
from adk_triaging_agent.utils import patch_request
|
||||
from adk_triaging_agent.utils import post_request
|
||||
from google.adk import Agent
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
import requests
|
||||
|
||||
LABEL_TO_OWNER = {
|
||||
@@ -34,7 +34,7 @@ LABEL_TO_OWNER = {
|
||||
"tools": "seanzhou1023",
|
||||
"eval": "ankursharmas",
|
||||
"live": "hangfei",
|
||||
"models": "selcukgun",
|
||||
"models": "genquan9",
|
||||
"tracing": "Jacksunwei",
|
||||
"core": "Jacksunwei",
|
||||
"web": "wyf7107",
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
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.agents.llm_agent import LlmAgent
|
||||
from google.adk.auth.auth_credential import AuthCredentialTypes
|
||||
from google.adk.tools.bigquery.bigquery_credentials import BigQueryCredentialsConfig
|
||||
from google.adk.tools.bigquery.bigquery_toolset import BigQueryToolset
|
||||
from google.adk.tools.bigquery.config import BigQueryToolConfig
|
||||
from google.adk.tools.bigquery.config import WriteMode
|
||||
import google.auth
|
||||
@@ -62,7 +62,7 @@ bigquery_toolset = BigQueryToolset(
|
||||
|
||||
# The variable name `root_agent` determines what your root agent is for the
|
||||
# debug CLI
|
||||
root_agent = llm_agent.Agent(
|
||||
root_agent = LlmAgent(
|
||||
model="gemini-2.0-flash",
|
||||
name="bigquery_agent",
|
||||
description=(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user