You've already forked adk-python
mirror of
https://github.com/encounter/adk-python.git
synced 2026-03-30 10:57:20 -07:00
chore: set up Github workflow for ADK release analyzer for doc updates
PiperOrigin-RevId: 805434018
This commit is contained in:
committed by
Copybara-Service
parent
7148e0e82e
commit
957dc628ab
@@ -0,0 +1,41 @@
|
||||
name: Analyze New Release for ADK Docs Updates
|
||||
|
||||
on:
|
||||
# Runs on every new release.
|
||||
release:
|
||||
types: [published]
|
||||
# Manual trigger for testing and retrying.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
analyze-new-release-for-adk-docs-updates:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install requests google-adk
|
||||
|
||||
- name: Run Analyzing Script
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
|
||||
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
||||
GOOGLE_GENAI_USE_VERTEXAI: 0
|
||||
DOC_OWNER: 'google'
|
||||
CODE_OWNER: 'google'
|
||||
DOC_REPO: 'adk-docs'
|
||||
CODE_REPO: 'adk-python'
|
||||
INTERACTIVE: 0
|
||||
PYTHONPATH: contributing/samples/adk_documentation
|
||||
run: python -m adk_release_analyzer.main
|
||||
@@ -0,0 +1,100 @@
|
||||
# ADK Release Analyzer Agent
|
||||
|
||||
The ADK Release Analyzer Agent is a Python-based agent designed to help keep
|
||||
documentation up-to-date with code changes. It analyzes the differences between
|
||||
two releases of the `google/adk-python` repository, identifies required updates
|
||||
in the `google/adk-docs` repository, and automatically generates a GitHub issue
|
||||
with detailed instructions for documentation changes.
|
||||
|
||||
This agent can be operated in two distinct modes:
|
||||
|
||||
* an interactive mode for local use
|
||||
* a fully automated mode for integration into workflows.
|
||||
|
||||
---
|
||||
|
||||
## Interactive Mode
|
||||
|
||||
This mode allows you to run the agent locally to review its recommendations in
|
||||
real-time before any changes are made.
|
||||
|
||||
### Features
|
||||
|
||||
* **Web Interface**: The agent's interactive mode can be rendered in a web
|
||||
browser using the ADK's `adk web` command.
|
||||
* **User Approval**: In interactive mode, the agent is instructed to ask for
|
||||
your confirmation before creating an issue on GitHub with the documentation
|
||||
update instructions.
|
||||
* **Question & Answer**: You ask questions about the releases and code changes.
|
||||
The agent will provide answers based on related information.
|
||||
|
||||
### Running in Interactive Mode
|
||||
To run the agent in interactive mode, first set the required environment
|
||||
variables, ensuring `INTERACTIVE` is set to `1` or is unset. Then, execute the
|
||||
following command in your terminal:
|
||||
|
||||
```bash
|
||||
adk web contributing/samples/adk_documentation
|
||||
```
|
||||
|
||||
This will start a local server and provide a URL to access the agent's web
|
||||
interface in your browser.
|
||||
|
||||
---
|
||||
|
||||
## Automated Mode
|
||||
|
||||
For automated, hands-off analysis, the agent can be run as a script (`main.py`),
|
||||
for example as part of a CI/CD pipeline. The workflow is configured in
|
||||
`.github/workflows/analyze-releases-for-adk-docs-updates.yml` and automatically
|
||||
checks the most recent two releases for docs updates.
|
||||
|
||||
### Workflow Triggers
|
||||
The GitHub workflow is configured to run on specific triggers:
|
||||
|
||||
- **Release Events**: The workflow executes automatically whenever a new release
|
||||
is `published`.
|
||||
|
||||
- **Manual Dispatch**: The workflow also runs when manually triggered for
|
||||
testing and retrying.
|
||||
|
||||
### Automated Issue Creation
|
||||
|
||||
When running in automated mode, the agent operates non-interactively. It creates
|
||||
a GitHub issue with the documentation update instructions directly without
|
||||
requiring user approval. This behavior is configured by setting the
|
||||
`INTERACTIVE` environment variable to `0`.
|
||||
|
||||
---
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Whether running in interactive or automated mode, the agent requires the
|
||||
following setup.
|
||||
|
||||
### Dependencies
|
||||
|
||||
The agent requires the following Python libraries.
|
||||
|
||||
```bash
|
||||
pip install --upgrade pip
|
||||
pip install google-adk
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The following environment variables are required for the agent to connect to
|
||||
the necessary services.
|
||||
|
||||
* `GITHUB_TOKEN`: **(Required)** A GitHub Personal Access Token with issues:write permissions for the documentation repository.
|
||||
* `GOOGLE_API_KEY`: **(Required)** Your API key for the Gemini API.
|
||||
* `DOC_OWNER`: The GitHub organization or username that owns the documentation repository (defaults to `google`).
|
||||
* `CODE_OWNER`: The GitHub organization or username that owns the code repository (defaults to `google`).
|
||||
* `DOC_REPO`: The name of the documentation repository (defaults to `adk-docs`).
|
||||
* `CODE_REPO`: The name of the code repository (defaults to `adk-python`).
|
||||
* `LOCAL_REPOS_DIR_PATH`: The local directory to clone the repositories into (defaults to `/tmp`).
|
||||
* `INTERACTIVE`: Controls the agent's interaction mode. Set to 1 for interactive mode (default), and 0 for automated mode.
|
||||
|
||||
For local execution, you can place these variables in a `.env` file in the
|
||||
project's root directory. For automated workflows, they should be configured as
|
||||
environment variables or secrets.
|
||||
@@ -91,7 +91,8 @@ root_agent = Agent(
|
||||
Explanation of why this change is necessary.
|
||||
|
||||
**Reference**:
|
||||
Reference to the code change.
|
||||
Reference to the code change (e.g. https://github.com/google/adk-python/commit/b3b70035c432670a5f0b5cdd1e9467f43b80495c).
|
||||
Reference to the code file (e.g. src/google/adk/tools/spanner/metadata_tool.py).
|
||||
```
|
||||
- When referncing doc file, use the full relative path of the doc file in the ADK Docs repository (e.g. docs/sessions/memory.md).
|
||||
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 @@ root_agent = Agent(
|
||||
- **File Paths:** Always use absolute paths when calling the tools to read files, list directories, or search the codebase.
|
||||
- **Tool Call Parallelism:** Execute multiple independent tool calls in parallel when feasible (i.e. searching the codebase).
|
||||
- **Explaination:** Provide concise explanations for your actions and reasoning for each step.
|
||||
- **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).
|
||||
- **Sorting:** Sort the recommended changes by the importance of the changes, from the most important to the least important.
|
||||
- Here are the importance groups: Feature changes > Bug fixes > Other changes.
|
||||
- Within each importance group, sort the changes by the number of files they affect.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from adk_release_analyzer import agent
|
||||
from adk_release_analyzer.settings import CODE_OWNER
|
||||
from adk_release_analyzer.settings import CODE_REPO
|
||||
from adk_release_analyzer.settings import DOC_OWNER
|
||||
from adk_release_analyzer.settings import DOC_REPO
|
||||
from adk_release_analyzer.utils import call_agent_async
|
||||
from google.adk.cli.utils import logs
|
||||
from google.adk.runners import InMemoryRunner
|
||||
|
||||
APP_NAME = "adk_release_analyzer"
|
||||
USER_ID = "adk_release_analyzer_user"
|
||||
|
||||
logs.setup_adk_logger(level=logging.DEBUG)
|
||||
|
||||
|
||||
async def main():
|
||||
runner = InMemoryRunner(
|
||||
agent=agent.root_agent,
|
||||
app_name=APP_NAME,
|
||||
)
|
||||
session = await runner.session_service.create_session(
|
||||
app_name=APP_NAME,
|
||||
user_id=USER_ID,
|
||||
)
|
||||
|
||||
response = await call_agent_async(
|
||||
runner,
|
||||
USER_ID,
|
||||
session.id,
|
||||
"Please analyze the most recent two releases of ADK Python!",
|
||||
)
|
||||
print(f"<<<< Agent Final Output: {response}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_time = time.time()
|
||||
print(
|
||||
f"Start analyzing {CODE_OWNER}/{CODE_REPO} releases for"
|
||||
f" {DOC_OWNER}/{DOC_REPO} updates at"
|
||||
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(start_time))}"
|
||||
)
|
||||
print("-" * 80)
|
||||
asyncio.run(main())
|
||||
print("-" * 80)
|
||||
end_time = time.time()
|
||||
print(
|
||||
"Triaging finished at"
|
||||
f" {time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(end_time))}",
|
||||
)
|
||||
print("Total script execution time:", f"{end_time - start_time:.2f} seconds")
|
||||
@@ -17,6 +17,9 @@ from typing import Dict
|
||||
from typing import List
|
||||
|
||||
from adk_release_analyzer.settings import GITHUB_TOKEN
|
||||
from google.adk.agents.run_config import RunConfig
|
||||
from google.adk.runners import Runner
|
||||
from google.genai import types
|
||||
import requests
|
||||
|
||||
HEADERS = {
|
||||
@@ -70,3 +73,26 @@ def patch_request(url: str, payload: Any) -> Dict[str, Any]:
|
||||
response = requests.patch(url, headers=HEADERS, json=payload, timeout=60)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
async def call_agent_async(
|
||||
runner: Runner, user_id: str, session_id: str, prompt: str
|
||||
) -> str:
|
||||
"""Call the agent asynchronously with the user's prompt."""
|
||||
content = types.Content(
|
||||
role="user", parts=[types.Part.from_text(text=prompt)]
|
||||
)
|
||||
|
||||
final_response_text = ""
|
||||
async for event in runner.run_async(
|
||||
user_id=user_id,
|
||||
session_id=session_id,
|
||||
new_message=content,
|
||||
run_config=RunConfig(save_input_blobs_as_artifacts=False),
|
||||
):
|
||||
if event.content and event.content.parts:
|
||||
if text := "".join(part.text or "" for part in event.content.parts):
|
||||
if event.author != "user":
|
||||
final_response_text += text
|
||||
|
||||
return final_response_text
|
||||
|
||||
Reference in New Issue
Block a user