feat: auto-decline draft-responses when agent determines no reply needed#5522
feat: auto-decline draft-responses when agent determines no reply needed#5522marcusquinn merged 1 commit intomainfrom
Conversation
- Add AGENT COMPOSE INSTRUCTION to contribution-watch-helper.sh auto-draft section: after composing, if recommendation is no reply/no action/decline, call draft-response-helper.sh reject instead of leaving issue open (t5520) - Add agent instruction comments to draft template body so compose agent knows to call reject for no-reply cases - Update notification issue 'How to respond' section with clearer guidance including note that agent will auto-decline no-reply drafts - Add deterministic safety net in check-approvals: auto-declines open draft issues where body contains no-reply indicators, no user comment exists, and 24h grace period has elapsed (catches compose agent failures) - Update cmd_help to document the new auto-decline safety net behaviour Closes #5520
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the efficiency of handling draft responses by automating the closure of issues where no reply is deemed necessary. It introduces both a proactive instruction for the AI agent to reject such drafts immediately and a robust fallback safety net to ensure these drafts are eventually closed without manual intervention, thereby reducing operational overhead and streamlining the workflow for users. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
WalkthroughTwo shell scripts now include documentation and a deterministic safety net for auto-declining draft responses. The compose agent receives instructions to call Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Mon Mar 23 00:51:45 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.agents/scripts/draft-response-helper.sh (1)
861-862: Consider usinggrep -Efor extended regex portability.The alternation pattern with
\|works on GNU grep (macOS Homebrew / Linux default), but isn't POSIX-compliant. For maximum portability across grep implementations, use the-Eflag for extended regular expressions.🔧 Suggested fix for portability
- if echo "$sa_combined_text" | grep -qi \ - "no reply needed\|no action needed\|no action required\|recommendation: decline\|no reply is needed\|decline this draft\|not necessary to reply\|no response needed\|no response required\|no reply necessary"; then + if echo "$sa_combined_text" | grep -qiE \ + "no reply needed|no action needed|no action required|recommendation: decline|no reply is needed|decline this draft|not necessary to reply|no response needed|no response required|no reply necessary"; thenNote: The same pattern appears elsewhere in this file (e.g., line 624) without
-E, so this is consistent with existing style — just flagging for future consideration.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.agents/scripts/draft-response-helper.sh around lines 861 - 862, The grep invocation checking sa_combined_text uses backslash-escaped alternation which is not POSIX-portable; update the command that references the variable sa_combined_text (the if-block containing the grep check) to use grep -E and switch the alternation to use unescaped '|' (e.g., "no reply needed|no action needed|...") so it works across grep implementations; apply the same change to the other occurrences of the same pattern (such as the similar check earlier in the script).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.agents/scripts/draft-response-helper.sh:
- Around line 861-862: The grep invocation checking sa_combined_text uses
backslash-escaped alternation which is not POSIX-portable; update the command
that references the variable sa_combined_text (the if-block containing the grep
check) to use grep -E and switch the alternation to use unescaped '|' (e.g., "no
reply needed|no action needed|...") so it works across grep implementations;
apply the same change to the other occurrences of the same pattern (such as the
similar check earlier in the script).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 43e01d22-73b3-45f5-aeb7-46fbc807484b
📒 Files selected for processing (2)
.agents/scripts/contribution-watch-helper.sh.agents/scripts/draft-response-helper.sh
There was a problem hiding this comment.
Code Review
This pull request introduces a valuable safety net to auto-decline draft responses that recommend no reply. The implementation is well-structured, particularly the new logic in cmd_check_approvals. I have identified a few areas for improvement. My primary concern is a potentially incorrect jq filter that might cause the safety net to misfire by only checking for comments from a single user, instead of any user. Additionally, I've provided suggestions to enhance the efficiency of date parsing and to simplify the logic for detecting 'no-reply' indicators. The date parsing suggestion also removes the suppression of stderr, which could hide errors. These changes should make the new feature more robust and maintainable.
| # Check for user comments on this notification issue | ||
| local sa_comments | ||
| sa_comments=$(gh api --paginate "repos/${slug}/issues/${sa_issue_number}/comments?per_page=100" \ | ||
| --jq "[.[] | select(.user.login == \"${username}\") | select(.user.login | test(\"\\\\[bot\\\\]\$\"; \"i\") | not)]" \ |
There was a problem hiding this comment.
The jq filter select(.user.login == "${username}") restricts the comment search to a single, specific user (${username}). However, the feature's goal is to act when "no user comment exists", which implies checking for comments from any non-bot user. The current implementation could lead to incorrect auto-declines if a user other than ${username} has commented. To correctly check for comments from any non-bot user, the filter for a specific username should be removed.
| --jq "[.[] | select(.user.login == \"${username}\") | select(.user.login | test(\"\\\\[bot\\\\]\$\"; \"i\") | not)]" \ | |
| --jq "[.[] | select(.user.login | test("\\[bot\\]$"; "i") | not)]" \ |
| if date -j -f "%Y-%m-%dT%H:%M:%SZ" "$sa_created" +%s &>/dev/null 2>&1; then | ||
| sa_created_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$sa_created" +%s 2>/dev/null) || sa_created_epoch=0 | ||
| elif date -d "$sa_created" +%s &>/dev/null 2>&1; then | ||
| # GNU date fallback (Linux) | ||
| sa_created_epoch=$(date -d "$sa_created" +%s 2>/dev/null) || sa_created_epoch=0 | ||
| fi |
There was a problem hiding this comment.
The current date parsing logic calls the date command up to two times for each successful conversion (once to check for command success, and once to capture the output). This can be made more efficient and readable by attempting the conversion, capturing the exit code, and then trying the fallback if needed. This avoids redundant process calls. Also, avoid suppressing stderr with 2>/dev/null on commands that parse configuration files (e.g., date), as it can hide syntax errors and make debugging difficult.
| if date -j -f "%Y-%m-%dT%H:%M:%SZ" "$sa_created" +%s &>/dev/null 2>&1; then | |
| sa_created_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$sa_created" +%s 2>/dev/null) || sa_created_epoch=0 | |
| elif date -d "$sa_created" +%s &>/dev/null 2>&1; then | |
| # GNU date fallback (Linux) | |
| sa_created_epoch=$(date -d "$sa_created" +%s 2>/dev/null) || sa_created_epoch=0 | |
| fi | |
| local sa_created_epoch | |
| # Try macOS `date` first | |
| sa_created_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$sa_created" +%s) | |
| local mac_date_exit_code=$? | |
| # If it fails, try GNU `date` as a fallback | |
| if [[ $mac_date_exit_code -ne 0 ]]; then | |
| sa_created_epoch=$(date -d "$sa_created" +%s) | |
| fi | |
| sa_created_epoch=${sa_created_epoch:-0} |
References
- Avoid suppressing stderr with
2>/dev/nullon commands that parse configuration files (e.g.,jq), as it can hide syntax errors and make debugging difficult. - In shell scripts, capture a command's exit code in a variable instead of using
$?directly in conditionals. This aligns with ShellCheck SC2181 and improves clarity for multi-way branches.
| local sa_no_reply=false | ||
| if echo "$sa_combined_text" | grep -qi \ | ||
| "no reply needed\|no action needed\|no action required\|recommendation: decline\|no reply is needed\|decline this draft\|not necessary to reply\|no response needed\|no response required\|no reply necessary"; then | ||
| sa_no_reply=true | ||
| fi | ||
|
|
||
| if [[ "$sa_no_reply" == "true" ]]; then | ||
| _log_info "check-approvals safety-net: auto-declining draft ${sa_draft_id} (no-reply indicators found, no user comment, grace period elapsed)" | ||
| echo " Safety net: auto-declining draft ${sa_draft_id} (no-reply indicators, no user comment, 24h elapsed)" | ||
| cmd_reject "$sa_draft_id" "Auto-declined: no-reply indicators in draft body, no user comment after 24h grace period" | ||
| auto_declined=$((auto_declined + 1)) | ||
| actions_taken=$((actions_taken + 1)) | ||
| fi |
There was a problem hiding this comment.
The logic for checking "no-reply" indicators can be simplified. The sa_no_reply variable is set and then immediately checked in the subsequent if statement. These steps can be combined by using the grep command's exit status directly as the condition for the if statement, which makes the code more concise.
| local sa_no_reply=false | |
| if echo "$sa_combined_text" | grep -qi \ | |
| "no reply needed\|no action needed\|no action required\|recommendation: decline\|no reply is needed\|decline this draft\|not necessary to reply\|no response needed\|no response required\|no reply necessary"; then | |
| sa_no_reply=true | |
| fi | |
| if [[ "$sa_no_reply" == "true" ]]; then | |
| _log_info "check-approvals safety-net: auto-declining draft ${sa_draft_id} (no-reply indicators found, no user comment, grace period elapsed)" | |
| echo " Safety net: auto-declining draft ${sa_draft_id} (no-reply indicators, no user comment, 24h elapsed)" | |
| cmd_reject "$sa_draft_id" "Auto-declined: no-reply indicators in draft body, no user comment after 24h grace period" | |
| auto_declined=$((auto_declined + 1)) | |
| actions_taken=$((actions_taken + 1)) | |
| fi | |
| # Match no-reply indicators (case-insensitive) | |
| if echo "$sa_combined_text" | grep -qi \ | |
| "no reply needed\|no action needed\|no action required\|recommendation: decline\|no reply is needed\|decline this draft\|not necessary to reply\|no response needed\|no response required\|no reply necessary"; then | |
| _log_info "check-approvals safety-net: auto-declining draft ${sa_draft_id} (no-reply indicators found, no user comment, grace period elapsed)" | |
| echo " Safety net: auto-declining draft ${sa_draft_id} (no-reply indicators, no user comment, 24h elapsed)" | |
| cmd_reject "$sa_draft_id" "Auto-declined: no-reply indicators in draft body, no user comment after 24h grace period" | |
| auto_declined=$((auto_declined + 1)) | |
| actions_taken=$((actions_taken + 1)) | |
| fi |
The safety-net auto-decline logic (t5520) was filtering comments to only
those from the authenticated agent user (`${username}`), then excluding
bots. This meant a comment from any *other* human user was invisible to
the check, causing incorrect auto-declines when a non-agent user had
already engaged on the issue.
Remove the username equality filter; keep only the bot-exclusion test so
the guard correctly fires when *any* non-bot user has commented.
Fixes #5559 (Gemini review feedback from PR #5522)



Summary
Change 1 (agent instruction): Added
AGENT COMPOSE INSTRUCTIONcomment block tocontribution-watch-helper.shauto-draft section and to the draft template body indraft-response-helper.sh. When the compose agent determines no reply is needed, it now has explicit guidance to calldraft-response-helper.sh reject <draft_id> "No reply needed"immediately instead of leaving the notification issue open.Change 2 (deterministic safety net): Added a second pass in
cmd_check_approvalsthat auto-declines open draft issues where: (1) the draft body contains clear no-reply indicators (e.g. "no reply needed", "no action required", "recommendation: decline"), (2) no user comment exists on the notification issue, and (3) the draft was created more than 24h ago (grace period to avoid premature auto-decline of drafts still being composed).UX improvement: Updated the notification issue "How to respond" section with clearer guidance including a note that the agent will auto-decline no-reply drafts without requiring user input.
Help text: Updated
cmd_helpto document the new auto-decline safety net behaviour.Root cause addressed
Issues #3, #5, #7 on the
draft-responsesrepo all recommended no reply but required manual closure. The compose step had no mechanism to act on its own "no reply" determination — it wrote the draft text but left the notification issue open. This PR adds both the primary fix (agent instruction) and a fallback (deterministic safety net).Closes #5520
Summary by CodeRabbit
New Features
Documentation