Skip to content

Commit 6fbc000

Browse files
committed
Merge remote-tracking branch 'upstream/main' into feat/add-metadata-parameter
2 parents 823b0e6 + 3fb8c7e commit 6fbc000

20 files changed

Lines changed: 643 additions & 154 deletions

File tree

contributing/samples/adk_team/adk_pr_triaging_agent/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ADK Pull Request Triaging Assistant
22

3-
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.
3+
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, and assign the component owner based on a predefined set of rules.
44

55
This agent can be operated in two distinct modes:
66

@@ -16,7 +16,7 @@ This mode allows you to run the agent locally to review its recommendations in r
1616
### Features
1717

1818
- **Web Interface**: The agent's interactive mode can be rendered in a web browser using the ADK's `adk web` command.
19-
- **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.
19+
- **User Approval**: In interactive mode, the agent is instructed to ask for your confirmation before applying a label or assigning an owner to a GitHub pull request.
2020

2121
### Running in Interactive Mode
2222

@@ -42,7 +42,7 @@ The GitHub workflow is configured to run on specific triggers:
4242

4343
### Automated Labeling
4444

45-
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.
45+
When running as part of the GitHub workflow, the agent operates non-interactively. It identifies and applies the best label and assigns the component owner directly without requiring user approval. This behavior is configured by setting the `INTERACTIVE` environment variable to `0` in the workflow file.
4646

4747
### Workflow Configuration
4848

contributing/samples/adk_team/adk_pr_triaging_agent/agent.py

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from pathlib import Path
1615
from typing import Any
1716

1817
from adk_pr_triaging_agent.settings import GITHUB_BASE_URL
@@ -24,7 +23,6 @@
2423
from adk_pr_triaging_agent.utils import get_request
2524
from adk_pr_triaging_agent.utils import is_assignable
2625
from adk_pr_triaging_agent.utils import post_request
27-
from adk_pr_triaging_agent.utils import read_file
2826
from adk_pr_triaging_agent.utils import run_graphql_query
2927
from google.adk import Agent
3028
import requests
@@ -59,17 +57,13 @@
5957
"web": "wyf7107",
6058
}
6159

62-
CONTRIBUTING_MD = read_file(
63-
Path(__file__).resolve().parents[4] / "CONTRIBUTING.md"
64-
)
65-
6660
APPROVAL_INSTRUCTION = (
67-
"Do not ask for user approval for labeling, commenting, or assigning!"
61+
"Do not ask for user approval for labeling or assigning!"
6862
" If you can't find appropriate labels for the PR, do not label it."
6963
)
7064
if IS_INTERACTIVE:
7165
APPROVAL_INSTRUCTION = (
72-
"Only label, comment, or assign when the user approves the action!"
66+
"Only label or assign when the user approves the action!"
7367
)
7468

7569

@@ -259,32 +253,6 @@ def assign_owner_to_pr(pr_number: int, label: str) -> dict[str, Any]:
259253
}
260254

261255

