Skip to content

Commit 957dc62

Browse files
xuanyang15copybara-github
authored andcommitted
chore: set up Github workflow for ADK release analyzer for doc updates
PiperOrigin-RevId: 805434018
1 parent 7148e0e commit 957dc62

File tree

5 files changed

+238
-1
lines changed

5 files changed

+238
-1
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Analyze New Release for ADK Docs Updates
2+
3+
on:
4+
# Runs on every new release.
5+
release:
6+
types: [published]
7+
# Manual trigger for testing and retrying.
8+
workflow_dispatch:
9+
10+
jobs:
11+
analyze-new-release-for-adk-docs-updates:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: read
15+
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Set up Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: '3.11'
24+
25+
- name: Install dependencies
26+
run: |
27+
python -m pip install --upgrade pip
28+
pip install requests google-adk
29+
30+
- name: Run Analyzing Script
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
33+
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
34+
GOOGLE_GENAI_USE_VERTEXAI: 0
35+
DOC_OWNER: 'google'
36+
CODE_OWNER: 'google'
37+
DOC_REPO: 'adk-docs'
38+
CODE_REPO: 'adk-python'
39+
INTERACTIVE: 0
40+
PYTHONPATH: contributing/samples/adk_documentation
41+
run: python -m adk_release_analyzer.main
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# ADK Release Analyzer Agent
2+
3+
The ADK Release Analyzer Agent is a Python-based agent designed to help keep
4+
documentation up-to-date with code changes. It analyzes the differences between
5+
two releases of the `google/adk-python` repository, identifies required updates
6+
in the `google/adk-docs` repository, and automatically generates a GitHub issue
7+
with detailed instructions for documentation changes.
8+
9+
This agent can be operated in two distinct modes:
10+
11+
* an interactive mode for local use
12+
* a fully automated mode for integration into workflows.
13+
14+
---
15+
16+
## Interactive Mode
17+
18+
This mode allows you to run the agent locally to review its recommendations in
19+
real-time before any changes are made.
20+
21+
### Features
22+
23+
* **Web Interface**: The agent's interactive mode can be rendered in a web
24+
browser using the ADK's `adk web` command.
25+
* **User Approval**: In interactive mode, the agent is instructed to ask for
26+
your confirmation before creating an issue on GitHub with the documentation
27+
update instructions.
28+
* **Question & Answer**: You ask questions about the releases and code changes.
29+
The agent will provide answers based on related information.
30+
31+
### Running in Interactive Mode
32+
To run the agent in interactive mode, first set the required environment
33+
variables, ensuring `INTERACTIVE` is set to `1` or is unset. Then, execute the
34+
following command in your terminal:
35+
36+
```bash
37+
adk web contributing/samples/adk_documentation
38+
```
39+
40+
This will start a local server and provide a URL to access the agent's web
41+
interface in your browser.
42+
43+
---
44+
45+
## Automated Mode
46+
47+
For automated, hands-off analysis, the agent can be run as a script (`main.py`),
48+
for example as part of a CI/CD pipeline. The workflow is configured in
49+
`.github/workflows/analyze-releases-for-adk-docs-updates.yml` and automatically
50+
checks the most recent two releases for docs updates.
51+
52+
### Workflow Triggers
53+
The GitHub workflow is configured to run on specific triggers:
54+
55+
- **Release Events**: The workflow executes automatically whenever a new release
56+
is `published`.
57+
58+
- **Manual Dispatch**: The workflow also runs when manually triggered for
59+
testing and retrying.
60+
61+
### Automated Issue Creation
62+
63+
When running in automated mode, the agent operates non-interactively. It creates
64+
a GitHub issue with the documentation update instructions directly without
65+
requiring user approval. This behavior is configured by setting the
66+
`INTERACTIVE` environment variable to `0`.
67+
68+
---
69+
70+
## Setup and Configuration
71+
72+
Whether running in interactive or automated mode, the agent requires the
73+
following setup.
74+
75+
### Dependencies
76+
77+
The agent requires the following Python libraries.
78+
79+
```bash
80+
pip install --upgrade pip
81+
pip install google-adk
82+
```
83+
84+
### Environment Variables
85+
86+
The following environment variables are required for the agent to connect to
87+
the necessary services.
88+
89+
* `GITHUB_TOKEN`: **(Required)** A GitHub Personal Access Token with issues:write permissions for the documentation repository.
90+
* `GOOGLE_API_KEY`: **(Required)** Your API key for the Gemini API.
91+
* `DOC_OWNER`: The GitHub organization or username that owns the documentation repository (defaults to `google`).
92+
* `CODE_OWNER`: The GitHub organization or username that owns the code repository (defaults to `google`).
93+
* `DOC_REPO`: The name of the documentation repository (defaults to `adk-docs`).
94+
* `CODE_REPO`: The name of the code repository (defaults to `adk-python`).
95+
* `LOCAL_REPOS_DIR_PATH`: The local directory to clone the repositories into (defaults to `/tmp`).
96+
* `INTERACTIVE`: Controls the agent's interaction mode. Set to 1 for interactive mode (default), and 0 for automated mode.
97+
98+
For local execution, you can place these variables in a `.env` file in the
99+
project's root directory. For automated workflows, they should be configured as
100+
environment variables or secrets.

