Explorar o código

fix: remove AI triage workflow

The GitHub Models API requires specialized authentication that is not available
through secrets.GITHUB_TOKEN. The workflow consistently fails with 401 Unauthorized.

The rule-based label automation (labeler.yml) continues to function correctly
and provides automated labeling based on structured template fields.
Daniel Gibbs hai 1 mes
pai
achega
a183369e55
Modificáronse 1 ficheiros con 0 adicións e 229 borrados
  1. 0 229
      .github/workflows/ai-triage.yml

+ 0 - 229
.github/workflows/ai-triage.yml

@@ -1,229 +0,0 @@
-name: AI Issue Triage
-on:
-  issues:
-    types:
-      - opened
-      - edited
-
-permissions:
-  issues: write
-  contents: read
-
-jobs:
-  ai-triage:
-    if: github.repository_owner == 'GameServerManagers'
-    runs-on: ubuntu-latest
-    steps:
-      - name: Triage issue with GitHub Models
-        uses: actions/github-script@v7
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        with:
-          script: |
-            const title  = context.payload.issue.title  || '';
-            const body   = context.payload.issue.body   || '';
-            const number = context.payload.issue.number;
-            const owner  = context.repo.owner;
-            const repo   = context.repo.repo;
-            const AI_MARKER = '<!-- ai-triage -->';
-
-            function parseTriageResponse(raw) {
-              const input = (raw || '').trim();
-              if (!input) return {};
-
-              const candidates = [input];
-              const fenced = input.match(/```(?:json)?\s*([\s\S]*?)```/i);
-              if (fenced?.[1]) candidates.push(fenced[1].trim());
-
-              const firstBrace = input.indexOf('{');
-              const lastBrace = input.lastIndexOf('}');
-              if (firstBrace !== -1 && lastBrace > firstBrace) {
-                candidates.push(input.slice(firstBrace, lastBrace + 1));
-              }
-
-              for (const candidate of candidates) {
-                try {
-                  return JSON.parse(candidate);
-                } catch (_err) {
-                  // Continue trying fallbacks.
-                }
-              }
-
-              return {};
-            }
-
-            // For short bodies, apply "needs: more info" label directly.
-            // Skip the AI call but still label the issue.
-            const isShortBody = body.trim().length < 80;
-            if (isShortBody) {
-              try {
-                await github.rest.issues.addLabels({
-                  owner, repo, issue_number: number,
-                  labels: ['needs: more info'],
-                });
-              } catch (err) {
-                console.log('Could not apply label for short body:', err.message);
-              }
-              return;
-            }
-
-            // ── Call GitHub Models ────────────────────────────────────────
-            let triage;
-            try {
-              const res = await fetch(
-                'https://models.inference.ai.azure.com/chat/completions',
-                {
-                  method: 'POST',
-                  headers: {
-                    'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
-                    'Content-Type': 'application/json',
-                  },
-                  body: JSON.stringify({
-                    model: 'gpt-4o-mini',
-                    temperature: 0.1,
-                    max_tokens: 400,
-                    messages: [
-                      {
-                        role: 'system',
-                        content:
-                          'You are a triage assistant for LinuxGSM, an open-source ' +
-                          'Linux game server manager. Your role is to:\n' +
-                          '1. Analyze issue quality (completeness, clarity)\n' +
-                          '2. Extract game names mentioned in the issue, even if misspelled or abbreviated\n' +
-                          '3. Suggest corrections for likely typos using fuzzy matching\n' +
-                          '4. Respond ONLY with a valid JSON object — no markdown fences.\n\n' +
-                          'Common game name variations and typos you should recognize:\n' +
-                          '- "Valhiem" → "Valheim"\n' +
-                          '- "Rrust" → "Rust"\n' +
-                          '- "Conterstrike" / "CS" / "CSGO" → "Counter-Strike: Global Offensive"\n' +
-                          '- "Garrys" / "GMod" → "Garrys Mod"\n' +
-                          '- "ARK" / "Ark" → "ARK: Survival Evolved"\n' +
-                          '- "DayZ" / "Dayz" → "DayZ"\n' +
-                          '- "Insurgency Sandstorm" / "Insurgency 2" → "Insurgency: Sandstorm"',
-                      },
-                      {
-                        role: 'user',
-                        content:
-                          `Title: ${title}\n\nBody:\n${body.slice(0, 3000)}\n\n` +
-                          'Respond with this JSON schema:\n' +
-                          '{\n' +
-                          '  "quality": "good" | "ok" | "poor",\n' +
-                          '  "missing_info": ["list of specific missing fields"],\n' +
-                          '  "detected_game": "canonical game name if one is mentioned, or null",\n' +
-                          '  "game_confidence": "high" | "medium" | "low" | null,\n' +
-                          '  "game_note": "correction suggestion if the user misspelled a game name, or empty string",\n' +
-                          '  "comment": "one or two sentence note to the reporter, or empty string"\n' +
-                          '}',
-                      },
-                    ],
-                  }),
-                }
-              );
-
-              if (!res.ok) {
-                console.log(`GitHub Models returned ${res.status} — skipping AI triage.`);
-                return;
-              }
-
-              const data = await res.json();
-              const raw  = data.choices?.[0]?.message?.content || '{}';
-              triage = parseTriageResponse(raw);
-            } catch (err) {
-              // Never fail the workflow if the AI call errors — it's advisory only.
-              console.log('AI triage skipped:', err.message);
-              return;
-            }
-
-            if (!triage || typeof triage !== 'object') {
-              triage = {};
-            }
-
-            // ── Act on the result ────────────────────────────────────────
-            const isPoor    = triage.quality === 'poor';
-            const missing   = Array.isArray(triage.missing_info) ? triage.missing_info : [];
-            const hasIssues = isPoor || missing.length > 0;
-
-            // Prepare labels to apply
-            const labelsToApply = [];
-
-            // Check if a game was detected with high confidence
-            const detectedGame = triage.detected_game;
-            const gameConfidence = triage.game_confidence;
-
-            if (detectedGame && gameConfidence === 'high') {
-              labelsToApply.push(`game: ${detectedGame}`);
-            }
-
-            // Apply "needs: more info" label if quality issues detected
-            if (hasIssues) {
-              labelsToApply.push('needs: more info');
-            }
-
-            // Apply labels one-by-one so a single failure does not block all labels.
-            const uniqueLabels = [...new Set(labelsToApply)];
-            for (const label of uniqueLabels) {
-              try {
-                await github.rest.issues.addLabels({
-                  owner,
-                  repo,
-                  issue_number: number,
-                  labels: [label],
-                });
-              } catch (err) {
-                console.log(`Could not apply label "${label}":`, err.message);
-              }
-            }
-
-            // Post a comment only when there is something specific to say
-            const gameNote = triage.game_note || '';
-            const reporterComment = triage.comment || '';
-
-            if (!hasIssues && !gameNote) return;
-
-            const missingBlock = missing.length > 0
-              ? `\n\n**Missing information:**\n${missing.map(m => `- ${m}`).join('\n')}`
-              : '';
-
-            const gameBlock = gameNote
-              ? `\n\n**Game name note:** ${gameNote}`
-              : '';
-
-            const triageCommentBody =
-              `${AI_MARKER}\n` +
-              `Thanks for opening this issue! 👋\n\n` +
-              `${reporterComment}` +
-              `${missingBlock}` +
-              `${gameBlock}\n\n` +
-              `_This note was generated automatically by AI triage and may not be perfect. ` +
-              `A maintainer will review shortly._`;
-
-            try {
-              const comments = await github.rest.issues.listComments({
-                owner,
-                repo,
-                issue_number: number,
-                per_page: 100,
-              });
-
-              const existingAiComment = comments.data.find(
-                (comment) => comment.user?.type === 'Bot' && comment.body?.includes(AI_MARKER)
-              );
-
-              if (existingAiComment) {
-                await github.rest.issues.updateComment({
-                  owner,
-                  repo,
-                  comment_id: existingAiComment.id,
-                  body: triageCommentBody,
-                });
-              } else {
-                await github.rest.issues.createComment({
-                  owner,
-                  repo,
-                  issue_number: number,
-                  body: triageCommentBody,
-                });
-              }
-            } catch (err) {
-              console.log('Could not post comment:', err.message);
-            }