-
Notifications
You must be signed in to change notification settings - Fork 88
feat: review queue as readiness gate with Slack notifications #1240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fd84aa7
26aca4b
828043c
a3b6099
2ac1605
fd718d0
f30f85c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -100,16 +100,14 @@ jobs: | |
| first line of the PR body (read your session ID from the | ||
| AGENTIC_SESSION_NAME environment variable): | ||
| <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.issue.outputs.number }} last_action=<ISO8601_NOW> retry_count=0 --> | ||
| At the bottom of the PR body, add a session link: | ||
| --- | ||
| 🤖 [Ambient Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME) | ||
| 6. Add the `ambient-code:managed` label to the PR. | ||
| 7. After creating the PR, send a Slack notification: | ||
| ```bash | ||
| curl -X POST -H 'Content-type: application/json' \ | ||
| --data '{"text":"PR created for #${{ steps.issue.outputs.number }}\n*PR*: <PR_URL>\n*Session*: '"$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"'"}' \ | ||
| "$SLACK_WEBHOOK_URL" | ||
| ``` | ||
| Only send if SLACK_WEBHOOK_URL is set. | ||
| 8. Ensure CI passes. If it fails, investigate and fix. | ||
| 9. Do not merge. Leave the PR open for human review. | ||
| 7. Ensure CI passes. If it fails, investigate and fix. | ||
| 8. Do not merge. Leave the PR open for human review. | ||
| 9. When you comment on the PR, include this footer at the end: | ||
| _🤖 [Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME)_ | ||
| repos: >- | ||
| [{"url": "https://github.com/${{ github.repository }}", "branch": "main"}] | ||
| model: claude-opus-4-6 | ||
|
|
@@ -231,13 +229,17 @@ jobs: | |
| 4. Ensure the PR body contains this frontmatter as the first line | ||
| (read your session ID from the AGENTIC_SESSION_NAME environment variable): | ||
| <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.context.outputs.number }} last_action=<ISO8601_NOW> retry_count=<N> --> | ||
| Increment retry_count from whatever it was before. If retry_count reaches 3 or more, | ||
| stop working, add `ambient-code:needs-human` label, remove `ambient-code:managed` label, | ||
| Only increment retry_count if you actually had to fix something (CI failure, | ||
| conflict, review comment). If the PR is already healthy, do NOT increment — | ||
| just update last_action. If retry_count reaches 3 or more, stop working, | ||
| add `ambient-code:needs-human` label, remove `ambient-code:managed` label, | ||
| comment "AI was unable to resolve after 3 attempts. Needs human attention.", | ||
| and send a Slack notification (see below). | ||
| 5. Add the `ambient-code:managed` label. | ||
| 6. Do not merge. Do not close. Do not force-push. | ||
| 7. If fundamentally broken beyond repair, add a comment explaining and stop. | ||
| 8. When you comment on the PR, include this footer at the end: | ||
| _🤖 [Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME)_ | ||
|
|
||
| ## Slack Notifications | ||
|
|
||
|
|
@@ -293,16 +295,14 @@ jobs: | |
| first line of the PR body (read your session ID from the | ||
| AGENTIC_SESSION_NAME environment variable): | ||
| <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.context.outputs.number }} last_action=<ISO8601_NOW> retry_count=0 --> | ||
| At the bottom of the PR body, add a session link: | ||
| --- | ||
| 🤖 [Ambient Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME) | ||
| 6. Add the `ambient-code:managed` label to the PR. | ||
| 7. After creating the PR, send a Slack notification: | ||
| ```bash | ||
| curl -X POST -H 'Content-type: application/json' \ | ||
| --data '{"text":"PR created for #${{ steps.context.outputs.number }}\n*PR*: <PR_URL>\n*Session*: '"$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"'"}' \ | ||
| "$SLACK_WEBHOOK_URL" | ||
| ``` | ||
| Only send if SLACK_WEBHOOK_URL is set. | ||
| 8. Ensure CI passes. If it fails, investigate and fix. | ||
| 9. Do not merge. Leave the PR open for human review. | ||
| 7. Ensure CI passes. If it fails, investigate and fix. | ||
| 8. Do not merge. Leave the PR open for human review. | ||
| 9. When you comment on the PR, include this footer at the end: | ||
| _🤖 [Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME)_ | ||
| repos: >- | ||
| [{"url": "https://github.com/${{ github.repository }}", "branch": "main"}] | ||
| model: claude-opus-4-6 | ||
|
|
@@ -552,10 +552,49 @@ jobs: | |
| print(f" Failed to create session: {e}") | ||
| return None | ||
|
|
||
| # Get all open ambient-code:managed PRs (include updatedAt to avoid per-PR API calls) | ||
| BOT_LOGINS = ["github-actions[bot]", "ambient-code[bot]", "ambient-bot"] | ||
|
|
||
| def needs_attention(pr_number): | ||
| """Check if a PR has actionable issues that need the fixer's attention. | ||
| Returns (needs_work, reason) tuple.""" | ||
| # Check CI status | ||
| checks_json = gh("pr", "checks", str(pr_number), "--repo", REPO, | ||
| "--json", "name,state", | ||
| "--jq", "[.[] | .state] | unique") | ||
| try: | ||
| states = json.loads(checks_json) if checks_json else [] | ||
| except json.JSONDecodeError: | ||
| states = [] | ||
|
|
||
| if not states: | ||
| pass # No CI checks — nothing to fix | ||
| elif "FAILURE" in states: | ||
| return True, "CI failing" | ||
|
|
||
| # Check for merge conflicts | ||
| mergeable = gh("pr", "view", str(pr_number), "--repo", REPO, | ||
| "--json", "mergeable", "--jq", ".mergeable") | ||
| if mergeable == "CONFLICTING": | ||
| return True, "merge conflicts" | ||
|
|
||
| # Check for changes_requested from non-bot users | ||
| bot_filter = " and ".join([f'.user.login != "{b}"' for b in BOT_LOGINS]) | ||
| try: | ||
| reviews_raw = gh("api", f"repos/{REPO}/pulls/{pr_number}/reviews", | ||
| "--jq", f'[.[] | select(.state == "CHANGES_REQUESTED" and {bot_filter})] | length') | ||
| changes_requested = int(reviews_raw) if reviews_raw else 0 | ||
| except (ValueError, TypeError): | ||
| changes_requested = 0 | ||
|
|
||
| if changes_requested > 0: | ||
| return True, "changes requested" | ||
|
Comment on lines
+583
to
+590
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="${GITHUB_REPOSITORY:-$(gh repo view --json nameWithOwner --jq '.nameWithOwner')}"
gh pr list --repo "$repo" --state open --label "ambient-code:managed" --json number --jq '.[].number' |
while read -r pr; do
reviews="$(gh api --paginate "repos/$repo/pulls/$pr/reviews" | jq -cs 'add')"
python - "$pr" <<'PY' <<<"$reviews"
import json, sys
pr = sys.argv[1]
bots = {"github-actions[bot]", "ambient-code[bot]", "ambient-bot"}
reviews = json.load(sys.stdin)
historical = any(
r.get("state") == "CHANGES_REQUESTED"
and r.get("user", {}).get("login") not in bots
for r in reviews
)
latest = {}
for r in sorted(reviews, key=lambda r: r.get("submitted_at") or ""):
login = r.get("user", {}).get("login")
if login and login not in bots:
latest[login] = r.get("state")
active = any(state == "CHANGES_REQUESTED" for state in latest.values())
if historical and not active:
print(f"PR #{pr} has stale CHANGES_REQUESTED history but no active latest non-bot changes request")
PY
doneRepository: ambient-code/platform Length of output: 1796 🏁 Script executed: fd -t f amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 47 🏁 Script executed: ls -la .github/workflows/ | head -30Repository: ambient-code/platform Length of output: 1922 🏁 Script executed: sed -n '570,600p' .github/workflows/amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 1482 🏁 Script executed: sed -n '1,100p' .github/workflows/amber-issue-handler.yml | grep -A 30 "def gh"Repository: ambient-code/platform Length of output: 47 🏁 Script executed: grep -n "def gh" .github/workflows/amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 93 🏁 Script executed: sed -n '434,460p' .github/workflows/amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 1437 🌐 Web query:
💡 Result: Use the REST endpoint List reviews for a pull request:
Example: # page 1
curl -i -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/OWNER/REPO/pulls/123/reviews?per_page=100&page=1"
# page 2, 3, ... until there's no rel="next" in the Link headerIf you also need the inline comments for each review, fetch them per review id:
Sources: GitHub REST “Pull request reviews” docs [1], GitHub REST pagination guide (Link headers / 🏁 Script executed: sed -n '575,595p' .github/workflows/amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 1081 🌐 Web query:
💡 Result:
Notes:
Sources Citations: 🌐 Web query:
💡 Result: To get the latest review state per reviewer and the PR’s overall review decision, you have two practical options: 1) GraphQL API (best: server computes “latest per user”)Query the PR’s overall decision via Example: query($owner:String!, $repo:String!, $number:Int!) {
repository(owner:$owner, name:$repo) {
pullRequest(number:$number) {
reviewDecision
latestOpinionatedReviews(first: 100) {
nodes {
author { login }
state
submittedAt
url
}
}
}
}
}
2) REST API (you compute “latest per user” yourself)Call “List reviews for a pull request”, then group by Endpoint:
Sources[1] GitHub Community discussion referencing Count only each reviewer's latest non-bot review state, not all historical entries. Add The current code counts every Use one of:
Current problematic snippetreviews_raw = gh("api", f"repos/{REPO}/pulls/{pr_number}/reviews",
"--jq", f'[.[] | select(.state == "CHANGES_REQUESTED" and {bot_filter})] | length')
changes_requested = int(reviews_raw) if reviews_raw else 0🤖 Prompt for AI Agents |
||
|
|
||
| return False, "healthy" | ||
|
Comment on lines
+557
to
+592
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if any ambient-code:managed PRs currently have no CI checks
gh pr list --repo "$GITHUB_REPOSITORY" --state open --label "ambient-code:managed" --json number --jq '.[].number' | while read -r pr; do
checks=$(gh pr checks "$pr" --repo "$GITHUB_REPOSITORY" --json name 2>/dev/null | jq 'length')
if [ "$checks" = "0" ] || [ -z "$checks" ]; then
echo "PR #$pr has no CI checks"
fi
doneRepository: ambient-code/platform Length of output: 246 🏁 Script executed: # Find and inspect the is_ready_to_review function to compare CI handling
fd -e yml -e yaml | head -20Repository: ambient-code/platform Length of output: 1233 🏁 Script executed: # Look at the actual amber-issue-handler.yml file around the flagged lines
wc -l .github/workflows/amber-issue-handler.ymlRepository: ambient-code/platform Length of output: 110 🏁 Script executed: # Search for is_ready_to_review to see how it differs from needs_attention
rg "is_ready_to_review" .github/workflows/ -A 20Repository: ambient-code/platform Length of output: 3498 Add handling for PRs with no CI checks. When Result: PRs without CI are neither fixed nor queued for review. Consider either:
🤖 Prompt for AI Agents |
||
|
|
||
| # Get all open ambient-code:managed PRs | ||
| prs_json = gh("pr", "list", "--repo", REPO, "--state", "open", | ||
| "--label", "ambient-code:managed", "--limit", "200", | ||
| "--json", "number,body,title,updatedAt") | ||
| "--json", "number,body,title") | ||
| prs = json.loads(prs_json) if prs_json else [] | ||
| print(f"Found {len(prs)} ambient-code:managed PRs") | ||
|
|
||
|
|
@@ -576,12 +615,13 @@ jobs: | |
| session_id = fm["session_id"] | ||
| source = fm["source"] | ||
|
|
||
| # Check for changes using updatedAt from gh pr list (no extra API call) | ||
| updated_at = pr.get("updatedAt", "") | ||
| if updated_at and updated_at <= fm["last_action"]: | ||
| print(f"PR #{number}: no changes since {fm['last_action']} (updatedAt={updated_at}), skipping") | ||
| # Only trigger if the PR actually needs work | ||
| needs_work, reason = needs_attention(number) | ||
| if not needs_work: | ||
| print(f"PR #{number}: {reason}, skipping") | ||
| skipped += 1 | ||
| continue | ||
| print(f"PR #{number}: {reason}") | ||
|
|
||
| # Trigger fix — reuse session if exists, create new if not | ||
| print(f"PR #{number}: triggering fix (session_id={session_id or 'new'})") | ||
|
|
@@ -602,12 +642,17 @@ jobs: | |
| 4. Ensure the PR body contains this frontmatter as the first line | ||
| (read your session ID from the AGENTIC_SESSION_NAME environment variable): | ||
| <!-- acp:session_id=$AGENTIC_SESSION_NAME source={source} last_action=<ISO8601_NOW> retry_count=<N> --> | ||
| The current retry_count is {current_retry}. Increment it by 1. | ||
| The current retry_count is {current_retry}. Only increment retry_count if | ||
| you actually had to fix something (CI failure, conflict, review comment). | ||
| If the PR is already healthy (CI green, no conflicts, no open reviews), | ||
| do NOT increment — just update last_action. | ||
| If retry_count reaches 3 or more, stop working, add `ambient-code:needs-human` label, | ||
| remove `ambient-code:managed` label, comment on the PR, and send a Slack notification. | ||
| 5. Add the `ambient-code:managed` label. | ||
| 6. Do not merge. Do not close. Do not force-push. | ||
| 7. If fundamentally broken beyond repair, add a comment explaining and stop. | ||
| 8. When you comment on the PR, include this footer at the end: | ||
| _🤖 [Session]($PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME)_ | ||
|
|
||
| ## Slack Notifications | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.