262-
def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
263-
"""Add the specified comment to the given PR number.
264-
265-
Args:
266-
pr_number: the number of the GitHub pull request
267-
comment: the comment to add
268-
269-
Returns:
270-
The status of this request, with the applied comment when successful.
271-
"""
272-
print(f"Attempting to add comment '{comment}' to issue #{pr_number}")
273-
274-
# Pull Request is a special issue in GitHub, so we can use issue url for PR.
275-
url = f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{pr_number}/comments"
276-
payload = {"body": comment}
277-
278-
try:
279-
post_request(url, payload)
280-
except requests.exceptions.RequestException as e:
281-
return error_response(f"Error: {e}")
282-
return {
283-
"status": "success",
284-
"added_comment": comment,
285-
}
286-
287-
288256
def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]:
289257
"""List open pull requests that need triaging.
290258
@@ -348,8 +316,6 @@ def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]:
348316
- Get the pull request details.
349317
- Add a label to the pull request.
350318
- Assign the component owner (the shepherd) to the pull request.
351-
- Check if the pull request is following the contribution guidelines.
352-
- Add a comment to the pull request if it's not following the guidelines.
353319
354320
**IMPORTANT: {APPROVAL_INSTRUCTION}**
355321
@@ -367,59 +333,30 @@ def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]:
367333
- If it's about Model Context Protocol (e.g. MCP tool, MCP toolset, MCP session management etc.), label it with "mcp".
368334
- If you can't find an appropriate labels for the PR, follow the previous instruction that starts with "IMPORTANT:".
369335
370-
Here is the contribution guidelines:
371-
`{CONTRIBUTING_MD}`
372-
373-
Here are the guidelines for checking if the PR is following the guidelines:
374-
- 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).
375-
376-
Here are the guidelines for the comment:
377-
- **Be Polite and Helpful:** Start with a friendly tone.
378-
- **Be Specific:** Clearly list only the sections from the contribution guidelines that are still missing.
379-
- **Address the Author:** Mention the PR author by their username (e.g., `@username`).
380-
- **Provide Context:** Explain *why* the information or action is needed.
381-
- **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.
382-
- **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.
383-
384-
**Example Comment for a PR:**
385-
> **Response from ADK Triaging Agent**
386-
>
387-
> Hello @[pr-author-username], thank you for creating this PR!
388-
>
389-
> 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?
390-
>
391-
> In addition, could you please provide logs or screenshot after the fix is applied?
392-
>
393-
> This information will help reviewers to review your PR more efficiently. Thanks!
394-
395336
# 4. Steps
396337
- If you are asked to find pull requests that need triaging, use `list_untriaged_pull_requests` first.
397338
- For each pull request to be triaged:
398339
- Call the `get_pull_request_details` tool to get the details of the PR.
399-
- Skip the PR (i.e. do not label or comment) if any of the following is true:
340+
- Skip the PR (i.e. do not label) if any of the following is true:
400341
- the PR is closed
401342
- the PR is labeled with "google-contributor"
402343
- the PR is already labelled with the above labels (e.g. "documentation", "services", "tools", etc.).
403-
- Check if the PR is following the contribution guidelines.
404-
- 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).
405-
- If it's following the guidelines, recommend or add a label to the PR.
344+
- Recommend or add a label to the PR.
406345
- After you add a component label, assign the component owner (the shepherd) to the PR:
407346
- Call `assign_owner_to_pr` with the same label you applied.
408347
- Skip assignment if the PR already has an assignee.
409-
- If the tool reports the owner is not assignable, just note it; do not comment about it.
348+
- If the tool reports the owner is not assignable, just note it.
410349
411350
# 5. Output
412351
Present the following in an easy to read format highlighting PR number and your label.
413352
- The PR summary in a few sentence
414353
- The label you recommended or added with the justification
415354
- The owner you assigned (or why you did not)
416-
- The comment you recommended or added to the PR with the justification
417355
""",
418356
tools=[
419357
list_untriaged_pull_requests,
420358
get_pull_request_details,
421359
add_label_to_pr,
422360
assign_owner_to_pr,
423-
add_comment_to_pr,
424361
],
425362
)

contributing/samples/live/live_bidi_streaming_tools_agent/agent.py

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@
2222

2323

2424
async def monitor_stock_price(stock_symbol: str) -> AsyncGenerator[str, None]:
25-
"""This function will monitor the price for the given stock_symbol in a continuous, streaming and asynchronously way."""
25+
"""Starts a background monitor for the price of the given stock_symbol.
26+
27+
Call this function ONLY ONCE to initiate monitoring. Once started, it runs
28+
continuously in the background and automatically streams price alerts.
29+
30+
CRITICAL: Do NOT call this function again to "check" or "poll" for updates.
31+
Simply wait for the background task to yield new values and report them.
32+
Calling this again while running will launch a duplicate background task.
33+
"""
2634
print(f"Start monitor stock price for {stock_symbol}!")
2735

