4242 runs-on : ubuntu-latest
4343 timeout-minutes : 30
4444 steps :
45+ - name : Acknowledge issue
46+ env :
47+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
48+ run : |
49+ gh api repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/reactions \
50+ -X POST -f content=eyes --silent || true
51+
4552 - name : Resolve issue details
4653 id : issue
4754 env :
6673 echo "skip=false" >> $GITHUB_OUTPUT
6774 fi
6875
76+ - name : Post immediate acknowledgement
77+ if : steps.existing.outputs.skip != 'true'
78+ env :
79+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
80+ run : |
81+ gh issue comment ${{ steps.issue.outputs.number }} --repo "${{ github.repository }}" \
82+ --body "🤖 Amber is working on this issue. A PR will be created shortly with the \`ambient-code:managed\` label."
83+
6984 - name : Create session
7085 if : steps.existing.outputs.skip != 'true'
7186 id : session
@@ -100,16 +115,25 @@ jobs:
100115 first line of the PR body (read your session ID from the
101116 AGENTIC_SESSION_NAME environment variable):
102117 <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.issue.outputs.number }} last_action=<ISO8601_NOW> retry_count=0 -->
118+ At the bottom of the PR body, add a session link:
119+ ---
120+ 🤖 [Ambient Session](<SESSION_URL>)
103121 6. Add the `ambient-code:managed` label to the PR.
104- 7. After creating the PR, send a Slack notification:
105- ```bash
106- curl -X POST -H 'Content-type: application/json' \
107- --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"'"}' \
108- "$SLACK_WEBHOOK_URL"
109- ```
110- Only send if SLACK_WEBHOOK_URL is set.
111- 8. Ensure CI passes. If it fails, investigate and fix.
112- 9. Do not merge. Leave the PR open for human review.
122+ 7. Ensure CI passes. If it fails, investigate and fix.
123+ 8. Do not merge. Leave the PR open for human review.
124+ 9. When you comment on the PR, include this footer at the end:
125+ _🤖 [Session](<SESSION_URL>)_
126+
127+ ## Session URL
128+
129+ IMPORTANT: Wherever a session link is needed (PR body, comments, Slack),
130+ you MUST first resolve the URL by reading the environment variables. Run:
131+ ```bash
132+ echo "$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"
133+ ```
134+ Use the resolved output as the actual URL. Do NOT write `$PLATFORM_HOST`,
135+ `$AGENTIC_SESSION_NAMESPACE`, or `$AGENTIC_SESSION_NAME` literally in any
136+ markdown link — always substitute their actual values.
113137 repos : >-
114138 [{"url": "https://github.com/${{ github.repository }}", "branch": "main"}]
115139 model : claude-opus-4-6
@@ -118,15 +142,32 @@ jobs:
118142 environment-variables : >-
119143 {"SLACK_WEBHOOK_URL": "${{ secrets.SLACK_WEBHOOK_URL }}", "PLATFORM_HOST": "${{ secrets.PLATFORM_HOST }}"}
120144
121- - name : Post-session labels and comment
145+ - name : Post-session update comment
122146 if : steps.existing.outputs.skip != 'true'
123147 env :
124148 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
125149 SESSION_NAME : ${{ steps.session.outputs.session-name }}
126150 SESSION_PHASE : ${{ steps.session.outputs.session-phase }}
151+ SESSION_URL : ${{ steps.session.outputs.session-url }}
152+ PLATFORM_HOST : ${{ secrets.PLATFORM_HOST }}
153+ AMBIENT_PROJECT : ${{ secrets.AMBIENT_PROJECT }}
127154 run : |
128155 if [ -n "$SESSION_NAME" ]; then
129- gh issue comment ${{ steps.issue.outputs.number }} --repo "${{ github.repository }}" --body "Session \`$SESSION_NAME\` created (phase: $SESSION_PHASE). PR will have the \`ambient-code:managed\` label."
156+ # Build session link — prefer session-url output, fall back to constructed URL
157+ if [ -n "$SESSION_URL" ]; then
158+ LINK="$SESSION_URL"
159+ elif [ -n "$PLATFORM_HOST" ] && [ -n "$AMBIENT_PROJECT" ]; then
160+ LINK="${PLATFORM_HOST%/}/projects/$AMBIENT_PROJECT/sessions/$SESSION_NAME"
161+ else
162+ LINK=""
163+ fi
164+
165+ if [ -n "$LINK" ]; then
166+ BODY="🤖 Amber session completed (phase: $SESSION_PHASE). [View session]($LINK)"
167+ else
168+ BODY="🤖 Amber session \`$SESSION_NAME\` completed (phase: $SESSION_PHASE)."
169+ fi
170+ gh issue comment ${{ steps.issue.outputs.number }} --repo "${{ github.repository }}" --body "$BODY"
130171 fi
131172
132173 - name : Session summary
@@ -158,6 +199,13 @@ jobs:
158199 runs-on : ubuntu-latest
159200 timeout-minutes : 30
160201 steps :
202+ - name : Acknowledge comment
203+ env :
204+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
205+ run : |
206+ gh api repos/${{ github.repository }}/issues/comments/${{ github.event.comment.id }}/reactions \
207+ -X POST -f content=eyes --silent || true
208+
161209 - name : Resolve context
162210 id : context
163211 env :
@@ -231,13 +279,28 @@ jobs:
231279 4. Ensure the PR body contains this frontmatter as the first line
232280 (read your session ID from the AGENTIC_SESSION_NAME environment variable):
233281 <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.context.outputs.number }} last_action=<ISO8601_NOW> retry_count=<N> -->
234- Increment retry_count from whatever it was before. If retry_count reaches 3 or more,
235- stop working, add `ambient-code:needs-human` label, remove `ambient-code:managed` label,
282+ Only increment retry_count if you actually had to fix something (CI failure,
283+ conflict, review comment). If the PR is already healthy, do NOT increment —
284+ just update last_action. If retry_count reaches 3 or more, stop working,
285+ add `ambient-code:needs-human` label, remove `ambient-code:managed` label,
236286 comment "AI was unable to resolve after 3 attempts. Needs human attention.",
237287 and send a Slack notification (see below).
238288 5. Add the `ambient-code:managed` label.
239289 6. Do not merge. Do not close. Do not force-push.
240290 7. If fundamentally broken beyond repair, add a comment explaining and stop.
291+ 8. When you comment on the PR, include this footer at the end:
292+ _🤖 [Session](<SESSION_URL>)_
293+
294+ ## Session URL
295+
296+ IMPORTANT: Wherever a session link is needed (PR body, comments, Slack),
297+ you MUST first resolve the URL by reading the environment variables. Run:
298+ ```bash
299+ echo "$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"
300+ ```
301+ Use the resolved output as the actual URL. Do NOT write `$PLATFORM_HOST`,
302+ `$AGENTIC_SESSION_NAMESPACE`, or `$AGENTIC_SESSION_NAME` literally in any
303+ markdown link — always substitute their actual values.
241304
242305 ## Slack Notifications
243306
@@ -293,16 +356,25 @@ jobs:
293356 first line of the PR body (read your session ID from the
294357 AGENTIC_SESSION_NAME environment variable):
295358 <!-- acp:session_id=$AGENTIC_SESSION_NAME source=#${{ steps.context.outputs.number }} last_action=<ISO8601_NOW> retry_count=0 -->
359+ At the bottom of the PR body, add a session link:
360+ ---
361+ 🤖 [Ambient Session](<SESSION_URL>)
296362 6. Add the `ambient-code:managed` label to the PR.
297- 7. After creating the PR, send a Slack notification:
298- ```bash
299- curl -X POST -H 'Content-type: application/json' \
300- --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"'"}' \
301- "$SLACK_WEBHOOK_URL"
302- ```
303- Only send if SLACK_WEBHOOK_URL is set.
304- 8. Ensure CI passes. If it fails, investigate and fix.
305- 9. Do not merge. Leave the PR open for human review.
363+ 7. Ensure CI passes. If it fails, investigate and fix.
364+ 8. Do not merge. Leave the PR open for human review.
365+ 9. When you comment on the PR, include this footer at the end:
366+ _🤖 [Session](<SESSION_URL>)_
367+
368+ ## Session URL
369+
370+ IMPORTANT: Wherever a session link is needed (PR body, comments, Slack),
371+ you MUST first resolve the URL by reading the environment variables. Run:
372+ ```bash
373+ echo "$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"
374+ ```
375+ Use the resolved output as the actual URL. Do NOT write `$PLATFORM_HOST`,
376+ `$AGENTIC_SESSION_NAMESPACE`, or `$AGENTIC_SESSION_NAME` literally in any
377+ markdown link — always substitute their actual values.
306378 repos : >-
307379 [{"url": "https://github.com/${{ github.repository }}", "branch": "main"}]
308380 model : claude-opus-4-6
@@ -552,10 +624,49 @@ jobs:
552624 print(f" Failed to create session: {e}")
553625 return None
554626
555- # Get all open ambient-code:managed PRs (include updatedAt to avoid per-PR API calls)
627+ BOT_LOGINS = ["github-actions[bot]", "ambient-code[bot]", "ambient-bot"]
628+
629+ def needs_attention(pr_number):
630+ """Check if a PR has actionable issues that need the fixer's attention.
631+ Returns (needs_work, reason) tuple."""
632+ # Check CI status
633+ checks_json = gh("pr", "checks", str(pr_number), "--repo", REPO,
634+ "--json", "name,state",
635+ "--jq", "[.[] | .state] | unique")
636+ try:
637+ states = json.loads(checks_json) if checks_json else []
638+ except json.JSONDecodeError:
639+ states = []
640+
641+ if not states:
642+ pass # No CI checks — nothing to fix
643+ elif "FAILURE" in states:
644+ return True, "CI failing"
645+
646+ # Check for merge conflicts
647+ mergeable = gh("pr", "view", str(pr_number), "--repo", REPO,
648+ "--json", "mergeable", "--jq", ".mergeable")
649+ if mergeable == "CONFLICTING":
650+ return True, "merge conflicts"
651+
652+ # Check for changes_requested from non-bot users
653+ bot_filter = " and ".join([f'.user.login != "{b}"' for b in BOT_LOGINS])
654+ try:
655+ reviews_raw = gh("api", f"repos/{REPO}/pulls/{pr_number}/reviews",
656+ "--jq", f'[.[] | select(.state == "CHANGES_REQUESTED" and {bot_filter})] | length')
657+ changes_requested = int(reviews_raw) if reviews_raw else 0
658+ except (ValueError, TypeError):
659+ changes_requested = 0
660+
661+ if changes_requested > 0:
662+ return True, "changes requested"
663+
664+ return False, "healthy"
665+
666+ # Get all open ambient-code:managed PRs
556667 prs_json = gh("pr", "list", "--repo", REPO, "--state", "open",
557668 "--label", "ambient-code:managed", "--limit", "200",
558- "--json", "number,body,title,updatedAt ")
669+ "--json", "number,body,title")
559670 prs = json.loads(prs_json) if prs_json else []
560671 print(f"Found {len(prs)} ambient-code:managed PRs")
561672
@@ -576,12 +687,13 @@ jobs:
576687 session_id = fm["session_id"]
577688 source = fm["source"]
578689
579- # Check for changes using updatedAt from gh pr list (no extra API call)
580- updated_at = pr.get("updatedAt", "" )
581- if updated_at and updated_at <= fm["last_action"] :
582- print(f"PR #{number}: no changes since {fm['last_action']} (updatedAt={updated_at}) , skipping")
690+ # Only trigger if the PR actually needs work
691+ needs_work, reason = needs_attention(number )
692+ if not needs_work :
693+ print(f"PR #{number}: {reason} , skipping")
583694 skipped += 1
584695 continue
696+ print(f"PR #{number}: {reason}")
585697
586698 # Trigger fix — reuse session if exists, create new if not
587699 print(f"PR #{number}: triggering fix (session_id={session_id or 'new'})")
@@ -602,12 +714,28 @@ jobs:
602714 4. Ensure the PR body contains this frontmatter as the first line
603715 (read your session ID from the AGENTIC_SESSION_NAME environment variable):
604716 <!-- acp:session_id=$AGENTIC_SESSION_NAME source={source} last_action=<ISO8601_NOW> retry_count=<N> -->
605- The current retry_count is {current_retry}. Increment it by 1.
717+ The current retry_count is {current_retry}. Only increment retry_count if
718+ you actually had to fix something (CI failure, conflict, review comment).
719+ If the PR is already healthy (CI green, no conflicts, no open reviews),
720+ do NOT increment — just update last_action.
606721 If retry_count reaches 3 or more, stop working, add `ambient-code:needs-human` label,
607722 remove `ambient-code:managed` label, comment on the PR, and send a Slack notification.
608723 5. Add the `ambient-code:managed` label.
609724 6. Do not merge. Do not close. Do not force-push.
610725 7. If fundamentally broken beyond repair, add a comment explaining and stop.
726+ 8. When you comment on the PR, include this footer at the end:
727+ _🤖 [Session](<SESSION_URL>)_
728+
729+ ## Session URL
730+
731+ IMPORTANT: Wherever a session link is needed (PR body, comments, Slack),
732+ you MUST first resolve the URL by reading the environment variables. Run:
733+ ```bash
734+ echo "$PLATFORM_HOST/projects/$AGENTIC_SESSION_NAMESPACE/sessions/$AGENTIC_SESSION_NAME"
735+ ```
736+ Use the resolved output as the actual URL. Do NOT write `$PLATFORM_HOST`,
737+ `$AGENTIC_SESSION_NAMESPACE`, or `$AGENTIC_SESSION_NAME` literally in any
738+ markdown link — always substitute their actual values.
611739
612740 ## Slack Notifications
613741
0 commit comments