Skip to content

Commit c780688

Browse files
committed
Merge upstream/main into vzgpt-core
2 parents 72946e2 + 61a3933 commit c780688

29 files changed

Lines changed: 6921 additions & 5065 deletions

.agents/skills/adk-issue-analyze/SKILL.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@ description: Analyze and triage a GitHub issue for the adk-python repository. Us
88
This skill provides a structured workflow for analyzing, verifying, and triaging GitHub issues from the `google/adk-python` repository. When instructed to analyze/triage an issue, follow this read-only workflow.
99

1010
> [!IMPORTANT]
11-
> This skill is strictly **read-only**: Do NOT modify any code, create new branches, or write any implementation during this phase.
11+
> **Strict Read-Only Constraint**:
12+
> This skill is strictly **read-only**. You MUST NOT modify any code, create new branches, or write any implementation. Your role is only to analyze the issue and output the report. Do NOT use file creation or editing tools (e.g. `write_to_file`, `replace_file_content`, `edit_file`, etc.).
13+
>
14+
> **Strict Tooling Constraint**:
15+
> Do NOT use `curl`, `wget`, or any HTTP requests to fetch issue/PR content. You MUST parse/extract the issue number and use strictly the custom `fetch_github_issue` / `fetch_github_pr` python tools (or the `gh` command).
1216
1317
## Step 1: Retrieve and Parse the Issue
1418
1. **Extract the issue number**: Parse the number from the link or prompt (e.g., `https://github.com/google/adk-python/issues/5882` -> `5882`).
15-
2. **Fetch issue details**: Use the `gh` CLI tool to fetch issue details in JSON format:
19+
2. **Fetch issue details**: Use the custom python tool `fetch_github_issue(issue_number=<number>)` to get the issue metadata. This is the preferred method as it avoids command execution policy issues.
20+
*If the custom python tool is not available, fall back to running the gh command:*
1621
```bash
1722
gh issue view <issue_number> --repo google/adk-python --json number,title,body,state,labels,comments,assignees,createdAt,closedAt
1823
```
19-
*If the `gh` CLI is not available or errors out, use `read_url_content` to fetch the public GitHub issue page:*
20-
```
21-
https://github.com/google/adk-python/issues/<issue_number>
22-
```
2324

2425
---
2526

