Skip to content

Commit 8501792

Browse files
authored
Merge branch 'google:main' into main
2 parents 8aaaa3f + 0b79f8d commit 8501792

32 files changed

Lines changed: 1080 additions & 834 deletions

File tree

.github/workflows/pr-triage.yml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,24 @@
1515
name: ADK Pull Request Triaging Agent
1616

1717
on:
18-
pull_request_target:
19-
types: [opened, reopened, edited]
18+
schedule:
19+
# Run every 6 hours
20+
- cron: '0 */6 * * *'
2021
workflow_dispatch:
2122
inputs:
2223
pr_number:
23-
description: 'The Pull Request number to triage'
24-
required: true
24+
description: 'The Pull Request number to triage (leave empty for batch mode)'
25+
required: false
26+
type: 'string'
27+
pr_count:
28+
description: 'Number of PRs to process in batch mode (default: 10)'
29+
required: false
30+
default: '10'
2531
type: 'string'
2632

2733
jobs:
2834
agent-triage-pull-request:
29-
if: >-
30-
github.event_name == 'workflow_dispatch' || (
31-
github.event.pull_request.head.repo.full_name == github.repository &&
32-
!contains(github.event.pull_request.labels.*.name, 'google-contributor')
33-
)
35+
if: github.repository == 'google/adk-python'
3436
runs-on: ubuntu-latest
3537
permissions:
3638
pull-requests: write
@@ -57,7 +59,8 @@ jobs:
5759
GOOGLE_GENAI_USE_VERTEXAI: 0
5860
OWNER: 'google'
5961
REPO: 'adk-python'
60-
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
62+
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number || '' }}
63+
PR_COUNT_TO_PROCESS: ${{ github.event.inputs.pr_count || '10' }}
6164
INTERACTIVE: ${{ vars.PR_TRIAGE_INTERACTIVE }}
6265
PYTHONPATH: contributing/samples/adk_team
6366
run: python -m adk_pr_triaging_agent.main

AGENTS.md

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,3 @@
1-
# AI Coding Assistant Context
2-
3-
This document provides context for AI coding assistants (Antigravity, Gemini CLI, etc.) to understand the ADK Python project and assist with development.
4-
5-
## ADK Knowledge, Architecture, and Style
6-
7-
For all matters regarding ADK development, please use the appropriate skill:
8-
9-
- **`adk-architecture`**: Use this skill whenever you need to understand the architecture, event flow, or state management of the ADK system, or when designing or modifying core components and public APIs.
10-
- Read `.agents/skills/adk-architecture/SKILL.md` for full instructions.
11-
- **`adk-style`**: Use this skill whenever writing code, tests, or reviewing PRs for the ADK project to ensure compliance with styling and coding conventions. Also use it for committing, bug fixing, and testing rules.
12-
- Read `.agents/skills/adk-style/SKILL.md` for full instructions.
13-
- **`adk-git`**: Use this skill for any git operation (commit, push, pull, rebase, etc.). It provides guidelines for Conventional Commits and branch naming.
14-
- Read `.agents/skills/adk-git/SKILL.md` for full instructions.
15-
- **`adk-sample-creator`**: Use this skill when creating new samples demonstrating features or agent patterns, or when adding examples to subdirectories under `contributing/`.
16-
- Read `.agents/skills/adk-sample-creator/SKILL.md` for full instructions.
17-
- **`adk-review`**: Use this skill to review local changes for errors, style compliance, unintended outcomes, and to check if associated design docs, guides, samples, or tests need updates.
18-
- Read `.agents/skills/adk-review/SKILL.md` for full instructions.
19-
- **`adk-issue`**: Use this skill when analyzing, triaging, and resolving GitHub issues for the adk-python repository (orchestrating both triage and fix implementation). Do NOT use this skill if the "/adk-issue-analyze" command is explicitly requested.
20-
- Read `.agents/skills/adk-issue/SKILL.md` for full instructions.
21-
- **`adk-issue-analyze`**: Use this skill to fetch, inspect, and analyze a GitHub issue in a strictly read-only manner. Use this skill when the "/adk-issue-analyze" command is explicitly called.
22-
- Read `.agents/skills/adk-issue-analyze/SKILL.md` for full instructions.
23-
- **`adk-issue-fix`**: Use this skill to implement the code changes, unit tests, and documentation updates for an approved GitHub issue fix. Use this skill when the "/adk-issue-fix" command is explicitly called.
24-
- Read `.agents/skills/adk-issue-fix/SKILL.md` for full instructions.
25-
- **`adk-pr-analyze`**: Use this skill to fetch, inspect, and analyze a GitHub pull request in a strictly read-only manner. Use this skill when the "/adk-pr-analyze" command is explicitly called.
26-
- Read `.agents/skills/adk-pr-analyze/SKILL.md` for full instructions.
27-
- **`adk-pr-triage`**: Use this skill to orchestrate triaging and reviewing GitHub pull requests (PRs) (orchestrating both analysis and user review/checkout). Do NOT use this skill if the "/adk-pr-analyze" command is explicitly requested.
28-
- Read `.agents/skills/adk-pr-triage/SKILL.md` for full instructions.
29-
30-
311
## Project Overview
322

