diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml deleted file mode 100644 index a2aa1fa12..000000000 --- a/.github/workflows/ai-triage.yml +++ /dev/null @@ -1,205 +0,0 @@ -name: AI triage (comment + optional PR) - -on: -# issues: -# types: [opened] - issue_comment: - types: [created] - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - ai_first_reply: - runs-on: ubuntu-latest - # Run when: issue opened OR a '/codex' comment on an issue (not PR) - if: > - (github.event_name == 'issues' || - (github.event_name == 'issue_comment' && - github.event.action == 'created' && - github.event.comment.body == '/codex' && - github.event.issue.pull_request == null)) - && contains(github.event.issue.labels.*.name, 'bug') - steps: - - name: Compose and post AI reply - uses: actions/github-script@v7 - env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - with: - script: | - const issue = context.payload.issue; - const { owner, repo } = context.repo; - - // Optional repo context - let readmeText = ''; - try { - const readme = await github.rest.repos.getReadme({ owner, repo }); - readmeText = Buffer.from(readme.data.content, 'base64').toString('utf8'); - if (readmeText.length > 18000) readmeText = readmeText.slice(0, 18000) + "\n...[truncated]..."; - } catch {} - - const system = ` - You are an open-source triage assistant. - Write a concise, actionable first reply for a new bug report. - Focus on diagnosing the problem and suggesting potential fixes. - Minimize follow-up questions and avoid inventing repo facts. - Propose next steps and link to repo files only when certain. - `.trim(); - - const user = ` - Repository: ${owner}/${repo} - Issue #${issue.number}: ${issue.title} - - Issue body: - ${issue.body || '(no body provided)'} - - README excerpt: - ${readmeText || '(none)'} - `.trim(); - - const res = await fetch('https://api.openai.com/v1/responses', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`, - }, - body: JSON.stringify({ - model: 'gpt-4o-mini', - input: [ - { role: 'system', content: system }, - { role: 'user', content: user } - ], - }), - }); - - if (!res.ok) { - const txt = await res.text(); - await github.rest.issues.createComment({ - owner, repo, issue_number: issue.number, - body: `⚠️ AI reply failed (${res.status}).\n\n\`\`\`\n${txt}\n\`\`\`` - }); - return; - } - - const data = await res.json(); - const text = data.output_text - || data.output?.map(p => p.content?.map(c => c.text ?? '').join('')).join('\n') - || data?.choices?.[0]?.message?.content - || 'Thanks for opening this issue — we will take a look!'; - - await github.rest.issues.createComment({ - owner, repo, issue_number: issue.number, body: text - }); - - ai_autofix_pr: - runs-on: ubuntu-latest - needs: ai_first_reply - # Same trigger conditions as above AND issue has label 'auto-pr' - if: > - (github.event_name == 'issues' || - (github.event_name == 'issue_comment' && - github.event.action == 'created' && - github.event.comment.body == '/codex' && - github.event.issue.pull_request == null)) - && contains(github.event.issue.labels.*.name, 'auto-pr') - && contains(github.event.issue.labels.*.name, 'bug') - steps: - - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - - name: Generate patch with OpenAI (unified diff) - id: genpatch - uses: actions/github-script@v7 - env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - with: - result-encoding: string - script: | - const { owner, repo } = context.repo; - const issue = context.payload.issue; - - let readmeText = ''; - try { - const readme = await github.rest.repos.getReadme({ owner, repo }); - readmeText = Buffer.from(readme.data.content, 'base64').toString('utf8'); - if (readmeText.length > 12000) readmeText = readmeText.slice(0, 12000) + "\n...[truncated]..."; - } catch {} - - const system = ` - You are a code-change generator. - Output ONLY a git unified diff (git apply compatible). No prose, no backticks. - Keep changes minimal and safe; if unsure, output an empty diff. - `.trim(); - - const user = ` - Repo: ${owner}/${repo} - Issue #${issue.number}: ${issue.title} - - Issue body: - ${issue.body || '(no body)'} - - README excerpt: - ${readmeText || '(none)'} - `.trim(); - - const res = await fetch('https://api.openai.com/v1/responses', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`, - }, - body: JSON.stringify({ - model: 'gpt-4o-mini', - input: [ - { role: 'system', content: system }, - { role: 'user', content: user } - ], - }), - }); - - if (!res.ok) { - const txt = await res.text(); - core.setFailed(`OpenAI error ${res.status}: ${txt}`); - } else { - const data = await res.json(); - const patch = ( - data.output_text - || data.output?.map(p => p.content?.map(c => c.text ?? '').join('')).join('\n') - || data?.choices?.[0]?.message?.content - || '' - ).trim(); - return patch; - } - - - name: Apply patch (if any) - id: apply - shell: bash - run: | - set -euo pipefail - patch="${{ steps.genpatch.outputs.result }}" - if [ -z "$patch" ]; then - echo "No patch produced; skipping PR." - echo "skip_pr=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "$patch" > ai.patch - git apply --whitespace=fix ai.patch - echo "skip_pr=false" >> "$GITHUB_OUTPUT" - - - name: Create Pull Request - if: steps.apply.outputs.skip_pr == 'false' - uses: peter-evans/create-pull-request@v7 - with: - branch: ai/autofix-${{ github.event.issue.number }} - title: AI autofix for #${{ github.event.issue.number }} - commit-message: AI autofix for #${{ github.event.issue.number }} - body: | - This PR was generated automatically from issue #${{ github.event.issue.number }}. - - Label `auto-pr` triggered patch creation. Please review carefully. - labels: auto-pr, ai-generated - delete-branch: true