@@ -63,7 +64,6 @@ Search for any existing pull requests that attempt to resolve the issue:
6364
```
6465
- **Analyze progress**: Check if the PR is open, merged, or closed, and if it successfully fixes the issue according to the repository's testing patterns.
6566
- **Present the structured report**: Format and present your findings structured as a premium report following the **Report Template** below.
66-
- **Offer to create a fix**: If no existing PR is found, you MUST explicitly ask the user: "Would you like me to create and implement a fix for this issue in the workspace? (Note: The changes and tests will be created in a new branch but NOT committed, so you can review and iterate on them.)"
6767

6868
---
6969

@@ -109,6 +109,15 @@ Present your final analysis as a high-quality markdown response using the follow
109109
---
110110

111111
## Tips & Best Practices
112+
> [!IMPORTANT]
113+
> **Command Sandbox Policy**:
114+
> When running commands via `run_command`, you MUST ONLY use `gh` or `git` commands. Commands like `curl`, `wget`, or direct HTTP network requests are strictly forbidden and will be automatically denied.
115+
> Furthermore, you MUST ONLY use simple commands without special characters (such as `;`, `&`, `|`, `$`, `` ` ``, `<`, `>`, `\n`, `\r`, `(`, `)`, `{`, `}`, `\`). The runner environment runs a security policy that automatically denies any commands containing these characters. Always run clean `gh` or `git` commands directly with arguments, without redirections, command chaining, or shell expansions.
116+
117+
> [!IMPORTANT]
118+
> **Strict Read-Only Enforcement**:
119+
> When executing the `adk-issue-analyze` skill, you MUST NOT use any file modification or editing tools (such as `edit_file`, `replace_file_content`, `write_to_file`, `notebook_edit`, etc.). Your output must strictly be a text markdown report following the template provided, without editing any workspace files or writing/fixing code.
120+
112121
> [!TIP]
113122
> Always use explicit repository qualifiers (`--repo google/adk-python`) when running `gh` commands to avoid failures due to custom internal or local git remotes.
114123

.agents/skills/adk-pr-triage/SKILL.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ This skill guides AI assistants in conducting a highly professional, rigorous, a
3030
> Wait for instructions before performing any branch creation or Gerrit push.
3131
---
3232
## Phase 1: Retrieve and Parse the PR & Linked Context (Read-Only)
33+
> [!IMPORTANT]
34+
> **Strict Tooling Constraint**: Do NOT use `curl`, `wget`, or any HTTP requests to fetch PR/issue content. You MUST parse/extract the numbers and use strictly the custom `fetch_github_issue` / `fetch_github_pr` python tools, the `gh` command, or the helper scripts provided.
35+
3336
### Step 1: Extract PR Identifier, Verify CLA Signature & PR Assignment (Mandatory Entry Gate)
3437
1. **Identify the PR identifier**: Parse the PR number or URL from the prompt (e.g., `https://github.com/google/adk-python/pull/5885` -> `5885`).
3538
2. **CRITICAL COMPLIANCE & ASSIGNMENT GATES - Run Verification Script**:
@@ -63,10 +66,11 @@ This skill guides AI assistants in conducting a highly professional, rigorous, a
6366
- **PR IS ALREADY ASSIGNED TO YOU**: Proceed directly with Step 1.3.
6467
3. **Parse PR Details from Script Output**: The verification script in Step 2 outputs the complete PR details JSON directly to standard output, wrapped in `[PR_METADATA_JSON]` and `[/PR_METADATA_JSON]` tags. Do NOT write to or read from local cache files, and do NOT make separate network commands to fetch PR details. Parse the JSON metadata directly from the command's stdout:
6568
* **Key JSON Attributes**: `number`, `title`, `body`, `state`, `url`, `author`, `additions`, `deletions`, `changedFiles`, `labels`, `assignees`, `closingIssuesReferences` (used to locate linked issues).
66-
4. **Locate and Fetch Linked Issue(s)**: Extract linked closing issues directly from the `closingIssuesReferences` array in the parsed JSON metadata from the script's stdout. If any closing issues are linked, fetch their details to understand the original problem statement:
67-
```bash
68-
gh issue view <issue_number> --repo google/adk-python --json number,title,body,state
69-
```
69+
4. **Locate and Fetch Linked Issue(s)**: Extract linked closing issues directly from the `closingIssuesReferences` array in the parsed JSON metadata from the script's stdout. If any closing issues are linked, fetch their details using the custom python tool `fetch_github_issue(issue_number=<number>)`. This is preferred as it avoids command execution policy issues.
70+
*If the custom python tool is not available, run the gh command:*
71+
```bash
72+
gh issue view <issue_number> --repo google/adk-python --json number,title,body,state
73+
```
7074
### Step 2: Retrieve the Complete Diff
7175
1. **Fetch pull request changes**: Run the `gh pr diff` command to view the actual line-by-line diff of the PR:
7276
```bash
@@ -280,6 +284,11 @@ Please let me know if you have any questions on these suggestions, and let's wor
280284
````
281285
---
282286
## Tips & Best Practices
287+
> [!IMPORTANT]
288+
> **Command Sandbox Policy**:
289+
> When running commands via `run_command`, you MUST ONLY use `gh` or `git` commands. Commands like `curl`, `wget`, or direct HTTP network requests are strictly forbidden and will be automatically denied.
290+
> Furthermore, you MUST ONLY use simple commands without special characters (such as `;`, `&`, `|`, `$`, `` ` ``, `<`, `>`, `\n`, `\r`, `(`, `)`, `{`, `}`, `\`). The runner environment runs a security policy that automatically denies any commands containing these characters. Always run clean `gh` or `git` commands directly with arguments, without redirections, command chaining, or shell expansions.
291+
283292
> [!TIP]
284293
> Always verify the baseline behavior in your active workspace before claiming something is a bug or invalid. Reading the current source files using `view_file` gives you full context.
285294
> [!IMPORTANT]
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: ADK Issue Triage & Analysis
16+
17+
on:
18+
issues:
19+
types: [opened]
20+
issue_comment:
21+
types: [created]
22+
workflow_dispatch:
23+
inputs:
24+
issue_url:
25+
description: 'The URL of the GitHub issue to analyze'
26+
required: true
27+
type: string
28+
29+
jobs:
30+
issue-analyze:
31+
if: >-
32+
github.repository == 'google/adk-python' && (
33+
github.event_name == 'issues' ||
34+
github.event_name == 'workflow_dispatch' ||
35+
(github.event_name == 'issue_comment' &&
36+
!github.event.issue.pull_request &&
37+
startsWith(github.event.comment.body, '/adk-issue-analyze') && (
38+
github.event.comment.author_association == 'OWNER' ||
39+
github.event.comment.author_association == 'MEMBER' ||
40+
github.event.comment.author_association == 'COLLABORATOR'
41+
))
42+
)
43+
runs-on: ubuntu-latest
44+
permissions:
45+
issues: write
46+
contents: read
47+
48+
steps:
49+
- name: Checkout repository
50+
uses: actions/checkout@v6
51+
52+
- name: Set up Python
53+
uses: actions/setup-python@v6
54+
with:
55+
python-version: '3.11'
56+
57+
- name: Authenticate to Google Cloud
58+
id: auth
59+
uses: 'google-github-actions/auth@v3'
60+
with:
61+
credentials_json: '${{ secrets.ADK_GCP_SA_KEY }}'
62+
63+
- name: Install Google Antigravity SDK
64+
run: pip install google-antigravity
65+
66+
- name: Run Antigravity Triage
67+
env:
68+
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
69+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
70+
run: |
71+
python scripts/run_antigravity.py "/adk-issue-analyze ${{ github.event.issue.html_url || inputs.issue_url }}" > triage_report.md
72+
cat triage_report.md
73+
74+
- name: Post Triage Report as Comment
75+
env:
76+
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
77+
run: |
78+
gh issue comment "${{ github.event.issue.html_url || inputs.issue_url }}" --body-file triage_report.md

scripts/run_antigravity.py

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Runner script to execute prompts/commands via the Antigravity SDK."""
16+
17+
import argparse
18+
import asyncio
19+
import os
20+
import shlex
21+
import sys
22+
from typing import Any
23+
24+
try:
25+
from google.antigravity import Agent
26+
from google.antigravity import CapabilitiesConfig
27+
from google.antigravity import LocalAgentConfig
28+
from google.antigravity.hooks import policy
29+
from google.antigravity.types import Text
30+
from google.antigravity.types import Thought
31+
from google.antigravity.types import ToolCall
32+
from google.antigravity.types import ToolResult
33+
except ImportError:
34+
print(
35+
"Error: google-antigravity package is not installed. Run 'pip install"
36+
" google-antigravity'",
37+
file=sys.stderr,
38+
)
39+
sys.exit(1)
40+
41+
42+
def _is_safe_command(args: dict[str, Any]) -> bool:
43+
"""Validates if the command is a safe 'gh' or 'git' execution with no shell injections."""
44+
cmd = (args.get("command_line") or args.get("CommandLine") or "").strip()
45+
if not cmd:
46+
return False
47+
48+
# Forbid shell metacharacters and control characters
49+
forbidden_chars = {
50+
";",
51+
"&",
52+
"|",
53+
"$",
54+
"`",
55+
"<",
56+
">",
57+
"\n",
58+
"\r",
59+
"(",
60+
")",
61+
"\\",
62+
"{",
63+
"}",
64+
}
65+
if any(char in cmd for char in forbidden_chars):
66+
return False
67+
68+
try:
69+
tokens = shlex.split(cmd)
70+
except ValueError:
71+
return False
72+
73+
if not tokens:
74+
return False
75+
76+
return tokens[0] in {"gh", "git"}
77+
78+
79+
def fetch_github_issue(issue_number: int) -> str:
80+
"""Fetches the details of a GitHub issue from the google/adk-python repository.
81+
82+
Args:
83+
issue_number: The issue number (e.g. 5949).
84+
"""
85+
import subprocess
86+
87+
# Use curl to fetch the issue details.
88+
# This supports running it outside of the gh CLI environment (e.g. without login/remotes setup).
89+
cmd = [
90+
"curl",
91+
"-s",
92+
]
93+
token = os.environ.get("GITHUB_TOKEN")
94+
if token:
95+
cmd.extend(["-H", f"Authorization: token {token}"])
96+
cmd.append(
97+
f"https://api.github.com/repos/google/adk-python/issues/{issue_number}"
98+
)
99+
100+
try:
101+
res = subprocess.run(cmd, capture_output=True, text=True, check=False)
102+
if res.returncode != 0:
103+
return (
104+
f"Error: Failed to fetch issue {issue_number}: {res.stderr.strip()}"
105+
)
106+
return res.stdout.strip()
107+
except Exception as e:
108+
return f"Error: Failed to run curl command: {e}"
109+
110+
111+
def fetch_github_pr(pr_number: int) -> str:
112+
"""Fetches the details of a GitHub Pull Request from the google/adk-python repository.
113+
114+
Args:
115+
pr_number: The PR number (e.g. 5956).
116+
"""
117+
import subprocess
118+
119+
# Use curl to fetch the PR details.
120+
# This supports running it outside of the gh CLI environment (e.g. without login/remotes setup).
121+
cmd = [
122+
"curl",
123+
"-s",
124+
]
125+
token = os.environ.get("GITHUB_TOKEN")
126+
if token:
127+
cmd.extend(["-H", f"Authorization: token {token}"])
128+
cmd.append(
129+
f"https://api.github.com/repos/google/adk-python/pulls/{pr_number}"
130+
)
131+
132+
try:
133+
res = subprocess.run(cmd, capture_output=True, text=True, check=False)
134+
if res.returncode != 0:
135+
return f"Error: Failed to fetch PR {pr_number}: {res.stderr.strip()}"
136+
return res.stdout.strip()
137+
except Exception as e:
138+
return f"Error: Failed to run curl command: {e}"
139+
140+
141+
async def main():
142+
parser = argparse.ArgumentParser(
143+
description=(
144+
"Runner script to execute prompts/commands via the Antigravity SDK."
145+
)
146+
)
147+
parser.add_argument(
148+
"--show-steps",
149+
action="store_true",
150+
help="Show intermediate thoughts, tool calls, and tool results.",
151+
)
152+
parser.add_argument(
153+
"prompt",
154+
nargs="+",
155+
help="The prompt to send to the Antigravity Agent.",
156+
)
157+
parsed_args = parser.parse_args()
158+
159+
show_steps = parsed_args.show_steps
160+
prompt = " ".join(parsed_args.prompt)
161+
162+
# Ensure GEMINI_API_KEY is set (using GOOGLE_API_KEY as fallback)
163+
if "GOOGLE_API_KEY" in os.environ and "GEMINI_API_KEY" not in os.environ:
164+
os.environ["GEMINI_API_KEY"] = os.environ["GOOGLE_API_KEY"]
165+
166+
if "GEMINI_API_KEY" not in os.environ:
167+
print(
168+
"Error: GEMINI_API_KEY environment variable is not set.",
169+
file=sys.stderr,
170+
)
171+
sys.exit(1)
172+
173+
skills_dir = os.path.abspath(
174+
os.path.join(os.path.dirname(__file__), "..", ".agents", "skills")
175+
)
176+
config = LocalAgentConfig(
177+
capabilities=CapabilitiesConfig(),
178+
tools=[fetch_github_issue, fetch_github_pr],
179+
policies=[
180+
policy.deny(
181+
"run_command",
182+
when=lambda args: not _is_safe_command(args),
183+
name="only_allow_gh_and_git",
184+
),
185+
],
186+
skills_paths=[skills_dir],
187+
)
188+
189+
try:
190+
async with Agent(config) as agent:
191+
response = await agent.chat(prompt)
192+
if show_steps:
193+
in_thinking = False
194+
async for chunk in response.chunks:
195+
if isinstance(chunk, Thought):
196+
if not in_thinking:
197+
sys.stdout.write("[Thinking...]\n")
198+
in_thinking = True
199+
sys.stdout.write(chunk.text)
200+
sys.stdout.flush()
201+
elif isinstance(chunk, ToolCall):
202+
if in_thinking:
203+
sys.stdout.write("\n[End of Thinking]\n")
204+
in_thinking = False
205+
print(
206+
f"\n[Calling Tool: {chunk.name} with args: {chunk.args}]",
207+
flush=True,
208+
)
209+
elif isinstance(chunk, ToolResult):
210+
status = f"Error: {chunk.error}" if chunk.error else "Success"
211+
print(f"\n[Tool {chunk.name} finished: {status}]", flush=True)
212+
elif isinstance(chunk, Text):
213+
if in_thinking:
214+
sys.stdout.write("\n[End of Thinking]\n")
215+
in_thinking = False
216+
sys.stdout.write(chunk.text)
217+
sys.stdout.flush()
218+
if in_thinking:
219+
sys.stdout.write("\n[End of Thinking]\n")
220+
else:
221+
async for token in response:
222+
sys.stdout.write(token)
223+
sys.stdout.flush()
224+
print()
225+
except Exception as e: # pylint: disable=broad-exception-caught
226+
print(f"\nError running Antigravity Agent: {e}", file=sys.stderr)
227+
sys.exit(1)
228+
229+
230+
if __name__ == "__main__":
231+
asyncio.run(main())

0 commit comments

Comments
 (0)