333
The Agent Development Kit (ADK) is an open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents.
@@ -45,6 +15,10 @@ The Agent Development Kit (ADK) is an open-source, code-first Python toolkit for
4515

4616
For details on how the Runner works and the invocation lifecycle, please refer to the `adk-architecture` skill and the referenced documentation therein.
4717

18+
## ADK Knowledge, Architecture, and Style
19+
20+
Skills related to ADK development are in `.agents/skills/`.
21+
4822
## Project Architecture
4923

5024
For detailed architecture patterns, component descriptions, and core interfaces, please refer to the **`adk-architecture`** skill at `.agents/skills/adk-architecture/SKILL.md`.

contributing/samples/adk_team/adk_pr_triaging_agent/agent.py

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from adk_pr_triaging_agent.settings import REPO
2222
from adk_pr_triaging_agent.utils import error_response
2323
from adk_pr_triaging_agent.utils import get_diff
24+
from adk_pr_triaging_agent.utils import get_request
2425
from adk_pr_triaging_agent.utils import post_request
2526
from adk_pr_triaging_agent.utils import read_file
2627
from adk_pr_triaging_agent.utils import run_graphql_query
@@ -219,6 +220,56 @@ def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
219220
}
220221

221222

223+
def list_untriaged_pull_requests(pr_count: int) -> dict[str, Any]:
224+
"""List open pull requests that need triaging.
225+
226+
Returns pull requests that need triaging (i.e. do not have google-contributor
227+
label and do not have any allowed triage category labels).
228+
229+
Args:
230+
pr_count: number of pull requests to return
231+
232+
Returns:
233+
The status of this request, with a list of pull requests when successful.
234+
"""
235+
url = f"{GITHUB_BASE_URL}/search/issues"
236+
query = f"repo:{OWNER}/{REPO} is:open is:pr"
237+
params = {
238+
"q": query,
239+
"sort": "updated",
240+
"order": "desc",
241+
"per_page": 100,
242+
"page": 1,
243+
}
244+
245+
try:
246+
response = get_request(url, params)
247+
except requests.exceptions.RequestException as e:
248+
return error_response(f"Error: {e}")
249+
250+
issues = response.get("items", [])
251+
triage_labels = set(ALLOWED_LABELS)
252+
untriaged_prs = []
253+
254+
for pr in issues:
255+
pr_labels = {label["name"] for label in pr.get("labels", [])}
256+
if "google-contributor" in pr_labels:
257+
continue
258+
# If it already has any of the ALLOWED_LABELS, skip it.
259+
if pr_labels & triage_labels:
260+
continue
261+
262+
untriaged_prs.append({
263+
"number": pr["number"],
264+
"title": pr["title"],
265+
})
266+
267+
if len(untriaged_prs) >= pr_count:
268+
break
269+
270+
return {"status": "success", "pull_requests": untriaged_prs}
271+
272+
222273
root_agent = Agent(
223274
model="gemini-3.5-flash",
224275
name="adk_pr_triaging_assistant",
@@ -276,15 +327,16 @@ def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
276327
> This information will help reviewers to review your PR more efficiently. Thanks!
277328
278329
# 4. Steps
279-
When you are given a PR, here are the steps you should take:
280-
- Call the `get_pull_request_details` tool to get the details of the PR.
281-
- Skip the PR (i.e. do not label or comment) if any of the following is true:
282-
- the PR is closed
283-
- the PR is labeled with "google-contributor"
284-
- the PR is already labelled with the above labels (e.g. "documentation", "services", "tools", etc.).
285-
- Check if the PR is following the contribution guidelines.
286-
- 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).
287-
- If it's following the guidelines, recommend or add a label to the PR.
330+
- If you are asked to find pull requests that need triaging, use `list_untriaged_pull_requests` first.
331+
- For each pull request to be triaged:
332+
- Call the `get_pull_request_details` tool to get the details of the PR.
333+
- Skip the PR (i.e. do not label or comment) if any of the following is true:
334+
- the PR is closed
335+
- the PR is labeled with "google-contributor"
336+
- the PR is already labelled with the above labels (e.g. "documentation", "services", "tools", etc.).
337+
- Check if the PR is following the contribution guidelines.
338+
- 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).
339+
- If it's following the guidelines, recommend or add a label to the PR.
288340
289341
# 5. Output
290342
Present the following in an easy to read format highlighting PR number and your label.
@@ -293,6 +345,7 @@ def add_comment_to_pr(pr_number: int, comment: str) -> dict[str, Any]:
293345
- The comment you recommended or added to the PR with the justification
294346
""",
295347
tools=[
348+
list_untriaged_pull_requests,
296349
get_pull_request_details,
297350
add_label_to_pr,
298351
add_comment_to_pr,

contributing/samples/adk_team/adk_pr_triaging_agent/main.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from adk_pr_triaging_agent import agent
2020
from adk_pr_triaging_agent.settings import OWNER
21+
from adk_pr_triaging_agent.settings import PR_COUNT_TO_PROCESS
2122
from adk_pr_triaging_agent.settings import PULL_REQUEST_NUMBER
2223
from adk_pr_triaging_agent.settings import REPO
2324
from adk_pr_triaging_agent.utils import call_agent_async
@@ -41,13 +42,20 @@ async def main():
4142
)
4243

4344
pr_number = parse_number_string(PULL_REQUEST_NUMBER)
44-
if not pr_number:
45+
if pr_number:
46+
prompt = f"Please triage pull request #{pr_number}!"
47+
else:
48+
pr_count = parse_number_string(PR_COUNT_TO_PROCESS, default_value=10)
4549
print(
46-
f"Error: Invalid pull request number received: {PULL_REQUEST_NUMBER}."
50+
"No pull request number received. Operating in batch mode (limit:"
51+
f" {pr_count})."
52+
)
53+
prompt = (
54+
f"Please use 'list_untriaged_pull_requests' to find {pr_count} pull"
55+
" requests that need triaging, then triage each one according to your"
56+
" instructions."
4757
)
48-
return
4958

50-
prompt = f"Please triage pull request #{pr_number}!"
5159
response = await call_agent_async(runner, USER_ID, session.id, prompt)
5260
print(f"<<<< Agent Final Output: {response}\n")
5361

contributing/samples/adk_team/adk_pr_triaging_agent/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
OWNER = os.getenv("OWNER", "google")
2929
REPO = os.getenv("REPO", "adk-python")
3030
PULL_REQUEST_NUMBER = os.getenv("PULL_REQUEST_NUMBER")
31+
PR_COUNT_TO_PROCESS = os.getenv("PR_COUNT_TO_PROCESS", "10")
3132

3233
IS_INTERACTIVE = os.environ.get("INTERACTIVE", "1").lower() in ["true", "1"]

src/google/adk/agents/config_agent_utils.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ def _load_config_from_path(config_path: str) -> AgentConfig:
8686
"""Load an agent's configuration from a YAML file.
8787
8888
Args:
89-
config_path: Path to the YAML config file. Both relative and absolute
90-
paths are accepted.
89+
config_path: Path to the YAML config file. Both relative and absolute paths
90+
are accepted.
9191
9292
Returns:
9393
The loaded and validated AgentConfig object.
@@ -124,21 +124,31 @@ def resolve_agent_reference(
124124
Args:
125125
ref_config: The agent reference configuration (AgentRefConfig).
126126
referencing_agent_config_abs_path: The absolute path to the agent config
127-
that contains the reference.
127+
that contains the reference.
128128
129129
Returns:
130130
The created agent instance.
131131
"""
132132
if ref_config.config_path:
133133
if os.path.isabs(ref_config.config_path):
134-
return from_config(ref_config.config_path)
135-
else:
136-
return from_config(
137-
os.path.join(
138-
os.path.dirname(referencing_agent_config_abs_path),
139-
ref_config.config_path,
140-
)
134+
raise ValueError(
135+
"Absolute paths are not allowed in AgentRefConfig config_path:"
136+
f" {ref_config.config_path!r}"
141137
)
138+
agent_dir = os.path.dirname(referencing_agent_config_abs_path)
139+
resolved_path = os.path.realpath(
140+
os.path.join(agent_dir, ref_config.config_path)
141+
)
142+
canonical_agent_dir = os.path.realpath(agent_dir)
143+
if (
144+
os.path.commonpath([canonical_agent_dir, resolved_path])
145+
!= canonical_agent_dir
146+
):
147+
raise ValueError(
148+
f"Path traversal detected: config_path {ref_config.config_path!r}"
149+
" resolves outside the agent directory"
150+
)
151+
return from_config(resolved_path)
142152
elif ref_config.code:
143153
return _resolve_agent_code_reference(ref_config.code)
144154
else:

src/google/adk/cli/cli_tools_click.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,7 +2000,6 @@ def cli_api_server(
20002000
"cloud_run",
20012001
context_settings={
20022002
"allow_extra_args": True,
2003-
"allow_interspersed_args": False,
20042003
},
20052004
)
20062005
@click.option(
@@ -2177,34 +2176,7 @@ def cli_deploy_cloud_run(
21772176

21782177
_warn_if_with_ui(with_ui)
21792178

2180-
# Parse arguments to separate gcloud args (after --) from regular args
2181-
gcloud_args = []
2182-
if "--" in ctx.args:
2183-
separator_index = ctx.args.index("--")
2184-
gcloud_args = ctx.args[separator_index + 1 :]
2185-
regular_args = ctx.args[:separator_index]
2186-
2187-
# If there are regular args before --, that's an error
2188-
if regular_args:
2189-
click.secho(
2190-
"Error: Unexpected arguments after agent path and before '--':"
2191-
f" {' '.join(regular_args)}. \nOnly arguments after '--' are passed"
2192-
" to gcloud.",
2193-
fg="red",
2194-
err=True,
2195-
)
2196-
ctx.exit(2)
2197-
else:
2198-
# No -- separator, treat all args as an error to enforce the new behavior
2199-
if ctx.args:
2200-
click.secho(
2201-
f"Error: Unexpected arguments: {' '.join(ctx.args)}. \nUse '--' to"
2202-
" separate gcloud arguments, e.g.: adk deploy cloud_run [options]"
2203-
" agent_path -- --min-instances=2",
2204-
fg="red",
2205-
err=True,
2206-
)
2207-
ctx.exit(2)
2179+
gcloud_args = ctx.args
22082180

22092181
try:
22102182
from . import cli_deploy

src/google/adk/cli/utils/local_storage.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ async def append_event(self, session: Session, event: Event) -> Event:
236236
service = await self._get_service(session.app_name)
237237
return await service.append_event(session, event)
238238

239+
async def close(self) -> None:
240+
"""Closes all underlying session services."""
241+
for service in self._services.values():
242+
if hasattr(service, "close"):
243+
await service.close()
244+
self._services.clear()
245+
246+
async def __aenter__(self) -> PerAgentDatabaseSessionService:
247+
"""Enters the async context manager."""
248+
return self
249+
250+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
251+
"""Exits the async context manager and closes the service."""
252+
await self.close()
253+
239254

240255
class PerAgentFileArtifactService(BaseArtifactService):
241256
"""Routes artifact storage to per-agent `.adk/artifacts` folders."""

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -578,18 +578,9 @@ async def run_live(
578578
# initial_history_in_client_content to True. This tells the Live server
579579
# that the provided history already includes the model's past responses,
580580
# preventing the server from generating duplicate responses for those replayed turns.
581-
#
582-
# ``history_config`` is only supported by the Gemini Developer API
583-
# backend; the Vertex AI / Gemini Enterprise Agent Platform backend has
584-
# no such field on its live setup message and rejects it. On Vertex,
585-
# history is instead seeded by ``send_history`` below
586-
# (``send_client_content`` with prior turns), so we skip
587-
# ``history_config`` for that backend.
588581
if (
589582
llm_request.contents
590583
and not invocation_context.live_session_resumption_handle
591-
and isinstance(llm, Gemini)
592-
and llm._api_backend == GoogleLLMVariant.GEMINI_API # pylint: disable=protected-access
593584
):
594585
if not llm_request.live_connect_config:
595586
llm_request.live_connect_config = types.LiveConnectConfig()

src/google/adk/integrations/agent_registry/agent_registry.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@
6262

6363
logger = logging.getLogger("google_adk." + __name__)
6464

65-
AGENT_REGISTRY_BASE_URL = "https://agentregistry.googleapis.com/v1alpha"
66-
AGENT_REGISTRY_MTLS_BASE_URL = (
67-
"https://agentregistry.mtls.googleapis.com/v1alpha"
68-
)
65+
AGENT_REGISTRY_BASE_URL = "https://agentregistry.googleapis.com/v1"
66+
AGENT_REGISTRY_MTLS_BASE_URL = "https://agentregistry.mtls.googleapis.com/v1"
6967

7068
_TRANSPORT_MAPPING = {
7169
"HTTP_JSON": A2ATransport.http_json,

0 commit comments

Comments
 (0)