feat(platform/copilot): Agent-Building Mode - compaction-proof guide + automatic engine switch #11316
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: AutoGPT Platform - Dev Deploy PR Event Dispatcher | |
| on: | |
| pull_request: | |
| types: [closed, synchronize] | |
| issue_comment: | |
| types: [created] | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| jobs: | |
| dispatch: | |
| runs-on: ubuntu-latest | |
| # Serialize per PR so rapid pushes/comments don't race each other's | |
| # dispatches. Deliberately NOT cancel-in-progress: cancelling could kill an | |
| # in-flight !undeploy dispatch when a push lands right after it. | |
| concurrency: | |
| group: preview-dispatch-${{ github.event.pull_request.number || github.event.issue.number }} | |
| steps: | |
| - name: Check comment permissions and deployment status | |
| id: check_status | |
| if: github.event_name == 'issue_comment' && github.event.issue.pull_request | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const commentBody = context.payload.comment.body.trim(); | |
| const commentUser = context.payload.comment.user.login; | |
| const prAuthor = context.payload.issue.user.login; | |
| const authorAssociation = context.payload.comment.author_association; | |
| // Check permissions | |
| const hasPermission = ( | |
| authorAssociation === 'OWNER' || | |
| authorAssociation === 'MEMBER' || | |
| authorAssociation === 'COLLABORATOR' | |
| ); | |
| core.setOutput('comment_body', commentBody); | |
| core.setOutput('has_permission', hasPermission); | |
| if (!hasPermission && (commentBody === '!deploy' || commentBody === '!undeploy')) { | |
| core.setOutput('permission_denied', 'true'); | |
| return; | |
| } | |
| if (commentBody !== '!deploy' && commentBody !== '!undeploy') { | |
| return; | |
| } | |
| // Process deploy command | |
| if (commentBody === '!deploy') { | |
| core.setOutput('should_deploy', 'true'); | |
| } | |
| // Process undeploy command | |
| else if (commentBody === '!undeploy') { | |
| core.setOutput('should_undeploy', 'true'); | |
| } | |
| - name: Post permission denied comment | |
| if: steps.check_status.outputs.permission_denied == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `❌ **Permission denied**: Only the repository owners, members, or collaborators can use deployment commands.` | |
| }); | |
| - name: Get PR details for deployment | |
| id: pr_details | |
| if: steps.check_status.outputs.should_deploy == 'true' || steps.check_status.outputs.should_undeploy == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const pr = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number | |
| }); | |
| core.setOutput('pr_number', pr.data.number); | |
| core.setOutput('pr_title', pr.data.title); | |
| core.setOutput('pr_state', pr.data.state); | |
| - name: Dispatch Deploy Event | |
| if: steps.check_status.outputs.should_deploy == 'true' | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.DISPATCH_TOKEN }} | |
| repository: Significant-Gravitas/AutoGPT_cloud_infrastructure | |
| event-type: pr-event | |
| client-payload: | | |
| { | |
| "action": "deploy", | |
| "pr_number": "${{ steps.pr_details.outputs.pr_number }}", | |
| "pr_title": ${{ toJSON(steps.pr_details.outputs.pr_title) }}, | |
| "pr_state": "${{ steps.pr_details.outputs.pr_state }}", | |
| "repo": "${{ github.repository }}" | |
| } | |
| - name: Post deploy success comment | |
| if: steps.check_status.outputs.should_deploy == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `🚀 **Deploying PR #${{ steps.pr_details.outputs.pr_number }}** to development environment...` | |
| }); | |
| - name: Dispatch Undeploy Event (from comment) | |
| if: steps.check_status.outputs.should_undeploy == 'true' | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.DISPATCH_TOKEN }} | |
| repository: Significant-Gravitas/AutoGPT_cloud_infrastructure | |
| event-type: pr-event | |
| client-payload: | | |
| { | |
| "action": "undeploy", | |
| "pr_number": "${{ steps.pr_details.outputs.pr_number }}", | |
| "pr_title": ${{ toJSON(steps.pr_details.outputs.pr_title) }}, | |
| "pr_state": "${{ steps.pr_details.outputs.pr_state }}", | |
| "repo": "${{ github.repository }}" | |
| } | |
| - name: Post undeploy success comment | |
| if: steps.check_status.outputs.should_undeploy == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `🗑️ **Undeploying PR #${{ steps.pr_details.outputs.pr_number }}** from development environment...` | |
| }); | |
| - name: Check deployment status on PR close | |
| id: check_pr_close | |
| if: github.event_name == 'pull_request' && github.event.action == 'closed' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| // Paginate: listComments returns only the first 30 by default, so a | |
| // later !deploy/!undeploy on a busy PR would be missed and corrupt the | |
| // active-deployment scan. | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| per_page: 100 | |
| }); | |
| let lastDeployIndex = -1; | |
| let lastUndeployIndex = -1; | |
| comments.forEach((comment, index) => { | |
| if (comment.body.trim() === '!deploy') { | |
| lastDeployIndex = index; | |
| } else if (comment.body.trim() === '!undeploy') { | |
| lastUndeployIndex = index; | |
| } | |
| }); | |
| // Should undeploy if there's a !deploy without a subsequent !undeploy | |
| const shouldUndeploy = lastDeployIndex !== -1 && lastDeployIndex > lastUndeployIndex; | |
| core.setOutput('should_undeploy', shouldUndeploy); | |
| - name: Dispatch Undeploy Event (PR closed with active deployment) | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'closed' && | |
| steps.check_pr_close.outputs.should_undeploy == 'true' | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.DISPATCH_TOKEN }} | |
| repository: Significant-Gravitas/AutoGPT_cloud_infrastructure | |
| event-type: pr-event | |
| client-payload: | | |
| { | |
| "action": "undeploy", | |
| "pr_number": "${{ github.event.pull_request.number }}", | |
| "pr_title": ${{ toJSON(github.event.pull_request.title) }}, | |
| "pr_state": "${{ github.event.pull_request.state }}", | |
| "repo": "${{ github.repository }}" | |
| } | |
| - name: Post PR close undeploy comment | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'closed' && | |
| steps.check_pr_close.outputs.should_undeploy == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `🧹 **Auto-undeploying**: PR closed with active deployment. Cleaning up development environment for PR #${{ github.event.pull_request.number }}.` | |
| }); | |
| # Auto-redeploy: previews go stale silently when a PR is pushed to and nobody | |
| # remembers to re-run !deploy. Reuse the close-handler's active-deployment scan | |
| # (last !deploy with no later !undeploy) and refresh the preview if one is active. | |
| - name: Check deployment status on PR update | |
| id: check_pr_sync | |
| # Same-repo branches only: a fork author must not be able to push | |
| # unreviewed code onto a preview that a collaborator !deployed once. | |
| # Fork PRs keep the manual !deploy flow (explicit human per update). | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'synchronize' && | |
| github.event.pull_request.head.repo.full_name == github.repository | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| // Paginate: listComments returns only the first 30 by default, so a | |
| // later !deploy/!undeploy on a busy PR would be missed and corrupt the | |
| // active-deployment scan. | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| per_page: 100 | |
| }); | |
| let lastDeployIndex = -1; | |
| let lastUndeployIndex = -1; | |
| // Unlike the close/undeploy scan, this path TRIGGERS a deploy, so | |
| // only commands from authorized authors count — otherwise a | |
| // drive-by !deploy comment (ignored by the comment handler's | |
| // permission gate) would arm auto-redeploy for the next push. | |
| const allowed = ['OWNER', 'MEMBER', 'COLLABORATOR']; | |
| comments.forEach((comment, index) => { | |
| if (!allowed.includes(comment.author_association)) return; | |
| if (comment.body.trim() === '!deploy') { | |
| lastDeployIndex = index; | |
| } else if (comment.body.trim() === '!undeploy') { | |
| lastUndeployIndex = index; | |
| } | |
| }); | |
| // Redeploy only if there's an active deployment (a !deploy without a subsequent !undeploy) | |
| const shouldDeploy = lastDeployIndex !== -1 && lastDeployIndex > lastUndeployIndex; | |
| core.setOutput('should_deploy', shouldDeploy); | |
| - name: Dispatch Deploy Event (PR updated with active deployment) | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'synchronize' && | |
| steps.check_pr_sync.outputs.should_deploy == 'true' | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.DISPATCH_TOKEN }} | |
| repository: Significant-Gravitas/AutoGPT_cloud_infrastructure | |
| event-type: pr-event | |
| client-payload: | | |
| { | |
| "action": "deploy", | |
| "pr_number": "${{ github.event.pull_request.number }}", | |
| "pr_title": ${{ toJSON(github.event.pull_request.title) }}, | |
| "pr_state": "${{ github.event.pull_request.state }}", | |
| "repo": "${{ github.repository }}" | |
| } | |
| - name: Post PR update redeploy comment | |
| if: >- | |
| github.event_name == 'pull_request' && | |
| github.event.action == 'synchronize' && | |
| steps.check_pr_sync.outputs.should_deploy == 'true' | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `🔄 **Auto-redeploying**: new commits pushed to a PR with an active deployment. Refreshing development environment for PR #${{ github.event.pull_request.number }}.` | |
| }); |