2836
# Let's mock stock price change.
@@ -51,13 +59,21 @@ async def monitor_stock_price(stock_symbol: str) -> AsyncGenerator[str, None]:
5159
async def monitor_video_stream(
5260
input_stream: LiveRequestQueue,
5361
) -> AsyncGenerator[str, None]:
54-
"""Monitor how many people are in the video streams."""
62+
"""Starts a background monitor for the video stream.
63+
64+
Call this function ONLY ONCE to initiate monitoring. Once started, it runs
65+
continuously in the background and automatically streams updates back to
66+
you whenever the person count changes.
67+
68+
CRITICAL: Do NOT call this function again to "check" or "poll" for updates.
69+
Simply wait for the background task to yield new values and report them.
70+
Calling this again while running will launch a duplicate background task.
71+
"""
5572
from google.genai import Client
5673

5774
print("start monitor_video_stream!")
58-
from google.genai import Client
5975

60-
client = Client(enterprise=False)
76+
client = Client()
6177
prompt_text = (
6278
"Count the number of people in this image. Just respond with a numeric"
6379
" number."
@@ -90,6 +106,7 @@ async def monitor_video_stream(
90106

91107
# Call the model to generate content based on the provided image and prompt
92108
response = client.models.generate_content(
109+
model="gemini-2.5-flash",
93110
contents=contents,
94111
config=genai_types.GenerateContentConfig(
95112
system_instruction=(
@@ -99,12 +116,12 @@ async def monitor_video_stream(
99116
)
100117
),
101118
)
119+
new_count = response.candidates[0].content.parts[0].text.strip()
102120
if not last_count:
103-
last_count = response.candidates[0].content.parts[0].text
104-
elif last_count != response.candidates[0].content.parts[0].text:
105-
last_count = response.candidates[0].content.parts[0].text
106-
yield response
107-
print("response:", response)
121+
last_count = new_count
122+
elif last_count != new_count:
123+
last_count = new_count
124+
yield new_count
108125

109126
# Wait before checking for new images
110127
await asyncio.sleep(0.5)
@@ -135,6 +152,11 @@ def stop_streaming(function_name: str):
135152
You can use monitor_video_stream function to do that. When monitor_video_stream
136153
returns the alert, you should tell the users.
137154
When users want to monitor a stock price, you can use monitor_stock_price.
155+
CRITICAL: Only call the monitor tools (monitor_video_stream, monitor_stock_price) at most once per request.
156+
Once called, these tools run continuously in the background. Do NOT call them again to "poll" or "check" for updates.
157+
Instead, simply wait for the background tool to stream a new message/alert to you, and then report that alert to the user.
158+
Calling the tool again while it is already running will cause duplicate tasks and errors.
159+
If you need to stop a monitor, call stop_streaming. Only after stopping can you call the monitor tool again if needed.
138160
Don't ask too many questions. Don't be too talkative.
139161
""",
140162
tools=[

src/google/adk/cli/api_server.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,10 @@ async def get_runner_async(self, app_name: str) -> Runner:
742742
return self.runner_dict[app_name]
743743

744744
# Create new runner
745-
agent_or_app = self.agent_loader.load_agent(app_name)
745+
try:
746+
agent_or_app = self.agent_loader.load_agent(app_name)
747+
except ValueError as ve:
748+
raise HTTPException(status_code=404, detail=str(ve)) from ve
746749

747750
if self.default_llm_model:
748751
from .cli import _override_default_llm_model
@@ -1162,7 +1165,10 @@ async def get_adk_app_info(app_name: str) -> AppInfo:
11621165
" mode."
11631166
),
11641167
)
1165-
agent_or_app = self.agent_loader.load_agent(app_name)
1168+
try:
1169+
agent_or_app = self.agent_loader.load_agent(app_name)
1170+
except ValueError as ve:
1171+
raise HTTPException(status_code=404, detail=str(ve)) from ve
11661172
root_agent = self._get_root_agent(agent_or_app)
11671173
if isinstance(root_agent, LlmAgent):
11681174
return AppInfo(

src/google/adk/flows/llm_flows/contents.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ def _build_task_input_user_content(
387387
try:
388388
import json as _json
389389

390-
text = _json.dumps(dict(fc.args))
390+
text = _json.dumps(dict(fc.args), ensure_ascii=False)
391391
except (TypeError, ValueError):
392392
text = str(fc.args)
393393
parts = [types.Part(text=text)]

0 commit comments

Comments
 (0)