Files
adk-python/contributing/samples/adk_triaging_agent/agent.py
T

205 lines
6.8 KiB
Python
Raw Normal View History

2025-06-04 21:25:02 -07:00
# 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
2025-06-04 21:38:49 -07:00
from adk_triaging_agent.settings import BOT_LABEL
from adk_triaging_agent.settings import GITHUB_BASE_URL
from adk_triaging_agent.settings import IS_INTERACTIVE
from adk_triaging_agent.settings import OWNER
from adk_triaging_agent.settings import REPO
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
2025-06-04 21:25:02 -07:00
from google.adk import Agent
2025-06-04 21:38:49 -07:00
import requests
2025-06-04 21:25:02 -07:00
LABEL_TO_OWNER = {
"agent engine": "yeesian",
"documentation": "polong-lin",
"services": "DeanChensj",
"question": "",
"tools": "seanzhou1023",
"eval": "ankursharmas",
"live": "hangfei",
"models": "selcukgun",
"tracing": "Jacksunwei",
"core": "Jacksunwei",
"web": "wyf7107",
}
2025-06-04 21:25:02 -07:00
APPROVAL_INSTRUCTION = (
"Do not ask for user approval for labeling! If you can't find appropriate"
" labels for the issue, do not label it."
)
if IS_INTERACTIVE:
APPROVAL_INSTRUCTION = "Only label them when the user approves the labeling!"
def list_unlabeled_issues(issue_count: int) -> dict[str, Any]:
"""List most recent `issue_count` numer of unlabeled issues in the repo.
2025-06-04 21:25:02 -07:00
2025-06-04 21:38:49 -07:00
Args:
issue_count: number of issues to return
2025-06-04 21:25:02 -07:00
Returns:
The status of this request, with a list of issues when successful.
2025-06-04 21:38:49 -07:00
"""
url = f"{GITHUB_BASE_URL}/search/issues"
query = f"repo:{OWNER}/{REPO} is:open is:issue no:label"
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)
unlabeled_issues = []
2025-06-04 21:38:49 -07:00
for issue in issues:
if not issue.get("labels", None):
unlabeled_issues.append(issue)
return {"status": "success", "issues": unlabeled_issues}
2025-06-04 21:25:02 -07:00
def add_label_and_owner_to_issue(
issue_number: int, label: str
) -> dict[str, Any]:
"""Add the specified label and owner to the given issue number.
2025-06-04 21:38:49 -07:00
Args:
issue_number: issue number of the Github issue.
2025-06-04 21:38:49 -07:00
label: label to assign
Returns:
The the status of this request, with the applied label and assigned owner
when successful.
2025-06-04 21:38:49 -07:00
"""
print(f"Attempting to add label '{label}' to issue #{issue_number}")
if label not in LABEL_TO_OWNER:
return error_response(
f"Error: Label '{label}' is not an allowed label. Will not apply."
)
label_url = (
f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/labels"
)
label_payload = [label, BOT_LABEL]
2025-06-04 21:38:49 -07:00
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,
}
assignee_url = (
f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/assignees"
)
assignee_payload = {"assignees": [owner]}
try:
response = post_request(assignee_url, assignee_payload)
except requests.exceptions.RequestException as e:
return error_response(f"Error: {e}")
return {
"status": "success",
"message": response,
"applied_label": label,
"assigned_owner": owner,
}
2025-06-04 21:25:02 -07:00
def change_issue_type(issue_number: int, issue_type: str) -> dict[str, Any]:
"""Change the issue type of the given issue number.
Args:
issue_number: issue number of the Github issue, in string foramt.
issue_type: issue type to assign
Returns:
The the status of this request, with the applied issue type when successful.
"""
print(
f"Attempting to change issue type '{issue_type}' to issue #{issue_number}"
)
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}"
payload = {"type": issue_type}
try:
response = patch_request(url, payload)
except requests.exceptions.RequestException as e:
return error_response(f"Error: {e}")
return {"status": "success", "message": response, "issue_type": issue_type}
2025-06-04 21:25:02 -07:00
root_agent = Agent(
model="gemini-2.5-pro",
2025-06-04 21:38:49 -07:00
name="adk_triaging_assistant",
description="Triage ADK issues.",
instruction=f"""
You are a triaging bot for the Github {REPO} repo with the owner {OWNER}. You will help get issues, and recommend a label.
IMPORTANT: {APPROVAL_INSTRUCTION}
2025-06-04 21:25:02 -07:00
Here are the rules for labeling:
2025-06-04 21:34:33 -07:00
- 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 "web"
- If the user is asking about a question, label it with "question"
2025-06-04 21:34:33 -07:00
- 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 it's about agent engine, label it with "agent engine".
- If you can't find a appropriate labels for the issue, follow the previous instruction that starts with "IMPORTANT:".
Call the `add_label_and_owner_to_issue` tool to label the issue, which will also assign the issue to the owner of the label.
After you label the issue, call the `change_issue_type` tool to change the issue type:
- If the issue is a bug report, change the issue type to "Bug".
- If the issue is a feature request, change the issue type to "Feature".
- Otherwise, **do not change the issue type**.
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
- the owner of the label if you assign the issue to an owner
2025-06-04 21:25:02 -07:00
""",
tools=[
list_unlabeled_issues,
add_label_and_owner_to_issue,
change_issue_type,
],
2025-06-04 21:25:02 -07:00
)