diff --git a/contrib/samples/github/adkreleasedocs/README.md b/contrib/samples/github/adkreleasedocs/README.md index 8e9b17129..e3bc4fc1d 100644 --- a/contrib/samples/github/adkreleasedocs/README.md +++ b/contrib/samples/github/adkreleasedocs/README.md @@ -17,7 +17,8 @@ The agent (`AdkDocsReleaseAnalyzerAgent`) is equipped with function tools hand-rolled REST code, no local cloning): 1. `list_releases` — find the two most recent release tags to compare. -2. `find_doc_issues` — list open `docs updates` issues to avoid duplicates. +2. `find_doc_issues` — list open `docs updates` issues for this code repo (one + language) to avoid duplicates. 3. `find_pull_requests_for_issue` — check whether an issue already has PRs. 4. `get_changed_files` — list files changed between the two tags (compare API). 5. `get_file_diff` — fetch the patch for an individual file. @@ -83,6 +84,7 @@ Variable | Required | Default | Description `CODE_OWNER` | no | `google` | Owner of the code repository. `DOC_REPO` | no | `adk-docs` | Docs repository name. `CODE_REPO` | no | `adk-java` | Code repository name. +`CODE_LANGUAGE` | no | `Java` | Implementation language documented (docs stay single-language). `CODE_SOURCE_PATH_FILTER` | no | `core/src/main/java/` | Only analyze changes under this path. `MODEL` | no | `gemini-pro-latest` | Model to use (a Pro model helps with deeper code understanding). diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java index ee487ce29..c032c8b31 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerAgent.java @@ -62,13 +62,18 @@ private static String buildInstruction() { rejection - report it instead. # 1. Identity - You are the ADK Docs Release Analyzer. You compare two releases of the ADK code repository and, - when documentation needs updating, file ONE GitHub issue and open a pull request per - recommendation that applies a SUBSTANTIVE documentation update. A substantive update means real - content: conceptual prose AND a complete, idiomatic %CODE_REPO% code example, or a brand new page - when a feature is undocumented for this language. Merely toggling a language-support label/pill - (e.g. adding a `` tag) is NOT acceptable on its own. All access is through - GitHub tools; you never clone repositories locally. + You are the ADK Docs Release Analyzer for the %CODE_LANGUAGE% implementation of ADK (the + %CODE_REPO% repository). You compare two releases of that repository and, when documentation + needs updating, file ONE GitHub issue and open a pull request per recommendation that applies a + SUBSTANTIVE documentation update. A substantive update means real content: conceptual prose AND a + complete, idiomatic %CODE_LANGUAGE% code example, or a brand new page when a feature is + undocumented for %CODE_LANGUAGE%. Merely toggling a language-support label/pill (e.g. adding a + `` tag) is NOT acceptable on its own. All access is through GitHub tools; + you never clone repositories locally. + + SINGLE LANGUAGE: you document ONLY %CODE_LANGUAGE%. Never add, edit, or remove code examples or + sections for any other language (e.g. Python, TypeScript, Go, or the other JVM language). Read + other languages' docs only as a structural reference and leave their content untouched. # 2. Repositories - Code repository: %CODE_OWNER%/%CODE_REPO% (source of truth for APIs and real example code) @@ -78,8 +83,9 @@ private static String buildInstruction() { 1. Call `list_releases` for %CODE_OWNER%/%CODE_REPO%. - By default compare the two most recent releases (newest = end_tag, second newest = start_tag). If the user specifies tags, use those instead. - 2. DEDUPE: call `find_doc_issues` for %DOC_OWNER%/%DOC_REPO% and look for an open issue titled - "Found docs updates needed from %CODE_REPO% release to ". + 2. DEDUPE: call `find_doc_issues` for %DOC_OWNER%/%DOC_REPO% with code_repo="%CODE_REPO%" (this + returns only %CODE_REPO% release issues, never other languages'). Look for an open issue + titled "Found docs updates needed from %CODE_REPO% release to ". - If it exists, note its issue number and call `find_pull_requests_for_issue` for it. If that issue ALREADY has pull requests, STOP and report that it is already handled (issue + PR URLs). If the issue exists but has NO pull requests, reuse it (skip step 8) and continue. @@ -98,9 +104,10 @@ API precisely (classes, functions, parameters, defaults, return types). (tabbed code blocks / per-language sections). Skip docs/api-reference/ (auto-generated). 7. Decide the real documentation work for each change. Every recommendation must add real content, for example: - - Add a complete %CODE_REPO% code example to the relevant page, mirroring the existing - Python/Java tabs or sections (add the language tab/section WITH working code). - - Add or expand conceptual prose explaining the feature and how to use it in this language. + - Add a complete %CODE_LANGUAGE% code example to the relevant page, mirroring how other + languages are already presented (add the %CODE_LANGUAGE% tab/section WITH working code; + leave the other languages' tabs untouched). + - Add or expand conceptual prose explaining the feature and how to use it in %CODE_LANGUAGE%. - If the feature has NO page, CREATE a new page (full prose + example) at a sensible docs path. - Update the language-support label/pill too, but ALWAYS together with the content above. If NO documentation changes are warranted, create nothing and report that. @@ -138,6 +145,7 @@ API precisely (classes, functions, parameters, defaults, return types). """ .replace("%CODE_OWNER%", Settings.CODE_OWNER) .replace("%CODE_REPO%", Settings.CODE_REPO) + .replace("%CODE_LANGUAGE%", Settings.CODE_LANGUAGE) .replace("%DOC_OWNER%", Settings.DOC_OWNER) .replace("%DOC_REPO%", Settings.DOC_REPO) .replace("%CODE_SOURCE_PATH_FILTER%", Settings.CODE_SOURCE_PATH_FILTER); diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java index 2eb677746..fdf7d6ac3 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/AdkDocsReleaseAnalyzerRun.java @@ -51,6 +51,8 @@ public final class AdkDocsReleaseAnalyzerRun implements Runnable { names = "--dry-run", negatable = true, defaultValue = "true", + // Keeps "--dry-run" = true; without it picocli assigns the opposite of defaultValue. + fallbackValue = "true", description = "Preview the issue without creating it (default). Use --no-dry-run to file it for real.") private boolean dryRun; diff --git a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java index 3f945ac21..6172cedad 100644 --- a/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java +++ b/contrib/samples/github/adkreleasedocs/src/main/java/com/example/adkdocs/Settings.java @@ -24,6 +24,9 @@ final class Settings { static final String DOC_REPO = envOrDefault("DOC_REPO", "adk-docs"); static final String CODE_REPO = envOrDefault("CODE_REPO", "adk-java"); + /** Implementation language documented by this analyzer; docs stay single-language. */ + static final String CODE_LANGUAGE = envOrDefault("CODE_LANGUAGE", "Java"); + /** Only changes under this path in the code repo are analyzed. */ static final String CODE_SOURCE_PATH_FILTER = envOrDefault("CODE_SOURCE_PATH_FILTER", "core/src/main/java/"); diff --git a/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java b/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java index e36fe3159..6f934e7a7 100644 --- a/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java +++ b/contrib/samples/github/githubtools/src/main/java/com/example/github/GitHubTools.java @@ -334,18 +334,30 @@ public static Map createIssue( @Schema( name = "find_doc_issues", description = - "Lists OPEN issues in a repository that carry the 'docs updates' label. Call this before" - + " creating an issue to avoid filing a duplicate for the same release range.") + "Lists OPEN issues in a repository that carry the 'docs updates' label, restricted to a" + + " single code repository's release issues. Call this before creating an issue to" + + " avoid filing a duplicate for the same release range.") public static Map findDocIssues( @Schema(name = "repo_owner", description = "The repository owner.") String repoOwner, - @Schema(name = "repo_name", description = "The repository name.") String repoName) { + @Schema(name = "repo_name", description = "The repository name.") String repoName, + @Schema( + name = "code_repo", + description = + "Only return issues whose title mentions this code repository (e.g." + + " \"adk-java\"), so results stay scoped to one language. Pass an empty" + + " string for no filter.") + String codeRepo) { try { GHRepository repo = connect().getRepository(repoOwner + "/" + repoName); + String filter = codeRepo == null ? "" : codeRepo.trim().toLowerCase(Locale.ROOT); List> issues = new ArrayList<>(); for (GHIssue issue : repo.getIssues(GHIssueState.OPEN)) { if (issue.isPullRequest() || !hasDocsLabel(issue)) { continue; } + if (!issue.getTitle().toLowerCase(Locale.ROOT).contains(filter)) { + continue; + } Map info = new LinkedHashMap<>(); info.put("number", issue.getNumber()); info.put("title", issue.getTitle());