|
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | 14 |
|
15 | | -from typing import Any |
16 | | - |
17 | 15 | from adk_answering_agent.settings import BOT_RESPONSE_LABEL |
18 | 16 | from adk_answering_agent.settings import IS_INTERACTIVE |
19 | 17 | from adk_answering_agent.settings import OWNER |
20 | 18 | from adk_answering_agent.settings import REPO |
21 | 19 | from adk_answering_agent.settings import VERTEXAI_DATASTORE_ID |
22 | | -from adk_answering_agent.utils import error_response |
23 | | -from adk_answering_agent.utils import run_graphql_query |
| 20 | +from adk_answering_agent.tools import add_comment_to_discussion |
| 21 | +from adk_answering_agent.tools import add_label_to_discussion |
| 22 | +from adk_answering_agent.tools import convert_gcs_links_to_https |
| 23 | +from adk_answering_agent.tools import get_discussion_and_comments |
24 | 24 | from google.adk.agents.llm_agent import Agent |
25 | 25 | from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool |
26 | | -import requests |
27 | 26 |
|
28 | 27 | if IS_INTERACTIVE: |
29 | 28 | APPROVAL_INSTRUCTION = ( |
|
35 | 34 | " comment." |
36 | 35 | ) |
37 | 36 |
|
38 | | - |
39 | | -def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]: |
40 | | - """Fetches a discussion and its comments using the GitHub GraphQL API. |
41 | | -
|
42 | | - Args: |
43 | | - discussion_number: The number of the GitHub discussion. |
44 | | -
|
45 | | - Returns: |
46 | | - A dictionary with the request status and the discussion details. |
47 | | - """ |
48 | | - print(f"Attempting to get discussion #{discussion_number} and its comments") |
49 | | - query = """ |
50 | | - query($owner: String!, $repo: String!, $discussionNumber: Int!) { |
51 | | - repository(owner: $owner, name: $repo) { |
52 | | - discussion(number: $discussionNumber) { |
53 | | - id |
54 | | - title |
55 | | - body |
56 | | - createdAt |
57 | | - closed |
58 | | - author { |
59 | | - login |
60 | | - } |
61 | | - # For each discussion, fetch the latest 20 labels. |
62 | | - labels(last: 20) { |
63 | | - nodes { |
64 | | - id |
65 | | - name |
66 | | - } |
67 | | - } |
68 | | - # For each discussion, fetch the latest 100 comments. |
69 | | - comments(last: 100) { |
70 | | - nodes { |
71 | | - id |
72 | | - body |
73 | | - createdAt |
74 | | - author { |
75 | | - login |
76 | | - } |
77 | | - # For each discussion, fetch the latest 50 replies |
78 | | - replies(last: 50) { |
79 | | - nodes { |
80 | | - id |
81 | | - body |
82 | | - createdAt |
83 | | - author { |
84 | | - login |
85 | | - } |
86 | | - } |
87 | | - } |
88 | | - } |
89 | | - } |
90 | | - } |
91 | | - } |
92 | | - } |
93 | | - """ |
94 | | - variables = { |
95 | | - "owner": OWNER, |
96 | | - "repo": REPO, |
97 | | - "discussionNumber": discussion_number, |
98 | | - } |
99 | | - try: |
100 | | - response = run_graphql_query(query, variables) |
101 | | - if "errors" in response: |
102 | | - return error_response(str(response["errors"])) |
103 | | - discussion_data = ( |
104 | | - response.get("data", {}).get("repository", {}).get("discussion") |
105 | | - ) |
106 | | - if not discussion_data: |
107 | | - return error_response(f"Discussion #{discussion_number} not found.") |
108 | | - return {"status": "success", "discussion": discussion_data} |
109 | | - except requests.exceptions.RequestException as e: |
110 | | - return error_response(str(e)) |
111 | | - |
112 | | - |
113 | | -def add_comment_to_discussion( |
114 | | - discussion_id: str, comment_body: str |
115 | | -) -> dict[str, Any]: |
116 | | - """Adds a comment to a specific discussion. |
117 | | -
|
118 | | - Args: |
119 | | - discussion_id: The GraphQL node ID of the discussion. |
120 | | - comment_body: The content of the comment in Markdown. |
121 | | -
|
122 | | - Returns: |
123 | | - The status of the request and the new comment's details. |
124 | | - """ |
125 | | - print(f"Adding comment to discussion {discussion_id}") |
126 | | - query = """ |
127 | | - mutation($discussionId: ID!, $body: String!) { |
128 | | - addDiscussionComment(input: {discussionId: $discussionId, body: $body}) { |
129 | | - comment { |
130 | | - id |
131 | | - body |
132 | | - createdAt |
133 | | - author { |
134 | | - login |
135 | | - } |
136 | | - } |
137 | | - } |
138 | | - } |
139 | | - """ |
140 | | - variables = {"discussionId": discussion_id, "body": comment_body} |
141 | | - try: |
142 | | - response = run_graphql_query(query, variables) |
143 | | - if "errors" in response: |
144 | | - return error_response(str(response["errors"])) |
145 | | - new_comment = ( |
146 | | - response.get("data", {}).get("addDiscussionComment", {}).get("comment") |
147 | | - ) |
148 | | - return {"status": "success", "comment": new_comment} |
149 | | - except requests.exceptions.RequestException as e: |
150 | | - return error_response(str(e)) |
151 | | - |
152 | | - |
153 | | -def get_label_id(label_name: str) -> str | None: |
154 | | - """Helper function to find the GraphQL node ID for a given label name.""" |
155 | | - print(f"Finding ID for label '{label_name}'...") |
156 | | - query = """ |
157 | | - query($owner: String!, $repo: String!, $labelName: String!) { |
158 | | - repository(owner: $owner, name: $repo) { |
159 | | - label(name: $labelName) { |
160 | | - id |
161 | | - } |
162 | | - } |
163 | | - } |
164 | | - """ |
165 | | - variables = {"owner": OWNER, "repo": REPO, "labelName": label_name} |
166 | | - |
167 | | - try: |
168 | | - response = run_graphql_query(query, variables) |
169 | | - if "errors" in response: |
170 | | - print( |
171 | | - f"[Warning] Error from GitHub API response for label '{label_name}':" |
172 | | - f" {response['errors']}" |
173 | | - ) |
174 | | - return None |
175 | | - label_info = response["data"].get("repository", {}).get("label") |
176 | | - if label_info: |
177 | | - return label_info.get("id") |
178 | | - print(f"[Warning] Label information for '{label_name}' not found.") |
179 | | - return None |
180 | | - except requests.exceptions.RequestException as e: |
181 | | - print(f"[Warning] Error from GitHub API: {e}") |
182 | | - return None |
183 | | - |
184 | | - |
185 | | -def add_label_to_discussion( |
186 | | - discussion_id: str, label_name: str |
187 | | -) -> dict[str, Any]: |
188 | | - """Adds a label to a specific discussion. |
189 | | -
|
190 | | - Args: |
191 | | - discussion_id: The GraphQL node ID of the discussion. |
192 | | - label_name: The name of the label to add (e.g., "bug"). |
193 | | -
|
194 | | - Returns: |
195 | | - The status of the request and the label details. |
196 | | - """ |
197 | | - print( |
198 | | - f"Attempting to add label '{label_name}' to discussion {discussion_id}..." |
199 | | - ) |
200 | | - # First, get the GraphQL ID of the label by its name |
201 | | - label_id = get_label_id(label_name) |
202 | | - if not label_id: |
203 | | - return error_response(f"Label '{label_name}' not found.") |
204 | | - |
205 | | - # Then, perform the mutation to add the label to the discussion |
206 | | - mutation = """ |
207 | | - mutation AddLabel($discussionId: ID!, $labelId: ID!) { |
208 | | - addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) { |
209 | | - clientMutationId |
210 | | - } |
211 | | - } |
212 | | - """ |
213 | | - variables = {"discussionId": discussion_id, "labelId": label_id} |
214 | | - try: |
215 | | - response = run_graphql_query(mutation, variables) |
216 | | - if "errors" in response: |
217 | | - return error_response(str(response["errors"])) |
218 | | - return {"status": "success", "label_id": label_id, "label_name": label_name} |
219 | | - except requests.exceptions.RequestException as e: |
220 | | - return error_response(str(e)) |
221 | | - |
222 | | - |
223 | 37 | root_agent = Agent( |
224 | 38 | model="gemini-2.5-pro", |
225 | 39 | name="adk_answering_agent", |
@@ -249,28 +63,20 @@ def add_label_to_discussion( |
249 | 63 | information that is not in the document store. Do not invent citations which are not in the document store. |
250 | 64 | * **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. |
251 | 65 | * If you can't find the answer or information in the document store, **do not** respond. |
252 | | - * Include a bolded note (e.g. "Response from ADK Answering Agent") in your comment |
253 | | - to indicate this comment was added by an ADK Answering Agent. |
254 | | - * Have an empty line between the note and the rest of your response. |
255 | 66 | * Inlclude a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>". |
256 | 67 | * Have a divider line between the TLDR and your detail response. |
257 | 68 | * Do not respond to any other discussion except the one specified by the user. |
258 | 69 | * Please include your justification for your decision in your output |
259 | 70 | to the user who is telling with you. |
260 | 71 | * If you uses citation from the document store, please provide a footnote |
261 | | - referencing the source document format it as: "[1] URL of the document". |
262 | | - * Replace the "gs://prefix/" part, e.g. "gs://adk-qa-bucket/", to be "https://github.com/google/" |
263 | | - * Add "blob/main/" after the repo name, e.g. "adk-python", "adk-docs", for example: |
264 | | - * If the original URL is "gs://adk-qa-bucket/adk-python/src/google/adk/version.py", |
265 | | - then the citation URL is "https://github.com/google/adk-python/blob/main/src/google/adk/version.py", |
266 | | - * If the original URL is "gs://adk-qa-bucket/adk-docs/docs/index.md", |
267 | | - then the citation URL is "https://github.com/google/adk-docs/blob/main/docs/index.md" |
268 | | - * If the file is a html file, replace the ".html" to be ".md" |
| 72 | + referencing the source document format it as: "[1] publicly accessible HTTPS URL of the document". |
| 73 | + * You can use the `convert_gcs_links_to_https` tool to convert GCS links to HTTPS links. |
269 | 74 | """, |
270 | 75 | tools=[ |
271 | 76 | VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID), |
272 | 77 | get_discussion_and_comments, |
273 | 78 | add_comment_to_discussion, |
274 | 79 | add_label_to_discussion, |
| 80 | + convert_gcs_links_to_https, |
275 | 81 | ], |
276 | 82 | ) |
0 commit comments