Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/daily-team-status.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/smoke-claude.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/smoke-codex.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/smoke-copilot.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

174 changes: 174 additions & 0 deletions actions/setup/js/handle_agent_failure.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,161 @@ const { getFooterAgentFailureIssueMessage, getFooterAgentFailureCommentMessage,
const { renderTemplate } = require("./messages_core.cjs");
const fs = require("fs");

/**
* Search for or create the parent issue for all agentic workflow failures
* @returns {Promise<{number: number, node_id: string}>} Parent issue number and node ID
*/
async function ensureParentIssue() {
const { owner, repo } = context.repo;
const parentTitle = "[aw] Agentic Workflow Issues";
const parentLabel = "agentic-workflows";

core.info(`Searching for parent issue: "${parentTitle}"`);

// Search for existing parent issue
const searchQuery = `repo:${owner}/${repo} is:issue is:open label:${parentLabel} in:title "${parentTitle}"`;

try {
const searchResult = await github.rest.search.issuesAndPullRequests({
q: searchQuery,
per_page: 1,
});

if (searchResult.data.total_count > 0) {
const existingIssue = searchResult.data.items[0];
core.info(`Found existing parent issue #${existingIssue.number}: ${existingIssue.html_url}`);
return {
number: existingIssue.number,
node_id: existingIssue.node_id,
};
}
} catch (error) {
core.warning(`Error searching for parent issue: ${getErrorMessage(error)}`);
}

// Create parent issue if it doesn't exist
core.info("No parent issue found, creating one");

const parentBodyContent = `# Agentic Workflow Failures

This issue tracks all failures from agentic workflows in this repository. Each failed workflow run creates a sub-issue linked here for organization and easy filtering.

## Purpose

This parent issue helps you:
- View all workflow failures in one place by checking the sub-issues below
- Filter out failure issues from your main issue list using \`no:parent-issue\`
- Track the health of your agentic workflows over time

## Sub-Issues

All individual workflow failure issues are linked as sub-issues below. Click on any sub-issue to see details about a specific failure.

## Troubleshooting Failed Workflows

### Using debug-agentic-workflow Agent (Recommended)

The fastest way to investigate a failure is with the **debug-agentic-workflow** custom agent:

1. In GitHub Copilot Chat, type \`/agent\` and select **debug-agentic-workflow**
2. When prompted, provide the workflow run URL
3. The agent will help you analyze logs, identify root causes, and suggest fixes

### Using gh-aw CLI

You can also debug failures using the \`gh-aw\` CLI:

\`\`\`bash
# Download and analyze workflow logs
gh aw logs <workflow-run-url>

# Audit a specific workflow run
gh aw audit <run-id>
\`\`\`

### Manual Investigation

1. Click on a sub-issue to see the failed workflow details
2. Follow the workflow run link in the issue
3. Review the agent job logs for error messages
4. Check the workflow configuration in your repository

## Resources

- [GitHub Agentic Workflows Documentation](https://github.com/githubnext/gh-aw)
- [Troubleshooting Guide](https://github.com/githubnext/gh-aw/blob/main/docs/troubleshooting.md)

---

> This issue is automatically managed by GitHub Agentic Workflows. Do not close this issue manually.`;

// Add expiration marker (7 days from now)
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + 7);
const parentBody = `${parentBodyContent}\n\n<!-- gh-aw-expires: ${expirationDate.toISOString()} -->`;

try {
const newIssue = await github.rest.issues.create({
owner,
repo,
title: parentTitle,
body: parentBody,
labels: [parentLabel],
});

core.info(`✓ Created parent issue #${newIssue.data.number}: ${newIssue.data.html_url}`);
return {
number: newIssue.data.number,
node_id: newIssue.data.node_id,
};
} catch (error) {
core.error(`Failed to create parent issue: ${getErrorMessage(error)}`);
throw error;
}
}

/**
* Link an issue as a sub-issue to a parent issue
* @param {string} parentNodeId - GraphQL node ID of the parent issue
* @param {string} subIssueNodeId - GraphQL node ID of the sub-issue
* @param {number} parentNumber - Parent issue number (for logging)
* @param {number} subIssueNumber - Sub-issue number (for logging)
*/
async function linkSubIssue(parentNodeId, subIssueNodeId, parentNumber, subIssueNumber) {
core.info(`Linking issue #${subIssueNumber} as sub-issue of #${parentNumber}`);

try {
// Use GraphQL to link the sub-issue
await github.graphql(
`mutation($parentId: ID!, $subIssueId: ID!) {
addSubIssue(input: {issueId: $parentId, subIssueId: $subIssueId}) {
issue {
id
number
}
subIssue {
id
number
}
}
}`,
{
parentId: parentNodeId,
subIssueId: subIssueNodeId,
}
);

core.info(`✓ Successfully linked #${subIssueNumber} as sub-issue of #${parentNumber}`);
} catch (error) {
const errorMessage = getErrorMessage(error);
if (errorMessage.includes("Field 'addSubIssue' doesn't exist") || errorMessage.includes("not yet available")) {
core.warning(`Sub-issue API not available. Issue #${subIssueNumber} created but not linked to parent.`);
} else {
core.warning(`Failed to link sub-issue: ${errorMessage}`);
}
}
}

/**
* Handle agent job failure by creating or updating a failure tracking issue
* This script is called from the conclusion job when the agent job has failed
Expand All @@ -31,6 +186,15 @@ async function main() {

const { owner, repo } = context.repo;

// Ensure parent issue exists first
let parentIssue;
try {
parentIssue = await ensureParentIssue();
} catch (error) {
core.warning(`Could not create parent issue, proceeding without parent: ${getErrorMessage(error)}`);
// Continue without parent issue
}

// Sanitize workflow name for title
const sanitizedWorkflowName = sanitizeContent(workflowName, { maxLength: 100 });
const issueTitle = `[aw] ${sanitizedWorkflowName} failed`;
Expand Down Expand Up @@ -181,6 +345,16 @@ The debug agent will help you:
});

core.info(`✓ Created new issue #${newIssue.data.number}: ${newIssue.data.html_url}`);

// Link as sub-issue to parent if parent issue was created
if (parentIssue) {
try {
await linkSubIssue(parentIssue.node_id, newIssue.data.node_id, parentIssue.number, newIssue.data.number);
} catch (error) {
core.warning(`Could not link issue as sub-issue: ${getErrorMessage(error)}`);
// Continue even if linking fails
}
}
}
} catch (error) {
core.warning(`Failed to create or update failure tracking issue: ${getErrorMessage(error)}`);
Expand Down
Loading