|
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 |
| - comment_body = ( |
141 |
| - "**Response from ADK Answering Agent (experimental, answer may be" |
142 |
| - " inaccurate)**\n\n" |
143 |
| - + comment_body |
144 |
| - ) |
145 |
| - |
146 |
| - variables = {"discussionId": discussion_id, "body": comment_body} |
147 |
| - try: |
148 |
| - response = run_graphql_query(query, variables) |
149 |
| - if "errors" in response: |
150 |
| - return error_response(str(response["errors"])) |
151 |
| - new_comment = ( |
152 |
| - response.get("data", {}).get("addDiscussionComment", {}).get("comment") |
153 |
| - ) |
154 |
| - return {"status": "success", "comment": new_comment} |
155 |
| - except requests.exceptions.RequestException as e: |
156 |
| - return error_response(str(e)) |
157 |
| - |
158 |
| - |
159 |
| -def get_label_id(label_name: str) -> str | None: |
160 |
| - """Helper function to find the GraphQL node ID for a given label name.""" |
161 |
| - print(f"Finding ID for label '{label_name}'...") |
162 |
| - query = """ |
163 |
| - query($owner: String!, $repo: String!, $labelName: String!) { |
164 |
| - repository(owner: $owner, name: $repo) { |
165 |
| - label(name: $labelName) { |
166 |
| - id |
167 |
| - } |
168 |
| - } |
169 |
| - } |
170 |
| - """ |
171 |
| - variables = {"owner": OWNER, "repo": REPO, "labelName": label_name} |
172 |
| - |
173 |
| - try: |
174 |
| - response = run_graphql_query(query, variables) |
175 |
| - if "errors" in response: |
176 |
| - print( |
177 |
| - f"[Warning] Error from GitHub API response for label '{label_name}':" |
178 |
| - f" {response['errors']}" |
179 |
| - ) |
180 |
| - return None |
181 |
| - label_info = response["data"].get("repository", {}).get("label") |
182 |
| - if label_info: |
183 |
| - return label_info.get("id") |
184 |
| - print(f"[Warning] Label information for '{label_name}' not found.") |
185 |
| - return None |
186 |
| - except requests.exceptions.RequestException as e: |
187 |
| - print(f"[Warning] Error from GitHub API: {e}") |
188 |
| - return None |
189 |
| - |
190 |
| - |
191 |
| -def add_label_to_discussion( |
192 |
| - discussion_id: str, label_name: str |
193 |
| -) -> dict[str, Any]: |
194 |
| - """Adds a label to a specific discussion. |
195 |
| -
|
196 |
| - Args: |
197 |
| - discussion_id: The GraphQL node ID of the discussion. |
198 |
| - label_name: The name of the label to add (e.g., "bug"). |
199 |
| -
|
200 |
| - Returns: |
201 |
| - The status of the request and the label details. |
202 |
| - """ |
203 |
| - print( |
204 |
| - f"Attempting to add label '{label_name}' to discussion {discussion_id}..." |
205 |
| - ) |
206 |
| - # First, get the GraphQL ID of the label by its name |
207 |
| - label_id = get_label_id(label_name) |
208 |
| - if not label_id: |
209 |
| - return error_response(f"Label '{label_name}' not found.") |
210 |
| - |
211 |
| - # Then, perform the mutation to add the label to the discussion |
212 |
| - mutation = """ |
213 |
| - mutation AddLabel($discussionId: ID!, $labelId: ID!) { |
214 |
| - addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) { |
215 |
| - clientMutationId |
216 |
| - } |
217 |
| - } |
218 |
| - """ |
219 |
| - variables = {"discussionId": discussion_id, "labelId": label_id} |
220 |
| - try: |
221 |
| - response = run_graphql_query(mutation, variables) |
222 |
| - if "errors" in response: |
223 |
| - return error_response(str(response["errors"])) |
224 |
| - return {"status": "success", "label_id": label_id, "label_name": label_name} |
225 |
| - except requests.exceptions.RequestException as e: |
226 |
| - return error_response(str(e)) |
227 |
| - |
228 |
| - |
229 | 37 | root_agent = Agent(
|
230 | 38 | model="gemini-2.5-pro",
|
231 | 39 | name="adk_answering_agent",
|
@@ -261,19 +69,14 @@ def add_label_to_discussion(
|
261 | 69 | * Please include your justification for your decision in your output
|
262 | 70 | to the user who is telling with you.
|
263 | 71 | * If you uses citation from the document store, please provide a footnote
|
264 |
| - referencing the source document format it as: "[1] URL of the document". |
265 |
| - * Replace the "gs://prefix/" part, e.g. "gs://adk-qa-bucket/", to be "https://github.com/google/" |
266 |
| - * Add "blob/main/" after the repo name, e.g. "adk-python", "adk-docs", for example: |
267 |
| - * If the original URL is "gs://adk-qa-bucket/adk-python/src/google/adk/version.py", |
268 |
| - then the citation URL is "https://github.com/google/adk-python/blob/main/src/google/adk/version.py", |
269 |
| - * If the original URL is "gs://adk-qa-bucket/adk-docs/docs/index.md", |
270 |
| - then the citation URL is "https://github.com/google/adk-docs/blob/main/docs/index.md" |
271 |
| - * 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. |
272 | 74 | """,
|
273 | 75 | tools=[
|
274 | 76 | VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID),
|
275 | 77 | get_discussion_and_comments,
|
276 | 78 | add_comment_to_discussion,
|
277 | 79 | add_label_to_discussion,
|
| 80 | + convert_gcs_links_to_https, |
278 | 81 | ],
|
279 | 82 | )
|
0 commit comments