contributing/samples/adk_documentation/adk_release_analyzer/agent.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@
9191
Explanation of why this change is necessary.
9292
9393
**Reference**:
94-
Reference to the code change.
94+
Reference to the code change (e.g. https://github.com/google/adk-python/commit/b3b70035c432670a5f0b5cdd1e9467f43b80495c).
95+
Reference to the code file (e.g. src/google/adk/tools/spanner/metadata_tool.py).
9596
```
9697
- When referncing doc file, use the full relative path of the doc file in the ADK Docs repository (e.g. docs/sessions/memory.md).
9798
9. Create or recommend to create a Github issue in the Github Repository {DOC_REPO} with the instructions using the `create_issue` tool.
@@ -103,6 +104,7 @@
103104
- **File Paths:** Always use absolute paths when calling the tools to read files, list directories, or search the codebase.
104105
- **Tool Call Parallelism:** Execute multiple independent tool calls in parallel when feasible (i.e. searching the codebase).
105106
- **Explaination:** Provide concise explanations for your actions and reasoning for each step.
107+
- **Reference:** For each recommended change, reference the code changes (i.e. links to the commits) **AND** the code files (i.e. relative paths to the code files in the codebase).
106108
- **Sorting:** Sort the recommended changes by the importance of the changes, from the most important to the least important.
107109
- Here are the importance groups: Feature changes > Bug fixes > Other changes.
108110
- Within each importance group, sort the changes by the number of files they affect.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2025 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+
import asyncio
16+
import logging
17+
import time
18+
19+
from adk_release_analyzer import agent
20+
from adk_release_analyzer.settings import CODE_OWNER
21+
from adk_release_analyzer.settings import CODE_REPO
22+
from adk_release_analyzer.settings import DOC_OWNER
23+
from adk_release_analyzer.settings import DOC_REPO
24+
from adk_release_analyzer.utils import call_agent_async
25+
from google.adk.cli.utils import logs
26+
from google.adk.runners import InMemoryRunner
27+
28+
APP_NAME = "adk_release_analyzer"
29+
USER_ID = "adk_release_analyzer_user"
30+
31+
logs.setup_adk_logger(level=logging.DEBUG)
32+
33+
34+
async def main():
35+
runner = InMemoryRunner(
36+
agent=agent.root_agent,
37+
app_name=APP_NAME,
38+
)
39+
session = await runner.session_service.create_session(
40+
app_name=APP_NAME,
41+
user_id=USER_ID,
42+
)
43+
44+
response = await call_agent_async(
45+
runner,
46+
USER_ID,
47+
session.id,
48+
"Please analyze the most recent two releases of ADK Python!",
49+
)
50+
print(f"<<<< Agent Final Output: {response}\n")
51+
52+
53+
if __name__ == "__main__":
54+
start_time = time.time()
55+
print(
56+
f"Start analyzing {CODE_OWNER}/{CODE_REPO} releases for"
57+
f" {DOC_OWNER}/{DOC_REPO} updates at"
58+
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(start_time))}"
59+
)
60+
print("-" * 80)
61+
asyncio.run(main())
62+
print("-" * 80)
63+
end_time = time.time()
64+
print(
65+
"Triaging finished at"
66+
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(end_time))}",
67+
)
68+
print("Total script execution time:", f"{end_time - start_time:.2f} seconds")

contributing/samples/adk_documentation/adk_release_analyzer/utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
from typing import List
1818

1919
from adk_release_analyzer.settings import GITHUB_TOKEN
20+
from google.adk.agents.run_config import RunConfig
21+
from google.adk.runners import Runner
22+
from google.genai import types
2023
import requests
2124

2225
HEADERS = {
@@ -70,3 +73,26 @@ def patch_request(url: str, payload: Any) -> Dict[str, Any]:
7073
response = requests.patch(url, headers=HEADERS, json=payload, timeout=60)
7174
response.raise_for_status()
7275
return response.json()
76+
77+
78+
async def call_agent_async(
79+
runner: Runner, user_id: str, session_id: str, prompt: str
80+
) -> str:
81+
"""Call the agent asynchronously with the user's prompt."""
82+
content = types.Content(
83+
role="user", parts=[types.Part.from_text(text=prompt)]
84+
)
85+
86+
final_response_text = ""
87+
async for event in runner.run_async(
88+
user_id=user_id,
89+
session_id=session_id,
90+
new_message=content,
91+
run_config=RunConfig(save_input_blobs_as_artifacts=False),
92+
):
93+
if event.content and event.content.parts:
94+
if text := "".join(part.text or "" for part in event.content.parts):
95+
if event.author != "user":
96+
final_response_text += text
97+
98+
return final_response_text

0 commit comments

Comments
 (0)